aboutsummaryrefslogtreecommitdiff
path: root/core/state/dump.go
diff options
context:
space:
mode:
authorDeterminant <[email protected]>2020-06-28 14:47:41 -0400
committerDeterminant <[email protected]>2020-06-28 14:47:41 -0400
commitd235e2c6a5788ec4a6cff15a16f56b38a3876a0d (patch)
tree5f2727f7a50ee5840f889c82776d3a30a88dd59b /core/state/dump.go
parent13ebd8bd9468e9d769d598b0ca2afb72ba78cb97 (diff)
...
Diffstat (limited to 'core/state/dump.go')
-rw-r--r--core/state/dump.go158
1 files changed, 158 insertions, 0 deletions
diff --git a/core/state/dump.go b/core/state/dump.go
new file mode 100644
index 0000000..91c7d08
--- /dev/null
+++ b/core/state/dump.go
@@ -0,0 +1,158 @@
+// Copyright 2014 The go-ethereum Authors
+// This file is part of the go-ethereum library.
+//
+// The go-ethereum library is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// The go-ethereum library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
+
+package state
+
+import (
+ "encoding/json"
+ "fmt"
+
+ "github.com/ava-labs/go-ethereum/common"
+ "github.com/ava-labs/go-ethereum/common/hexutil"
+ "github.com/ava-labs/go-ethereum/log"
+ "github.com/ava-labs/go-ethereum/rlp"
+ "github.com/ava-labs/go-ethereum/trie"
+)
+
+// DumpAccount represents an account in the state
+type DumpAccount struct {
+ Balance string `json:"balance"`
+ Nonce uint64 `json:"nonce"`
+ Root string `json:"root"`
+ CodeHash string `json:"codeHash"`
+ Code string `json:"code,omitempty"`
+ Storage map[common.Hash]string `json:"storage,omitempty"`
+ Address *common.Address `json:"address,omitempty"` // Address only present in iterative (line-by-line) mode
+ SecureKey hexutil.Bytes `json:"key,omitempty"` // If we don't have address, we can output the key
+
+}
+
+// Dump represents the full dump in a collected format, as one large map
+type Dump struct {
+ Root string `json:"root"`
+ Accounts map[common.Address]DumpAccount `json:"accounts"`
+}
+
+// iterativeDump is a 'collector'-implementation which dump output line-by-line iteratively
+type iterativeDump json.Encoder
+
+// Collector interface which the state trie calls during iteration
+type collector interface {
+ onRoot(common.Hash)
+ onAccount(common.Address, DumpAccount)
+}
+
+func (self *Dump) onRoot(root common.Hash) {
+ self.Root = fmt.Sprintf("%x", root)
+}
+
+func (self *Dump) onAccount(addr common.Address, account DumpAccount) {
+ self.Accounts[addr] = account
+}
+
+func (self iterativeDump) onAccount(addr common.Address, account DumpAccount) {
+ dumpAccount := &DumpAccount{
+ Balance: account.Balance,
+ Nonce: account.Nonce,
+ Root: account.Root,
+ CodeHash: account.CodeHash,
+ Code: account.Code,
+ Storage: account.Storage,
+ SecureKey: account.SecureKey,
+ Address: nil,
+ }
+ if addr != (common.Address{}) {
+ dumpAccount.Address = &addr
+ }
+ (*json.Encoder)(&self).Encode(dumpAccount)
+}
+func (self iterativeDump) onRoot(root common.Hash) {
+ (*json.Encoder)(&self).Encode(struct {
+ Root common.Hash `json:"root"`
+ }{root})
+}
+
+func (self *StateDB) dump(c collector, excludeCode, excludeStorage, excludeMissingPreimages bool) {
+ emptyAddress := (common.Address{})
+ missingPreimages := 0
+ c.onRoot(self.trie.Hash())
+ it := trie.NewIterator(self.trie.NodeIterator(nil))
+ for it.Next() {
+ var data Account
+ if err := rlp.DecodeBytes(it.Value, &data); err != nil {
+ panic(err)
+ }
+ addr := common.BytesToAddress(self.trie.GetKey(it.Key))
+ obj := newObject(nil, addr, data)
+ account := DumpAccount{
+ Balance: data.Balance.String(),
+ Nonce: data.Nonce,
+ Root: common.Bytes2Hex(data.Root[:]),
+ CodeHash: common.Bytes2Hex(data.CodeHash),
+ }
+ if emptyAddress == addr {
+ // Preimage missing
+ missingPreimages++
+ if excludeMissingPreimages {
+ continue
+ }
+ account.SecureKey = it.Key
+ }
+ if !excludeCode {
+ account.Code = common.Bytes2Hex(obj.Code(self.db))
+ }
+ if !excludeStorage {
+ account.Storage = make(map[common.Hash]string)
+ storageIt := trie.NewIterator(obj.getTrie(self.db).NodeIterator(nil))
+ for storageIt.Next() {
+ _, content, _, err := rlp.Split(storageIt.Value)
+ if err != nil {
+ log.Error("Failed to decode the value returned by iterator", "error", err)
+ continue
+ }
+ account.Storage[common.BytesToHash(self.trie.GetKey(storageIt.Key))] = common.Bytes2Hex(content)
+ }
+ }
+ c.onAccount(addr, account)
+ }
+ if missingPreimages > 0 {
+ log.Warn("Dump incomplete due to missing preimages", "missing", missingPreimages)
+ }
+}
+
+// RawDump returns the entire state an a single large object
+func (self *StateDB) RawDump(excludeCode, excludeStorage, excludeMissingPreimages bool) Dump {
+ dump := &Dump{
+ Accounts: make(map[common.Address]DumpAccount),
+ }
+ self.dump(dump, excludeCode, excludeStorage, excludeMissingPreimages)
+ return *dump
+}
+
+// Dump returns a JSON string representing the entire state as a single json-object
+func (self *StateDB) Dump(excludeCode, excludeStorage, excludeMissingPreimages bool) []byte {
+ dump := self.RawDump(excludeCode, excludeStorage, excludeMissingPreimages)
+ json, err := json.MarshalIndent(dump, "", " ")
+ if err != nil {
+ fmt.Println("dump err", err)
+ }
+ return json
+}
+
+// IterativeDump dumps out accounts as json-objects, delimited by linebreaks on stdout
+func (self *StateDB) IterativeDump(excludeCode, excludeStorage, excludeMissingPreimages bool, output *json.Encoder) {
+ self.dump(iterativeDump(*output), excludeCode, excludeStorage, excludeMissingPreimages)
+}