core/state: do not ignore null addr while iterative dump (#27320)

fixes bug which caused the zero-address to be ignored during an iterative state-dump.

---------

Co-authored-by: Martin Holst Swende <martin@swende.se>
This commit is contained in:
Park Changwan 2023-05-23 19:10:26 +09:00 committed by GitHub
parent a190da9d68
commit bfded65ed8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 60 additions and 16 deletions

View File

@ -389,7 +389,10 @@ type Alloc map[common.Address]core.GenesisAccount
func (g Alloc) OnRoot(common.Hash) {} func (g Alloc) OnRoot(common.Hash) {}
func (g Alloc) OnAccount(addr common.Address, dumpAccount state.DumpAccount) { func (g Alloc) OnAccount(addr *common.Address, dumpAccount state.DumpAccount) {
if addr == nil {
return
}
balance, _ := new(big.Int).SetString(dumpAccount.Balance, 10) balance, _ := new(big.Int).SetString(dumpAccount.Balance, 10)
var storage map[common.Hash]common.Hash var storage map[common.Hash]common.Hash
if dumpAccount.Storage != nil { if dumpAccount.Storage != nil {
@ -404,7 +407,7 @@ func (g Alloc) OnAccount(addr common.Address, dumpAccount state.DumpAccount) {
Balance: balance, Balance: balance,
Nonce: dumpAccount.Nonce, Nonce: dumpAccount.Nonce,
} }
g[addr] = genesisAccount g[*addr] = genesisAccount
} }
// saveFile marshals the object to the given file // saveFile marshals the object to the given file

View File

@ -44,7 +44,7 @@ type DumpCollector interface {
// OnRoot is called with the state root // OnRoot is called with the state root
OnRoot(common.Hash) OnRoot(common.Hash)
// OnAccount is called once for each account in the trie // OnAccount is called once for each account in the trie
OnAccount(common.Address, DumpAccount) OnAccount(*common.Address, DumpAccount)
} }
// DumpAccount represents an account in the state. // DumpAccount represents an account in the state.
@ -72,8 +72,10 @@ func (d *Dump) OnRoot(root common.Hash) {
} }
// OnAccount implements DumpCollector interface // OnAccount implements DumpCollector interface
func (d *Dump) OnAccount(addr common.Address, account DumpAccount) { func (d *Dump) OnAccount(addr *common.Address, account DumpAccount) {
d.Accounts[addr] = account if addr != nil {
d.Accounts[*addr] = account
}
} }
// IteratorDump is an implementation for iterating over data. // IteratorDump is an implementation for iterating over data.
@ -89,8 +91,10 @@ func (d *IteratorDump) OnRoot(root common.Hash) {
} }
// OnAccount implements DumpCollector interface // OnAccount implements DumpCollector interface
func (d *IteratorDump) OnAccount(addr common.Address, account DumpAccount) { func (d *IteratorDump) OnAccount(addr *common.Address, account DumpAccount) {
d.Accounts[addr] = account if addr != nil {
d.Accounts[*addr] = account
}
} }
// iterativeDump is a DumpCollector-implementation which dumps output line-by-line iteratively. // iterativeDump is a DumpCollector-implementation which dumps output line-by-line iteratively.
@ -99,7 +103,7 @@ type iterativeDump struct {
} }
// OnAccount implements DumpCollector interface // OnAccount implements DumpCollector interface
func (d iterativeDump) OnAccount(addr common.Address, account DumpAccount) { func (d iterativeDump) OnAccount(addr *common.Address, account DumpAccount) {
dumpAccount := &DumpAccount{ dumpAccount := &DumpAccount{
Balance: account.Balance, Balance: account.Balance,
Nonce: account.Nonce, Nonce: account.Nonce,
@ -108,10 +112,7 @@ func (d iterativeDump) OnAccount(addr common.Address, account DumpAccount) {
Code: account.Code, Code: account.Code,
Storage: account.Storage, Storage: account.Storage,
SecureKey: account.SecureKey, SecureKey: account.SecureKey,
Address: nil, Address: addr,
}
if addr != (common.Address{}) {
dumpAccount.Address = &addr
} }
d.Encode(dumpAccount) d.Encode(dumpAccount)
} }
@ -152,16 +153,20 @@ func (s *StateDB) DumpToCollector(c DumpCollector, conf *DumpConfig) (nextKey []
CodeHash: data.CodeHash, CodeHash: data.CodeHash,
SecureKey: it.Key, SecureKey: it.Key,
} }
addrBytes := s.trie.GetKey(it.Key) var (
addrBytes = s.trie.GetKey(it.Key)
addr = common.BytesToAddress(addrBytes)
address *common.Address
)
if addrBytes == nil { if addrBytes == nil {
// Preimage missing // Preimage missing
missingPreimages++ missingPreimages++
if conf.OnlyWithAddresses { if conf.OnlyWithAddresses {
continue continue
} }
account.SecureKey = it.Key } else {
address = &addr
} }
addr := common.BytesToAddress(addrBytes)
obj := newObject(s, addr, data) obj := newObject(s, addr, data)
if !conf.SkipCode { if !conf.SkipCode {
account.Code = obj.Code(s.db) account.Code = obj.Code(s.db)
@ -183,7 +188,7 @@ func (s *StateDB) DumpToCollector(c DumpCollector, conf *DumpConfig) (nextKey []
account.Storage[common.BytesToHash(s.trie.GetKey(storageIt.Key))] = common.Bytes2Hex(content) account.Storage[common.BytesToHash(s.trie.GetKey(storageIt.Key))] = common.Bytes2Hex(content)
} }
} }
c.OnAccount(addr, account) c.OnAccount(address, account)
accounts++ accounts++
if time.Since(logged) > 8*time.Second { if time.Since(logged) > 8*time.Second {
log.Info("Trie dumping in progress", "at", it.Key, "accounts", accounts, log.Info("Trie dumping in progress", "at", it.Key, "accounts", accounts,

View File

@ -18,6 +18,7 @@ package state
import ( import (
"bytes" "bytes"
"encoding/json"
"math/big" "math/big"
"testing" "testing"
@ -92,6 +93,41 @@ func TestDump(t *testing.T) {
} }
} }
func TestIterativeDump(t *testing.T) {
db := rawdb.NewMemoryDatabase()
sdb, _ := New(types.EmptyRootHash, NewDatabaseWithConfig(db, &trie.Config{Preimages: true}), nil)
s := &stateTest{db: db, state: sdb}
// generate a few entries
obj1 := s.state.GetOrNewStateObject(common.BytesToAddress([]byte{0x01}))
obj1.AddBalance(big.NewInt(22))
obj2 := s.state.GetOrNewStateObject(common.BytesToAddress([]byte{0x01, 0x02}))
obj2.SetCode(crypto.Keccak256Hash([]byte{3, 3, 3, 3, 3, 3, 3}), []byte{3, 3, 3, 3, 3, 3, 3})
obj3 := s.state.GetOrNewStateObject(common.BytesToAddress([]byte{0x02}))
obj3.SetBalance(big.NewInt(44))
obj4 := s.state.GetOrNewStateObject(common.BytesToAddress([]byte{0x00}))
obj4.AddBalance(big.NewInt(1337))
// write some of them to the trie
s.state.updateStateObject(obj1)
s.state.updateStateObject(obj2)
s.state.Commit(false)
b := &bytes.Buffer{}
s.state.IterativeDump(nil, json.NewEncoder(b))
// check that DumpToCollector contains the state objects that are in trie
got := b.String()
want := `{"root":"0xd5710ea8166b7b04bc2bfb129d7db12931cee82f75ca8e2d075b4884322bf3de"}
{"balance":"22","nonce":0,"root":"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421","codeHash":"0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470","address":"0x0000000000000000000000000000000000000001","key":"0x1468288056310c82aa4c01a7e12a10f8111a0560e72b700555479031b86c357d"}
{"balance":"1337","nonce":0,"root":"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421","codeHash":"0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470","address":"0x0000000000000000000000000000000000000000","key":"0x5380c7b7ae81a58eb98d9c78de4a1fd7fd9535fc953ed2be602daaa41767312a"}
{"balance":"0","nonce":0,"root":"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421","codeHash":"0x87874902497a5bb968da31a2998d8f22e949d1ef6214bcdedd8bae24cca4b9e3","code":"0x03030303030303","address":"0x0000000000000000000000000000000000000102","key":"0xa17eacbc25cda025e81db9c5c62868822c73ce097cee2a63e33a2e41268358a1"}
{"balance":"44","nonce":0,"root":"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421","codeHash":"0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470","address":"0x0000000000000000000000000000000000000002","key":"0xd52688a8f926c816ca1e079067caba944f158e764817b83fc43594370ca9cf62"}
`
if got != want {
t.Errorf("DumpToCollector mismatch:\ngot: %s\nwant: %s\n", got, want)
}
}
func TestNull(t *testing.T) { func TestNull(t *testing.T) {
s := newStateTest() s := newStateTest()
address := common.HexToAddress("0x823140710bf13990e4500136726d8b55") address := common.HexToAddress("0x823140710bf13990e4500136726d8b55")