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