diff --git a/common/types.go b/common/types.go index 93fb0904545e..b1de56073b6e 100644 --- a/common/types.go +++ b/common/types.go @@ -19,6 +19,7 @@ package common import ( "bytes" "database/sql/driver" + "encoding/binary" "encoding/hex" "encoding/json" "errors" @@ -65,6 +66,13 @@ func BigToHash(b *big.Int) Hash { return BytesToHash(b.Bytes()) } // If b is larger than len(h), b will be cropped from the left. func HexToHash(s string) Hash { return BytesToHash(FromHex(s)) } +// Uint64ToHash sets the lowest 8 bytes of hash to u in big endian format. +func Uint64ToHash(u uint64) Hash { + var h Hash + binary.BigEndian.PutUint64(h[24:], u) + return h +} + // Less compares two hashes. func (h Hash) Less(other Hash) bool { return bytes.Compare(h[:], other[:]) < 0 diff --git a/consensus/misc/eip4788.go b/consensus/misc/eip4788.go new file mode 100644 index 000000000000..6a1fae0115bb --- /dev/null +++ b/consensus/misc/eip4788.go @@ -0,0 +1,47 @@ +// Copyright 2023 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see . + +package misc + +import ( + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/state" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/params" +) + +// ApplyBeaconRoot adds the beacon root from the header to the state. +func ApplyBeaconRoot(header *types.Header, state *state.StateDB) { + // If EIP-4788 is enabled, we need to store the block root + timeKey, time, rootKey, root := calcBeaconRootIndices(header) + state.SetState(params.BeaconRootsStorageAddress, timeKey, time) + state.SetState(params.BeaconRootsStorageAddress, rootKey, root) + // We also need to ensure that the BeaconRoot address has nonzero nonce. + if state.GetNonce(params.BeaconRootsStorageAddress) == 0 { + state.SetNonce(params.BeaconRootsStorageAddress, 1) + } +} + +func calcBeaconRootIndices(header *types.Header) (timeKey, time, rootKey, root common.Hash) { + // timeKey -> header.Time + timeIndex := header.Time % params.HistoricalRootsModulus + timeKey = common.Uint64ToHash(timeIndex) + time = common.Uint64ToHash(header.Time) + // rootKey -> header.BeaconRoot + rootKey = common.Uint64ToHash(timeIndex + params.HistoricalRootsModulus) + root = *header.BeaconRoot + return +} diff --git a/consensus/misc/eip4788_test.go b/consensus/misc/eip4788_test.go new file mode 100644 index 000000000000..5b1f581993af --- /dev/null +++ b/consensus/misc/eip4788_test.go @@ -0,0 +1,63 @@ +// Copyright 2023 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see . + +package misc + +import ( + "encoding/json" + "os" + "testing" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" +) + +type tcInput struct { + HeaderTime uint64 + HeaderBeaconRoot common.Hash + + TimeKey common.Hash + Time common.Hash + RootKey common.Hash + Root common.Hash +} + +func TestCalcBeaconRootIndices(t *testing.T) { + data, err := os.ReadFile("./testdata/eip4788_beaconroot.json") + if err != nil { + t.Fatal(err) + } + var tests []tcInput + if err := json.Unmarshal(data, &tests); err != nil { + t.Fatal(err) + } + for i, tc := range tests { + header := types.Header{Time: tc.HeaderTime, BeaconRoot: &tc.HeaderBeaconRoot} + haveTimeKey, haveTime, haveRootKey, haveRoot := calcBeaconRootIndices(&header) + if haveTimeKey != tc.TimeKey { + t.Errorf("test %d: invalid time key: \nhave %v\nwant %v", i, haveTimeKey, tc.TimeKey) + } + if haveTime != tc.Time { + t.Errorf("test %d: invalid time: \nhave %v\nwant %v", i, haveTime, tc.Time) + } + if haveRootKey != tc.RootKey { + t.Errorf("test %d: invalid root key: \nhave %v\nwant %v", i, haveRootKey, tc.RootKey) + } + if haveRoot != tc.Root { + t.Errorf("test %d: invalid root: \nhave %v\nwant %v", i, haveRoot, tc.Root) + } + } +} diff --git a/consensus/misc/testdata/eip4788_beaconroot.json b/consensus/misc/testdata/eip4788_beaconroot.json new file mode 100644 index 000000000000..3279d3ff5de0 --- /dev/null +++ b/consensus/misc/testdata/eip4788_beaconroot.json @@ -0,0 +1,26 @@ +[ + { + "HeaderTime": 0, + "HeaderBeaconRoot": "0x0100000000000000000000000000000000000000000000000000000000000000", + "TimeKey": "0x0000000000000000000000000000000000000000000000000000000000000000", + "Time": "0x0000000000000000000000000000000000000000000000000000000000000000", + "RootKey": "0x0000000000000000000000000000000000000000000000000000000000018000", + "Root": "0x0100000000000000000000000000000000000000000000000000000000000000" + }, + { + "HeaderTime": 120265298769267, + "HeaderBeaconRoot": "0xfffefc0000000000000000000000000000000000000000000000000000000000", + "TimeKey": "0x000000000000000000000000000000000000000000000000000000000000f573", + "Time": "0x00000000000000000000000000000000000000000000000000006d6172697573", + "RootKey": "0x0000000000000000000000000000000000000000000000000000000000027573", + "Root": "0xfffefc0000000000000000000000000000000000000000000000000000000000" + }, + { + "HeaderTime": 18446744073709551615, + "HeaderBeaconRoot": "0xfffefcffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "TimeKey": "0x000000000000000000000000000000000000000000000000000000000000ffff", + "Time": "0x000000000000000000000000000000000000000000000000ffffffffffffffff", + "RootKey": "0x0000000000000000000000000000000000000000000000000000000000027fff", + "Root": "0xfffefcffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" + } +] \ No newline at end of file diff --git a/core/state_processor.go b/core/state_processor.go index fcaf5a8ff3c9..2431eb937eef 100644 --- a/core/state_processor.go +++ b/core/state_processor.go @@ -71,6 +71,15 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg if p.config.DAOForkSupport && p.config.DAOForkBlock != nil && p.config.DAOForkBlock.Cmp(block.Number()) == 0 { misc.ApplyDAOHardFork(statedb) } + if p.config.IsCancun(blockNumber, block.Time()) { + if header.BeaconRoot == nil { + return nil, nil, 0, errors.New("expected beacon root post-cancun") + } + misc.ApplyBeaconRoot(header, statedb) + } else if header.BeaconRoot != nil { + return nil, nil, 0, errors.New("beacon root set pre-cancun") + } + var ( context = NewEVMBlockContext(header, p.bc, nil) vmenv = vm.NewEVM(context, vm.TxContext{}, statedb, p.config, cfg) diff --git a/core/types/block.go b/core/types/block.go index 4452f4bb21f8..1ca822323337 100644 --- a/core/types/block.go +++ b/core/types/block.go @@ -90,6 +90,9 @@ type Header struct { // ExcessBlobGas was added by EIP-4844 and is ignored in legacy headers. ExcessBlobGas *uint64 `json:"excessBlobGas" rlp:"optional"` + + // BeaconRoot was added by EIP-4788 and is ignored in legacy headers. + BeaconRoot *common.Hash `json:"beaconRoot" rlp:"optional"` } // field type overrides for gencodec @@ -378,6 +381,10 @@ func (b *Block) BlobGasUsed() *uint64 { return blobGasUsed } +func (b *Block) BeaconRoot() *common.Hash { + return b.header.BeaconRoot +} + func (b *Block) Header() *Header { return CopyHeader(b.header) } // Body returns the non-header content of the block. diff --git a/core/vm/contracts.go b/core/vm/contracts.go index 6041be6c9f49..f3455c69d51e 100644 --- a/core/vm/contracts.go +++ b/core/vm/contracts.go @@ -34,12 +34,16 @@ import ( "golang.org/x/crypto/ripemd160" ) +type StateReader interface { + GetState(common.Address, common.Hash) common.Hash +} + // PrecompiledContract is the basic interface for native Go contracts. The implementation // requires a deterministic gas count based on the input size of the Run method of the // contract. type PrecompiledContract interface { - RequiredGas(input []byte) uint64 // RequiredPrice calculates the contract gas use - Run(input []byte) ([]byte, error) // Run runs the precompiled contract + RequiredGas(input []byte) uint64 // RequiredPrice calculates the contract gas use + Run(statedb StateReader, input []byte) ([]byte, error) // Run runs the precompiled contract } // PrecompiledContractsHomestead contains the default set of pre-compiled Ethereum @@ -105,6 +109,7 @@ var PrecompiledContractsCancun = map[common.Address]PrecompiledContract{ common.BytesToAddress([]byte{8}): &bn256PairingIstanbul{}, common.BytesToAddress([]byte{9}): &blake2F{}, common.BytesToAddress([]byte{20}): &kzgPointEvaluation{}, + params.BeaconRootsStorageAddress: &beaconRoot{}, } // PrecompiledContractsBLS contains the set of pre-compiled Ethereum @@ -168,13 +173,13 @@ func ActivePrecompiles(rules params.Rules) []common.Address { // - the returned bytes, // - the _remaining_ gas, // - any error that occurred -func RunPrecompiledContract(p PrecompiledContract, input []byte, suppliedGas uint64) (ret []byte, remainingGas uint64, err error) { +func RunPrecompiledContract(stateDB StateReader, p PrecompiledContract, input []byte, suppliedGas uint64) (ret []byte, remainingGas uint64, err error) { gasCost := p.RequiredGas(input) if suppliedGas < gasCost { return nil, 0, ErrOutOfGas } suppliedGas -= gasCost - output, err := p.Run(input) + output, err := p.Run(stateDB, input) return output, suppliedGas, err } @@ -185,7 +190,7 @@ func (c *ecrecover) RequiredGas(input []byte) uint64 { return params.EcrecoverGas } -func (c *ecrecover) Run(input []byte) ([]byte, error) { +func (c *ecrecover) Run(stateDB StateReader, input []byte) ([]byte, error) { const ecRecoverInputLength = 128 input = common.RightPadBytes(input, ecRecoverInputLength) @@ -226,7 +231,7 @@ type sha256hash struct{} func (c *sha256hash) RequiredGas(input []byte) uint64 { return uint64(len(input)+31)/32*params.Sha256PerWordGas + params.Sha256BaseGas } -func (c *sha256hash) Run(input []byte) ([]byte, error) { +func (c *sha256hash) Run(stateDB StateReader, input []byte) ([]byte, error) { h := sha256.Sum256(input) return h[:], nil } @@ -241,7 +246,7 @@ type ripemd160hash struct{} func (c *ripemd160hash) RequiredGas(input []byte) uint64 { return uint64(len(input)+31)/32*params.Ripemd160PerWordGas + params.Ripemd160BaseGas } -func (c *ripemd160hash) Run(input []byte) ([]byte, error) { +func (c *ripemd160hash) Run(stateDB StateReader, input []byte) ([]byte, error) { ripemd := ripemd160.New() ripemd.Write(input) return common.LeftPadBytes(ripemd.Sum(nil), 32), nil @@ -257,8 +262,8 @@ type dataCopy struct{} func (c *dataCopy) RequiredGas(input []byte) uint64 { return uint64(len(input)+31)/32*params.IdentityPerWordGas + params.IdentityBaseGas } -func (c *dataCopy) Run(in []byte) ([]byte, error) { - return common.CopyBytes(in), nil +func (c *dataCopy) Run(stateDB StateReader, input []byte) ([]byte, error) { + return common.CopyBytes(input), nil } // bigModExp implements a native big integer exponential modular operation. @@ -383,7 +388,7 @@ func (c *bigModExp) RequiredGas(input []byte) uint64 { return gas.Uint64() } -func (c *bigModExp) Run(input []byte) ([]byte, error) { +func (c *bigModExp) Run(stateDB StateReader, input []byte) ([]byte, error) { var ( baseLen = new(big.Int).SetBytes(getData(input, 0, 32)).Uint64() expLen = new(big.Int).SetBytes(getData(input, 32, 32)).Uint64() @@ -463,7 +468,7 @@ func (c *bn256AddIstanbul) RequiredGas(input []byte) uint64 { return params.Bn256AddGasIstanbul } -func (c *bn256AddIstanbul) Run(input []byte) ([]byte, error) { +func (c *bn256AddIstanbul) Run(stateDB StateReader, input []byte) ([]byte, error) { return runBn256Add(input) } @@ -476,7 +481,7 @@ func (c *bn256AddByzantium) RequiredGas(input []byte) uint64 { return params.Bn256AddGasByzantium } -func (c *bn256AddByzantium) Run(input []byte) ([]byte, error) { +func (c *bn256AddByzantium) Run(stateDB StateReader, input []byte) ([]byte, error) { return runBn256Add(input) } @@ -501,7 +506,7 @@ func (c *bn256ScalarMulIstanbul) RequiredGas(input []byte) uint64 { return params.Bn256ScalarMulGasIstanbul } -func (c *bn256ScalarMulIstanbul) Run(input []byte) ([]byte, error) { +func (c *bn256ScalarMulIstanbul) Run(stateDB StateReader, input []byte) ([]byte, error) { return runBn256ScalarMul(input) } @@ -514,7 +519,7 @@ func (c *bn256ScalarMulByzantium) RequiredGas(input []byte) uint64 { return params.Bn256ScalarMulGasByzantium } -func (c *bn256ScalarMulByzantium) Run(input []byte) ([]byte, error) { +func (c *bn256ScalarMulByzantium) Run(stateDB StateReader, input []byte) ([]byte, error) { return runBn256ScalarMul(input) } @@ -569,7 +574,7 @@ func (c *bn256PairingIstanbul) RequiredGas(input []byte) uint64 { return params.Bn256PairingBaseGasIstanbul + uint64(len(input)/192)*params.Bn256PairingPerPointGasIstanbul } -func (c *bn256PairingIstanbul) Run(input []byte) ([]byte, error) { +func (c *bn256PairingIstanbul) Run(stateDB StateReader, input []byte) ([]byte, error) { return runBn256Pairing(input) } @@ -582,7 +587,7 @@ func (c *bn256PairingByzantium) RequiredGas(input []byte) uint64 { return params.Bn256PairingBaseGasByzantium + uint64(len(input)/192)*params.Bn256PairingPerPointGasByzantium } -func (c *bn256PairingByzantium) Run(input []byte) ([]byte, error) { +func (c *bn256PairingByzantium) Run(stateDB StateReader, input []byte) ([]byte, error) { return runBn256Pairing(input) } @@ -608,7 +613,7 @@ var ( errBlake2FInvalidFinalFlag = errors.New("invalid final flag") ) -func (c *blake2F) Run(input []byte) ([]byte, error) { +func (c *blake2F) Run(stateDB StateReader, input []byte) ([]byte, error) { // Make sure the input is valid (correct length and final flag) if len(input) != blake2FInputLength { return nil, errBlake2FInvalidInputLength @@ -662,7 +667,7 @@ func (c *bls12381G1Add) RequiredGas(input []byte) uint64 { return params.Bls12381G1AddGas } -func (c *bls12381G1Add) Run(input []byte) ([]byte, error) { +func (c *bls12381G1Add) Run(stateDB StateReader, input []byte) ([]byte, error) { // Implements EIP-2537 G1Add precompile. // > G1 addition call expects `256` bytes as an input that is interpreted as byte concatenation of two G1 points (`128` bytes each). // > Output is an encoding of addition operation result - single G1 point (`128` bytes). @@ -700,7 +705,7 @@ func (c *bls12381G1Mul) RequiredGas(input []byte) uint64 { return params.Bls12381G1MulGas } -func (c *bls12381G1Mul) Run(input []byte) ([]byte, error) { +func (c *bls12381G1Mul) Run(stateDB StateReader, input []byte) ([]byte, error) { // Implements EIP-2537 G1Mul precompile. // > G1 multiplication call expects `160` bytes as an input that is interpreted as byte concatenation of encoding of G1 point (`128` bytes) and encoding of a scalar value (`32` bytes). // > Output is an encoding of multiplication operation result - single G1 point (`128` bytes). @@ -750,7 +755,7 @@ func (c *bls12381G1MultiExp) RequiredGas(input []byte) uint64 { return (uint64(k) * params.Bls12381G1MulGas * discount) / 1000 } -func (c *bls12381G1MultiExp) Run(input []byte) ([]byte, error) { +func (c *bls12381G1MultiExp) Run(stateDB StateReader, input []byte) ([]byte, error) { // Implements EIP-2537 G1MultiExp precompile. // G1 multiplication call expects `160*k` bytes as an input that is interpreted as byte concatenation of `k` slices each of them being a byte concatenation of encoding of G1 point (`128` bytes) and encoding of a scalar value (`32` bytes). // Output is an encoding of multiexponentiation operation result - single G1 point (`128` bytes). @@ -793,7 +798,7 @@ func (c *bls12381G2Add) RequiredGas(input []byte) uint64 { return params.Bls12381G2AddGas } -func (c *bls12381G2Add) Run(input []byte) ([]byte, error) { +func (c *bls12381G2Add) Run(stateDB StateReader, input []byte) ([]byte, error) { // Implements EIP-2537 G2Add precompile. // > G2 addition call expects `512` bytes as an input that is interpreted as byte concatenation of two G2 points (`256` bytes each). // > Output is an encoding of addition operation result - single G2 point (`256` bytes). @@ -831,7 +836,7 @@ func (c *bls12381G2Mul) RequiredGas(input []byte) uint64 { return params.Bls12381G2MulGas } -func (c *bls12381G2Mul) Run(input []byte) ([]byte, error) { +func (c *bls12381G2Mul) Run(stateDB StateReader, input []byte) ([]byte, error) { // Implements EIP-2537 G2MUL precompile logic. // > G2 multiplication call expects `288` bytes as an input that is interpreted as byte concatenation of encoding of G2 point (`256` bytes) and encoding of a scalar value (`32` bytes). // > Output is an encoding of multiplication operation result - single G2 point (`256` bytes). @@ -881,7 +886,7 @@ func (c *bls12381G2MultiExp) RequiredGas(input []byte) uint64 { return (uint64(k) * params.Bls12381G2MulGas * discount) / 1000 } -func (c *bls12381G2MultiExp) Run(input []byte) ([]byte, error) { +func (c *bls12381G2MultiExp) Run(stateDB StateReader, input []byte) ([]byte, error) { // Implements EIP-2537 G2MultiExp precompile logic // > G2 multiplication call expects `288*k` bytes as an input that is interpreted as byte concatenation of `k` slices each of them being a byte concatenation of encoding of G2 point (`256` bytes) and encoding of a scalar value (`32` bytes). // > Output is an encoding of multiexponentiation operation result - single G2 point (`256` bytes). @@ -924,7 +929,7 @@ func (c *bls12381Pairing) RequiredGas(input []byte) uint64 { return params.Bls12381PairingBaseGas + uint64(len(input)/384)*params.Bls12381PairingPerPairGas } -func (c *bls12381Pairing) Run(input []byte) ([]byte, error) { +func (c *bls12381Pairing) Run(stateDB StateReader, input []byte) ([]byte, error) { // Implements EIP-2537 Pairing precompile logic. // > Pairing call expects `384*k` bytes as an inputs that is interpreted as byte concatenation of `k` slices. Each slice has the following structure: // > - `128` bytes of G1 point encoding @@ -1003,7 +1008,7 @@ func (c *bls12381MapG1) RequiredGas(input []byte) uint64 { return params.Bls12381MapG1Gas } -func (c *bls12381MapG1) Run(input []byte) ([]byte, error) { +func (c *bls12381MapG1) Run(stateDB StateReader, input []byte) ([]byte, error) { // Implements EIP-2537 Map_To_G1 precompile. // > Field-to-curve call expects `64` bytes an an input that is interpreted as a an element of the base field. // > Output of this call is `128` bytes and is G1 point following respective encoding rules. @@ -1038,7 +1043,7 @@ func (c *bls12381MapG2) RequiredGas(input []byte) uint64 { return params.Bls12381MapG2Gas } -func (c *bls12381MapG2) Run(input []byte) ([]byte, error) { +func (c *bls12381MapG2) Run(stateDB StateReader, input []byte) ([]byte, error) { // Implements EIP-2537 Map_FP2_TO_G2 precompile logic. // > Field-to-curve call expects `128` bytes an an input that is interpreted as a an element of the quadratic extension field. // > Output of this call is `256` bytes and is G2 point following respective encoding rules. @@ -1093,7 +1098,7 @@ var ( ) // Run executes the point evaluation precompile. -func (b *kzgPointEvaluation) Run(input []byte) ([]byte, error) { +func (b *kzgPointEvaluation) Run(stateDB StateReader, input []byte) ([]byte, error) { if len(input) != blobVerifyInputLength { return nil, errBlobVerifyInvalidInputLength } @@ -1135,3 +1140,28 @@ func kZGToVersionedHash(kzg kzg4844.Commitment) common.Hash { return h } + +// BeaconRoot is a stateful precompile that returns a beacon root. +type beaconRoot struct{} + +func (c *beaconRoot) RequiredGas(input []byte) uint64 { + return params.BeaconRootPrecompileGas +} + +func (c *beaconRoot) Run(stateDB StateReader, input []byte) ([]byte, error) { + if len(input) != common.HashLength { + return nil, errors.New("invalid input length") + } + var timestamp common.Hash + copy(timestamp[:], input) + // retrieve stored timestamp + timeIndex := binary.BigEndian.Uint64(timestamp[24:]) % params.HistoricalRootsModulus + recordedTimestamp := stateDB.GetState(params.BeaconRootsStorageAddress, common.Uint64ToHash(timeIndex)) + if recordedTimestamp != timestamp { + return make([]byte, 32), nil + } + // retrieve stored beacon root + rootIndex := timeIndex + params.HistoricalRootsModulus + beaconRoot := stateDB.GetState(params.BeaconRootsStorageAddress, common.Uint64ToHash(rootIndex)) + return beaconRoot[:], nil +} diff --git a/core/vm/contracts_test.go b/core/vm/contracts_test.go index 5b1e874e91b4..d2507a112395 100644 --- a/core/vm/contracts_test.go +++ b/core/vm/contracts_test.go @@ -97,7 +97,7 @@ func testPrecompiled(addr string, test precompiledTest, t *testing.T) { in := common.Hex2Bytes(test.Input) gas := p.RequiredGas(in) t.Run(fmt.Sprintf("%s-Gas=%d", test.Name, gas), func(t *testing.T) { - if res, _, err := RunPrecompiledContract(p, in, gas); err != nil { + if res, _, err := RunPrecompiledContract(nil, p, in, gas); err != nil { t.Error(err) } else if common.Bytes2Hex(res) != test.Expected { t.Errorf("Expected %v, got %v", test.Expected, common.Bytes2Hex(res)) @@ -119,7 +119,7 @@ func testPrecompiledOOG(addr string, test precompiledTest, t *testing.T) { gas := p.RequiredGas(in) - 1 t.Run(fmt.Sprintf("%s-Gas=%d", test.Name, gas), func(t *testing.T) { - _, _, err := RunPrecompiledContract(p, in, gas) + _, _, err := RunPrecompiledContract(nil, p, in, gas) if err.Error() != "out of gas" { t.Errorf("Expected error [out of gas], got [%v]", err) } @@ -136,7 +136,7 @@ func testPrecompiledFailure(addr string, test precompiledFailureTest, t *testing in := common.Hex2Bytes(test.Input) gas := p.RequiredGas(in) t.Run(test.Name, func(t *testing.T) { - _, _, err := RunPrecompiledContract(p, in, gas) + _, _, err := RunPrecompiledContract(nil, p, in, gas) if err.Error() != test.ExpectedError { t.Errorf("Expected error [%v], got [%v]", test.ExpectedError, err) } @@ -168,7 +168,7 @@ func benchmarkPrecompiled(addr string, test precompiledTest, bench *testing.B) { bench.ResetTimer() for i := 0; i < bench.N; i++ { copy(data, in) - res, _, err = RunPrecompiledContract(p, data, reqGas) + res, _, err = RunPrecompiledContract(nil, p, data, reqGas) } bench.StopTimer() elapsed := uint64(time.Since(start)) diff --git a/core/vm/evm.go b/core/vm/evm.go index 40e2f3554f46..eb048bcf8d04 100644 --- a/core/vm/evm.go +++ b/core/vm/evm.go @@ -220,7 +220,7 @@ func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas } if isPrecompile { - ret, gas, err = RunPrecompiledContract(p, input, gas) + ret, gas, err = RunPrecompiledContract(evm.StateDB, p, input, gas) } else { // Initialise a new contract and set the code that is to be used by the EVM. // The contract is a scoped environment for this execution context only. @@ -283,7 +283,7 @@ func (evm *EVM) CallCode(caller ContractRef, addr common.Address, input []byte, // It is allowed to call precompiles, even via delegatecall if p, isPrecompile := evm.precompile(addr); isPrecompile { - ret, gas, err = RunPrecompiledContract(p, input, gas) + ret, gas, err = RunPrecompiledContract(evm.StateDB, p, input, gas) } else { addrCopy := addr // Initialise a new contract and set the code that is to be used by the EVM. @@ -328,7 +328,7 @@ func (evm *EVM) DelegateCall(caller ContractRef, addr common.Address, input []by // It is allowed to call precompiles, even via delegatecall if p, isPrecompile := evm.precompile(addr); isPrecompile { - ret, gas, err = RunPrecompiledContract(p, input, gas) + ret, gas, err = RunPrecompiledContract(evm.StateDB, p, input, gas) } else { addrCopy := addr // Initialise a new contract and make initialise the delegate values @@ -377,7 +377,7 @@ func (evm *EVM) StaticCall(caller ContractRef, addr common.Address, input []byte } if p, isPrecompile := evm.precompile(addr); isPrecompile { - ret, gas, err = RunPrecompiledContract(p, input, gas) + ret, gas, err = RunPrecompiledContract(evm.StateDB, p, input, gas) } else { // At this point, we use a copy of address. If we don't, the go compiler will // leak the 'contract' to the outer scope, and make allocation for 'contract' diff --git a/params/protocol_params.go b/params/protocol_params.go index b5c57789be2d..e84563e4b42a 100644 --- a/params/protocol_params.go +++ b/params/protocol_params.go @@ -16,7 +16,11 @@ package params -import "math/big" +import ( + "math/big" + + "github.com/ethereum/go-ethereum/common" +) const ( GasLimitBoundDivisor uint64 = 1024 // The bound divisor of the gas limit, used in update calculations. @@ -160,6 +164,9 @@ const ( RefundQuotient uint64 = 2 RefundQuotientEIP3529 uint64 = 5 + HistoricalRootsModulus uint64 = 98304 // Limits how many historical roots are stored by EIP-4788 + BeaconRootPrecompileGas uint64 = 4200 // Price for retrieving a beacon root from the beacon root precompile + BlobTxBytesPerFieldElement = 32 // Size in bytes of a field element BlobTxFieldElementsPerBlob = 4096 // Number of field elements stored in a single data blob BlobTxHashVersion = 0x01 // Version byte of the commitment hash @@ -179,4 +186,6 @@ var ( GenesisDifficulty = big.NewInt(131072) // Difficulty of the Genesis block. MinimumDifficulty = big.NewInt(131072) // The minimum that the difficulty may ever be. DurationLimit = big.NewInt(13) // The decision boundary on the blocktime duration used to determine whether difficulty should go up or not. + + BeaconRootsStorageAddress common.Address = common.BytesToAddress([]byte{0xb}) // Address where historical beacon roots are stored as per EIP-4788 ) diff --git a/tests/fuzzers/bls12381/precompile_fuzzer.go b/tests/fuzzers/bls12381/precompile_fuzzer.go index cab2bcba3863..f1083ad7a888 100644 --- a/tests/fuzzers/bls12381/precompile_fuzzer.go +++ b/tests/fuzzers/bls12381/precompile_fuzzer.go @@ -92,7 +92,7 @@ func fuzz(id byte, data []byte) int { } cpy := make([]byte, len(data)) copy(cpy, data) - _, err := precompile.Run(cpy) + _, err := precompile.Run(nil, cpy) if !bytes.Equal(cpy, data) { panic(fmt.Sprintf("input data modified, precompile %d: %x %x", id, data, cpy)) }