gitlab.com/yannislg/go-pulse@v0.0.0-20210722055913-a3e24e95638d/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/ethereum/go-ethereum/common"
    28  	"github.com/ethereum/go-ethereum/common/hexutil"
    29  	"github.com/ethereum/go-ethereum/common/math"
    30  	"github.com/ethereum/go-ethereum/consensus"
    31  	"github.com/ethereum/go-ethereum/consensus/ethash"
    32  	"github.com/ethereum/go-ethereum/core"
    33  	"github.com/ethereum/go-ethereum/core/rawdb"
    34  	"github.com/ethereum/go-ethereum/core/state"
    35  	"github.com/ethereum/go-ethereum/core/state/snapshot"
    36  	"github.com/ethereum/go-ethereum/core/types"
    37  	"github.com/ethereum/go-ethereum/core/vm"
    38  	"github.com/ethereum/go-ethereum/params"
    39  	"github.com/ethereum/go-ethereum/rlp"
    40  )
    41  
    42  // A BlockTest checks handling of entire blocks.
    43  type BlockTest struct {
    44  	json btJSON
    45  }
    46  
    47  // UnmarshalJSON implements json.Unmarshaler interface.
    48  func (t *BlockTest) UnmarshalJSON(in []byte) error {
    49  	return json.Unmarshal(in, &t.json)
    50  }
    51  
    52  type btJSON struct {
    53  	Blocks     []btBlock             `json:"blocks"`
    54  	Genesis    btHeader              `json:"genesisBlockHeader"`
    55  	Pre        core.GenesisAlloc     `json:"pre"`
    56  	Post       core.GenesisAlloc     `json:"postState"`
    57  	BestBlock  common.UnprefixedHash `json:"lastblockhash"`
    58  	Network    string                `json:"network"`
    59  	SealEngine string                `json:"sealEngine"`
    60  }
    61  
    62  type btBlock struct {
    63  	BlockHeader  *btHeader
    64  	Rlp          string
    65  	UncleHeaders []*btHeader
    66  }
    67  
    68  //go:generate gencodec -type btHeader -field-override btHeaderMarshaling -out gen_btheader.go
    69  
    70  type btHeader struct {
    71  	Bloom            types.Bloom
    72  	Coinbase         common.Address
    73  	MixHash          common.Hash
    74  	Nonce            types.BlockNonce
    75  	Number           *big.Int
    76  	Hash             common.Hash
    77  	ParentHash       common.Hash
    78  	ReceiptTrie      common.Hash
    79  	StateRoot        common.Hash
    80  	TransactionsTrie common.Hash
    81  	UncleHash        common.Hash
    82  	ExtraData        []byte
    83  	Difficulty       *big.Int
    84  	GasLimit         uint64
    85  	GasUsed          uint64
    86  	Timestamp        uint64
    87  }
    88  
    89  type btHeaderMarshaling struct {
    90  	ExtraData  hexutil.Bytes
    91  	Number     *math.HexOrDecimal256
    92  	Difficulty *math.HexOrDecimal256
    93  	GasLimit   math.HexOrDecimal64
    94  	GasUsed    math.HexOrDecimal64
    95  	Timestamp  math.HexOrDecimal64
    96  }
    97  
    98  func (t *BlockTest) Run(snapshotter bool) error {
    99  	config, ok := Forks[t.json.Network]
   100  	if !ok {
   101  		return UnsupportedForkError{t.json.Network}
   102  	}
   103  
   104  	// import pre accounts & construct test genesis block & state root
   105  	db := rawdb.NewMemoryDatabase()
   106  	gblock, err := t.genesis(config).Commit(db)
   107  	if err != nil {
   108  		return err
   109  	}
   110  	if gblock.Hash() != t.json.Genesis.Hash {
   111  		return fmt.Errorf("genesis block hash doesn't match test: computed=%x, test=%x", gblock.Hash().Bytes()[:6], t.json.Genesis.Hash[:6])
   112  	}
   113  	if gblock.Root() != t.json.Genesis.StateRoot {
   114  		return fmt.Errorf("genesis block state root does not match test: computed=%x, test=%x", gblock.Root().Bytes()[:6], t.json.Genesis.StateRoot[:6])
   115  	}
   116  	var engine consensus.Engine
   117  	if t.json.SealEngine == "NoProof" {
   118  		engine = ethash.NewFaker()
   119  	} else {
   120  		engine = ethash.NewShared()
   121  	}
   122  	cache := &core.CacheConfig{TrieCleanLimit: 0}
   123  	if snapshotter {
   124  		cache.SnapshotLimit = 1
   125  		cache.SnapshotWait = true
   126  	}
   127  	chain, err := core.NewBlockChain(db, cache, config, engine, vm.Config{}, nil)
   128  	if err != nil {
   129  		return err
   130  	}
   131  	defer chain.Stop()
   132  
   133  	validBlocks, err := t.insertBlocks(chain)
   134  	if err != nil {
   135  		return err
   136  	}
   137  	cmlast := chain.CurrentBlock().Hash()
   138  	if common.Hash(t.json.BestBlock) != cmlast {
   139  		return fmt.Errorf("last block hash validation mismatch: want: %x, have: %x", t.json.BestBlock, cmlast)
   140  	}
   141  	newDB, err := chain.State()
   142  	if err != nil {
   143  		return err
   144  	}
   145  	if err = t.validatePostState(newDB); err != nil {
   146  		return fmt.Errorf("post state validation failed: %v", err)
   147  	}
   148  	// Cross-check the snapshot-to-hash against the trie hash
   149  	if snapshotter {
   150  		snapTree := chain.Snapshot()
   151  		root := chain.CurrentBlock().Root()
   152  		it, err := snapTree.AccountIterator(root, common.Hash{})
   153  		if err != nil {
   154  			return fmt.Errorf("Could not create iterator for root %x: %v", root, err)
   155  		}
   156  		generatedRoot := snapshot.GenerateTrieRoot(it)
   157  		if generatedRoot != root {
   158  			return fmt.Errorf("Snapshot corruption, got %d exp %d", generatedRoot, root)
   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  	}
   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 _, 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  			return nil, fmt.Errorf("block insertion should have failed")
   216  		}
   217  
   218  		// validate RLP decoding by checking all values against test file JSON
   219  		if err = validateHeader(b.BlockHeader, cb.Header()); err != nil {
   220  			return nil, fmt.Errorf("deserialised block header validation failed: %v", err)
   221  		}
   222  		validBlocks = append(validBlocks, b)
   223  	}
   224  	return validBlocks, nil
   225  }
   226  
   227  func validateHeader(h *btHeader, h2 *types.Header) error {
   228  	if h.Bloom != h2.Bloom {
   229  		return fmt.Errorf("bloom: want: %x have: %x", h.Bloom, h2.Bloom)
   230  	}
   231  	if h.Coinbase != h2.Coinbase {
   232  		return fmt.Errorf("coinbase: want: %x have: %x", h.Coinbase, h2.Coinbase)
   233  	}
   234  	if h.MixHash != h2.MixDigest {
   235  		return fmt.Errorf("MixHash: want: %x have: %x", h.MixHash, h2.MixDigest)
   236  	}
   237  	if h.Nonce != h2.Nonce {
   238  		return fmt.Errorf("nonce: want: %x have: %x", h.Nonce, h2.Nonce)
   239  	}
   240  	if h.Number.Cmp(h2.Number) != 0 {
   241  		return fmt.Errorf("number: want: %v have: %v", h.Number, h2.Number)
   242  	}
   243  	if h.ParentHash != h2.ParentHash {
   244  		return fmt.Errorf("parent hash: want: %x have: %x", h.ParentHash, h2.ParentHash)
   245  	}
   246  	if h.ReceiptTrie != h2.ReceiptHash {
   247  		return fmt.Errorf("receipt hash: want: %x have: %x", h.ReceiptTrie, h2.ReceiptHash)
   248  	}
   249  	if h.TransactionsTrie != h2.TxHash {
   250  		return fmt.Errorf("tx hash: want: %x have: %x", h.TransactionsTrie, h2.TxHash)
   251  	}
   252  	if h.StateRoot != h2.Root {
   253  		return fmt.Errorf("state hash: want: %x have: %x", h.StateRoot, h2.Root)
   254  	}
   255  	if h.UncleHash != h2.UncleHash {
   256  		return fmt.Errorf("uncle hash: want: %x have: %x", h.UncleHash, h2.UncleHash)
   257  	}
   258  	if !bytes.Equal(h.ExtraData, h2.Extra) {
   259  		return fmt.Errorf("extra data: want: %x have: %x", h.ExtraData, h2.Extra)
   260  	}
   261  	if h.Difficulty.Cmp(h2.Difficulty) != 0 {
   262  		return fmt.Errorf("difficulty: want: %v have: %v", h.Difficulty, h2.Difficulty)
   263  	}
   264  	if h.GasLimit != h2.GasLimit {
   265  		return fmt.Errorf("gasLimit: want: %d have: %d", h.GasLimit, h2.GasLimit)
   266  	}
   267  	if h.GasUsed != h2.GasUsed {
   268  		return fmt.Errorf("gasUsed: want: %d have: %d", h.GasUsed, h2.GasUsed)
   269  	}
   270  	if h.Timestamp != h2.Time {
   271  		return fmt.Errorf("timestamp: want: %v have: %v", h.Timestamp, h2.Time)
   272  	}
   273  	return nil
   274  }
   275  
   276  func (t *BlockTest) validatePostState(statedb *state.StateDB) error {
   277  	// validate post state accounts in test file against what we have in state db
   278  	for addr, acct := range t.json.Post {
   279  		// address is indirectly verified by the other fields, as it's the db key
   280  		code2 := statedb.GetCode(addr)
   281  		balance2 := statedb.GetBalance(addr)
   282  		nonce2 := statedb.GetNonce(addr)
   283  		if !bytes.Equal(code2, acct.Code) {
   284  			return fmt.Errorf("account code mismatch for addr: %s want: %v have: %s", addr, acct.Code, hex.EncodeToString(code2))
   285  		}
   286  		if balance2.Cmp(acct.Balance) != 0 {
   287  			return fmt.Errorf("account balance mismatch for addr: %s, want: %d, have: %d", addr, acct.Balance, balance2)
   288  		}
   289  		if nonce2 != acct.Nonce {
   290  			return fmt.Errorf("account nonce mismatch for addr: %s want: %d have: %d", addr, acct.Nonce, nonce2)
   291  		}
   292  	}
   293  	return nil
   294  }
   295  
   296  func (t *BlockTest) validateImportedHeaders(cm *core.BlockChain, validBlocks []btBlock) error {
   297  	// to get constant lookup when verifying block headers by hash (some tests have many blocks)
   298  	bmap := make(map[common.Hash]btBlock, len(t.json.Blocks))
   299  	for _, b := range validBlocks {
   300  		bmap[b.BlockHeader.Hash] = b
   301  	}
   302  	// iterate over blocks backwards from HEAD and validate imported
   303  	// headers vs test file. some tests have reorgs, and we import
   304  	// block-by-block, so we can only validate imported headers after
   305  	// all blocks have been processed by BlockChain, as they may not
   306  	// be part of the longest chain until last block is imported.
   307  	for b := cm.CurrentBlock(); b != nil && b.NumberU64() != 0; b = cm.GetBlockByHash(b.Header().ParentHash) {
   308  		if err := validateHeader(bmap[b.Hash()].BlockHeader, b.Header()); err != nil {
   309  			return fmt.Errorf("imported block header validation failed: %v", err)
   310  		}
   311  	}
   312  	return nil
   313  }
   314  
   315  func (bb *btBlock) decode() (*types.Block, error) {
   316  	data, err := hexutil.Decode(bb.Rlp)
   317  	if err != nil {
   318  		return nil, err
   319  	}
   320  	var b types.Block
   321  	err = rlp.DecodeBytes(data, &b)
   322  	return &b, err
   323  }