github.com/zhiqiangxu/go-ethereum@v1.9.16-0.20210824055606-be91cfdebc48/core/state/dump.go (about) 1 // Copyright 2014 The go-ethereum Authors 2 // This file is part of the go-ethereum library. 3 // 4 // The go-ethereum library is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU Lesser General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // The go-ethereum library is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU Lesser General Public License for more details. 13 // 14 // You should have received a copy of the GNU Lesser General Public License 15 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. 16 17 package state 18 19 import ( 20 "encoding/json" 21 "fmt" 22 23 "github.com/zhiqiangxu/go-ethereum/common" 24 "github.com/zhiqiangxu/go-ethereum/common/hexutil" 25 "github.com/zhiqiangxu/go-ethereum/log" 26 "github.com/zhiqiangxu/go-ethereum/rlp" 27 "github.com/zhiqiangxu/go-ethereum/trie" 28 ) 29 30 // DumpAccount represents an account in the state. 31 type DumpAccount struct { 32 Balance string `json:"balance"` 33 Nonce uint64 `json:"nonce"` 34 Root string `json:"root"` 35 CodeHash string `json:"codeHash"` 36 Code string `json:"code,omitempty"` 37 Storage map[common.Hash]string `json:"storage,omitempty"` 38 Address *common.Address `json:"address,omitempty"` // Address only present in iterative (line-by-line) mode 39 SecureKey hexutil.Bytes `json:"key,omitempty"` // If we don't have address, we can output the key 40 41 } 42 43 // Dump represents the full dump in a collected format, as one large map. 44 type Dump struct { 45 Root string `json:"root"` 46 Accounts map[common.Address]DumpAccount `json:"accounts"` 47 } 48 49 // iterativeDump is a 'collector'-implementation which dump output line-by-line iteratively. 50 type iterativeDump struct { 51 *json.Encoder 52 } 53 54 // IteratorDump is an implementation for iterating over data. 55 type IteratorDump struct { 56 Root string `json:"root"` 57 Accounts map[common.Address]DumpAccount `json:"accounts"` 58 Next []byte `json:"next,omitempty"` // nil if no more accounts 59 } 60 61 // Collector interface which the state trie calls during iteration 62 type collector interface { 63 onRoot(common.Hash) 64 onAccount(common.Address, DumpAccount) 65 } 66 67 func (d *Dump) onRoot(root common.Hash) { 68 d.Root = fmt.Sprintf("%x", root) 69 } 70 71 func (d *Dump) onAccount(addr common.Address, account DumpAccount) { 72 d.Accounts[addr] = account 73 } 74 func (d *IteratorDump) onRoot(root common.Hash) { 75 d.Root = fmt.Sprintf("%x", root) 76 } 77 78 func (d *IteratorDump) onAccount(addr common.Address, account DumpAccount) { 79 d.Accounts[addr] = account 80 } 81 82 func (d iterativeDump) onAccount(addr common.Address, account DumpAccount) { 83 dumpAccount := &DumpAccount{ 84 Balance: account.Balance, 85 Nonce: account.Nonce, 86 Root: account.Root, 87 CodeHash: account.CodeHash, 88 Code: account.Code, 89 Storage: account.Storage, 90 SecureKey: account.SecureKey, 91 Address: nil, 92 } 93 if addr != (common.Address{}) { 94 dumpAccount.Address = &addr 95 } 96 d.Encode(dumpAccount) 97 } 98 99 func (d iterativeDump) onRoot(root common.Hash) { 100 d.Encode(struct { 101 Root common.Hash `json:"root"` 102 }{root}) 103 } 104 105 func (s *StateDB) dump(c collector, excludeCode, excludeStorage, excludeMissingPreimages bool, start []byte, maxResults int) (nextKey []byte) { 106 missingPreimages := 0 107 c.onRoot(s.trie.Hash()) 108 109 var count int 110 it := trie.NewIterator(s.trie.NodeIterator(start)) 111 for it.Next() { 112 var data Account 113 if err := rlp.DecodeBytes(it.Value, &data); err != nil { 114 panic(err) 115 } 116 account := DumpAccount{ 117 Balance: data.Balance.String(), 118 Nonce: data.Nonce, 119 Root: common.Bytes2Hex(data.Root[:]), 120 CodeHash: common.Bytes2Hex(data.CodeHash), 121 } 122 addrBytes := s.trie.GetKey(it.Key) 123 if addrBytes == nil { 124 // Preimage missing 125 missingPreimages++ 126 if excludeMissingPreimages { 127 continue 128 } 129 account.SecureKey = it.Key 130 } 131 addr := common.BytesToAddress(addrBytes) 132 obj := newObject(nil, addr, data) 133 if !excludeCode { 134 account.Code = common.Bytes2Hex(obj.Code(s.db)) 135 } 136 if !excludeStorage { 137 account.Storage = make(map[common.Hash]string) 138 storageIt := trie.NewIterator(obj.getTrie(s.db).NodeIterator(nil)) 139 for storageIt.Next() { 140 _, content, _, err := rlp.Split(storageIt.Value) 141 if err != nil { 142 log.Error("Failed to decode the value returned by iterator", "error", err) 143 continue 144 } 145 account.Storage[common.BytesToHash(s.trie.GetKey(storageIt.Key))] = common.Bytes2Hex(content) 146 } 147 } 148 c.onAccount(addr, account) 149 count++ 150 if maxResults > 0 && count >= maxResults { 151 if it.Next() { 152 nextKey = it.Key 153 } 154 break 155 } 156 } 157 if missingPreimages > 0 { 158 log.Warn("Dump incomplete due to missing preimages", "missing", missingPreimages) 159 } 160 161 return nextKey 162 } 163 164 // RawDump returns the entire state an a single large object 165 func (s *StateDB) RawDump(excludeCode, excludeStorage, excludeMissingPreimages bool) Dump { 166 dump := &Dump{ 167 Accounts: make(map[common.Address]DumpAccount), 168 } 169 s.dump(dump, excludeCode, excludeStorage, excludeMissingPreimages, nil, 0) 170 return *dump 171 } 172 173 // Dump returns a JSON string representing the entire state as a single json-object 174 func (s *StateDB) Dump(excludeCode, excludeStorage, excludeMissingPreimages bool) []byte { 175 dump := s.RawDump(excludeCode, excludeStorage, excludeMissingPreimages) 176 json, err := json.MarshalIndent(dump, "", " ") 177 if err != nil { 178 fmt.Println("dump err", err) 179 } 180 return json 181 } 182 183 // IterativeDump dumps out accounts as json-objects, delimited by linebreaks on stdout 184 func (s *StateDB) IterativeDump(excludeCode, excludeStorage, excludeMissingPreimages bool, output *json.Encoder) { 185 s.dump(iterativeDump{output}, excludeCode, excludeStorage, excludeMissingPreimages, nil, 0) 186 } 187 188 // IteratorDump dumps out a batch of accounts starts with the given start key 189 func (s *StateDB) IteratorDump(excludeCode, excludeStorage, excludeMissingPreimages bool, start []byte, maxResults int) IteratorDump { 190 iterator := &IteratorDump{ 191 Accounts: make(map[common.Address]DumpAccount), 192 } 193 iterator.Next = s.dump(iterator, excludeCode, excludeStorage, excludeMissingPreimages, start, maxResults) 194 return *iterator 195 }