github.com/core-coin/go-core/v2@v2.1.9/core/state/dump.go (about) 1 // Copyright 2014 by the Authors 2 // This file is part of the go-core library. 3 // 4 // The go-core 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-core 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-core 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/core-coin/go-core/v2/common" 24 "github.com/core-coin/go-core/v2/common/hexutil" 25 "github.com/core-coin/go-core/v2/log" 26 "github.com/core-coin/go-core/v2/rlp" 27 "github.com/core-coin/go-core/v2/trie" 28 ) 29 30 // DumpCollector interface which the state trie calls during iteration 31 type DumpCollector interface { 32 // OnRoot is called with the state root 33 OnRoot(common.Hash) 34 // OnAccount is called once for each account in the trie 35 OnAccount(common.Address, DumpAccount) 36 } 37 38 // DumpAccount represents an account in the state. 39 type DumpAccount struct { 40 Balance string `json:"balance"` 41 Nonce uint64 `json:"nonce"` 42 Root string `json:"root"` 43 CodeHash string `json:"codeHash"` 44 Code string `json:"code,omitempty"` 45 Storage map[common.Hash]string `json:"storage,omitempty"` 46 Address *common.Address `json:"address,omitempty"` // Address only present in iterative (line-by-line) mode 47 SecureKey hexutil.Bytes `json:"key,omitempty"` // If we don't have address, we can output the key 48 49 } 50 51 // Dump represents the full dump in a collected format, as one large map. 52 type Dump struct { 53 Root string `json:"root"` 54 Accounts map[common.Address]DumpAccount `json:"accounts"` 55 } 56 57 // OnRoot implements DumpCollector interface 58 func (d *Dump) OnRoot(root common.Hash) { 59 d.Root = fmt.Sprintf("%x", root) 60 } 61 62 // OnAccount implements DumpCollector interface 63 func (d *Dump) OnAccount(addr common.Address, account DumpAccount) { 64 d.Accounts[addr] = account 65 } 66 67 // IteratorDump is an implementation for iterating over data. 68 type IteratorDump struct { 69 Root string `json:"root"` 70 Accounts map[common.Address]DumpAccount `json:"accounts"` 71 Next []byte `json:"next,omitempty"` // nil if no more accounts 72 } 73 74 // OnRoot implements DumpCollector interface 75 func (d *IteratorDump) OnRoot(root common.Hash) { 76 d.Root = fmt.Sprintf("%x", root) 77 } 78 79 // OnAccount implements DumpCollector interface 80 func (d *IteratorDump) OnAccount(addr common.Address, account DumpAccount) { 81 d.Accounts[addr] = account 82 } 83 84 // iterativeDump is a DumpCollector-implementation which dumps output line-by-line iteratively. 85 type iterativeDump struct { 86 *json.Encoder 87 } 88 89 // OnAccount implements DumpCollector interface 90 func (d iterativeDump) OnAccount(addr common.Address, account DumpAccount) { 91 dumpAccount := &DumpAccount{ 92 Balance: account.Balance, 93 Nonce: account.Nonce, 94 Root: account.Root, 95 CodeHash: account.CodeHash, 96 Code: account.Code, 97 Storage: account.Storage, 98 SecureKey: account.SecureKey, 99 Address: nil, 100 } 101 if addr != (common.Address{}) { 102 dumpAccount.Address = &addr 103 } 104 d.Encode(dumpAccount) 105 } 106 107 // OnRoot implements DumpCollector interface 108 func (d iterativeDump) OnRoot(root common.Hash) { 109 d.Encode(struct { 110 Root common.Hash `json:"root"` 111 }{root}) 112 } 113 114 func (s *StateDB) DumpToCollector(c DumpCollector, excludeCode, excludeStorage, excludeMissingPreimages bool, start []byte, maxResults int) (nextKey []byte) { 115 missingPreimages := 0 116 c.OnRoot(s.trie.Hash()) 117 118 var count int 119 it := trie.NewIterator(s.trie.NodeIterator(start)) 120 for it.Next() { 121 var data Account 122 if err := rlp.DecodeBytes(it.Value, &data); err != nil { 123 panic(err) 124 } 125 account := DumpAccount{ 126 Balance: data.Balance.String(), 127 Nonce: data.Nonce, 128 Root: common.Bytes2Hex(data.Root[:]), 129 CodeHash: common.Bytes2Hex(data.CodeHash), 130 } 131 addrBytes := s.trie.GetKey(it.Key) 132 if addrBytes == nil { 133 // Preimage missing 134 missingPreimages++ 135 if excludeMissingPreimages { 136 continue 137 } 138 account.SecureKey = it.Key 139 } 140 addr := common.BytesToAddress(addrBytes) 141 obj := newObject(nil, addr, data) 142 if !excludeCode { 143 account.Code = common.Bytes2Hex(obj.Code(s.db)) 144 } 145 if !excludeStorage { 146 account.Storage = make(map[common.Hash]string) 147 storageIt := trie.NewIterator(obj.getTrie(s.db).NodeIterator(nil)) 148 for storageIt.Next() { 149 _, content, _, err := rlp.Split(storageIt.Value) 150 if err != nil { 151 log.Error("Failed to decode the value returned by iterator", "error", err) 152 continue 153 } 154 account.Storage[common.BytesToHash(s.trie.GetKey(storageIt.Key))] = common.Bytes2Hex(content) 155 } 156 } 157 c.OnAccount(addr, account) 158 count++ 159 if maxResults > 0 && count >= maxResults { 160 if it.Next() { 161 nextKey = it.Key 162 } 163 break 164 } 165 } 166 if missingPreimages > 0 { 167 log.Warn("Dump incomplete due to missing preimages", "missing", missingPreimages) 168 } 169 170 return nextKey 171 } 172 173 // RawDump returns the entire state an a single large object 174 func (s *StateDB) RawDump(excludeCode, excludeStorage, excludeMissingPreimages bool) Dump { 175 dump := &Dump{ 176 Accounts: make(map[common.Address]DumpAccount), 177 } 178 s.DumpToCollector(dump, excludeCode, excludeStorage, excludeMissingPreimages, nil, 0) 179 return *dump 180 } 181 182 // Dump returns a JSON string representing the entire state as a single json-object 183 func (s *StateDB) Dump(excludeCode, excludeStorage, excludeMissingPreimages bool) []byte { 184 dump := s.RawDump(excludeCode, excludeStorage, excludeMissingPreimages) 185 json, err := json.MarshalIndent(dump, "", " ") 186 if err != nil { 187 fmt.Println("Dump err", err) 188 } 189 return json 190 } 191 192 // IterativeDump dumps out accounts as json-objects, delimited by linebreaks on stdout 193 func (s *StateDB) IterativeDump(excludeCode, excludeStorage, excludeMissingPreimages bool, output *json.Encoder) { 194 s.DumpToCollector(iterativeDump{output}, excludeCode, excludeStorage, excludeMissingPreimages, nil, 0) 195 } 196 197 // IteratorDump dumps out a batch of accounts starts with the given start key 198 func (s *StateDB) IteratorDump(excludeCode, excludeStorage, excludeMissingPreimages bool, start []byte, maxResults int) IteratorDump { 199 iterator := &IteratorDump{ 200 Accounts: make(map[common.Address]DumpAccount), 201 } 202 iterator.Next = s.DumpToCollector(iterator, excludeCode, excludeStorage, excludeMissingPreimages, start, maxResults) 203 return *iterator 204 }