From 884bf1e9d90daf9cad0976fe0d1e51d0d7656577 Mon Sep 17 00:00:00 2001 From: frozen <355847+Frozen@users.noreply.github.com> Date: Mon, 22 Sep 2025 15:10:57 -0500 Subject: [PATCH 1/7] Transient storage functionality --- core/blockchain_test.go | 108 ++++++++++++ core/chain_makers.go | 347 +++++++++++++++++++++++++++++++++++++ core/chain_makers_test.go | 100 +++++++++++ core/state/statedb.go | 46 ++--- core/vm/interface.go | 12 +- core/vm/opcodes.go | 11 ++ core/vm/runtime/runtime.go | 21 ++- 7 files changed, 612 insertions(+), 33 deletions(-) create mode 100644 core/blockchain_test.go create mode 100644 core/chain_makers.go create mode 100644 core/chain_makers_test.go diff --git a/core/blockchain_test.go b/core/blockchain_test.go new file mode 100644 index 0000000000..b3a003e74d --- /dev/null +++ b/core/blockchain_test.go @@ -0,0 +1,108 @@ +package core + +import ( + "math/big" + "testing" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/consensus/ethash" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/crypto" + "github.com/harmony-one/harmony/core/rawdb" + "github.com/harmony-one/harmony/core/vm" + "github.com/harmony-one/harmony/internal/params" +) + +// TestTransientStorageReset ensures the transient storage is wiped correctly +// between transactions. +func TestTransientStorageReset(t *testing.T) { + var ( + engine = ethash.NewFaker() + key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") + address = crypto.PubkeyToAddress(key.PublicKey) + destAddress = crypto.CreateAddress(address, 0) + funds = big.NewInt(1000000000000000) + vmConfig = vm.Config{ + ExtraEips: []int{1153}, // Enable transient storage EIP + } + ) + code := append([]byte{ + // TLoad value with location 1 + byte(vm.PUSH1), 0x1, + byte(vm.TLOAD), + + // PUSH location + byte(vm.PUSH1), 0x1, + + // SStore location:value + byte(vm.SSTORE), + }, make([]byte, 32-6)...) + initCode := []byte{ + // TSTORE 1:1 + byte(vm.PUSH1), 0x1, + byte(vm.PUSH1), 0x1, + byte(vm.TSTORE), + + // Get the runtime-code on the stack + byte(vm.PUSH32)} + initCode = append(initCode, code...) + initCode = append(initCode, []byte{ + byte(vm.PUSH1), 0x0, // offset + byte(vm.MSTORE), + byte(vm.PUSH1), 0x6, // size + byte(vm.PUSH1), 0x0, // offset + byte(vm.RETURN), // return 6 bytes of zero-code + }...) + gspec := &Genesis{ + Config: params.TestChainConfig, + Alloc: GenesisAlloc{ + address: {Balance: funds}, + }, + } + nonce := uint64(0) + signer := types.HomesteadSigner{} + _, blocks, _ := GenerateChainWithGenesis(gspec, engine, 1, func(i int, b *BlockGen) { + fee := big.NewInt(1) + if b.header.BaseFee != nil { + fee = b.header.BaseFee + } + b.SetCoinbase(common.Address{1}) + tx, _ := types.SignNewTx(key, signer, &types.LegacyTx{ + Nonce: nonce, + GasPrice: new(big.Int).Set(fee), + Gas: 100000, + Data: initCode, + }) + nonce++ + b.AddTxWithVMConfig(tx, vmConfig) + + tx, _ = types.SignNewTx(key, signer, &types.LegacyTx{ + Nonce: nonce, + GasPrice: new(big.Int).Set(fee), + Gas: 100000, + To: &destAddress, + }) + b.AddTxWithVMConfig(tx, vmConfig) + nonce++ + }) + + // Initialize the blockchain with 1153 enabled. + chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), nil, gspec, nil, engine, vmConfig, nil, nil) + if err != nil { + t.Fatalf("failed to create tester chain: %v", err) + } + // Import the blocks + if _, err := chain.InsertChain(blocks); err != nil { + t.Fatalf("failed to insert into chain: %v", err) + } + // Check the storage + state, err := chain.StateAt(chain.CurrentHeader().Root()) + if err != nil { + t.Fatalf("Failed to load state %v", err) + } + loc := common.BytesToHash([]byte{1}) + slot := state.GetState(destAddress, loc) + if slot != (common.Hash{}) { + t.Fatalf("Unexpected dirty storage slot") + } +} diff --git a/core/chain_makers.go b/core/chain_makers.go new file mode 100644 index 0000000000..30ecce9361 --- /dev/null +++ b/core/chain_makers.go @@ -0,0 +1,347 @@ +// Copyright 2015 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 core + +import ( + "math/big" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/consensus" + //"github.com/ethereum/go-ethereum/consensus/misc" + //"github.com/ethereum/go-ethereum/core/state" + "github.com/ethereum/go-ethereum/core/types" + //"github.com/ethereum/go-ethereum/ethdb" + "github.com/ethereum/go-ethereum/params" + "github.com/harmony-one/harmony/block" + hmystate "github.com/harmony-one/harmony/core/state" + hmyTypes "github.com/harmony-one/harmony/core/types" + //"github.com/harmony-one/harmony/core/vm" +) + +// BlockGen creates blocks for testing. +// See GenerateChain for a detailed explanation. +type BlockGen struct { + i int + parent *types.Block + chain []*types.Block + header *block.Header + statedb *hmystate.DB + + gasPool *GasPool + txs []*types.Transaction + receipts []*hmyTypes.Receipt + uncles []*types.Header + + config *params.ChainConfig + engine consensus.Engine +} + +// SetCoinbase sets the coinbase of the generated block. +// It can be called at most once. +func (b *BlockGen) SetCoinbase(addr common.Address) { + if b.gasPool != nil { + if len(b.txs) > 0 { + panic("coinbase must be set before adding transactions") + } + panic("coinbase can only be set once") + } + b.header.SetCoinbase(addr) + b.gasPool = new(GasPool).AddGas(b.header.GasLimit()) +} + +// SetExtra sets the extra data field of the generated block. +func (b *BlockGen) SetExtra(data []byte) { + b.header.SetExtra(data) +} + +// SetNonce sets the nonce field of the generated block. +//func (b *BlockGen) SetNonce(nonce types.BlockNonce) { +// b.header.Setno = nonce +//} + +// SetDifficulty sets the difficulty field of the generated block. This method is +// useful for Clique tests where the difficulty does not depend on time. For the +// ethash tests, please use OffsetTime, which implicitly recalculates the diff. +//func (b *BlockGen) SetDifficulty(diff *big.Int) { +// b.header.Difficulty = diff +//} + +/* +func (b *BlockGen) addTx(bc BlockChain, vmConfig vm.Config, tx *hmyTypes.Transaction) { + if b.gasPool == nil { + b.SetCoinbase(common.Address{}) + } + b.statedb.SetTxContext(tx.Hash(), len(b.txs)) + addr := b.header.Coinbase() + gasUsed := b.header.GasUsed() + receipt, _, _, _, err := ApplyTransaction(bc, &addr, b.gasPool, b.statedb, b.header, tx, &gasUsed, vmConfig) + if err != nil { + panic(err) + } + b.txs = append(b.txs, tx) + b.receipts = append(b.receipts, receipt) +} + +// AddTx adds a transaction to the generated block. If no coinbase has +// been set, the block's coinbase is set to the zero address. +// +// AddTx panics if the transaction cannot be executed. In addition to +// the protocol-imposed limitations (gas limit, etc.), there are some +// further limitations on the content of transactions that can be +// added. Notably, contract code relying on the BLOCKHASH instruction +// will panic during execution. +func (b *BlockGen) AddTx(tx *types.Transaction) { + b.addTx(nil, vm.Config{}, tx) +} + +// AddTxWithChain adds a transaction to the generated block. If no coinbase has +// been set, the block's coinbase is set to the zero address. +// +// AddTxWithChain panics if the transaction cannot be executed. In addition to +// the protocol-imposed limitations (gas limit, etc.), there are some +// further limitations on the content of transactions that can be +// added. If contract code relies on the BLOCKHASH instruction, +// the block in chain will be returned. +func (b *BlockGen) AddTxWithChain(bc BlockChain, tx *types.Transaction) { + b.addTx(bc, vm.Config{}, tx) +} + +// GetBalance returns the balance of the given address at the generated block. +func (b *BlockGen) GetBalance(addr common.Address) *big.Int { + return b.statedb.GetBalance(addr) +} + +// AddUncheckedTx forcefully adds a transaction to the block without any +// validation. +// +// AddUncheckedTx will cause consensus failures when used during real +// chain processing. This is best used in conjunction with raw block insertion. +func (b *BlockGen) AddUncheckedTx(tx *types.Transaction) { + b.txs = append(b.txs, tx) +} + +// Number returns the block number of the block being generated. +func (b *BlockGen) Number() *big.Int { + return new(big.Int).Set(b.header.Number) +} + +// BaseFee returns the EIP-1559 base fee of the block being generated. +func (b *BlockGen) BaseFee() *big.Int { + return new(big.Int).Set(b.header.BaseFee) +} + +// AddUncheckedReceipt forcefully adds a receipts to the block without a +// backing transaction. +// +// AddUncheckedReceipt will cause consensus failures when used during real +// chain processing. This is best used in conjunction with raw block insertion. +func (b *BlockGen) AddUncheckedReceipt(receipt *types.Receipt) { + b.receipts = append(b.receipts, receipt) +} + +// TxNonce returns the next valid transaction nonce for the +// account at addr. It panics if the account does not exist. +func (b *BlockGen) TxNonce(addr common.Address) uint64 { + if !b.statedb.Exist(addr) { + panic("account does not exist") + } + return b.statedb.GetNonce(addr) +} + +// AddUncle adds an uncle header to the generated block. +func (b *BlockGen) AddUncle(h *types.Header) { + // The uncle will have the same timestamp and auto-generated difficulty + h.Time = b.header.Time() + + var parent *types.Header + for i := b.i - 1; i >= 0; i-- { + if b.chain[i].Hash() == h.ParentHash { + parent = b.chain[i].Header() + break + } + } + //chainreader := &fakeChainReader{config: b.config} + //h.Difficulty = b.engine.CalcDifficulty(chainreader, b.header.Time, parent) + + // The gas limit and price should be derived from the parent + h.GasLimit = parent.GasLimit + if b.config.IsLondon(h.Number) { + h.BaseFee = misc.CalcBaseFee(b.config, parent) + if !b.config.IsLondon(parent.Number) { + parentGasLimit := parent.GasLimit * params.ElasticityMultiplier + h.GasLimit = CalcGasLimit(parentGasLimit, parentGasLimit) + } + } + b.uncles = append(b.uncles, h) +} + +// PrevBlock returns a previously generated block by number. It panics if +// num is greater or equal to the number of the block being generated. +// For index -1, PrevBlock returns the parent block given to GenerateChain. +func (b *BlockGen) PrevBlock(index int) *types.Block { + if index >= b.i { + panic(fmt.Errorf("block index %d out of range (%d,%d)", index, -1, b.i)) + } + if index == -1 { + return b.parent + } + return b.chain[index] +} + +// OffsetTime modifies the time instance of a block, implicitly changing its +// associated difficulty. It's useful to test scenarios where forking is not +// tied to chain length directly. +//func (b *BlockGen) OffsetTime(seconds int64) { +// b.header.Time += uint64(seconds) +// if b.header.Time <= b.parent.Header().Time { +// panic("block time out of range") +// } +// chainreader := &fakeChainReader{config: b.config} +// b.header.Difficulty = b.engine.CalcDifficulty(chainreader, b.header.Time, b.parent.Header()) +//} + +// GenerateChain creates a chain of n blocks. The first block's +// parent will be the provided parent. db is used to store +// intermediate states and should contain the parent's state trie. +// +// The generator function is called with a new block generator for +// every block. Any transactions and uncles added to the generator +// become part of the block. If gen is nil, the blocks will be empty +// and their coinbase will be the zero address. +// +// Blocks created by GenerateChain do not contain valid proof of work +// values. Inserting them into BlockChain requires use of FakePow or +// a similar non-validating proof of work implementation. +func GenerateChain(config *params.ChainConfig, parent *types.Block, engine consensus.Engine, db ethdb.Database, n int, gen func(int, *BlockGen)) ([]*types.Block, []hmyTypes.Receipts) { + if config == nil { + config = params.TestChainConfig + } + blocks, receipts := make(types.Blocks, n), make([]types.Receipts, n) + chainreader := &fakeChainReader{config: config} + genblock := func(i int, parent *types.Block, statedb *state.StateDB) (*types.Block, types.Receipts) { + b := &BlockGen{i: i, chain: blocks, parent: parent, statedb: statedb, config: config, engine: engine} + b.header = makeHeader(chainreader, parent, statedb, b.engine) + + // Mutate the state and block according to any hard-fork specs + if daoBlock := config.DAOForkBlock; daoBlock != nil { + limit := new(big.Int).Add(daoBlock, params.DAOForkExtraRange) + if b.header.Number.Cmp(daoBlock) >= 0 && b.header.Number.Cmp(limit) < 0 { + if config.DAOForkSupport { + b.header.SetExtra(common.CopyBytes(params.DAOForkBlockExtra)) + } + } + } + if config.DAOForkSupport && config.DAOForkBlock != nil && config.DAOForkBlock.Cmp(b.header.Number()) == 0 { + misc.ApplyDAOHardFork(statedb) + } + // Execute any user modifications to the block + if gen != nil { + gen(i, b) + } + if b.engine != nil { + // Finalize and seal the block + block, _ := b.engine.FinalizeAndAssemble(chainreader, b.header, statedb, b.txs, b.uncles, b.receipts) + + // Write state changes to db + root, err := statedb.Commit(config.IsEIP158(b.header.Number())) + if err != nil { + panic(fmt.Sprintf("state write error: %v", err)) + } + if err := statedb.Database().TrieDB().Commit(root, false, nil); err != nil { + panic(fmt.Sprintf("trie write error: %v", err)) + } + return block, b.receipts + } + return nil, nil + } + for i := 0; i < n; i++ { + statedb, err := state.New(parent.Root(), state.NewDatabase(db), nil) + if err != nil { + panic(err) + } + block, receipt := genblock(i, parent, statedb) + blocks[i] = block + receipts[i] = receipt + parent = block + } + return blocks, receipts +} + +func makeHeader(chain consensus.ChainReader, parent *types.Block, state *state.StateDB, engine consensus.Engine) *types.Header { + var time uint64 + if parent.Time() == 0 { + time = 10 + } else { + time = parent.Time() + 10 // block time is fixed at 10 seconds + } + header := &types.Header{ + Root: state.IntermediateRoot(chain.Config().IsEIP158(parent.Number())), + ParentHash: parent.Hash(), + Coinbase: parent.Coinbase(), + Difficulty: engine.CalcDifficulty(chain, time, &types.Header{ + Number: parent.Number(), + Time: time - 10, + Difficulty: parent.Difficulty(), + UncleHash: parent.UncleHash(), + }), + GasLimit: parent.GasLimit(), + Number: new(big.Int).Add(parent.Number(), common.Big1), + Time: time, + } + if chain.Config().IsLondon(header.Number) { + header.BaseFee = misc.CalcBaseFee(chain.Config(), parent.Header()) + if !chain.Config().IsLondon(parent.Number()) { + parentGasLimit := parent.GasLimit() * params.ElasticityMultiplier + header.GasLimit = CalcGasLimit(parentGasLimit, parentGasLimit) + } + } + return header +} + +// makeHeaderChain creates a deterministic chain of headers rooted at parent. +func makeHeaderChain(parent *types.Header, n int, engine consensus.Engine, db ethdb.Database, seed int) []*types.Header { + blocks := makeBlockChain(types.NewBlockWithHeader(parent), n, engine, db, seed) + headers := make([]*types.Header, len(blocks)) + for i, block := range blocks { + headers[i] = block.Header() + } + return headers +} +*/ +// makeBlockChain creates a deterministic chain of blocks rooted at parent. +//func makeBlockChain(parent *types.Block, n int, engine consensus.Engine, db ethdb.Database, seed int) []*types.Block { +// blocks, _ := GenerateChain(params.TestChainConfig, parent, engine, db, n, func(i int, b *BlockGen) { +// b.SetCoinbase(common.Address{0: byte(seed), 19: byte(i)}) +// }) +// return blocks +//} + +type fakeChainReader struct { + config *params.ChainConfig +} + +// Config returns the chain configuration. +func (cr *fakeChainReader) Config() *params.ChainConfig { + return cr.config +} + +func (cr *fakeChainReader) CurrentHeader() *types.Header { return nil } +func (cr *fakeChainReader) GetHeaderByNumber(number uint64) *types.Header { return nil } +func (cr *fakeChainReader) GetHeaderByHash(hash common.Hash) *types.Header { return nil } +func (cr *fakeChainReader) GetHeader(hash common.Hash, number uint64) *types.Header { return nil } +func (cr *fakeChainReader) GetBlock(hash common.Hash, number uint64) *types.Block { return nil } +func (cr *fakeChainReader) GetTd(hash common.Hash, number uint64) *big.Int { return nil } diff --git a/core/chain_makers_test.go b/core/chain_makers_test.go new file mode 100644 index 0000000000..85a029f7c7 --- /dev/null +++ b/core/chain_makers_test.go @@ -0,0 +1,100 @@ +// Copyright 2015 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 core + +import ( + "fmt" + "math/big" + + "github.com/ethereum/go-ethereum/consensus/ethash" + "github.com/ethereum/go-ethereum/core/rawdb" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/core/vm" + "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/params" +) + +func ExampleGenerateChain() { + var ( + key1, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") + key2, _ = crypto.HexToECDSA("8a1f9a8f95be41cd7ccb6168179afb4504aefe388d1e14474d32c45c72ce7b7a") + key3, _ = crypto.HexToECDSA("49a7b37aa6f6645917e7b807e9d1c00d4fa71f18343b0d4122a4d2df64dd6fee") + addr1 = crypto.PubkeyToAddress(key1.PublicKey) + addr2 = crypto.PubkeyToAddress(key2.PublicKey) + addr3 = crypto.PubkeyToAddress(key3.PublicKey) + db = rawdb.NewMemoryDatabase() + ) + + // Ensure that key1 has some funds in the genesis block. + gspec := &Genesis{ + Config: ¶ms.ChainConfig{HomesteadBlock: new(big.Int)}, + Alloc: GenesisAlloc{addr1: {Balance: big.NewInt(1000000)}}, + } + genesis := gspec.MustCommit(db) + + // This call generates a chain of 5 blocks. The function runs for + // each block and adds different features to gen based on the + // block index. + signer := types.HomesteadSigner{} + chain, _ := GenerateChain(gspec.Config, genesis, ethash.NewFaker(), db, 5, func(i int, gen *BlockGen) { + switch i { + case 0: + // In block 1, addr1 sends addr2 some ether. + tx, _ := types.SignTx(types.NewTransaction(gen.TxNonce(addr1), addr2, big.NewInt(10000), params.TxGas, nil, nil), signer, key1) + gen.AddTx(tx) + case 1: + // In block 2, addr1 sends some more ether to addr2. + // addr2 passes it on to addr3. + tx1, _ := types.SignTx(types.NewTransaction(gen.TxNonce(addr1), addr2, big.NewInt(1000), params.TxGas, nil, nil), signer, key1) + tx2, _ := types.SignTx(types.NewTransaction(gen.TxNonce(addr2), addr3, big.NewInt(1000), params.TxGas, nil, nil), signer, key2) + gen.AddTx(tx1) + gen.AddTx(tx2) + case 2: + // Block 3 is empty but was mined by addr3. + gen.SetCoinbase(addr3) + gen.SetExtra([]byte("yeehaw")) + case 3: + // Block 4 includes blocks 2 and 3 as uncle headers (with modified extra data). + b2 := gen.PrevBlock(1).Header() + b2.Extra = []byte("foo") + gen.AddUncle(b2) + b3 := gen.PrevBlock(2).Header() + b3.Extra = []byte("foo") + gen.AddUncle(b3) + } + }) + + // Import the chain. This runs all block validation rules. + blockchain, _ := NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil) + defer blockchain.Stop() + + if i, err := blockchain.InsertChain(chain); err != nil { + fmt.Printf("insert error (block %d): %v\n", chain[i].NumberU64(), err) + return + } + + state, _ := blockchain.State() + fmt.Printf("last block: #%d\n", blockchain.CurrentBlock().Number()) + fmt.Println("balance of addr1:", state.GetBalance(addr1)) + fmt.Println("balance of addr2:", state.GetBalance(addr2)) + fmt.Println("balance of addr3:", state.GetBalance(addr3)) + // Output: + // last block: #5 + // balance of addr1: 989000 + // balance of addr2: 10000 + // balance of addr3: 19687500000000001000 +} diff --git a/core/state/statedb.go b/core/state/statedb.go index de885f6066..0fd14d3b17 100644 --- a/core/state/statedb.go +++ b/core/state/statedb.go @@ -31,9 +31,9 @@ import ( "github.com/ethereum/go-ethereum/trie" "github.com/harmony-one/harmony/core/rawdb" "github.com/harmony-one/harmony/core/state/snapshot" - types2 "github.com/harmony-one/harmony/core/types" common2 "github.com/harmony-one/harmony/internal/common" + "github.com/harmony-one/harmony/internal/params" "github.com/harmony-one/harmony/internal/utils" "github.com/harmony-one/harmony/numeric" "github.com/harmony-one/harmony/staking" @@ -1165,33 +1165,39 @@ func (db *DB) Commit(deleteEmptyObjects bool) (common.Hash, error) { return root, nil } -// PrepareAccessList handles the preparatory steps for executing a state transition with -// regards to both EIP-2929 and EIP-2930: +// Prepare handles the preparatory steps for executing a state transition with. +// This method must be invoked before state transition. // +// Berlin fork: // - Add sender to access list (2929) // - Add destination to access list (2929) // - Add precompiles to access list (2929) // - Add the contents of the optional tx access list (2930) // -// This method should only be called if Berlin/2929+2930 is applicable at the current number. -func (s *DB) PrepareAccessList(sender common.Address, dst *common.Address, precompiles []common.Address, list types2.AccessList) { - // Clear out any leftover from previous executions - s.accessList = newAccessList() - - s.AddAddressToAccessList(sender) - if dst != nil { - s.AddAddressToAccessList(*dst) - // If it's a create-tx, the destination will be added inside evm.create - } - for _, addr := range precompiles { - s.AddAddressToAccessList(addr) - } - for _, el := range list { - s.AddAddressToAccessList(el.Address) - for _, key := range el.StorageKeys { - s.AddSlotToAccessList(el.Address, key) +// Potential EIPs: +// - Reset transient storage(1153) +func (s *DB) Prepare(rules params.Rules, sender common.Address, dst *common.Address, precompiles []common.Address, list types2.AccessList) { + if rules.IsBerlin { + // Clear out any leftover from previous executions + s.accessList = newAccessList() + + s.AddAddressToAccessList(sender) + if dst != nil { + s.AddAddressToAccessList(*dst) + // If it's a create-tx, the destination will be added inside evm.create + } + for _, addr := range precompiles { + s.AddAddressToAccessList(addr) + } + for _, el := range list { + s.AddAddressToAccessList(el.Address) + for _, key := range el.StorageKeys { + s.AddSlotToAccessList(el.Address, key) + } } } + // Reset transient storage at the beginning of transaction execution + s.transientStorage = newTransientStorage() } /* diff --git a/core/vm/interface.go b/core/vm/interface.go index a5e3ef5041..9661ee9bef 100644 --- a/core/vm/interface.go +++ b/core/vm/interface.go @@ -21,7 +21,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/harmony-one/harmony/core/types" - htypes "github.com/harmony-one/harmony/core/types" + "github.com/harmony-one/harmony/internal/params" "github.com/harmony-one/harmony/numeric" staking "github.com/harmony-one/harmony/staking/types" ) @@ -58,9 +58,8 @@ type StateDB interface { GetCommittedState(common.Address, common.Hash) common.Hash GetState(common.Address, common.Hash) common.Hash SetState(common.Address, common.Hash, common.Hash) - - //GetTransientState(addr common.Address, key common.Hash) common.Hash - //SetTransientState(addr common.Address, key, value common.Hash) + GetTransientState(addr common.Address, key common.Hash) common.Hash + SetTransientState(addr common.Address, key, value common.Hash) Suicide(common.Address) bool HasSuicided(common.Address) bool @@ -72,7 +71,8 @@ type StateDB interface { // is defined according to EIP161 (balance = nonce = code = 0). Empty(common.Address) bool - PrepareAccessList(sender common.Address, dest *common.Address, precompiles []common.Address, txAccesses htypes.AccessList) + // PrepareAccessList(sender common.Address, dest *common.Address, precompiles []common.Address, txAccesses htypes.AccessList) + AddressInAccessList(addr common.Address) bool SlotInAccessList(addr common.Address, slot common.Hash) (addressOk bool, slotOk bool) // AddAddressToAccessList adds the given address to the access list. This operation is safe to perform @@ -82,6 +82,8 @@ type StateDB interface { // even if the feature/fork is not active yet AddSlotToAccessList(addr common.Address, slot common.Hash) + Prepare(rules params.Rules, sender common.Address, dest *common.Address, precompiles []common.Address, txAccesses types.AccessList) + RevertToSnapshot(int) Snapshot() int diff --git a/core/vm/opcodes.go b/core/vm/opcodes.go index 77d619abb9..c5ba815203 100644 --- a/core/vm/opcodes.go +++ b/core/vm/opcodes.go @@ -222,6 +222,11 @@ const ( SELFDESTRUCT OpCode = 0xff ) +const ( + TLOAD OpCode = 0xb3 + TSTORE OpCode = 0xb4 +) + // Since the opcodes aren't all in order we can't use a regular slice. var opCodeToString = map[OpCode]string{ // 0x0 range - arithmetic ops. @@ -376,6 +381,10 @@ var opCodeToString = map[OpCode]string{ LOG3: "LOG3", LOG4: "LOG4", + // 0xb0 range. + TLOAD: "TLOAD", + TSTORE: "TSTORE", + // 0xf0 range. CREATE: "CREATE", CALL: "CALL", @@ -466,6 +475,8 @@ var stringToOp = map[string]OpCode{ "GAS": GAS, "JUMPDEST": JUMPDEST, "PUSH0": PUSH0, + "TLOAD": TLOAD, + "TSTORE": TSTORE, "PUSH1": PUSH1, "PUSH2": PUSH2, "PUSH3": PUSH3, diff --git a/core/vm/runtime/runtime.go b/core/vm/runtime/runtime.go index 601f0a1d17..aa2517bf3f 100644 --- a/core/vm/runtime/runtime.go +++ b/core/vm/runtime/runtime.go @@ -109,11 +109,12 @@ func Execute(code, input []byte, cfg *Config) ([]byte, *state.DB, error) { address = common.BytesToAddress([]byte("contract")) vmenv = NewEnv(cfg) sender = vm.AccountRef(cfg.Origin) + rules = cfg.ChainConfig.Rules(vmenv.Context.EpochNumber, vmenv.Context.Random != nil) ) - - if rules := cfg.ChainConfig.Rules(vmenv.Context.EpochNumber); rules.IsBerlin { - //cfg.State.PrepareAccessList(cfg.Origin, &address, vm.ActivePrecompiles(rules), nil) - } + // Execute the preparatory steps for state transition which includes: + // - prepare accessList(post-berlin) + // - reset transient storage(eip 1153) + cfg.State.Prepare(rules, cfg.Origin, &address, vm.ActivePrecompiles(rules), nil) cfg.State.CreateAccount(address) // set the receiver's (the executing contract) code for execution. @@ -143,11 +144,13 @@ func Create(input []byte, cfg *Config) ([]byte, common.Address, uint64, error) { var ( vmenv = NewEnv(cfg) sender = vm.AccountRef(cfg.Origin) + rules = cfg.ChainConfig.Rules(vmenv.Context.BlockNumber, vmenv.Context.Random != nil) ) // Execute the preparatory steps for state transition which includes: + // - prepare accessList(post-berlin) // - reset transient storage(eip 1153) - // vmenv.StateDB.Prepare() TODO eip 1153 + cfg.State.Prepare(rules, cfg.Origin, nil, vm.ActivePrecompiles(rules), nil) // Call the code with the given configuration. code, address, leftOverGas, err := vmenv.Create( @@ -167,9 +170,11 @@ func Create(input []byte, cfg *Config) ([]byte, common.Address, uint64, error) { func Call(address common.Address, input []byte, cfg *Config) ([]byte, uint64, error) { setDefaults(cfg) - vmenv := NewEnv(cfg) - - sender := cfg.State.GetOrNewStateObject(cfg.Origin) + var ( + vmenv = NewEnv(cfg) + sender = cfg.State.GetOrNewStateObject(cfg.Origin) + rules = cfg.ChainConfig.Rules(vmenv.Context.EpochNumber, vmenv.Context.Random != nil) + ) // Execute the preparatory steps for state transition which includes: // - reset transient storage(eip 1153) From c65d8bdfb5f5280d54d505744ef0e470b76dfba2 Mon Sep 17 00:00:00 2001 From: frozen <355847+Frozen@users.noreply.github.com> Date: Mon, 22 Sep 2025 17:53:07 -0500 Subject: [PATCH 2/7] Commented code block in blockchain_test.go --- core/blockchain_test.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/core/blockchain_test.go b/core/blockchain_test.go index b3a003e74d..ae0e690b32 100644 --- a/core/blockchain_test.go +++ b/core/blockchain_test.go @@ -1,5 +1,6 @@ package core +/* import ( "math/big" "testing" @@ -106,3 +107,4 @@ func TestTransientStorageReset(t *testing.T) { t.Fatalf("Unexpected dirty storage slot") } } +*/ From 926ee5d602670cff39b86c7cc268aeca58d8aa85 Mon Sep 17 00:00:00 2001 From: frozen <355847+Frozen@users.noreply.github.com> Date: Mon, 22 Sep 2025 18:06:06 -0500 Subject: [PATCH 3/7] Refactor state transition rules and remove commented-out Prepare method --- core/state/statedb.go | 18 ------------------ core/vm/runtime/runtime.go | 2 +- 2 files changed, 1 insertion(+), 19 deletions(-) diff --git a/core/state/statedb.go b/core/state/statedb.go index 0fd14d3b17..fc14f88bcc 100644 --- a/core/state/statedb.go +++ b/core/state/statedb.go @@ -1200,24 +1200,6 @@ func (s *DB) Prepare(rules params.Rules, sender common.Address, dst *common.Addr s.transientStorage = newTransientStorage() } -/* - -// Prepare handles the preparatory steps for executing a state transition with. -// This method must be invoked before state transition. -// -// - reset transient storage (1153) -// -// todo(sun): berlin fork -// - add sender to access list (2929) -// - add destination to access list (2929) -// - add precompiles to access list (2929) -// - add the contents of the optional tx access list (2930) -func (db *DB) Prepare() { - // reset transient storage prior to transaction execution - db.transientStorage = newTransientStorage() -} -*/ - // AddAddressToAccessList adds the given address to the access list func (db *DB) AddAddressToAccessList(addr common.Address) { if db.accessList.AddAddress(addr) { diff --git a/core/vm/runtime/runtime.go b/core/vm/runtime/runtime.go index aa2517bf3f..1c5b176c10 100644 --- a/core/vm/runtime/runtime.go +++ b/core/vm/runtime/runtime.go @@ -144,7 +144,7 @@ func Create(input []byte, cfg *Config) ([]byte, common.Address, uint64, error) { var ( vmenv = NewEnv(cfg) sender = vm.AccountRef(cfg.Origin) - rules = cfg.ChainConfig.Rules(vmenv.Context.BlockNumber, vmenv.Context.Random != nil) + rules = cfg.ChainConfig.Rules(vmenv.Context.EpochNumber) ) // Execute the preparatory steps for state transition which includes: From 41d381ff752f980fb9766b5660dfc799ece45371 Mon Sep 17 00:00:00 2001 From: frozen <355847+Frozen@users.noreply.github.com> Date: Mon, 22 Sep 2025 18:34:07 -0500 Subject: [PATCH 4/7] Remove commented-out code block in chain_makers_test.go --- core/chain_makers_test.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/core/chain_makers_test.go b/core/chain_makers_test.go index 85a029f7c7..f185afaa3f 100644 --- a/core/chain_makers_test.go +++ b/core/chain_makers_test.go @@ -16,6 +16,7 @@ package core +/* import ( "fmt" "math/big" @@ -98,3 +99,4 @@ func ExampleGenerateChain() { // balance of addr2: 10000 // balance of addr3: 19687500000000001000 } +*/ From cb133c7b0f80f8594c7764f7ae610b071aed7fab Mon Sep 17 00:00:00 2001 From: frozen <355847+Frozen@users.noreply.github.com> Date: Mon, 22 Sep 2025 19:14:48 -0500 Subject: [PATCH 5/7] Remove unnecessary parameter from ChainConfig.Rules calls in runtime.go --- core/vm/runtime/runtime.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/vm/runtime/runtime.go b/core/vm/runtime/runtime.go index 1c5b176c10..2999694479 100644 --- a/core/vm/runtime/runtime.go +++ b/core/vm/runtime/runtime.go @@ -109,7 +109,7 @@ func Execute(code, input []byte, cfg *Config) ([]byte, *state.DB, error) { address = common.BytesToAddress([]byte("contract")) vmenv = NewEnv(cfg) sender = vm.AccountRef(cfg.Origin) - rules = cfg.ChainConfig.Rules(vmenv.Context.EpochNumber, vmenv.Context.Random != nil) + rules = cfg.ChainConfig.Rules(vmenv.Context.EpochNumber) ) // Execute the preparatory steps for state transition which includes: // - prepare accessList(post-berlin) @@ -173,7 +173,7 @@ func Call(address common.Address, input []byte, cfg *Config) ([]byte, uint64, er var ( vmenv = NewEnv(cfg) sender = cfg.State.GetOrNewStateObject(cfg.Origin) - rules = cfg.ChainConfig.Rules(vmenv.Context.EpochNumber, vmenv.Context.Random != nil) + rules = cfg.ChainConfig.Rules(vmenv.Context.EpochNumber) ) // Execute the preparatory steps for state transition which includes: From 9c32f5537a4e7bccde090e9f84e9f595c1b15ae7 Mon Sep 17 00:00:00 2001 From: frozen <355847+Frozen@users.noreply.github.com> Date: Mon, 22 Sep 2025 19:25:17 -0500 Subject: [PATCH 6/7] Refactor ActivePrecompiles function to use rules parameter instead of evm.chainRules --- core/chain_makers.go | 347 ------------------------------------------- core/vm/evm.go | 11 +- 2 files changed, 8 insertions(+), 350 deletions(-) delete mode 100644 core/chain_makers.go diff --git a/core/chain_makers.go b/core/chain_makers.go deleted file mode 100644 index 30ecce9361..0000000000 --- a/core/chain_makers.go +++ /dev/null @@ -1,347 +0,0 @@ -// Copyright 2015 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 core - -import ( - "math/big" - - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/consensus" - //"github.com/ethereum/go-ethereum/consensus/misc" - //"github.com/ethereum/go-ethereum/core/state" - "github.com/ethereum/go-ethereum/core/types" - //"github.com/ethereum/go-ethereum/ethdb" - "github.com/ethereum/go-ethereum/params" - "github.com/harmony-one/harmony/block" - hmystate "github.com/harmony-one/harmony/core/state" - hmyTypes "github.com/harmony-one/harmony/core/types" - //"github.com/harmony-one/harmony/core/vm" -) - -// BlockGen creates blocks for testing. -// See GenerateChain for a detailed explanation. -type BlockGen struct { - i int - parent *types.Block - chain []*types.Block - header *block.Header - statedb *hmystate.DB - - gasPool *GasPool - txs []*types.Transaction - receipts []*hmyTypes.Receipt - uncles []*types.Header - - config *params.ChainConfig - engine consensus.Engine -} - -// SetCoinbase sets the coinbase of the generated block. -// It can be called at most once. -func (b *BlockGen) SetCoinbase(addr common.Address) { - if b.gasPool != nil { - if len(b.txs) > 0 { - panic("coinbase must be set before adding transactions") - } - panic("coinbase can only be set once") - } - b.header.SetCoinbase(addr) - b.gasPool = new(GasPool).AddGas(b.header.GasLimit()) -} - -// SetExtra sets the extra data field of the generated block. -func (b *BlockGen) SetExtra(data []byte) { - b.header.SetExtra(data) -} - -// SetNonce sets the nonce field of the generated block. -//func (b *BlockGen) SetNonce(nonce types.BlockNonce) { -// b.header.Setno = nonce -//} - -// SetDifficulty sets the difficulty field of the generated block. This method is -// useful for Clique tests where the difficulty does not depend on time. For the -// ethash tests, please use OffsetTime, which implicitly recalculates the diff. -//func (b *BlockGen) SetDifficulty(diff *big.Int) { -// b.header.Difficulty = diff -//} - -/* -func (b *BlockGen) addTx(bc BlockChain, vmConfig vm.Config, tx *hmyTypes.Transaction) { - if b.gasPool == nil { - b.SetCoinbase(common.Address{}) - } - b.statedb.SetTxContext(tx.Hash(), len(b.txs)) - addr := b.header.Coinbase() - gasUsed := b.header.GasUsed() - receipt, _, _, _, err := ApplyTransaction(bc, &addr, b.gasPool, b.statedb, b.header, tx, &gasUsed, vmConfig) - if err != nil { - panic(err) - } - b.txs = append(b.txs, tx) - b.receipts = append(b.receipts, receipt) -} - -// AddTx adds a transaction to the generated block. If no coinbase has -// been set, the block's coinbase is set to the zero address. -// -// AddTx panics if the transaction cannot be executed. In addition to -// the protocol-imposed limitations (gas limit, etc.), there are some -// further limitations on the content of transactions that can be -// added. Notably, contract code relying on the BLOCKHASH instruction -// will panic during execution. -func (b *BlockGen) AddTx(tx *types.Transaction) { - b.addTx(nil, vm.Config{}, tx) -} - -// AddTxWithChain adds a transaction to the generated block. If no coinbase has -// been set, the block's coinbase is set to the zero address. -// -// AddTxWithChain panics if the transaction cannot be executed. In addition to -// the protocol-imposed limitations (gas limit, etc.), there are some -// further limitations on the content of transactions that can be -// added. If contract code relies on the BLOCKHASH instruction, -// the block in chain will be returned. -func (b *BlockGen) AddTxWithChain(bc BlockChain, tx *types.Transaction) { - b.addTx(bc, vm.Config{}, tx) -} - -// GetBalance returns the balance of the given address at the generated block. -func (b *BlockGen) GetBalance(addr common.Address) *big.Int { - return b.statedb.GetBalance(addr) -} - -// AddUncheckedTx forcefully adds a transaction to the block without any -// validation. -// -// AddUncheckedTx will cause consensus failures when used during real -// chain processing. This is best used in conjunction with raw block insertion. -func (b *BlockGen) AddUncheckedTx(tx *types.Transaction) { - b.txs = append(b.txs, tx) -} - -// Number returns the block number of the block being generated. -func (b *BlockGen) Number() *big.Int { - return new(big.Int).Set(b.header.Number) -} - -// BaseFee returns the EIP-1559 base fee of the block being generated. -func (b *BlockGen) BaseFee() *big.Int { - return new(big.Int).Set(b.header.BaseFee) -} - -// AddUncheckedReceipt forcefully adds a receipts to the block without a -// backing transaction. -// -// AddUncheckedReceipt will cause consensus failures when used during real -// chain processing. This is best used in conjunction with raw block insertion. -func (b *BlockGen) AddUncheckedReceipt(receipt *types.Receipt) { - b.receipts = append(b.receipts, receipt) -} - -// TxNonce returns the next valid transaction nonce for the -// account at addr. It panics if the account does not exist. -func (b *BlockGen) TxNonce(addr common.Address) uint64 { - if !b.statedb.Exist(addr) { - panic("account does not exist") - } - return b.statedb.GetNonce(addr) -} - -// AddUncle adds an uncle header to the generated block. -func (b *BlockGen) AddUncle(h *types.Header) { - // The uncle will have the same timestamp and auto-generated difficulty - h.Time = b.header.Time() - - var parent *types.Header - for i := b.i - 1; i >= 0; i-- { - if b.chain[i].Hash() == h.ParentHash { - parent = b.chain[i].Header() - break - } - } - //chainreader := &fakeChainReader{config: b.config} - //h.Difficulty = b.engine.CalcDifficulty(chainreader, b.header.Time, parent) - - // The gas limit and price should be derived from the parent - h.GasLimit = parent.GasLimit - if b.config.IsLondon(h.Number) { - h.BaseFee = misc.CalcBaseFee(b.config, parent) - if !b.config.IsLondon(parent.Number) { - parentGasLimit := parent.GasLimit * params.ElasticityMultiplier - h.GasLimit = CalcGasLimit(parentGasLimit, parentGasLimit) - } - } - b.uncles = append(b.uncles, h) -} - -// PrevBlock returns a previously generated block by number. It panics if -// num is greater or equal to the number of the block being generated. -// For index -1, PrevBlock returns the parent block given to GenerateChain. -func (b *BlockGen) PrevBlock(index int) *types.Block { - if index >= b.i { - panic(fmt.Errorf("block index %d out of range (%d,%d)", index, -1, b.i)) - } - if index == -1 { - return b.parent - } - return b.chain[index] -} - -// OffsetTime modifies the time instance of a block, implicitly changing its -// associated difficulty. It's useful to test scenarios where forking is not -// tied to chain length directly. -//func (b *BlockGen) OffsetTime(seconds int64) { -// b.header.Time += uint64(seconds) -// if b.header.Time <= b.parent.Header().Time { -// panic("block time out of range") -// } -// chainreader := &fakeChainReader{config: b.config} -// b.header.Difficulty = b.engine.CalcDifficulty(chainreader, b.header.Time, b.parent.Header()) -//} - -// GenerateChain creates a chain of n blocks. The first block's -// parent will be the provided parent. db is used to store -// intermediate states and should contain the parent's state trie. -// -// The generator function is called with a new block generator for -// every block. Any transactions and uncles added to the generator -// become part of the block. If gen is nil, the blocks will be empty -// and their coinbase will be the zero address. -// -// Blocks created by GenerateChain do not contain valid proof of work -// values. Inserting them into BlockChain requires use of FakePow or -// a similar non-validating proof of work implementation. -func GenerateChain(config *params.ChainConfig, parent *types.Block, engine consensus.Engine, db ethdb.Database, n int, gen func(int, *BlockGen)) ([]*types.Block, []hmyTypes.Receipts) { - if config == nil { - config = params.TestChainConfig - } - blocks, receipts := make(types.Blocks, n), make([]types.Receipts, n) - chainreader := &fakeChainReader{config: config} - genblock := func(i int, parent *types.Block, statedb *state.StateDB) (*types.Block, types.Receipts) { - b := &BlockGen{i: i, chain: blocks, parent: parent, statedb: statedb, config: config, engine: engine} - b.header = makeHeader(chainreader, parent, statedb, b.engine) - - // Mutate the state and block according to any hard-fork specs - if daoBlock := config.DAOForkBlock; daoBlock != nil { - limit := new(big.Int).Add(daoBlock, params.DAOForkExtraRange) - if b.header.Number.Cmp(daoBlock) >= 0 && b.header.Number.Cmp(limit) < 0 { - if config.DAOForkSupport { - b.header.SetExtra(common.CopyBytes(params.DAOForkBlockExtra)) - } - } - } - if config.DAOForkSupport && config.DAOForkBlock != nil && config.DAOForkBlock.Cmp(b.header.Number()) == 0 { - misc.ApplyDAOHardFork(statedb) - } - // Execute any user modifications to the block - if gen != nil { - gen(i, b) - } - if b.engine != nil { - // Finalize and seal the block - block, _ := b.engine.FinalizeAndAssemble(chainreader, b.header, statedb, b.txs, b.uncles, b.receipts) - - // Write state changes to db - root, err := statedb.Commit(config.IsEIP158(b.header.Number())) - if err != nil { - panic(fmt.Sprintf("state write error: %v", err)) - } - if err := statedb.Database().TrieDB().Commit(root, false, nil); err != nil { - panic(fmt.Sprintf("trie write error: %v", err)) - } - return block, b.receipts - } - return nil, nil - } - for i := 0; i < n; i++ { - statedb, err := state.New(parent.Root(), state.NewDatabase(db), nil) - if err != nil { - panic(err) - } - block, receipt := genblock(i, parent, statedb) - blocks[i] = block - receipts[i] = receipt - parent = block - } - return blocks, receipts -} - -func makeHeader(chain consensus.ChainReader, parent *types.Block, state *state.StateDB, engine consensus.Engine) *types.Header { - var time uint64 - if parent.Time() == 0 { - time = 10 - } else { - time = parent.Time() + 10 // block time is fixed at 10 seconds - } - header := &types.Header{ - Root: state.IntermediateRoot(chain.Config().IsEIP158(parent.Number())), - ParentHash: parent.Hash(), - Coinbase: parent.Coinbase(), - Difficulty: engine.CalcDifficulty(chain, time, &types.Header{ - Number: parent.Number(), - Time: time - 10, - Difficulty: parent.Difficulty(), - UncleHash: parent.UncleHash(), - }), - GasLimit: parent.GasLimit(), - Number: new(big.Int).Add(parent.Number(), common.Big1), - Time: time, - } - if chain.Config().IsLondon(header.Number) { - header.BaseFee = misc.CalcBaseFee(chain.Config(), parent.Header()) - if !chain.Config().IsLondon(parent.Number()) { - parentGasLimit := parent.GasLimit() * params.ElasticityMultiplier - header.GasLimit = CalcGasLimit(parentGasLimit, parentGasLimit) - } - } - return header -} - -// makeHeaderChain creates a deterministic chain of headers rooted at parent. -func makeHeaderChain(parent *types.Header, n int, engine consensus.Engine, db ethdb.Database, seed int) []*types.Header { - blocks := makeBlockChain(types.NewBlockWithHeader(parent), n, engine, db, seed) - headers := make([]*types.Header, len(blocks)) - for i, block := range blocks { - headers[i] = block.Header() - } - return headers -} -*/ -// makeBlockChain creates a deterministic chain of blocks rooted at parent. -//func makeBlockChain(parent *types.Block, n int, engine consensus.Engine, db ethdb.Database, seed int) []*types.Block { -// blocks, _ := GenerateChain(params.TestChainConfig, parent, engine, db, n, func(i int, b *BlockGen) { -// b.SetCoinbase(common.Address{0: byte(seed), 19: byte(i)}) -// }) -// return blocks -//} - -type fakeChainReader struct { - config *params.ChainConfig -} - -// Config returns the chain configuration. -func (cr *fakeChainReader) Config() *params.ChainConfig { - return cr.config -} - -func (cr *fakeChainReader) CurrentHeader() *types.Header { return nil } -func (cr *fakeChainReader) GetHeaderByNumber(number uint64) *types.Header { return nil } -func (cr *fakeChainReader) GetHeaderByHash(hash common.Hash) *types.Header { return nil } -func (cr *fakeChainReader) GetHeader(hash common.Hash, number uint64) *types.Header { return nil } -func (cr *fakeChainReader) GetBlock(hash common.Hash, number uint64) *types.Block { return nil } -func (cr *fakeChainReader) GetTd(hash common.Hash, number uint64) *big.Int { return nil } diff --git a/core/vm/evm.go b/core/vm/evm.go index 257eb86a65..055f200cc3 100644 --- a/core/vm/evm.go +++ b/core/vm/evm.go @@ -69,12 +69,17 @@ type ( // ActivePrecompiles returns the addresses of the precompiles enabled with the current // configuration func (evm *EVM) ActivePrecompiles() []common.Address { + return ActivePrecompiles(evm.chainRules) +} + +// ActivePrecompiles returns the precompiles enabled with the current configuration. +func ActivePrecompiles(rules params.Rules) []common.Address { switch { - case evm.chainRules.IsYoloV2: + case rules.IsYoloV2: return PrecompiledAddressesYoloV2 - case evm.chainRules.IsIstanbul: + case rules.IsIstanbul: return PrecompiledAddressesIstanbul - case evm.chainRules.IsByzantium: + case rules.IsByzantium: return PrecompiledAddressesByzantium default: return PrecompiledAddressesHomestead From eb959ce9bca4c5b8a247976ee4b8dea21c8ced6d Mon Sep 17 00:00:00 2001 From: frozen <355847+Frozen@users.noreply.github.com> Date: Tue, 23 Sep 2025 01:46:21 -0500 Subject: [PATCH 7/7] Refactor state transition preparation to use statedb.Prepare method --- core/vm/runtime/runtime.go | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/core/vm/runtime/runtime.go b/core/vm/runtime/runtime.go index 2999694479..20ad511ebc 100644 --- a/core/vm/runtime/runtime.go +++ b/core/vm/runtime/runtime.go @@ -171,14 +171,16 @@ func Call(address common.Address, input []byte, cfg *Config) ([]byte, uint64, er setDefaults(cfg) var ( - vmenv = NewEnv(cfg) - sender = cfg.State.GetOrNewStateObject(cfg.Origin) - rules = cfg.ChainConfig.Rules(vmenv.Context.EpochNumber) + vmenv = NewEnv(cfg) + sender = cfg.State.GetOrNewStateObject(cfg.Origin) + statedb = cfg.State + rules = cfg.ChainConfig.Rules(vmenv.Context.EpochNumber) ) // Execute the preparatory steps for state transition which includes: + // - prepare accessList(post-berlin) // - reset transient storage(eip 1153) - // vmenv.StateDB.Prepare() eip 1153 + statedb.Prepare(rules, cfg.Origin, &address, vm.ActivePrecompiles(rules), nil) // Call the code with the given configuration. ret, leftOverGas, err := vmenv.Call(