| 
									
										
										
										
											2015-07-07 02:54:22 +02:00
										 |  |  | // Copyright 2014 The go-ethereum Authors | 
					
						
							| 
									
										
										
										
											2015-07-22 18:48:40 +02:00
										 |  |  | // This file is part of the go-ethereum library. | 
					
						
							| 
									
										
										
										
											2015-07-07 02:54:22 +02:00
										 |  |  | // | 
					
						
							| 
									
										
										
										
											2015-07-23 18:35:11 +02:00
										 |  |  | // The go-ethereum library is free software: you can redistribute it and/or modify | 
					
						
							| 
									
										
										
										
											2015-07-07 02:54:22 +02:00
										 |  |  | // it under the terms of the GNU Lesser General Public License as published by | 
					
						
							|  |  |  | // the Free Software Foundation, either version 3 of the License, or | 
					
						
							|  |  |  | // (at your option) any later version. | 
					
						
							|  |  |  | // | 
					
						
							| 
									
										
										
										
											2015-07-22 18:48:40 +02:00
										 |  |  | // The go-ethereum library is distributed in the hope that it will be useful, | 
					
						
							| 
									
										
										
										
											2015-07-07 02:54:22 +02:00
										 |  |  | // but WITHOUT ANY WARRANTY; without even the implied warranty of | 
					
						
							| 
									
										
										
										
											2015-07-22 18:48:40 +02:00
										 |  |  | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 
					
						
							| 
									
										
										
										
											2015-07-07 02:54:22 +02:00
										 |  |  | // GNU Lesser General Public License for more details. | 
					
						
							|  |  |  | // | 
					
						
							|  |  |  | // You should have received a copy of the GNU Lesser General Public License | 
					
						
							| 
									
										
										
										
											2015-07-22 18:48:40 +02:00
										 |  |  | // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. | 
					
						
							| 
									
										
										
										
											2015-07-07 02:54:22 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-10-31 14:43:14 +01:00
										 |  |  | package state | 
					
						
							| 
									
										
										
										
											2014-08-06 09:53:00 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							|  |  |  | 	"encoding/json" | 
					
						
							|  |  |  | 	"fmt" | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-03-16 11:27:38 +01:00
										 |  |  | 	"github.com/ethereum/go-ethereum/common" | 
					
						
							| 
									
										
										
										
											2019-06-24 16:16:44 +02:00
										 |  |  | 	"github.com/ethereum/go-ethereum/common/hexutil" | 
					
						
							|  |  |  | 	"github.com/ethereum/go-ethereum/log" | 
					
						
							| 
									
										
										
										
											2016-09-22 21:04:58 +02:00
										 |  |  | 	"github.com/ethereum/go-ethereum/rlp" | 
					
						
							| 
									
										
										
										
											2017-04-18 13:37:10 +02:00
										 |  |  | 	"github.com/ethereum/go-ethereum/trie" | 
					
						
							| 
									
										
										
										
											2014-08-06 09:53:00 +02:00
										 |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-30 10:12:51 +02:00
										 |  |  | // DumpCollector interface which the state trie calls during iteration | 
					
						
							|  |  |  | type DumpCollector interface { | 
					
						
							|  |  |  | 	// OnRoot is called with the state root | 
					
						
							|  |  |  | 	OnRoot(common.Hash) | 
					
						
							|  |  |  | 	// OnAccount is called once for each account in the trie | 
					
						
							|  |  |  | 	OnAccount(common.Address, DumpAccount) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-31 18:08:44 +08:00
										 |  |  | // DumpAccount represents an account in the state. | 
					
						
							| 
									
										
										
										
											2016-09-22 21:04:58 +02:00
										 |  |  | type DumpAccount struct { | 
					
						
							| 
									
										
										
										
											2019-06-24 16:16:44 +02:00
										 |  |  | 	Balance   string                 `json:"balance"` | 
					
						
							|  |  |  | 	Nonce     uint64                 `json:"nonce"` | 
					
						
							|  |  |  | 	Root      string                 `json:"root"` | 
					
						
							|  |  |  | 	CodeHash  string                 `json:"codeHash"` | 
					
						
							|  |  |  | 	Code      string                 `json:"code,omitempty"` | 
					
						
							|  |  |  | 	Storage   map[common.Hash]string `json:"storage,omitempty"` | 
					
						
							|  |  |  | 	Address   *common.Address        `json:"address,omitempty"` // Address only present in iterative (line-by-line) mode | 
					
						
							|  |  |  | 	SecureKey hexutil.Bytes          `json:"key,omitempty"`     // If we don't have address, we can output the key | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-08-06 09:53:00 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-31 18:08:44 +08:00
										 |  |  | // Dump represents the full dump in a collected format, as one large map. | 
					
						
							| 
									
										
										
										
											2016-09-22 21:04:58 +02:00
										 |  |  | type Dump struct { | 
					
						
							| 
									
										
										
										
											2019-06-24 16:16:44 +02:00
										 |  |  | 	Root     string                         `json:"root"` | 
					
						
							|  |  |  | 	Accounts map[common.Address]DumpAccount `json:"accounts"` | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-30 10:12:51 +02:00
										 |  |  | // OnRoot implements DumpCollector interface | 
					
						
							|  |  |  | func (d *Dump) OnRoot(root common.Hash) { | 
					
						
							|  |  |  | 	d.Root = fmt.Sprintf("%x", root) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // OnAccount implements DumpCollector interface | 
					
						
							|  |  |  | func (d *Dump) OnAccount(addr common.Address, account DumpAccount) { | 
					
						
							|  |  |  | 	d.Accounts[addr] = account | 
					
						
							| 
									
										
										
										
											2019-11-22 15:56:05 +01:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2019-06-24 16:16:44 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-31 18:08:44 +08:00
										 |  |  | // IteratorDump is an implementation for iterating over data. | 
					
						
							|  |  |  | type IteratorDump struct { | 
					
						
							|  |  |  | 	Root     string                         `json:"root"` | 
					
						
							|  |  |  | 	Accounts map[common.Address]DumpAccount `json:"accounts"` | 
					
						
							|  |  |  | 	Next     []byte                         `json:"next,omitempty"` // nil if no more accounts | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-30 10:12:51 +02:00
										 |  |  | // OnRoot implements DumpCollector interface | 
					
						
							|  |  |  | func (d *IteratorDump) OnRoot(root common.Hash) { | 
					
						
							| 
									
										
										
										
											2019-11-22 15:56:05 +01:00
										 |  |  | 	d.Root = fmt.Sprintf("%x", root) | 
					
						
							| 
									
										
										
										
											2014-08-06 09:53:00 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-30 10:12:51 +02:00
										 |  |  | // OnAccount implements DumpCollector interface | 
					
						
							|  |  |  | func (d *IteratorDump) OnAccount(addr common.Address, account DumpAccount) { | 
					
						
							| 
									
										
										
										
											2019-11-22 15:56:05 +01:00
										 |  |  | 	d.Accounts[addr] = account | 
					
						
							| 
									
										
										
										
											2019-06-24 16:16:44 +02:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2020-03-31 18:08:44 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-30 10:12:51 +02:00
										 |  |  | // iterativeDump is a DumpCollector-implementation which dumps output line-by-line iteratively. | 
					
						
							|  |  |  | type iterativeDump struct { | 
					
						
							|  |  |  | 	*json.Encoder | 
					
						
							| 
									
										
										
										
											2020-03-31 18:08:44 +08:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2019-06-24 16:16:44 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-30 10:12:51 +02:00
										 |  |  | // OnAccount implements DumpCollector interface | 
					
						
							|  |  |  | func (d iterativeDump) OnAccount(addr common.Address, account DumpAccount) { | 
					
						
							| 
									
										
										
										
											2019-06-24 16:16:44 +02:00
										 |  |  | 	dumpAccount := &DumpAccount{ | 
					
						
							|  |  |  | 		Balance:   account.Balance, | 
					
						
							|  |  |  | 		Nonce:     account.Nonce, | 
					
						
							|  |  |  | 		Root:      account.Root, | 
					
						
							|  |  |  | 		CodeHash:  account.CodeHash, | 
					
						
							|  |  |  | 		Code:      account.Code, | 
					
						
							|  |  |  | 		Storage:   account.Storage, | 
					
						
							|  |  |  | 		SecureKey: account.SecureKey, | 
					
						
							|  |  |  | 		Address:   nil, | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if addr != (common.Address{}) { | 
					
						
							|  |  |  | 		dumpAccount.Address = &addr | 
					
						
							| 
									
										
										
										
											2014-08-06 09:53:00 +02:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2019-11-22 15:56:05 +01:00
										 |  |  | 	d.Encode(dumpAccount) | 
					
						
							| 
									
										
										
										
											2019-06-24 16:16:44 +02:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2019-11-22 15:56:05 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-30 10:12:51 +02:00
										 |  |  | // OnRoot implements DumpCollector interface | 
					
						
							|  |  |  | func (d iterativeDump) OnRoot(root common.Hash) { | 
					
						
							| 
									
										
										
										
											2019-11-22 15:56:05 +01:00
										 |  |  | 	d.Encode(struct { | 
					
						
							| 
									
										
										
										
											2019-06-24 16:16:44 +02:00
										 |  |  | 		Root common.Hash `json:"root"` | 
					
						
							|  |  |  | 	}{root}) | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2014-08-06 09:53:00 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-30 10:12:51 +02:00
										 |  |  | func (s *StateDB) DumpToCollector(c DumpCollector, excludeCode, excludeStorage, excludeMissingPreimages bool, start []byte, maxResults int) (nextKey []byte) { | 
					
						
							| 
									
										
										
										
											2019-06-24 16:16:44 +02:00
										 |  |  | 	missingPreimages := 0 | 
					
						
							| 
									
										
										
										
											2020-06-30 10:12:51 +02:00
										 |  |  | 	c.OnRoot(s.trie.Hash()) | 
					
						
							| 
									
										
										
										
											2020-03-31 18:08:44 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	var count int | 
					
						
							|  |  |  | 	it := trie.NewIterator(s.trie.NodeIterator(start)) | 
					
						
							| 
									
										
										
										
											2014-12-23 18:35:36 +01:00
										 |  |  | 	for it.Next() { | 
					
						
							| 
									
										
										
										
											2016-09-22 21:04:58 +02:00
										 |  |  | 		var data Account | 
					
						
							|  |  |  | 		if err := rlp.DecodeBytes(it.Value, &data); err != nil { | 
					
						
							| 
									
										
										
										
											2016-04-15 11:16:56 +02:00
										 |  |  | 			panic(err) | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2016-09-22 21:04:58 +02:00
										 |  |  | 		account := DumpAccount{ | 
					
						
							|  |  |  | 			Balance:  data.Balance.String(), | 
					
						
							|  |  |  | 			Nonce:    data.Nonce, | 
					
						
							|  |  |  | 			Root:     common.Bytes2Hex(data.Root[:]), | 
					
						
							|  |  |  | 			CodeHash: common.Bytes2Hex(data.CodeHash), | 
					
						
							| 
									
										
										
										
											2016-04-15 11:16:56 +02:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2020-05-07 15:06:31 +02:00
										 |  |  | 		addrBytes := s.trie.GetKey(it.Key) | 
					
						
							|  |  |  | 		if addrBytes == nil { | 
					
						
							| 
									
										
										
										
											2019-06-24 16:16:44 +02:00
										 |  |  | 			// Preimage missing | 
					
						
							|  |  |  | 			missingPreimages++ | 
					
						
							|  |  |  | 			if excludeMissingPreimages { | 
					
						
							|  |  |  | 				continue | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			account.SecureKey = it.Key | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2020-05-07 15:06:31 +02:00
										 |  |  | 		addr := common.BytesToAddress(addrBytes) | 
					
						
							| 
									
										
										
										
											2021-01-26 12:15:31 +01:00
										 |  |  | 		obj := newObject(s, addr, data) | 
					
						
							| 
									
										
										
										
											2019-06-24 16:16:44 +02:00
										 |  |  | 		if !excludeCode { | 
					
						
							| 
									
										
										
										
											2019-11-22 15:56:05 +01:00
										 |  |  | 			account.Code = common.Bytes2Hex(obj.Code(s.db)) | 
					
						
							| 
									
										
										
										
											2019-06-24 16:16:44 +02:00
										 |  |  | 		} | 
					
						
							|  |  |  | 		if !excludeStorage { | 
					
						
							|  |  |  | 			account.Storage = make(map[common.Hash]string) | 
					
						
							| 
									
										
										
										
											2019-11-22 15:56:05 +01:00
										 |  |  | 			storageIt := trie.NewIterator(obj.getTrie(s.db).NodeIterator(nil)) | 
					
						
							| 
									
										
										
										
											2019-06-24 16:16:44 +02:00
										 |  |  | 			for storageIt.Next() { | 
					
						
							| 
									
										
										
										
											2019-08-12 22:14:40 +08:00
										 |  |  | 				_, content, _, err := rlp.Split(storageIt.Value) | 
					
						
							|  |  |  | 				if err != nil { | 
					
						
							|  |  |  | 					log.Error("Failed to decode the value returned by iterator", "error", err) | 
					
						
							|  |  |  | 					continue | 
					
						
							|  |  |  | 				} | 
					
						
							| 
									
										
										
										
											2019-11-22 15:56:05 +01:00
										 |  |  | 				account.Storage[common.BytesToHash(s.trie.GetKey(storageIt.Key))] = common.Bytes2Hex(content) | 
					
						
							| 
									
										
										
										
											2019-06-24 16:16:44 +02:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2014-12-23 18:35:36 +01:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2020-06-30 10:12:51 +02:00
										 |  |  | 		c.OnAccount(addr, account) | 
					
						
							| 
									
										
										
										
											2020-03-31 18:08:44 +08:00
										 |  |  | 		count++ | 
					
						
							|  |  |  | 		if maxResults > 0 && count >= maxResults { | 
					
						
							|  |  |  | 			if it.Next() { | 
					
						
							|  |  |  | 				nextKey = it.Key | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			break | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2019-06-24 16:16:44 +02:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	if missingPreimages > 0 { | 
					
						
							|  |  |  | 		log.Warn("Dump incomplete due to missing preimages", "missing", missingPreimages) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2020-03-31 18:08:44 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	return nextKey | 
					
						
							| 
									
										
										
										
											2019-06-24 16:16:44 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // RawDump returns the entire state an a single large object | 
					
						
							| 
									
										
										
										
											2019-11-22 15:56:05 +01:00
										 |  |  | func (s *StateDB) RawDump(excludeCode, excludeStorage, excludeMissingPreimages bool) Dump { | 
					
						
							| 
									
										
										
										
											2019-06-24 16:16:44 +02:00
										 |  |  | 	dump := &Dump{ | 
					
						
							|  |  |  | 		Accounts: make(map[common.Address]DumpAccount), | 
					
						
							| 
									
										
										
										
											2014-12-23 18:35:36 +01:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2020-06-30 10:12:51 +02:00
										 |  |  | 	s.DumpToCollector(dump, excludeCode, excludeStorage, excludeMissingPreimages, nil, 0) | 
					
						
							| 
									
										
										
										
											2019-06-24 16:16:44 +02:00
										 |  |  | 	return *dump | 
					
						
							| 
									
										
										
										
											2015-02-28 19:15:57 +01:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2014-08-06 09:53:00 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-06-24 16:16:44 +02:00
										 |  |  | // Dump returns a JSON string representing the entire state as a single json-object | 
					
						
							| 
									
										
										
										
											2019-11-22 15:56:05 +01:00
										 |  |  | func (s *StateDB) Dump(excludeCode, excludeStorage, excludeMissingPreimages bool) []byte { | 
					
						
							|  |  |  | 	dump := s.RawDump(excludeCode, excludeStorage, excludeMissingPreimages) | 
					
						
							| 
									
										
										
										
											2019-06-24 16:16:44 +02:00
										 |  |  | 	json, err := json.MarshalIndent(dump, "", "    ") | 
					
						
							| 
									
										
										
										
											2014-08-06 09:53:00 +02:00
										 |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2020-06-30 10:12:51 +02:00
										 |  |  | 		fmt.Println("Dump err", err) | 
					
						
							| 
									
										
										
										
											2014-08-06 09:53:00 +02:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2014-08-17 12:42:32 +02:00
										 |  |  | 	return json | 
					
						
							| 
									
										
										
										
											2014-08-06 09:53:00 +02:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2019-06-24 16:16:44 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | // IterativeDump dumps out accounts as json-objects, delimited by linebreaks on stdout | 
					
						
							| 
									
										
										
										
											2019-11-22 15:56:05 +01:00
										 |  |  | func (s *StateDB) IterativeDump(excludeCode, excludeStorage, excludeMissingPreimages bool, output *json.Encoder) { | 
					
						
							| 
									
										
										
										
											2020-06-30 10:12:51 +02:00
										 |  |  | 	s.DumpToCollector(iterativeDump{output}, excludeCode, excludeStorage, excludeMissingPreimages, nil, 0) | 
					
						
							| 
									
										
										
										
											2020-03-31 18:08:44 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // IteratorDump dumps out a batch of accounts starts with the given start key | 
					
						
							|  |  |  | func (s *StateDB) IteratorDump(excludeCode, excludeStorage, excludeMissingPreimages bool, start []byte, maxResults int) IteratorDump { | 
					
						
							|  |  |  | 	iterator := &IteratorDump{ | 
					
						
							|  |  |  | 		Accounts: make(map[common.Address]DumpAccount), | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2020-06-30 10:12:51 +02:00
										 |  |  | 	iterator.Next = s.DumpToCollector(iterator, excludeCode, excludeStorage, excludeMissingPreimages, start, maxResults) | 
					
						
							| 
									
										
										
										
											2020-03-31 18:08:44 +08:00
										 |  |  | 	return *iterator | 
					
						
							| 
									
										
										
										
											2019-06-24 16:16:44 +02:00
										 |  |  | } |