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  }