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