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