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(