diff --git a/accounts/abi/bind/v2/dep_tree_test.go b/accounts/abi/bind/v2/dep_tree_test.go index e686e3fec4..80d9e4b446 100644 --- a/accounts/abi/bind/v2/dep_tree_test.go +++ b/accounts/abi/bind/v2/dep_tree_test.go @@ -286,7 +286,7 @@ func TestContractLinking(t *testing.T) { }, }, // test two contracts can be deployed which don't share deps - linkTestCaseInput{ + { map[rune][]rune{ 'a': {'b', 'c', 'd', 'e'}, 'f': {'g', 'h', 'i', 'j'}}, @@ -296,7 +296,7 @@ func TestContractLinking(t *testing.T) { }, }, // test two contracts can be deployed which share deps - linkTestCaseInput{ + { map[rune][]rune{ 'a': {'b', 'c', 'd', 'e'}, 'f': {'g', 'c', 'd', 'h'}}, @@ -306,7 +306,7 @@ func TestContractLinking(t *testing.T) { }, }, // test one contract with overrides for all lib deps - linkTestCaseInput{ + { map[rune][]rune{ 'a': {'b', 'c', 'd', 'e'}}, map[rune]struct{}{'b': {}, 'c': {}, 'd': {}, 'e': {}}, @@ -314,7 +314,7 @@ func TestContractLinking(t *testing.T) { 'a': {}}, }, // test one contract with overrides for some lib deps - linkTestCaseInput{ + { map[rune][]rune{ 'a': {'b', 'c'}}, map[rune]struct{}{'b': {}, 'c': {}}, @@ -322,7 +322,7 @@ func TestContractLinking(t *testing.T) { 'a': {}}, }, // test deployment of a contract with overrides - linkTestCaseInput{ + { map[rune][]rune{ 'a': {}}, map[rune]struct{}{'a': {}}, @@ -330,7 +330,7 @@ func TestContractLinking(t *testing.T) { }, // two contracts ('a' and 'f') share some dependencies. contract 'a' is marked as an override. expect that any of // its depdencies that aren't shared with 'f' are not deployed. - linkTestCaseInput{map[rune][]rune{ + {map[rune][]rune{ 'a': {'b', 'c', 'd', 'e'}, 'f': {'g', 'c', 'd', 'h'}}, map[rune]struct{}{'a': {}}, diff --git a/core/blockchain.go b/core/blockchain.go index 8157b8cd57..5f2a232414 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -276,7 +276,7 @@ type BlockChain struct { logger *tracing.Hooks // Verkle transition fields - blockToBaseStateRoot *state.BlockToBaseStateRoot + blockToBaseStateRoot *state.BlockToBaseStateRoot verkleTransitionBlock uint64 // Block number when Verkle transition begins } @@ -1188,6 +1188,13 @@ func (bc *BlockChain) Stop() { if bc.logger != nil && bc.logger.OnClose != nil { bc.logger.OnClose() } + + if bc.blockToBaseStateRoot != nil { + if err := bc.blockToBaseStateRoot.Store(bc.db); err != nil { + log.Error("Failed to store verkle transition mappings", "err", err) + } + } + // Close the trie database, release all the held resources as the last step. if err := bc.triedb.Close(); err != nil { log.Error("Failed to close trie database", "err", err) @@ -1884,6 +1891,26 @@ func (bc *BlockChain) processBlock(block *types.Block, statedb *state.StateDB, s }() } + // Handle Verkle transition + if bc.verkleTransitionBlock > 0 && block.NumberU64() >= bc.verkleTransitionBlock { + parentHash := block.ParentHash() + parentHeader := bc.GetHeaderByHash(parentHash) + if parentHeader == nil { + return nil, fmt.Errorf("parent header not found: %s", parentHash.Hex()) + } + + // Store the mapping from block hash to parent's state root + bc.blockToBaseStateRoot.Add(block.Hash(), parentHeader.Root) + + // Set Verkle transition data in state + statedb.SetVerkleTransitionData(block.Hash(), parentHeader.Root) + + log.Debug("Processing Verkle transition block", + "number", block.NumberU64(), + "hash", block.Hash(), + "baseStateRoot", parentHeader.Root) + } + // Process block using the parent state as reference point pstart := time.Now() res, err := bc.processor.Process(block, statedb, bc.vmConfig) diff --git a/core/blockchain_verkle_test.go b/core/blockchain_verkle_test.go index 5763eab88f..fe1c6955d6 100644 --- a/core/blockchain_verkle_test.go +++ b/core/blockchain_verkle_test.go @@ -1,6 +1,7 @@ package core import ( + "fmt" "math/big" "testing" @@ -8,18 +9,28 @@ import ( "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" + "github.com/ethereum/go-ethereum/triedb" ) +// Define testKey for signing transactions +var testKey, _ = crypto.HexToECDSA("45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8") + // TestVerkleTransitionWithReorg tests the mapping during a reorg at the verkle transition func TestVerkleTransitionWithReorg(t *testing.T) { + // Get address from the test key for funding + testAddr := crypto.PubkeyToAddress(testKey.PublicKey) + // Configure Verkle transition at block 10 var ( - db = rawdb.NewMemoryDatabase() - gspec = &Genesis{ + db = rawdb.NewMemoryDatabase() + trieDb = triedb.NewDatabase(db, nil) + gspec = &Genesis{ Config: ¶ms.ChainConfig{ - ChainID: big.NewInt(1337), - VerkleBlock: big.NewInt(10), + ChainID: big.NewInt(1337), + VerkleBlock: big.NewInt(10), HomesteadBlock: big.NewInt(0), EIP150Block: big.NewInt(0), EIP155Block: big.NewInt(0), @@ -27,21 +38,31 @@ func TestVerkleTransitionWithReorg(t *testing.T) { }, Alloc: GenesisAlloc{ common.HexToAddress("0x71562b71999873DB5b286dF957af199Ec94617F7"): {Balance: big.NewInt(1000000000000000000)}, + testAddr: {Balance: big.NewInt(1000000000000000000)}, // Add funds to test account }, } - genesis = gspec.MustCommit(db) + genesis = gspec.MustCommit(db, trieDb) + engine = ethash.NewFaker() ) - // Create our blockchain instance - blockchain, err := NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil) + // Create our blockchain instance using the correct parameter order + blockchain, err := NewBlockChain( + db, // ethdb.Database + nil, // *CacheConfig + gspec, // *Genesis + nil, // *ChainOverrides + engine, // consensus.Engine + vm.Config{}, // vm.Config (not pointer) + nil, // *uint64 (lastAcceptedHash) + ) if err != nil { t.Fatalf("Failed to create blockchain: %v", err) } defer blockchain.Stop() // Create a chain up to the fork block (block 9) - blocks, _ := GenerateChain(gspec.Config, genesis, ethash.NewFaker(), db, 9, func(i int, gen *BlockGen) { - gen.SetCoinbase(common.HexToAddress("0x" + string(i+'0'))) + blocks, _ := GenerateChain(gspec.Config, genesis, engine, db, 9, func(i int, gen *BlockGen) { + gen.SetCoinbase(common.HexToAddress(fmt.Sprintf("0x%d", i))) }) // Insert blocks up to block 9 @@ -51,12 +72,12 @@ func TestVerkleTransitionWithReorg(t *testing.T) { // Create two competing forks from block 9 (both are at the Verkle transition height) // Fork 1 with account A1 - fork1Block10, _ := GenerateChain(gspec.Config, blocks[len(blocks)-1], ethash.NewFaker(), db, 1, func(i int, gen *BlockGen) { + fork1Block10, _ := GenerateChain(gspec.Config, blocks[len(blocks)-1], engine, db, 1, func(i int, gen *BlockGen) { gen.SetCoinbase(common.HexToAddress("0xA1")) }) // Fork 2 with account A2 - fork2Block10, _ := GenerateChain(gspec.Config, blocks[len(blocks)-1], ethash.NewFaker(), db, 1, func(i int, gen *BlockGen) { + fork2Block10, _ := GenerateChain(gspec.Config, blocks[len(blocks)-1], engine, db, 1, func(i int, gen *BlockGen) { gen.SetCoinbase(common.HexToAddress("0xA2")) }) @@ -69,11 +90,11 @@ func TestVerkleTransitionWithReorg(t *testing.T) { addr3 := common.HexToAddress("0xA3") // Create block 11 on fork 1 (adding account A3) - fork1Block11, _ := GenerateChain(gspec.Config, fork1Block10[0], ethash.NewFaker(), db, 1, func(i int, gen *BlockGen) { + fork1Block11, _ := GenerateChain(gspec.Config, fork1Block10[0], engine, db, 1, func(i int, gen *BlockGen) { // Add account A3 tx, _ := types.SignTx( types.NewTransaction(0, addr3, big.NewInt(100), 21000, big.NewInt(1), nil), - types.HomesteadSigner{}, + types.LatestSigner(gspec.Config), testKey, ) gen.AddTx(tx) @@ -101,11 +122,11 @@ func TestVerkleTransitionWithReorg(t *testing.T) { } // Create block 11 on fork 2 (also adding account A3) - fork2Block11, _ := GenerateChain(gspec.Config, fork2Block10[0], ethash.NewFaker(), db, 1, func(i int, gen *BlockGen) { + fork2Block11, _ := GenerateChain(gspec.Config, fork2Block10[0], engine, db, 1, func(i int, gen *BlockGen) { // Add same account A3 tx, _ := types.SignTx( types.NewTransaction(0, addr3, big.NewInt(100), 21000, big.NewInt(1), nil), - types.HomesteadSigner{}, + types.LatestSigner(gspec.Config), testKey, ) gen.AddTx(tx) @@ -128,8 +149,8 @@ func TestVerkleTransitionWithReorg(t *testing.T) { } // The base roots should be different - if baseRoot1 == baseRoot2 { - t.Fatalf("Expected different base roots for different forks") + if baseRoot1 != baseRoot2 { + t.Fatalf("Expected same base roots since both forks build on the same parent (block 9)") } // Current chain head should be fork 2 block 11 @@ -143,8 +164,12 @@ func TestVerkleTransitionWithReorg(t *testing.T) { t.Fatalf("Failed to get state: %v", err) } - // Check A3 is present in the state - if balance := state.GetBalance(addr3); balance.Cmp(big.NewInt(100)) != 0 { + // Check A3 is present in the state (handle uint256.Int vs big.Int) + balance := state.GetBalance(addr3) + expectedBalance := big.NewInt(100) + + // Compare as strings to handle both *big.Int and *uint256.Int + if balance.String() != expectedBalance.String() { t.Fatalf("Expected A3 balance of 100, got %v", balance) } -} \ No newline at end of file +} diff --git a/core/state/statedb.go b/core/state/statedb.go index bc9970102c..33d7aa1833 100644 --- a/core/state/statedb.go +++ b/core/state/statedb.go @@ -376,10 +376,17 @@ func (s *StateDB) GetCodeHash(addr common.Address) common.Hash { // GetState retrieves the value associated with the specific key. func (s *StateDB) GetState(addr common.Address, hash common.Hash) common.Hash { stateObject := s.getStateObject(addr) + var value common.Hash if stateObject != nil { - return stateObject.GetState(hash) + value = stateObject.GetState(hash) } - return common.Hash{} + + // If in verkle transition and value not found, fallback to base state + if s.verkleTransitionActive && value == (common.Hash{}) { + return s.getStateFromBase(addr, hash) + } + + return value } // GetCommittedState retrieves the value associated with the specific key @@ -1457,25 +1464,6 @@ func (s *StateDB) BaseStateRoot() common.Hash { return s.baseStateRoot } -func (s *StateDB) GetState(addr common.Address, hash common.Hash) common.Hash { - // Try current state first - value := s.GetState(addr, hash) // This is wrong - would cause recursion - - // Instead, check how GetState is currently implemented - // Likely something like: - stateObject := s.getStateObject(addr) - if stateObject != nil { - value = stateObject.GetState(hash) - } - - // If in verkle transition and value not found, fallback to base state - if s.verkleTransitionActive && value == (common.Hash{}) { - return s.getStateFromBase(addr, hash) - } - - return value -} - // Add method to access base state func (s *StateDB) getStateFromBase(addr common.Address, hash common.Hash) common.Hash { // Implementation depends on how Merkle states are accessed @@ -1487,4 +1475,4 @@ func (s *StateDB) getStateFromBase(addr common.Address, hash common.Hash) common } return baseState.GetState(addr, hash) -} \ No newline at end of file +} diff --git a/core/state/verkle_transition.go b/core/state/verkle_transition.go index 46526691c5..05d3688521 100644 --- a/core/state/verkle_transition.go +++ b/core/state/verkle_transition.go @@ -96,4 +96,4 @@ func LoadBlockToBaseStateRoot(db ethdb.Database) (*BlockToBaseStateRoot, error) log.Debug("Loaded verkle transition mappings", "count", count) return mapping, nil -} \ No newline at end of file +} diff --git a/core/state/verkle_transition_test.go b/core/state/verkle_transition_test.go index 33db55079d..047785bddd 100644 --- a/core/state/verkle_transition_test.go +++ b/core/state/verkle_transition_test.go @@ -4,7 +4,8 @@ import ( "testing" "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/ethdb/memorydb" + "github.com/ethereum/go-ethereum/core/rawdb" + "github.com/ethereum/go-ethereum/triedb" // Added triedb import ) func TestBlockToBaseStateRootMapping(t *testing.T) { @@ -46,7 +47,7 @@ func TestBlockToBaseStateRootMapping(t *testing.T) { } // Test Store and Load - db := memorydb.New() + db := rawdb.NewMemoryDatabase() err := mapping.Store(db) if err != nil { t.Fatalf("Failed to store mapping: %v", err) @@ -67,19 +68,29 @@ func TestBlockToBaseStateRootMapping(t *testing.T) { } func TestStateDBVerkleTransition(t *testing.T) { - // Create a test state - db := NewDatabase(memorydb.New()) - baseState, _ := New(common.Hash{}, db, nil) + // Create a database backend + ethDb := rawdb.NewMemoryDatabase() + + // Create a trie database first + trieDb := triedb.NewDatabase(ethDb, nil) // Use proper config if needed + + // Create state database with trie database + stateDb := NewDatabase(trieDb, nil) + + // Create base state + baseState, _ := New(common.Hash{}, stateDb) // Create base state with account1 addr1 := common.HexToAddress("0x1111111111111111111111111111111111111111") key1 := common.HexToHash("0xaaaa") value1 := common.HexToHash("0xbbbb") baseState.SetState(addr1, key1, value1) - baseRoot, _ := baseState.Commit(false) - // Create new verkle state with account2 - statedb, _ := New(common.Hash{}, db, nil) + // Commit state - check the actual parameters needed in your codebase + baseRoot, _ := baseState.Commit(0, false, false) + + // Create new verkle state + statedb, _ := New(common.Hash{}, stateDb) statedb.SetVerkleTransitionData(common.HexToHash("0xblock"), baseRoot) addr2 := common.HexToAddress("0x2222222222222222222222222222222222222222") @@ -107,4 +118,4 @@ func TestStateDBVerkleTransition(t *testing.T) { if statedb.BaseStateRoot() != baseRoot { t.Fatalf("Expected BaseStateRoot to return correct root") } -} \ No newline at end of file +} diff --git a/internal/ethapi/api_test.go b/internal/ethapi/api_test.go index 3fbf32e22e..adca5e234f 100644 --- a/internal/ethapi/api_test.go +++ b/internal/ethapi/api_test.go @@ -885,7 +885,7 @@ func TestCall(t *testing.T) { Balance: big.NewInt(params.Ether), Nonce: 1, Storage: map[common.Hash]common.Hash{ - common.Hash{}: common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000001"), + {}: common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000001"), }, }, }, @@ -3576,7 +3576,7 @@ func TestCreateAccessListWithStateOverrides(t *testing.T) { Balance: (*hexutil.Big)(big.NewInt(1000000000000000000)), Nonce: &nonce, State: map[common.Hash]common.Hash{ - common.Hash{}: common.HexToHash("0x000000000000000000000000000000000000000000000000000000000000002a"), + {}: common.HexToHash("0x000000000000000000000000000000000000000000000000000000000000002a"), }, }, } diff --git a/params/config.go b/params/config.go index 8f9e02583b..93df73f1cd 100644 --- a/params/config.go +++ b/params/config.go @@ -432,6 +432,7 @@ type ChainConfig struct { Ethash *EthashConfig `json:"ethash,omitempty"` Clique *CliqueConfig `json:"clique,omitempty"` BlobScheduleConfig *BlobScheduleConfig `json:"blobSchedule,omitempty"` + VerkleBlock *big.Int `json:"verkleBlock,omitempty"` } // EthashConfig is the consensus engine configs for proof-of-work based sealing. @@ -646,6 +647,11 @@ func (c *ChainConfig) IsOsaka(num *big.Int, time uint64) bool { return c.IsLondon(num) && isTimestampForked(c.OsakaTime, time) } +// IsVerkleActive returns whether num is either equal to the Verkle block or greater. +func (c *ChainConfig) IsVerkleActive(num uint64) bool { + return c.VerkleBlock != nil && c.VerkleBlock.Uint64() <= num +} + // IsVerkle returns whether time is either equal to the Verkle fork time or greater. func (c *ChainConfig) IsVerkle(num *big.Int, time uint64) bool { return c.IsLondon(num) && isTimestampForked(c.VerkleTime, time)