github.1485827954.workers.dev/ethereum/go-ethereum@v1.14.3/tests/block_test_util.go (about)

     1  // Copyright 2015 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 tests implements execution of Ethereum JSON tests.
    18  package tests
    19  
    20  import (
    21  	"bytes"
    22  	"encoding/hex"
    23  	"encoding/json"
    24  	"fmt"
    25  	"math/big"
    26  	"os"
    27  	"reflect"
    28  
    29  	"github.com/ethereum/go-ethereum/common"
    30  	"github.com/ethereum/go-ethereum/common/hexutil"
    31  	"github.com/ethereum/go-ethereum/common/math"
    32  	"github.com/ethereum/go-ethereum/consensus/beacon"
    33  	"github.com/ethereum/go-ethereum/consensus/ethash"
    34  	"github.com/ethereum/go-ethereum/core"
    35  	"github.com/ethereum/go-ethereum/core/rawdb"
    36  	"github.com/ethereum/go-ethereum/core/state"
    37  	"github.com/ethereum/go-ethereum/core/tracing"
    38  	"github.com/ethereum/go-ethereum/core/types"
    39  	"github.com/ethereum/go-ethereum/core/vm"
    40  	"github.com/ethereum/go-ethereum/log"
    41  	"github.com/ethereum/go-ethereum/params"
    42  	"github.com/ethereum/go-ethereum/rlp"
    43  	"github.com/ethereum/go-ethereum/triedb"
    44  	"github.com/ethereum/go-ethereum/triedb/hashdb"
    45  	"github.com/ethereum/go-ethereum/triedb/pathdb"
    46  )
    47  
    48  // A BlockTest checks handling of entire blocks.
    49  type BlockTest struct {
    50  	json btJSON
    51  }
    52  
    53  // UnmarshalJSON implements json.Unmarshaler interface.
    54  func (t *BlockTest) UnmarshalJSON(in []byte) error {
    55  	return json.Unmarshal(in, &t.json)
    56  }
    57  
    58  type btJSON struct {
    59  	Blocks     []btBlock             `json:"blocks"`
    60  	Genesis    btHeader              `json:"genesisBlockHeader"`
    61  	Pre        types.GenesisAlloc    `json:"pre"`
    62  	Post       types.GenesisAlloc    `json:"postState"`
    63  	BestBlock  common.UnprefixedHash `json:"lastblockhash"`
    64  	Network    string                `json:"network"`
    65  	SealEngine string                `json:"sealEngine"`
    66  }
    67  
    68  type btBlock struct {
    69  	BlockHeader     *btHeader
    70  	ExpectException string
    71  	Rlp             string
    72  	UncleHeaders    []*btHeader
    73  }
    74  
    75  //go:generate go run github.com/fjl/gencodec -type btHeader -field-override btHeaderMarshaling -out gen_btheader.go
    76  
    77  type btHeader struct {
    78  	Bloom                 types.Bloom
    79  	Coinbase              common.Address
    80  	MixHash               common.Hash
    81  	Nonce                 types.BlockNonce
    82  	Number                *big.Int
    83  	Hash                  common.Hash
    84  	ParentHash            common.Hash
    85  	ReceiptTrie           common.Hash
    86  	StateRoot             common.Hash
    87  	TransactionsTrie      common.Hash
    88  	UncleHash             common.Hash
    89  	ExtraData             []byte
    90  	Difficulty            *big.Int
    91  	GasLimit              uint64
    92  	GasUsed               uint64
    93  	Timestamp             uint64
    94  	BaseFeePerGas         *big.Int
    95  	WithdrawalsRoot       *common.Hash
    96  	BlobGasUsed           *uint64
    97  	ExcessBlobGas         *uint64
    98  	ParentBeaconBlockRoot *common.Hash
    99  }
   100  
   101  type btHeaderMarshaling struct {
   102  	ExtraData     hexutil.Bytes
   103  	Number        *math.HexOrDecimal256
   104  	Difficulty    *math.HexOrDecimal256
   105  	GasLimit      math.HexOrDecimal64
   106  	GasUsed       math.HexOrDecimal64
   107  	Timestamp     math.HexOrDecimal64
   108  	BaseFeePerGas *math.HexOrDecimal256
   109  	BlobGasUsed   *math.HexOrDecimal64
   110  	ExcessBlobGas *math.HexOrDecimal64
   111  }
   112  
   113  func (t *BlockTest) Run(snapshotter bool, scheme string, tracer *tracing.Hooks, postCheck func(error, *core.BlockChain)) (result error) {
   114  	config, ok := Forks[t.json.Network]
   115  	if !ok {
   116  		return UnsupportedForkError{t.json.Network}
   117  	}
   118  	// import pre accounts & construct test genesis block & state root
   119  	var (
   120  		db    = rawdb.NewMemoryDatabase()
   121  		tconf = &triedb.Config{
   122  			Preimages: true,
   123  		}
   124  	)
   125  	if scheme == rawdb.PathScheme {
   126  		tconf.PathDB = pathdb.Defaults
   127  	} else {
   128  		tconf.HashDB = hashdb.Defaults
   129  	}
   130  	// Commit genesis state
   131  	gspec := t.genesis(config)
   132  	triedb := triedb.NewDatabase(db, tconf)
   133  	gblock, err := gspec.Commit(db, triedb)
   134  	if err != nil {
   135  		return err
   136  	}
   137  	triedb.Close() // close the db to prevent memory leak
   138  
   139  	if gblock.Hash() != t.json.Genesis.Hash {
   140  		return fmt.Errorf("genesis block hash doesn't match test: computed=%x, test=%x", gblock.Hash().Bytes()[:6], t.json.Genesis.Hash[:6])
   141  	}
   142  	if gblock.Root() != t.json.Genesis.StateRoot {
   143  		return fmt.Errorf("genesis block state root does not match test: computed=%x, test=%x", gblock.Root().Bytes()[:6], t.json.Genesis.StateRoot[:6])
   144  	}
   145  	// Wrap the original engine within the beacon-engine
   146  	engine := beacon.New(ethash.NewFaker())
   147  
   148  	cache := &core.CacheConfig{TrieCleanLimit: 0, StateScheme: scheme, Preimages: true}
   149  	if snapshotter {
   150  		cache.SnapshotLimit = 1
   151  		cache.SnapshotWait = true
   152  	}
   153  	chain, err := core.NewBlockChain(db, cache, gspec, nil, engine, vm.Config{
   154  		Tracer: tracer,
   155  	}, nil, nil)
   156  	if err != nil {
   157  		return err
   158  	}
   159  	defer chain.Stop()
   160  
   161  	validBlocks, err := t.insertBlocks(chain)
   162  	if err != nil {
   163  		return err
   164  	}
   165  	// Import succeeded: regardless of whether the _test_ succeeds or not, schedule
   166  	// the post-check to run
   167  	if postCheck != nil {
   168  		defer postCheck(result, chain)
   169  	}
   170  	cmlast := chain.CurrentBlock().Hash()
   171  	if common.Hash(t.json.BestBlock) != cmlast {
   172  		return fmt.Errorf("last block hash validation mismatch: want: %x, have: %x", t.json.BestBlock, cmlast)
   173  	}
   174  	newDB, err := chain.State()
   175  	if err != nil {
   176  		return err
   177  	}
   178  	if err = t.validatePostState(newDB); err != nil {
   179  		return fmt.Errorf("post state validation failed: %v", err)
   180  	}
   181  	// Cross-check the snapshot-to-hash against the trie hash
   182  	if snapshotter {
   183  		if err := chain.Snapshots().Verify(chain.CurrentBlock().Root); err != nil {
   184  			return err
   185  		}
   186  	}
   187  	return t.validateImportedHeaders(chain, validBlocks)
   188  }
   189  
   190  func (t *BlockTest) genesis(config *params.ChainConfig) *core.Genesis {
   191  	return &core.Genesis{
   192  		Config:        config,
   193  		Nonce:         t.json.Genesis.Nonce.Uint64(),
   194  		Timestamp:     t.json.Genesis.Timestamp,
   195  		ParentHash:    t.json.Genesis.ParentHash,
   196  		ExtraData:     t.json.Genesis.ExtraData,
   197  		GasLimit:      t.json.Genesis.GasLimit,
   198  		GasUsed:       t.json.Genesis.GasUsed,
   199  		Difficulty:    t.json.Genesis.Difficulty,
   200  		Mixhash:       t.json.Genesis.MixHash,
   201  		Coinbase:      t.json.Genesis.Coinbase,
   202  		Alloc:         t.json.Pre,
   203  		BaseFee:       t.json.Genesis.BaseFeePerGas,
   204  		BlobGasUsed:   t.json.Genesis.BlobGasUsed,
   205  		ExcessBlobGas: t.json.Genesis.ExcessBlobGas,
   206  	}
   207  }
   208  
   209  /*
   210  See https://github.com/ethereum/tests/wiki/Blockchain-Tests-II
   211  
   212  	Whether a block is valid or not is a bit subtle, it's defined by presence of
   213  	blockHeader, transactions and uncleHeaders fields. If they are missing, the block is
   214  	invalid and we must verify that we do not accept it.
   215  
   216  	Since some tests mix valid and invalid blocks we need to check this for every block.
   217  
   218  	If a block is invalid it does not necessarily fail the test, if it's invalidness is
   219  	expected we are expected to ignore it and continue processing and then validate the
   220  	post state.
   221  */
   222  func (t *BlockTest) insertBlocks(blockchain *core.BlockChain) ([]btBlock, error) {
   223  	validBlocks := make([]btBlock, 0)
   224  	// insert the test blocks, which will execute all transactions
   225  	for bi, b := range t.json.Blocks {
   226  		cb, err := b.decode()
   227  		if err != nil {
   228  			if b.BlockHeader == nil {
   229  				log.Info("Block decoding failed", "index", bi, "err", err)
   230  				continue // OK - block is supposed to be invalid, continue with next block
   231  			} else {
   232  				return nil, fmt.Errorf("block RLP decoding failed when expected to succeed: %v", err)
   233  			}
   234  		}
   235  		// RLP decoding worked, try to insert into chain:
   236  		blocks := types.Blocks{cb}
   237  		i, err := blockchain.InsertChain(blocks)
   238  		if err != nil {
   239  			if b.BlockHeader == nil {
   240  				continue // OK - block is supposed to be invalid, continue with next block
   241  			} else {
   242  				return nil, fmt.Errorf("block #%v insertion into chain failed: %v", blocks[i].Number(), err)
   243  			}
   244  		}
   245  		if b.BlockHeader == nil {
   246  			if data, err := json.MarshalIndent(cb.Header(), "", "  "); err == nil {
   247  				fmt.Fprintf(os.Stderr, "block (index %d) insertion should have failed due to: %v:\n%v\n",
   248  					bi, b.ExpectException, string(data))
   249  			}
   250  			return nil, fmt.Errorf("block (index %d) insertion should have failed due to: %v",
   251  				bi, b.ExpectException)
   252  		}
   253  
   254  		// validate RLP decoding by checking all values against test file JSON
   255  		if err = validateHeader(b.BlockHeader, cb.Header()); err != nil {
   256  			return nil, fmt.Errorf("deserialised block header validation failed: %v", err)
   257  		}
   258  		validBlocks = append(validBlocks, b)
   259  	}
   260  	return validBlocks, nil
   261  }
   262  
   263  func validateHeader(h *btHeader, h2 *types.Header) error {
   264  	if h.Bloom != h2.Bloom {
   265  		return fmt.Errorf("bloom: want: %x have: %x", h.Bloom, h2.Bloom)
   266  	}
   267  	if h.Coinbase != h2.Coinbase {
   268  		return fmt.Errorf("coinbase: want: %x have: %x", h.Coinbase, h2.Coinbase)
   269  	}
   270  	if h.MixHash != h2.MixDigest {
   271  		return fmt.Errorf("MixHash: want: %x have: %x", h.MixHash, h2.MixDigest)
   272  	}
   273  	if h.Nonce != h2.Nonce {
   274  		return fmt.Errorf("nonce: want: %x have: %x", h.Nonce, h2.Nonce)
   275  	}
   276  	if h.Number.Cmp(h2.Number) != 0 {
   277  		return fmt.Errorf("number: want: %v have: %v", h.Number, h2.Number)
   278  	}
   279  	if h.ParentHash != h2.ParentHash {
   280  		return fmt.Errorf("parent hash: want: %x have: %x", h.ParentHash, h2.ParentHash)
   281  	}
   282  	if h.ReceiptTrie != h2.ReceiptHash {
   283  		return fmt.Errorf("receipt hash: want: %x have: %x", h.ReceiptTrie, h2.ReceiptHash)
   284  	}
   285  	if h.TransactionsTrie != h2.TxHash {
   286  		return fmt.Errorf("tx hash: want: %x have: %x", h.TransactionsTrie, h2.TxHash)
   287  	}
   288  	if h.StateRoot != h2.Root {
   289  		return fmt.Errorf("state hash: want: %x have: %x", h.StateRoot, h2.Root)
   290  	}
   291  	if h.UncleHash != h2.UncleHash {
   292  		return fmt.Errorf("uncle hash: want: %x have: %x", h.UncleHash, h2.UncleHash)
   293  	}
   294  	if !bytes.Equal(h.ExtraData, h2.Extra) {
   295  		return fmt.Errorf("extra data: want: %x have: %x", h.ExtraData, h2.Extra)
   296  	}
   297  	if h.Difficulty.Cmp(h2.Difficulty) != 0 {
   298  		return fmt.Errorf("difficulty: want: %v have: %v", h.Difficulty, h2.Difficulty)
   299  	}
   300  	if h.GasLimit != h2.GasLimit {
   301  		return fmt.Errorf("gasLimit: want: %d have: %d", h.GasLimit, h2.GasLimit)
   302  	}
   303  	if h.GasUsed != h2.GasUsed {
   304  		return fmt.Errorf("gasUsed: want: %d have: %d", h.GasUsed, h2.GasUsed)
   305  	}
   306  	if h.Timestamp != h2.Time {
   307  		return fmt.Errorf("timestamp: want: %v have: %v", h.Timestamp, h2.Time)
   308  	}
   309  	if !reflect.DeepEqual(h.BaseFeePerGas, h2.BaseFee) {
   310  		return fmt.Errorf("baseFeePerGas: want: %v have: %v", h.BaseFeePerGas, h2.BaseFee)
   311  	}
   312  	if !reflect.DeepEqual(h.WithdrawalsRoot, h2.WithdrawalsHash) {
   313  		return fmt.Errorf("withdrawalsRoot: want: %v have: %v", h.WithdrawalsRoot, h2.WithdrawalsHash)
   314  	}
   315  	if !reflect.DeepEqual(h.BlobGasUsed, h2.BlobGasUsed) {
   316  		return fmt.Errorf("blobGasUsed: want: %v have: %v", h.BlobGasUsed, h2.BlobGasUsed)
   317  	}
   318  	if !reflect.DeepEqual(h.ExcessBlobGas, h2.ExcessBlobGas) {
   319  		return fmt.Errorf("excessBlobGas: want: %v have: %v", h.ExcessBlobGas, h2.ExcessBlobGas)
   320  	}
   321  	if !reflect.DeepEqual(h.ParentBeaconBlockRoot, h2.ParentBeaconRoot) {
   322  		return fmt.Errorf("parentBeaconBlockRoot: want: %v have: %v", h.ParentBeaconBlockRoot, h2.ParentBeaconRoot)
   323  	}
   324  	return nil
   325  }
   326  
   327  func (t *BlockTest) validatePostState(statedb *state.StateDB) error {
   328  	// validate post state accounts in test file against what we have in state db
   329  	for addr, acct := range t.json.Post {
   330  		// address is indirectly verified by the other fields, as it's the db key
   331  		code2 := statedb.GetCode(addr)
   332  		balance2 := statedb.GetBalance(addr).ToBig()
   333  		nonce2 := statedb.GetNonce(addr)
   334  		if !bytes.Equal(code2, acct.Code) {
   335  			return fmt.Errorf("account code mismatch for addr: %s want: %v have: %s", addr, acct.Code, hex.EncodeToString(code2))
   336  		}
   337  		if balance2.Cmp(acct.Balance) != 0 {
   338  			return fmt.Errorf("account balance mismatch for addr: %s, want: %d, have: %d", addr, acct.Balance, balance2)
   339  		}
   340  		if nonce2 != acct.Nonce {
   341  			return fmt.Errorf("account nonce mismatch for addr: %s want: %d have: %d", addr, acct.Nonce, nonce2)
   342  		}
   343  		for k, v := range acct.Storage {
   344  			v2 := statedb.GetState(addr, k)
   345  			if v2 != v {
   346  				return fmt.Errorf("account storage mismatch for addr: %s, slot: %x, want: %x, have: %x", addr, k, v, v2)
   347  			}
   348  		}
   349  	}
   350  	return nil
   351  }
   352  
   353  func (t *BlockTest) validateImportedHeaders(cm *core.BlockChain, validBlocks []btBlock) error {
   354  	// to get constant lookup when verifying block headers by hash (some tests have many blocks)
   355  	bmap := make(map[common.Hash]btBlock, len(t.json.Blocks))
   356  	for _, b := range validBlocks {
   357  		bmap[b.BlockHeader.Hash] = b
   358  	}
   359  	// iterate over blocks backwards from HEAD and validate imported
   360  	// headers vs test file. some tests have reorgs, and we import
   361  	// block-by-block, so we can only validate imported headers after
   362  	// all blocks have been processed by BlockChain, as they may not
   363  	// be part of the longest chain until last block is imported.
   364  	for b := cm.CurrentBlock(); b != nil && b.Number.Uint64() != 0; b = cm.GetBlockByHash(b.ParentHash).Header() {
   365  		if err := validateHeader(bmap[b.Hash()].BlockHeader, b); err != nil {
   366  			return fmt.Errorf("imported block header validation failed: %v", err)
   367  		}
   368  	}
   369  	return nil
   370  }
   371  
   372  func (bb *btBlock) decode() (*types.Block, error) {
   373  	data, err := hexutil.Decode(bb.Rlp)
   374  	if err != nil {
   375  		return nil, err
   376  	}
   377  	var b types.Block
   378  	err = rlp.DecodeBytes(data, &b)
   379  	return &b, err
   380  }