core/state: simplify/unify dump implementation(s)

This commit is contained in:
Martin Holst Swende 2023-11-10 12:50:37 +01:00
parent 9191e97ca3
commit 1a35e349c2
No known key found for this signature in database
GPG key ID: 683B438C05A5DDF0
2 changed files with 16 additions and 40 deletions

View file

@ -65,6 +65,9 @@ type DumpAccount struct {
type Dump struct { type Dump struct {
Root string `json:"root"` Root string `json:"root"`
Accounts map[string]DumpAccount `json:"accounts"` Accounts map[string]DumpAccount `json:"accounts"`
// Next can be set to represent that this dump is only partial, and Next
// is where an iterator should be positioned in order to continue the dump.
Next []byte `json:"next,omitempty"` // nil if no more accounts
} }
// OnRoot implements DumpCollector interface // OnRoot implements DumpCollector interface
@ -82,25 +85,6 @@ func (d *Dump) OnAccount(addr *common.Address, account DumpAccount) {
} }
} }
// IteratorDump is an implementation for iterating over data.
type IteratorDump struct {
Root string `json:"root"`
Accounts map[common.Address]DumpAccount `json:"accounts"`
Next []byte `json:"next,omitempty"` // nil if no more accounts
}
// OnRoot implements DumpCollector interface
func (d *IteratorDump) OnRoot(root common.Hash) {
d.Root = fmt.Sprintf("%x", root)
}
// OnAccount implements DumpCollector interface
func (d *IteratorDump) OnAccount(addr *common.Address, account DumpAccount) {
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.
type iterativeDump struct { type iterativeDump struct {
*json.Encoder *json.Encoder
@ -227,12 +211,13 @@ func (s *StateDB) DumpToCollector(c DumpCollector, conf *DumpConfig) (nextKey []
return nextKey return nextKey
} }
// RawDump returns the entire state an a single large object // RawDump returns the state. If the processing is aborted e.g. due to options
// reaching Max, the `Next` key is set on the returned Dump.
func (s *StateDB) RawDump(opts *DumpConfig) Dump { func (s *StateDB) RawDump(opts *DumpConfig) Dump {
dump := &Dump{ dump := &Dump{
Accounts: make(map[string]DumpAccount), Accounts: make(map[string]DumpAccount),
} }
s.DumpToCollector(dump, opts) dump.Next = s.DumpToCollector(dump, opts)
return *dump return *dump
} }
@ -241,7 +226,7 @@ func (s *StateDB) Dump(opts *DumpConfig) []byte {
dump := s.RawDump(opts) dump := s.RawDump(opts)
json, err := json.MarshalIndent(dump, "", " ") json, err := json.MarshalIndent(dump, "", " ")
if err != nil { if err != nil {
fmt.Println("Dump err", err) log.Error("Error dumping state", "err", err)
} }
return json return json
} }
@ -250,12 +235,3 @@ func (s *StateDB) Dump(opts *DumpConfig) []byte {
func (s *StateDB) IterativeDump(opts *DumpConfig, output *json.Encoder) { func (s *StateDB) IterativeDump(opts *DumpConfig, output *json.Encoder) {
s.DumpToCollector(iterativeDump{output}, opts) s.DumpToCollector(iterativeDump{output}, opts)
} }
// IteratorDump dumps out a batch of accounts starts with the given start key
func (s *StateDB) IteratorDump(opts *DumpConfig) IteratorDump {
iterator := &IteratorDump{
Accounts: make(map[common.Address]DumpAccount),
}
iterator.Next = s.DumpToCollector(iterator, opts)
return *iterator
}

View file

@ -133,7 +133,7 @@ func (api *DebugAPI) GetBadBlocks(ctx context.Context) ([]*BadBlockArgs, error)
const AccountRangeMaxResults = 256 const AccountRangeMaxResults = 256
// AccountRange enumerates all accounts in the given block and start point in paging request // AccountRange enumerates all accounts in the given block and start point in paging request
func (api *DebugAPI) AccountRange(blockNrOrHash rpc.BlockNumberOrHash, start hexutil.Bytes, maxResults int, nocode, nostorage, incompletes bool) (state.IteratorDump, error) { func (api *DebugAPI) AccountRange(blockNrOrHash rpc.BlockNumberOrHash, start hexutil.Bytes, maxResults int, nocode, nostorage, incompletes bool) (state.Dump, error) {
var stateDb *state.StateDB var stateDb *state.StateDB
var err error var err error
@ -144,7 +144,7 @@ func (api *DebugAPI) AccountRange(blockNrOrHash rpc.BlockNumberOrHash, start hex
// the miner and operate on those // the miner and operate on those
_, stateDb = api.eth.miner.Pending() _, stateDb = api.eth.miner.Pending()
if stateDb == nil { if stateDb == nil {
return state.IteratorDump{}, errors.New("pending state is not available") return state.Dump{}, errors.New("pending state is not available")
} }
} else { } else {
var header *types.Header var header *types.Header
@ -158,29 +158,29 @@ func (api *DebugAPI) AccountRange(blockNrOrHash rpc.BlockNumberOrHash, start hex
default: default:
block := api.eth.blockchain.GetBlockByNumber(uint64(number)) block := api.eth.blockchain.GetBlockByNumber(uint64(number))
if block == nil { if block == nil {
return state.IteratorDump{}, fmt.Errorf("block #%d not found", number) return state.Dump{}, fmt.Errorf("block #%d not found", number)
} }
header = block.Header() header = block.Header()
} }
if header == nil { if header == nil {
return state.IteratorDump{}, fmt.Errorf("block #%d not found", number) return state.Dump{}, fmt.Errorf("block #%d not found", number)
} }
stateDb, err = api.eth.BlockChain().StateAt(header.Root) stateDb, err = api.eth.BlockChain().StateAt(header.Root)
if err != nil { if err != nil {
return state.IteratorDump{}, err return state.Dump{}, err
} }
} }
} else if hash, ok := blockNrOrHash.Hash(); ok { } else if hash, ok := blockNrOrHash.Hash(); ok {
block := api.eth.blockchain.GetBlockByHash(hash) block := api.eth.blockchain.GetBlockByHash(hash)
if block == nil { if block == nil {
return state.IteratorDump{}, fmt.Errorf("block %s not found", hash.Hex()) return state.Dump{}, fmt.Errorf("block %s not found", hash.Hex())
} }
stateDb, err = api.eth.BlockChain().StateAt(block.Root()) stateDb, err = api.eth.BlockChain().StateAt(block.Root())
if err != nil { if err != nil {
return state.IteratorDump{}, err return state.Dump{}, err
} }
} else { } else {
return state.IteratorDump{}, errors.New("either block number or block hash must be specified") return state.Dump{}, errors.New("either block number or block hash must be specified")
} }
opts := &state.DumpConfig{ opts := &state.DumpConfig{
@ -193,7 +193,7 @@ func (api *DebugAPI) AccountRange(blockNrOrHash rpc.BlockNumberOrHash, start hex
if maxResults > AccountRangeMaxResults || maxResults <= 0 { if maxResults > AccountRangeMaxResults || maxResults <= 0 {
opts.Max = AccountRangeMaxResults opts.Max = AccountRangeMaxResults
} }
return stateDb.IteratorDump(opts), nil return stateDb.RawDump(opts), nil
} }
// StorageRangeResult is the result of a debug_storageRangeAt API call. // StorageRangeResult is the result of a debug_storageRangeAt API call.