trie: use unified emptyRootHash and emptyCodeHash (#26718)

This commit is contained in:
Daniel Liu 2025-03-25 21:43:02 +08:00 committed by Daniel Liu
parent c8b39cabae
commit 5328a637c0
8 changed files with 24 additions and 29 deletions

View file

@ -22,6 +22,7 @@ import (
"errors" "errors"
"github.com/XinFinOrg/XDPoSChain/common" "github.com/XinFinOrg/XDPoSChain/common"
"github.com/XinFinOrg/XDPoSChain/core/types"
) )
// Iterator is a key-value trie iterator that traverses a Trie. // Iterator is a key-value trie iterator that traverses a Trie.
@ -134,7 +135,7 @@ func (e seekError) Error() string {
} }
func newNodeIterator(trie *Trie, start []byte) NodeIterator { func newNodeIterator(trie *Trie, start []byte) NodeIterator {
if trie.Hash() == emptyState { if trie.Hash() == types.EmptyCodeHash {
return new(nodeIterator) return new(nodeIterator)
} }
it := &nodeIterator{trie: trie} it := &nodeIterator{trie: trie}
@ -259,7 +260,7 @@ func (it *nodeIterator) peek(descend bool) (*nodeIteratorState, *int, []byte, er
// Initialize the iterator if we've just started. // Initialize the iterator if we've just started.
root := it.trie.Hash() root := it.trie.Hash()
state := &nodeIteratorState{node: it.trie.root, index: -1} state := &nodeIteratorState{node: it.trie.root, index: -1}
if root != emptyRoot { if root != types.EmptyRootHash {
state.hash = root state.hash = root
} }
err := state.resolve(it.trie, nil) err := state.resolve(it.trie, nil)

View file

@ -23,6 +23,7 @@ import (
"testing" "testing"
"github.com/XinFinOrg/XDPoSChain/common" "github.com/XinFinOrg/XDPoSChain/common"
"github.com/XinFinOrg/XDPoSChain/core/types"
"github.com/XinFinOrg/XDPoSChain/ethdb/memorydb" "github.com/XinFinOrg/XDPoSChain/ethdb/memorydb"
) )
@ -295,7 +296,7 @@ func testIteratorContinueAfterError(t *testing.T, memonly bool) {
diskdb := memorydb.New() diskdb := memorydb.New()
triedb := NewDatabase(diskdb) triedb := NewDatabase(diskdb)
tr, _ := New(emptyRoot, triedb) tr, _ := New(types.EmptyRootHash, triedb)
for _, val := range testdata1 { for _, val := range testdata1 {
tr.Update([]byte(val.k), []byte(val.v)) tr.Update([]byte(val.k), []byte(val.v))
} }
@ -386,7 +387,7 @@ func testIteratorContinueAfterSeekError(t *testing.T, memonly bool) {
diskdb := memorydb.New() diskdb := memorydb.New()
triedb := NewDatabase(diskdb) triedb := NewDatabase(diskdb)
ctr, _ := New(emptyRoot, triedb) ctr, _ := New(types.EmptyRootHash, triedb)
for _, val := range testdata1 { for _, val := range testdata1 {
ctr.Update([]byte(val.k), []byte(val.v)) ctr.Update([]byte(val.k), []byte(val.v))
} }

View file

@ -22,6 +22,7 @@ import (
"fmt" "fmt"
"github.com/XinFinOrg/XDPoSChain/common" "github.com/XinFinOrg/XDPoSChain/common"
"github.com/XinFinOrg/XDPoSChain/core/types"
"github.com/XinFinOrg/XDPoSChain/ethdb" "github.com/XinFinOrg/XDPoSChain/ethdb"
"github.com/XinFinOrg/XDPoSChain/ethdb/memorydb" "github.com/XinFinOrg/XDPoSChain/ethdb/memorydb"
"github.com/XinFinOrg/XDPoSChain/log" "github.com/XinFinOrg/XDPoSChain/log"
@ -418,7 +419,7 @@ func VerifyRangeProof(rootHash common.Hash, firstKey []byte, keys [][]byte, valu
// Special case, there is no edge proof at all. The given range is expected // Special case, there is no edge proof at all. The given range is expected
// to be the whole leaf-set in the trie. // to be the whole leaf-set in the trie.
if firstProof == nil && lastProof == nil { if firstProof == nil && lastProof == nil {
emptytrie, err := New(emptyRoot, NewDatabase(memorydb.New())) emptytrie, err := New(types.EmptyRootHash, NewDatabase(memorydb.New()))
if err != nil { if err != nil {
return err, false return err, false
} }

View file

@ -26,6 +26,7 @@ import (
"sync" "sync"
"github.com/XinFinOrg/XDPoSChain/common" "github.com/XinFinOrg/XDPoSChain/common"
"github.com/XinFinOrg/XDPoSChain/core/types"
"github.com/XinFinOrg/XDPoSChain/ethdb" "github.com/XinFinOrg/XDPoSChain/ethdb"
"github.com/XinFinOrg/XDPoSChain/log" "github.com/XinFinOrg/XDPoSChain/log"
) )
@ -383,7 +384,7 @@ func (st *StackTrie) hashRec(hasher *hasher) {
return return
case emptyNode: case emptyNode:
st.val = emptyRoot.Bytes() st.val = types.EmptyRootHash.Bytes()
st.key = st.key[:0] st.key = st.key[:0]
st.nodeType = hashedNode st.nodeType = hashedNode
return return

View file

@ -23,6 +23,7 @@ import (
"github.com/XinFinOrg/XDPoSChain/common" "github.com/XinFinOrg/XDPoSChain/common"
"github.com/XinFinOrg/XDPoSChain/common/prque" "github.com/XinFinOrg/XDPoSChain/common/prque"
"github.com/XinFinOrg/XDPoSChain/core/rawdb" "github.com/XinFinOrg/XDPoSChain/core/rawdb"
"github.com/XinFinOrg/XDPoSChain/core/types"
"github.com/XinFinOrg/XDPoSChain/ethdb" "github.com/XinFinOrg/XDPoSChain/ethdb"
) )
@ -109,7 +110,7 @@ func NewSync(root common.Hash, database ethdb.KeyValueReader, callback LeafCallb
// AddSubTrie registers a new trie to the sync code, rooted at the designated parent. // AddSubTrie registers a new trie to the sync code, rooted at the designated parent.
func (s *Sync) AddSubTrie(root common.Hash, depth int, parent common.Hash, callback LeafCallback) { func (s *Sync) AddSubTrie(root common.Hash, depth int, parent common.Hash, callback LeafCallback) {
// Short circuit if the trie is empty or already known // Short circuit if the trie is empty or already known
if root == emptyRoot { if root == types.EmptyRootHash {
return return
} }
if s.membatch.hasNode(root) { if s.membatch.hasNode(root) {
@ -149,7 +150,7 @@ func (s *Sync) AddSubTrie(root common.Hash, depth int, parent common.Hash, callb
// as is. // as is.
func (s *Sync) AddCodeEntry(hash common.Hash, depth int, parent common.Hash) { func (s *Sync) AddCodeEntry(hash common.Hash, depth int, parent common.Hash) {
// Short circuit if the entry is empty or already known // Short circuit if the entry is empty or already known
if hash == emptyState { if hash == types.EmptyCodeHash {
return return
} }
if s.membatch.hasCode(hash) { if s.membatch.hasCode(hash) {

View file

@ -21,6 +21,7 @@ import (
"testing" "testing"
"github.com/XinFinOrg/XDPoSChain/common" "github.com/XinFinOrg/XDPoSChain/common"
"github.com/XinFinOrg/XDPoSChain/core/types"
"github.com/XinFinOrg/XDPoSChain/ethdb/memorydb" "github.com/XinFinOrg/XDPoSChain/ethdb/memorydb"
) )
@ -28,7 +29,7 @@ import (
func makeTestTrie() (*Database, *Trie, map[string][]byte) { func makeTestTrie() (*Database, *Trie, map[string][]byte) {
// Create an empty trie // Create an empty trie
triedb := NewDatabase(memorydb.New()) triedb := NewDatabase(memorydb.New())
trie, _ := New(emptyRoot, triedb) trie, _ := New(types.EmptyRootHash, triedb)
// Fill it with some arbitrary data // Fill it with some arbitrary data
content := make(map[string][]byte) content := make(map[string][]byte)
@ -90,8 +91,8 @@ func checkTrieConsistency(db *Database, root common.Hash) error {
func TestEmptySync(t *testing.T) { func TestEmptySync(t *testing.T) {
dbA := NewDatabase(memorydb.New()) dbA := NewDatabase(memorydb.New())
dbB := NewDatabase(memorydb.New()) dbB := NewDatabase(memorydb.New())
emptyA, _ := New(emptyRoot, dbA) emptyA, _ := New(types.EmptyRootHash, dbA)
emptyB, _ := New(emptyRoot, dbB) emptyB, _ := New(types.EmptyRootHash, dbB)
for i, trie := range []*Trie{emptyA, emptyB} { for i, trie := range []*Trie{emptyA, emptyB} {
if req := NewSync(trie.Hash(), memorydb.New(), nil, NewSyncBloom(1, memorydb.New())).Missing(1); len(req) != 0 { if req := NewSync(trie.Hash(), memorydb.New(), nil, NewSyncBloom(1, memorydb.New())).Missing(1); len(req) != 0 {

View file

@ -23,22 +23,10 @@ import (
"sync" "sync"
"github.com/XinFinOrg/XDPoSChain/common" "github.com/XinFinOrg/XDPoSChain/common"
"github.com/XinFinOrg/XDPoSChain/crypto" "github.com/XinFinOrg/XDPoSChain/core/types"
"github.com/XinFinOrg/XDPoSChain/log" "github.com/XinFinOrg/XDPoSChain/log"
) )
var (
// TODO(daniel):
// 1. remove file core/types/derive_sha.go, Ref: #21502
// 2. then replace emptyRoot, emptyState with types.EmptyRootHash, types.EmptyCodeHash, Ref: #26718
// emptyRoot is the known root hash of an empty trie.
emptyRoot = common.HexToHash("56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421")
// emptyState is the known hash of an empty state trie entry.
emptyState = crypto.Keccak256Hash(nil)
)
// LeafCallback is a callback type invoked when a trie operation reaches a leaf // LeafCallback is a callback type invoked when a trie operation reaches a leaf
// Node. It's used by state sync and commit to allow handling external references // Node. It's used by state sync and commit to allow handling external references
// between account and storage tries. // between account and storage tries.
@ -76,7 +64,7 @@ func New(root common.Hash, db *Database) (*Trie, error) {
trie := &Trie{ trie := &Trie{
Db: db, Db: db,
} }
if root != (common.Hash{}) && root != emptyRoot { if root != (common.Hash{}) && root != types.EmptyRootHash {
rootnode, err := trie.resolveHash(root[:], nil) rootnode, err := trie.resolveHash(root[:], nil)
if err != nil { if err != nil {
return nil, err return nil, err
@ -591,7 +579,7 @@ func (t *Trie) Commit(onleaf LeafCallback) (root common.Hash, err error) {
panic("commit called on trie with nil database") panic("commit called on trie with nil database")
} }
if t.root == nil { if t.root == nil {
return emptyRoot, nil return types.EmptyRootHash, nil
} }
// Derive the hash for all dirty nodes first. We hold the assumption // Derive the hash for all dirty nodes first. We hold the assumption
// in the following procedure that all nodes are hashed. // in the following procedure that all nodes are hashed.
@ -635,7 +623,7 @@ func (t *Trie) Commit(onleaf LeafCallback) (root common.Hash, err error) {
// hashRoot calculates the root hash of the given trie // hashRoot calculates the root hash of the given trie
func (t *Trie) hashRoot() (node, node, error) { func (t *Trie) hashRoot() (node, node, error) {
if t.root == nil { if t.root == nil {
return hashNode(emptyRoot.Bytes()), nil, nil return hashNode(types.EmptyRootHash.Bytes()), nil, nil
} }
// If the number of changes is below 100, we let one thread handle it // If the number of changes is below 100, we let one thread handle it
h := newHasher(t.unhashed >= 100) h := newHasher(t.unhashed >= 100)

View file

@ -29,6 +29,7 @@ import (
"testing/quick" "testing/quick"
"github.com/XinFinOrg/XDPoSChain/common" "github.com/XinFinOrg/XDPoSChain/common"
"github.com/XinFinOrg/XDPoSChain/core/types"
"github.com/XinFinOrg/XDPoSChain/crypto" "github.com/XinFinOrg/XDPoSChain/crypto"
"github.com/XinFinOrg/XDPoSChain/ethdb" "github.com/XinFinOrg/XDPoSChain/ethdb"
"github.com/XinFinOrg/XDPoSChain/ethdb/memorydb" "github.com/XinFinOrg/XDPoSChain/ethdb/memorydb"
@ -51,7 +52,7 @@ func newEmpty() *Trie {
func TestEmptyTrie(t *testing.T) { func TestEmptyTrie(t *testing.T) {
var trie Trie var trie Trie
res := trie.Hash() res := trie.Hash()
exp := emptyRoot exp := types.EmptyRootHash
if res != exp { if res != exp {
t.Errorf("expected %x got %x", exp, res) t.Errorf("expected %x got %x", exp, res)
} }
@ -503,7 +504,7 @@ func makeAccounts(size int) (addresses [][20]byte, accounts [][]byte) {
var ( var (
nonce = uint64(random.Int63()) nonce = uint64(random.Int63())
balance = new(big.Int).Rand(random, new(big.Int).Exp(common.Big2, common.Big256, nil)) balance = new(big.Int).Rand(random, new(big.Int).Exp(common.Big2, common.Big256, nil))
root = emptyRoot root = types.EmptyRootHash
code = crypto.Keccak256(nil) code = crypto.Keccak256(nil)
) )
accounts[i], _ = rlp.EncodeToBytes(&account{nonce, balance, root, code}) accounts[i], _ = rlp.EncodeToBytes(&account{nonce, balance, root, code})