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