mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-27 15:16:43 +00:00
core/state, core: add block-hash to base-state-root mapping for Verkle transition
This commit is contained in:
parent
a8240e46ea
commit
ffe1d2406c
8 changed files with 118 additions and 61 deletions
|
|
@ -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': {}},
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
package core
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math/big"
|
||||
"testing"
|
||||
|
||||
|
|
@ -8,14 +9,24 @@ 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()
|
||||
trieDb = triedb.NewDatabase(db, nil)
|
||||
gspec = &Genesis{
|
||||
Config: ¶ms.ChainConfig{
|
||||
ChainID: big.NewInt(1337),
|
||||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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")
|
||||
|
|
|
|||
|
|
@ -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"),
|
||||
},
|
||||
},
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
Loading…
Reference in a new issue