github.com/ethereumproject/go-ethereum@v5.5.2+incompatible/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 "bufio" 21 "bytes" 22 "compress/zlib" 23 "encoding/json" 24 "io" 25 "sort" 26 "sync" 27 28 "fmt" 29 "github.com/ethereumproject/go-ethereum/common" 30 "github.com/ethereumproject/go-ethereum/rlp" 31 "github.com/ethereumproject/go-ethereum/trie" 32 ) 33 34 type DumpAccount struct { 35 Balance string `json:"balance"` 36 Nonce uint64 `json:"nonce"` 37 Root string `json:"root"` 38 CodeHash string `json:"codeHash"` 39 Code string `json:"code"` 40 Storage map[string]string `json:"storage"` 41 } 42 43 type Dumps []Dump 44 45 type Dump struct { 46 Root string `json:"root"` 47 Accounts map[string]DumpAccount `json:"accounts"` 48 } 49 50 func lookupAddress(addr common.Address, addresses []common.Address) bool { 51 for _, add := range addresses { 52 if add.Hex() == addr.Hex() { 53 return true 54 } 55 } 56 return false 57 } 58 59 func (self *StateDB) RawDump(addresses []common.Address) Dump { 60 dump := Dump{ 61 Root: fmt.Sprintf("%x", self.trie.Hash()), 62 Accounts: make(map[string]DumpAccount), 63 } 64 65 it := trie.NewIterator(self.trie.NodeIterator(nil)) 66 for it.Next() { 67 addr := self.trie.GetKey(it.Key) 68 addrA := common.BytesToAddress(addr) 69 70 if addresses != nil && len(addresses) > 0 { 71 // check if address existing in argued addresses (lookup) 72 // if it's not one we're looking for, continue 73 if !lookupAddress(addrA, addresses) { 74 continue 75 } 76 } 77 78 var data Account 79 if err := rlp.DecodeBytes(it.Value, &data); err != nil { 80 panic(err) 81 } 82 83 obj := newObject(nil, addrA, data, nil) 84 account := DumpAccount{ 85 Balance: data.Balance.String(), 86 Nonce: data.Nonce, 87 Root: common.Bytes2Hex(data.Root[:]), 88 CodeHash: common.Bytes2Hex(data.CodeHash), 89 Code: common.Bytes2Hex(obj.Code(self.db)), 90 Storage: make(map[string]string), 91 } 92 storageIt := trie.NewIterator(obj.getTrie(self.db).NodeIterator(nil)) 93 for storageIt.Next() { 94 account.Storage[common.Bytes2Hex(self.trie.GetKey(storageIt.Key))] = common.Bytes2Hex(storageIt.Value) 95 } 96 dump.Accounts[common.Bytes2Hex(addr)] = account 97 } 98 return dump 99 } 100 101 const ZipperBlockLength = 1 * 1024 * 1024 102 const ZipperPieceLength = 64 * 1024 103 104 type Zipper struct { 105 MemBrk int 106 Mem []byte 107 Bf bytes.Buffer 108 } 109 110 type AddressedRawAccount struct { 111 DumpAccount 112 Addr string 113 } 114 115 type EncodedAccount struct { 116 Addr string 117 Json []byte 118 Error error 119 } 120 121 func (self *Zipper) ZipBytes(data []byte) (result []byte, err error) { 122 self.Bf.Reset() 123 wr, err := zlib.NewWriterLevel(&self.Bf, zlib.DefaultCompression) 124 if err != nil { 125 panic(err) 126 } 127 if _, err := wr.Write(data); err != nil { 128 panic(err) 129 } 130 wr.Close() 131 n := self.Bf.Len() 132 if n == 0 { 133 n = 1 134 } 135 if n > ZipperPieceLength { 136 result = self.Bf.Bytes() 137 self.Bf = bytes.Buffer{} 138 } else { 139 if n+self.MemBrk > ZipperBlockLength || self.Mem == nil { 140 self.Mem = make([]byte, ZipperBlockLength) 141 self.MemBrk = 0 142 } 143 result = self.Mem[self.MemBrk : self.MemBrk+n] 144 self.MemBrk = self.MemBrk + n 145 } 146 copy(result, self.Bf.Bytes()) 147 return 148 } 149 150 func (self *Zipper) UnZipBytes(data []byte) (result []byte, err error) { 151 var bf bytes.Buffer 152 r, err := zlib.NewReader(bytes.NewReader(data)) 153 if err != nil { 154 return 155 } 156 io.Copy(&bf, r) 157 r.Close() 158 result = bf.Bytes() 159 return 160 } 161 162 func iterator(sdb *StateDB, addresses []common.Address, c chan *AddressedRawAccount) { 163 it := trie.NewIterator(sdb.trie.NodeIterator(nil)) 164 for it.Next() { 165 addr := sdb.trie.GetKey(it.Key) 166 addrA := common.BytesToAddress(addr) 167 168 if addresses != nil && len(addresses) > 0 { 169 // check if address existing in argued addresses (lookup) 170 // if it's not one we're looking for, continue 171 if !lookupAddress(addrA, addresses) { 172 continue 173 } 174 } 175 176 var data Account 177 if err := rlp.DecodeBytes(it.Value, &data); err != nil { 178 panic(err) 179 } 180 181 obj := newObject(nil, addrA, data, nil) 182 account := AddressedRawAccount{ 183 DumpAccount: DumpAccount{ 184 Balance: data.Balance.String(), 185 Nonce: data.Nonce, 186 Root: common.Bytes2Hex(data.Root[:]), 187 CodeHash: common.Bytes2Hex(data.CodeHash), 188 Code: common.Bytes2Hex(obj.Code(sdb.db)), 189 Storage: make(map[string]string)}, 190 Addr: common.Bytes2Hex(addr), 191 } 192 storageIt := trie.NewIterator(obj.getTrie(sdb.db).NodeIterator(nil)) 193 for storageIt.Next() { 194 account.Storage[common.Bytes2Hex(sdb.trie.GetKey(storageIt.Key))] = common.Bytes2Hex(storageIt.Value) 195 } 196 c <- &account 197 } 198 close(c) 199 } 200 201 func compressor(c chan *AddressedRawAccount, cN chan EncodedAccount, wg *sync.WaitGroup) { 202 var zipper Zipper 203 defer wg.Done() 204 for { 205 select { 206 case account, ok := <-c: 207 if !ok { 208 return 209 } 210 if val, err := json.Marshal(account.DumpAccount); err != nil { 211 cN <- EncodedAccount{"", nil, err} 212 return 213 } else { 214 data, err := zipper.ZipBytes(val) 215 cN <- EncodedAccount{account.Addr, data, err} 216 if err != nil { 217 return 218 } 219 } 220 } 221 } 222 } 223 224 func encoder(c chan *AddressedRawAccount, cN chan EncodedAccount, wg *sync.WaitGroup) { 225 defer wg.Done() 226 for { 227 select { 228 case account, ok := <-c: 229 if !ok { 230 return 231 } 232 if val, err := json.Marshal(account.DumpAccount); err != nil { 233 cN <- EncodedAccount{"", nil, err} 234 return 235 } else { 236 cN <- EncodedAccount{account.Addr, val, nil} 237 if err != nil { 238 return 239 } 240 } 241 } 242 } 243 } 244 245 func (self *StateDB) LoadEncodedAccounts(addresses []common.Address) (accounts map[string][]byte, err error) { 246 247 accounts = make(map[string][]byte) 248 249 var wg sync.WaitGroup 250 c1 := make(chan *AddressedRawAccount, 10) 251 c2 := make(chan EncodedAccount, 10) 252 c3 := make(chan error) 253 254 for i := 0; i < 2; i++ { 255 wg.Add(1) 256 go compressor(c1, c2, &wg) 257 } 258 259 go iterator(self, addresses, c1) 260 261 go func() { 262 for { 263 acc, ok := <-c2 264 if !ok { 265 c3 <- nil 266 return 267 } 268 if acc.Error != nil { 269 c3 <- err 270 return 271 } 272 accounts[acc.Addr] = acc.Json 273 } 274 }() 275 276 wg.Wait() 277 close(c2) 278 err = <-c3 279 return 280 } 281 282 func writer(root string, zipped bool, prefix string, indent string, out io.Writer) func(chan EncodedAccount, chan error) { 283 284 return func(c chan EncodedAccount, cError chan error) { 285 var err error 286 defer func() { 287 cError <- err 288 }() 289 290 indent2 := prefix + indent 291 indent3 := indent2 + indent 292 293 var ( 294 js []byte 295 bf bytes.Buffer 296 ) 297 298 wr := bufio.NewWriter(out) 299 300 wr.WriteString(prefix) 301 wr.WriteString("{\n") 302 wr.WriteString(indent2) 303 wr.WriteString("\"root\": ") 304 305 js, err = json.Marshal(root) 306 if err != nil { 307 return 308 } 309 310 wr.Write(js) 311 wr.WriteString(",\n") 312 wr.WriteString(indent2) 313 wr.WriteString("\"accounts\": {\n") 314 nl := false 315 316 loop: 317 for { 318 select { 319 case acc, ok := <-c: 320 321 if !ok { 322 break loop 323 } 324 325 if acc.Error != nil { 326 err = acc.Error 327 return 328 } 329 330 if !nl { 331 nl = true 332 } else { 333 wr.WriteString(",\n") 334 } 335 336 wr.WriteString(indent3) 337 js, err = json.Marshal(acc.Addr) 338 if err != nil { 339 return 340 } 341 342 wr.Write(js) 343 wr.WriteString(": ") 344 bf.Reset() 345 if zipped { 346 var zipper Zipper 347 var r []byte 348 r, err = zipper.UnZipBytes(acc.Json) 349 if err != nil { 350 return 351 } 352 json.Indent(&bf, r, indent3, indent) 353 } else { 354 json.Indent(&bf, acc.Json, indent3, indent) 355 } 356 wr.Write(bf.Bytes()) 357 } 358 } 359 360 wr.WriteString("\n") 361 wr.WriteString(indent2) 362 wr.WriteString("}\n") 363 wr.WriteString(prefix) 364 wr.WriteString("}") 365 wr.Flush() 366 367 err = nil 368 return 369 } 370 } 371 372 func (self *StateDB) UnsortedRawDump(addresses []common.Address, fwr func(chan EncodedAccount, chan error)) (err error) { 373 374 var wg sync.WaitGroup 375 c1 := make(chan *AddressedRawAccount, 10) 376 c2 := make(chan EncodedAccount, 10) 377 c3 := make(chan error) 378 go iterator(self, addresses, c1) 379 for i := 0; i < 2; i++ { 380 wg.Add(1) 381 go encoder(c1, c2, &wg) 382 } 383 go fwr(c2, c3) 384 wg.Wait() 385 close(c2) 386 err = <-c3 387 return 388 } 389 390 func (self *StateDB) SortedDump(addresses []common.Address, prefix string, indent string, out io.Writer) (err error) { 391 392 var accounts map[string][]byte 393 394 accounts, err = self.LoadEncodedAccounts(addresses) 395 if err != nil { 396 return 397 } 398 399 fwr := writer(common.Bytes2Hex(self.trie.Hash().Bytes()), true, prefix, indent, out) 400 401 keys := make([]string, 0, len(accounts)) 402 for k := range accounts { 403 keys = append(keys, k) 404 } 405 sort.Strings(keys) 406 407 c1 := make(chan EncodedAccount, 1) 408 c2 := make(chan error, 1) 409 410 go fwr(c1, c2) 411 412 go func() { 413 for _, addr := range keys { 414 data := accounts[addr] 415 c1 <- EncodedAccount{addr, data, nil} 416 } 417 close(c1) 418 }() 419 420 err = <-c2 421 return 422 } 423 424 func (self *StateDB) UnsortedDump(addresses []common.Address, prefix string, indent string, out io.Writer) (err error) { 425 fwr := writer(common.Bytes2Hex(self.trie.Hash().Bytes()), false, prefix, indent, out) 426 return self.UnsortedRawDump(addresses, fwr) 427 } 428 429 func (self *StateDB) Dump(addresses []common.Address) []byte { 430 var bf bytes.Buffer 431 err := self.SortedDump(addresses, "", " ", &bf) 432 if err != nil { 433 return nil 434 } 435 return bf.Bytes() 436 }