github.1485827954.workers.dev/ethereum/go-ethereum@v1.14.3/cmd/devp2p/internal/ethtest/chain.go (about)

     1  // Copyright 2020 The go-ethereum Authors
     2  // This file is part of go-ethereum.
     3  //
     4  // go-ethereum is free software: you can redistribute it and/or modify
     5  // it under the terms of the GNU 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  // go-ethereum 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 General Public License for more details.
    13  //
    14  // You should have received a copy of the GNU General Public License
    15  // along with go-ethereum. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  package ethtest
    18  
    19  import (
    20  	"bytes"
    21  	"compress/gzip"
    22  	"crypto/ecdsa"
    23  	"encoding/json"
    24  	"errors"
    25  	"fmt"
    26  	"io"
    27  	"math/big"
    28  	"os"
    29  	"path/filepath"
    30  	"slices"
    31  	"sort"
    32  	"strings"
    33  
    34  	"github.com/ethereum/go-ethereum/common"
    35  	"github.com/ethereum/go-ethereum/common/hexutil"
    36  	"github.com/ethereum/go-ethereum/core"
    37  	"github.com/ethereum/go-ethereum/core/forkid"
    38  	"github.com/ethereum/go-ethereum/core/state"
    39  	"github.com/ethereum/go-ethereum/core/types"
    40  	"github.com/ethereum/go-ethereum/crypto"
    41  	"github.com/ethereum/go-ethereum/eth/protocols/eth"
    42  	"github.com/ethereum/go-ethereum/params"
    43  	"github.com/ethereum/go-ethereum/rlp"
    44  )
    45  
    46  // Chain is a lightweight blockchain-like store which can read a hivechain
    47  // created chain.
    48  type Chain struct {
    49  	genesis core.Genesis
    50  	blocks  []*types.Block
    51  	state   map[common.Address]state.DumpAccount // state of head block
    52  	senders map[common.Address]*senderInfo
    53  	config  *params.ChainConfig
    54  }
    55  
    56  // NewChain takes the given chain.rlp file, and decodes and returns
    57  // the blocks from the file.
    58  func NewChain(dir string) (*Chain, error) {
    59  	gen, err := loadGenesis(filepath.Join(dir, "genesis.json"))
    60  	if err != nil {
    61  		return nil, err
    62  	}
    63  	gblock := gen.ToBlock()
    64  
    65  	blocks, err := blocksFromFile(filepath.Join(dir, "chain.rlp"), gblock)
    66  	if err != nil {
    67  		return nil, err
    68  	}
    69  	state, err := readState(filepath.Join(dir, "headstate.json"))
    70  	if err != nil {
    71  		return nil, err
    72  	}
    73  	accounts, err := readAccounts(filepath.Join(dir, "accounts.json"))
    74  	if err != nil {
    75  		return nil, err
    76  	}
    77  	return &Chain{
    78  		genesis: gen,
    79  		blocks:  blocks,
    80  		state:   state,
    81  		senders: accounts,
    82  		config:  gen.Config,
    83  	}, nil
    84  }
    85  
    86  // senderInfo is an account record as output in the "accounts.json" file from
    87  // hivechain.
    88  type senderInfo struct {
    89  	Key   *ecdsa.PrivateKey `json:"key"`
    90  	Nonce uint64            `json:"nonce"`
    91  }
    92  
    93  // Head returns the chain head.
    94  func (c *Chain) Head() *types.Block {
    95  	return c.blocks[c.Len()-1]
    96  }
    97  
    98  // AccountsInHashOrder returns all accounts of the head state, ordered by hash of address.
    99  func (c *Chain) AccountsInHashOrder() []state.DumpAccount {
   100  	list := make([]state.DumpAccount, len(c.state))
   101  	i := 0
   102  	for addr, acc := range c.state {
   103  		addr := addr
   104  		list[i] = acc
   105  		list[i].Address = &addr
   106  		if len(acc.AddressHash) != 32 {
   107  			panic(fmt.Errorf("missing/invalid SecureKey in dump account %v", addr))
   108  		}
   109  		i++
   110  	}
   111  	slices.SortFunc(list, func(x, y state.DumpAccount) int {
   112  		return bytes.Compare(x.AddressHash, y.AddressHash)
   113  	})
   114  	return list
   115  }
   116  
   117  // CodeHashes returns all bytecode hashes contained in the head state.
   118  func (c *Chain) CodeHashes() []common.Hash {
   119  	var hashes []common.Hash
   120  	seen := make(map[common.Hash]struct{})
   121  	seen[types.EmptyCodeHash] = struct{}{}
   122  	for _, acc := range c.state {
   123  		h := common.BytesToHash(acc.CodeHash)
   124  		if _, ok := seen[h]; ok {
   125  			continue
   126  		}
   127  		hashes = append(hashes, h)
   128  		seen[h] = struct{}{}
   129  	}
   130  	slices.SortFunc(hashes, (common.Hash).Cmp)
   131  	return hashes
   132  }
   133  
   134  // Len returns the length of the chain.
   135  func (c *Chain) Len() int {
   136  	return len(c.blocks)
   137  }
   138  
   139  // ForkID gets the fork id of the chain.
   140  func (c *Chain) ForkID() forkid.ID {
   141  	return forkid.NewID(c.config, c.blocks[0], uint64(c.Len()), c.blocks[c.Len()-1].Time())
   142  }
   143  
   144  // TD calculates the total difficulty of the chain at the
   145  // chain head.
   146  func (c *Chain) TD() *big.Int {
   147  	sum := new(big.Int)
   148  	for _, block := range c.blocks[:c.Len()] {
   149  		sum.Add(sum, block.Difficulty())
   150  	}
   151  	return sum
   152  }
   153  
   154  // GetBlock returns the block at the specified number.
   155  func (c *Chain) GetBlock(number int) *types.Block {
   156  	return c.blocks[number]
   157  }
   158  
   159  // RootAt returns the state root for the block at the given height.
   160  func (c *Chain) RootAt(height int) common.Hash {
   161  	if height < c.Len() {
   162  		return c.blocks[height].Root()
   163  	}
   164  	return common.Hash{}
   165  }
   166  
   167  // GetSender returns the address associated with account at the index in the
   168  // pre-funded accounts list.
   169  func (c *Chain) GetSender(idx int) (common.Address, uint64) {
   170  	var accounts Addresses
   171  	for addr := range c.senders {
   172  		accounts = append(accounts, addr)
   173  	}
   174  	sort.Sort(accounts)
   175  	addr := accounts[idx]
   176  	return addr, c.senders[addr].Nonce
   177  }
   178  
   179  // IncNonce increases the specified signing account's pending nonce.
   180  func (c *Chain) IncNonce(addr common.Address, amt uint64) {
   181  	if _, ok := c.senders[addr]; !ok {
   182  		panic("nonce increment for non-signer")
   183  	}
   184  	c.senders[addr].Nonce += amt
   185  }
   186  
   187  // Balance returns the balance of an account at the head of the chain.
   188  func (c *Chain) Balance(addr common.Address) *big.Int {
   189  	bal := new(big.Int)
   190  	if acc, ok := c.state[addr]; ok {
   191  		bal, _ = bal.SetString(acc.Balance, 10)
   192  	}
   193  	return bal
   194  }
   195  
   196  // SignTx signs a transaction for the specified from account, so long as that
   197  // account was in the hivechain accounts dump.
   198  func (c *Chain) SignTx(from common.Address, tx *types.Transaction) (*types.Transaction, error) {
   199  	signer := types.LatestSigner(c.config)
   200  	acc, ok := c.senders[from]
   201  	if !ok {
   202  		return nil, fmt.Errorf("account not available for signing: %s", from)
   203  	}
   204  	return types.SignTx(tx, signer, acc.Key)
   205  }
   206  
   207  // GetHeaders returns the headers base on an ethGetPacketHeadersPacket.
   208  func (c *Chain) GetHeaders(req *eth.GetBlockHeadersPacket) ([]*types.Header, error) {
   209  	if req.Amount < 1 {
   210  		return nil, errors.New("no block headers requested")
   211  	}
   212  	var (
   213  		headers     = make([]*types.Header, req.Amount)
   214  		blockNumber uint64
   215  	)
   216  	// Range over blocks to check if our chain has the requested header.
   217  	for _, block := range c.blocks {
   218  		if block.Hash() == req.Origin.Hash || block.Number().Uint64() == req.Origin.Number {
   219  			headers[0] = block.Header()
   220  			blockNumber = block.Number().Uint64()
   221  		}
   222  	}
   223  	if headers[0] == nil {
   224  		return nil, fmt.Errorf("no headers found for given origin number %v, hash %v", req.Origin.Number, req.Origin.Hash)
   225  	}
   226  	if req.Reverse {
   227  		for i := 1; i < int(req.Amount); i++ {
   228  			blockNumber -= (1 - req.Skip)
   229  			headers[i] = c.blocks[blockNumber].Header()
   230  		}
   231  		return headers, nil
   232  	}
   233  	for i := 1; i < int(req.Amount); i++ {
   234  		blockNumber += (1 + req.Skip)
   235  		headers[i] = c.blocks[blockNumber].Header()
   236  	}
   237  	return headers, nil
   238  }
   239  
   240  // Shorten returns a copy chain of a desired height from the imported
   241  func (c *Chain) Shorten(height int) *Chain {
   242  	blocks := make([]*types.Block, height)
   243  	copy(blocks, c.blocks[:height])
   244  
   245  	config := *c.config
   246  	return &Chain{
   247  		blocks: blocks,
   248  		config: &config,
   249  	}
   250  }
   251  
   252  func loadGenesis(genesisFile string) (core.Genesis, error) {
   253  	chainConfig, err := os.ReadFile(genesisFile)
   254  	if err != nil {
   255  		return core.Genesis{}, err
   256  	}
   257  	var gen core.Genesis
   258  	if err := json.Unmarshal(chainConfig, &gen); err != nil {
   259  		return core.Genesis{}, err
   260  	}
   261  	return gen, nil
   262  }
   263  
   264  type Addresses []common.Address
   265  
   266  func (a Addresses) Len() int {
   267  	return len(a)
   268  }
   269  
   270  func (a Addresses) Less(i, j int) bool {
   271  	return bytes.Compare(a[i][:], a[j][:]) < 0
   272  }
   273  
   274  func (a Addresses) Swap(i, j int) {
   275  	tmp := a[i]
   276  	a[i] = a[j]
   277  	a[j] = tmp
   278  }
   279  
   280  func blocksFromFile(chainfile string, gblock *types.Block) ([]*types.Block, error) {
   281  	// Load chain.rlp.
   282  	fh, err := os.Open(chainfile)
   283  	if err != nil {
   284  		return nil, err
   285  	}
   286  	defer fh.Close()
   287  	var reader io.Reader = fh
   288  	if strings.HasSuffix(chainfile, ".gz") {
   289  		if reader, err = gzip.NewReader(reader); err != nil {
   290  			return nil, err
   291  		}
   292  	}
   293  	stream := rlp.NewStream(reader, 0)
   294  	var blocks = make([]*types.Block, 1)
   295  	blocks[0] = gblock
   296  	for i := 0; ; i++ {
   297  		var b types.Block
   298  		if err := stream.Decode(&b); err == io.EOF {
   299  			break
   300  		} else if err != nil {
   301  			return nil, fmt.Errorf("at block index %d: %v", i, err)
   302  		}
   303  		if b.NumberU64() != uint64(i+1) {
   304  			return nil, fmt.Errorf("block at index %d has wrong number %d", i, b.NumberU64())
   305  		}
   306  		blocks = append(blocks, &b)
   307  	}
   308  	return blocks, nil
   309  }
   310  
   311  func readState(file string) (map[common.Address]state.DumpAccount, error) {
   312  	f, err := os.ReadFile(file)
   313  	if err != nil {
   314  		return nil, fmt.Errorf("unable to read state: %v", err)
   315  	}
   316  	var dump state.Dump
   317  	if err := json.Unmarshal(f, &dump); err != nil {
   318  		return nil, fmt.Errorf("unable to unmarshal state: %v", err)
   319  	}
   320  
   321  	state := make(map[common.Address]state.DumpAccount)
   322  	for key, acct := range dump.Accounts {
   323  		var addr common.Address
   324  		if err := addr.UnmarshalText([]byte(key)); err != nil {
   325  			return nil, fmt.Errorf("invalid address %q", key)
   326  		}
   327  		state[addr] = acct
   328  	}
   329  	return state, nil
   330  }
   331  
   332  func readAccounts(file string) (map[common.Address]*senderInfo, error) {
   333  	f, err := os.ReadFile(file)
   334  	if err != nil {
   335  		return nil, fmt.Errorf("unable to read state: %v", err)
   336  	}
   337  	type account struct {
   338  		Key hexutil.Bytes `json:"key"`
   339  	}
   340  	keys := make(map[common.Address]account)
   341  	if err := json.Unmarshal(f, &keys); err != nil {
   342  		return nil, fmt.Errorf("unable to unmarshal accounts: %v", err)
   343  	}
   344  	accounts := make(map[common.Address]*senderInfo)
   345  	for addr, acc := range keys {
   346  		pk, err := crypto.HexToECDSA(common.Bytes2Hex(acc.Key))
   347  		if err != nil {
   348  			return nil, fmt.Errorf("unable to read private key for %s: %v", err, addr)
   349  		}
   350  		accounts[addr] = &senderInfo{Key: pk, Nonce: 0}
   351  	}
   352  	return accounts, nil
   353  }