github.com/fff-chain/go-fff@v0.0.0-20220726032732-1c84420b8a99/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/fff-chain/go-fff/common" 24 "github.com/fff-chain/go-fff/common/hexutil" 25 "github.com/fff-chain/go-fff/log" 26 "github.com/fff-chain/go-fff/rlp" 27 "github.com/fff-chain/go-fff/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 // DumpAccount represents an account in the state. 51 type FFFDumpAccount struct { 52 Balance string `json:"balance"` 53 Nonce uint64 `json:"nonce"` 54 Root string `json:"root"` 55 CodeHash string `json:"codeHash"` 56 Code string `json:"code,omitempty"` 57 Storage map[common.Hash]string `json:"storage,omitempty"` 58 Address *common.FFFAddress `json:"address,omitempty"` // Address only present in iterative (line-by-line) mode 59 SecureKey hexutil.Bytes `json:"key,omitempty"` // If we don't have address, we can output the key 60 61 } 62 63 func DumpAccountToFFFDumpAccount(d DumpAccount) FFFDumpAccount { 64 65 f:= new(FFFDumpAccount) 66 z:=common.AddressToFFFAddress(*d.Address) 67 f.Address=&z 68 f.Code=d.Code 69 f.Balance=d.Balance 70 f.CodeHash=d.CodeHash 71 f.SecureKey=d.SecureKey 72 f.Root=d.Root 73 f.Storage=d.Storage 74 f.Nonce=d.Nonce 75 return *f 76 77 } 78 // Dump represents the full dump in a collected format, as one large map. 79 type Dump struct { 80 Root string `json:"root"` 81 Accounts map[common.Address]DumpAccount `json:"accounts"` 82 } 83 // Dump represents the full dump in a collected format, as one large map. 84 type FFFDump struct { 85 Root string `json:"root"` 86 Accounts map[common.FFFAddress]FFFDumpAccount `json:"accounts"` 87 } 88 // OnRoot implements DumpCollector interface 89 func (d *Dump) OnRoot(root common.Hash) { 90 d.Root = fmt.Sprintf("%x", root) 91 } 92 93 // OnAccount implements DumpCollector interface 94 func (d *Dump) OnAccount(addr common.Address, account DumpAccount) { 95 d.Accounts[addr] = account 96 } 97 func DumpToFFFDump(d Dump) FFFDump { 98 newF:=new(FFFDump) 99 newF.Accounts=make(map[common.FFFAddress]FFFDumpAccount) 100 101 for k:=range d.Accounts { 102 newF.Accounts[common.AddressToFFFAddress(k)]=DumpAccountToFFFDumpAccount(d.Accounts[k]) 103 } 104 105 return *newF 106 107 } 108 109 // IteratorDump is an implementation for iterating over data. 110 type IteratorDump struct { 111 Root string `json:"root"` 112 Accounts map[common.Address]DumpAccount `json:"accounts"` 113 Next []byte `json:"next,omitempty"` // nil if no more accounts 114 } 115 // IteratorDump is an implementation for iterating over data. 116 type FFFIteratorDump struct { 117 Root string `json:"root"` 118 Accounts map[common.FFFAddress]FFFDumpAccount `json:"accounts"` 119 Next []byte `json:"next,omitempty"` // nil if no more accounts 120 } 121 func IteratorDumpToFFFIteratorDump(d IteratorDump) FFFIteratorDump { 122 newF:=new(FFFIteratorDump) 123 newF.Accounts=make(map[common.FFFAddress]FFFDumpAccount) 124 125 for k:=range d.Accounts { 126 newF.Accounts[common.AddressToFFFAddress(k)]=DumpAccountToFFFDumpAccount(d.Accounts[k]) 127 } 128 129 return *newF 130 131 } 132 // OnRoot implements DumpCollector interface 133 func (d *IteratorDump) OnRoot(root common.Hash) { 134 d.Root = fmt.Sprintf("%x", root) 135 } 136 137 // OnAccount implements DumpCollector interface 138 func (d *IteratorDump) OnAccount(addr common.Address, account DumpAccount) { 139 d.Accounts[addr] = account 140 } 141 142 // iterativeDump is a DumpCollector-implementation which dumps output line-by-line iteratively. 143 type iterativeDump struct { 144 *json.Encoder 145 } 146 147 // OnAccount implements DumpCollector interface 148 func (d iterativeDump) OnAccount(addr common.Address, account DumpAccount) { 149 dumpAccount := &DumpAccount{ 150 Balance: account.Balance, 151 Nonce: account.Nonce, 152 Root: account.Root, 153 CodeHash: account.CodeHash, 154 Code: account.Code, 155 Storage: account.Storage, 156 SecureKey: account.SecureKey, 157 Address: nil, 158 } 159 if addr != (common.Address{}) { 160 dumpAccount.Address = &addr 161 } 162 d.Encode(dumpAccount) 163 } 164 165 // OnRoot implements DumpCollector interface 166 func (d iterativeDump) OnRoot(root common.Hash) { 167 d.Encode(struct { 168 Root common.Hash `json:"root"` 169 }{root}) 170 } 171 172 func (s *StateDB) DumpToCollector(c DumpCollector, excludeCode, excludeStorage, excludeMissingPreimages bool, start []byte, maxResults int) (nextKey []byte) { 173 missingPreimages := 0 174 c.OnRoot(s.trie.Hash()) 175 176 var count int 177 it := trie.NewIterator(s.trie.NodeIterator(start)) 178 for it.Next() { 179 var data Account 180 if err := rlp.DecodeBytes(it.Value, &data); err != nil { 181 panic(err) 182 } 183 account := DumpAccount{ 184 Balance: data.Balance.String(), 185 Nonce: data.Nonce, 186 Root: common.Bytes2Hex(data.Root[:]), 187 CodeHash: common.Bytes2Hex(data.CodeHash), 188 } 189 addrBytes := s.trie.GetKey(it.Key) 190 if addrBytes == nil { 191 // Preimage missing 192 missingPreimages++ 193 if excludeMissingPreimages { 194 continue 195 } 196 account.SecureKey = it.Key 197 } 198 addr := common.BytesToAddress(addrBytes) 199 obj := newObject(s, addr, data) 200 if !excludeCode { 201 account.Code = common.Bytes2Hex(obj.Code(s.db)) 202 } 203 if !excludeStorage { 204 account.Storage = make(map[common.Hash]string) 205 storageIt := trie.NewIterator(obj.getTrie(s.db).NodeIterator(nil)) 206 for storageIt.Next() { 207 _, content, _, err := rlp.Split(storageIt.Value) 208 if err != nil { 209 log.Error("Failed to decode the value returned by iterator", "error", err) 210 continue 211 } 212 account.Storage[common.BytesToHash(s.trie.GetKey(storageIt.Key))] = common.Bytes2Hex(content) 213 } 214 } 215 c.OnAccount(addr, account) 216 count++ 217 if maxResults > 0 && count >= maxResults { 218 if it.Next() { 219 nextKey = it.Key 220 } 221 break 222 } 223 } 224 if missingPreimages > 0 { 225 log.Warn("Dump incomplete due to missing preimages", "missing", missingPreimages) 226 } 227 228 return nextKey 229 } 230 231 // RawDump returns the entire state an a single large object 232 func (s *StateDB) RawDump(excludeCode, excludeStorage, excludeMissingPreimages bool) Dump { 233 dump := &Dump{ 234 Accounts: make(map[common.Address]DumpAccount), 235 } 236 s.DumpToCollector(dump, excludeCode, excludeStorage, excludeMissingPreimages, nil, 0) 237 return *dump 238 } 239 // Dump returns a JSON string representing the entire state as a single json-object 240 func (s *StateDB) Dump(excludeCode, excludeStorage, excludeMissingPreimages bool) []byte { 241 dump := s.RawDump(excludeCode, excludeStorage, excludeMissingPreimages) 242 json, err := json.MarshalIndent(dump, "", " ") 243 if err != nil { 244 fmt.Println("Dump err", err) 245 } 246 return json 247 } 248 249 // IterativeDump dumps out accounts as json-objects, delimited by linebreaks on stdout 250 func (s *StateDB) IterativeDump(excludeCode, excludeStorage, excludeMissingPreimages bool, output *json.Encoder) { 251 s.DumpToCollector(iterativeDump{output}, excludeCode, excludeStorage, excludeMissingPreimages, nil, 0) 252 } 253 254 // IteratorDump dumps out a batch of accounts starts with the given start key 255 func (s *StateDB) IteratorDump(excludeCode, excludeStorage, excludeMissingPreimages bool, start []byte, maxResults int) IteratorDump { 256 iterator := &IteratorDump{ 257 Accounts: make(map[common.Address]DumpAccount), 258 } 259 iterator.Next = s.DumpToCollector(iterator, excludeCode, excludeStorage, excludeMissingPreimages, start, maxResults) 260 return *iterator 261 }