github.com/bigzoro/my_simplechain@v0.0.0-20240315012955-8ad0a2a29bb9/core/state/dump.go (about) 1 // Copyright 2014 The go-simplechain Authors 2 // This file is part of the go-simplechain library. 3 // 4 // The go-simplechain 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-simplechain 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-simplechain 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/bigzoro/my_simplechain/common" 24 "github.com/bigzoro/my_simplechain/common/hexutil" 25 "github.com/bigzoro/my_simplechain/log" 26 "github.com/bigzoro/my_simplechain/rlp" 27 "github.com/bigzoro/my_simplechain/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 // Collector interface which the state trie calls during iteration 55 type collector interface { 56 onRoot(common.Hash) 57 onAccount(common.Address, DumpAccount) 58 } 59 60 func (d *Dump) onRoot(root common.Hash) { 61 d.Root = fmt.Sprintf("%x", root) 62 } 63 64 func (d *Dump) onAccount(addr common.Address, account DumpAccount) { 65 d.Accounts[addr] = account 66 } 67 68 func (d iterativeDump) onAccount(addr common.Address, account DumpAccount) { 69 dumpAccount := &DumpAccount{ 70 Balance: account.Balance, 71 Nonce: account.Nonce, 72 Root: account.Root, 73 CodeHash: account.CodeHash, 74 Code: account.Code, 75 Storage: account.Storage, 76 SecureKey: account.SecureKey, 77 Address: nil, 78 } 79 if addr != (common.Address{}) { 80 dumpAccount.Address = &addr 81 } 82 d.Encode(dumpAccount) 83 } 84 85 func (d iterativeDump) onRoot(root common.Hash) { 86 d.Encode(struct { 87 Root common.Hash `json:"root"` 88 }{root}) 89 } 90 91 func (s *StateDB) dump(c collector, excludeCode, excludeStorage, excludeMissingPreimages bool) { 92 emptyAddress := (common.Address{}) 93 missingPreimages := 0 94 c.onRoot(s.trie.Hash()) 95 it := trie.NewIterator(s.trie.NodeIterator(nil)) 96 for it.Next() { 97 var data Account 98 if err := rlp.DecodeBytes(it.Value, &data); err != nil { 99 panic(err) 100 } 101 addr := common.BytesToAddress(s.trie.GetKey(it.Key)) 102 obj := newObject(nil, addr, data) 103 account := DumpAccount{ 104 Balance: data.Balance.String(), 105 Nonce: data.Nonce, 106 Root: common.Bytes2Hex(data.Root[:]), 107 CodeHash: common.Bytes2Hex(data.CodeHash), 108 } 109 if emptyAddress == addr { 110 // Preimage missing 111 missingPreimages++ 112 if excludeMissingPreimages { 113 continue 114 } 115 account.SecureKey = it.Key 116 } 117 if !excludeCode { 118 account.Code = common.Bytes2Hex(obj.Code(s.db)) 119 } 120 if !excludeStorage { 121 account.Storage = make(map[common.Hash]string) 122 storageIt := trie.NewIterator(obj.getTrie(s.db).NodeIterator(nil)) 123 for storageIt.Next() { 124 _, content, _, err := rlp.Split(storageIt.Value) 125 if err != nil { 126 log.Error("Failed to decode the value returned by iterator", "error", err) 127 continue 128 } 129 account.Storage[common.BytesToHash(s.trie.GetKey(storageIt.Key))] = common.Bytes2Hex(content) 130 } 131 } 132 c.onAccount(addr, account) 133 } 134 if missingPreimages > 0 { 135 log.Warn("Dump incomplete due to missing preimages", "missing", missingPreimages) 136 } 137 } 138 139 // RawDump returns the entire state an a single large object 140 func (s *StateDB) RawDump(excludeCode, excludeStorage, excludeMissingPreimages bool) Dump { 141 dump := &Dump{ 142 Accounts: make(map[common.Address]DumpAccount), 143 } 144 s.dump(dump, excludeCode, excludeStorage, excludeMissingPreimages) 145 return *dump 146 } 147 148 // Dump returns a JSON string representing the entire state as a single json-object 149 func (s *StateDB) Dump(excludeCode, excludeStorage, excludeMissingPreimages bool) []byte { 150 dump := s.RawDump(excludeCode, excludeStorage, excludeMissingPreimages) 151 json, err := json.MarshalIndent(dump, "", " ") 152 if err != nil { 153 fmt.Println("dump err", err) 154 } 155 return json 156 } 157 158 // IterativeDump dumps out accounts as json-objects, delimited by linebreaks on stdout 159 func (s *StateDB) IterativeDump(excludeCode, excludeStorage, excludeMissingPreimages bool, output *json.Encoder) { 160 s.dump(iterativeDump{output}, excludeCode, excludeStorage, excludeMissingPreimages) 161 }