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