github.com/bloxroute-labs/bor@v0.1.4/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/maticnetwork/bor/common"
    28  	"github.com/maticnetwork/bor/common/hexutil"
    29  	"github.com/maticnetwork/bor/common/math"
    30  	"github.com/maticnetwork/bor/consensus"
    31  	"github.com/maticnetwork/bor/consensus/ethash"
    32  	"github.com/maticnetwork/bor/core"
    33  	"github.com/maticnetwork/bor/core/rawdb"
    34  	"github.com/maticnetwork/bor/core/state"
    35  	"github.com/maticnetwork/bor/core/types"
    36  	"github.com/maticnetwork/bor/core/vm"
    37  	"github.com/maticnetwork/bor/params"
    38  	"github.com/maticnetwork/bor/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() 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  	chain, err := core.NewBlockChain(db, &core.CacheConfig{TrieCleanLimit: 0}, config, engine, vm.Config{}, nil)
   122  	if err != nil {
   123  		return err
   124  	}
   125  	defer chain.Stop()
   126  
   127  	validBlocks, err := t.insertBlocks(chain)
   128  	if err != nil {
   129  		return err
   130  	}
   131  	cmlast := chain.CurrentBlock().Hash()
   132  	if common.Hash(t.json.BestBlock) != cmlast {
   133  		return fmt.Errorf("last block hash validation mismatch: want: %x, have: %x", t.json.BestBlock, cmlast)
   134  	}
   135  	newDB, err := chain.State()
   136  	if err != nil {
   137  		return err
   138  	}
   139  	if err = t.validatePostState(newDB); err != nil {
   140  		return fmt.Errorf("post state validation failed: %v", err)
   141  	}
   142  	return t.validateImportedHeaders(chain, validBlocks)
   143  }
   144  
   145  func (t *BlockTest) genesis(config *params.ChainConfig) *core.Genesis {
   146  	return &core.Genesis{
   147  		Config:     config,
   148  		Nonce:      t.json.Genesis.Nonce.Uint64(),
   149  		Timestamp:  t.json.Genesis.Timestamp,
   150  		ParentHash: t.json.Genesis.ParentHash,
   151  		ExtraData:  t.json.Genesis.ExtraData,
   152  		GasLimit:   t.json.Genesis.GasLimit,
   153  		GasUsed:    t.json.Genesis.GasUsed,
   154  		Difficulty: t.json.Genesis.Difficulty,
   155  		Mixhash:    t.json.Genesis.MixHash,
   156  		Coinbase:   t.json.Genesis.Coinbase,
   157  		Alloc:      t.json.Pre,
   158  	}
   159  }
   160  
   161  /* See https://github.com/ethereum/tests/wiki/Blockchain-Tests-II
   162  
   163     Whether a block is valid or not is a bit subtle, it's defined by presence of
   164     blockHeader, transactions and uncleHeaders fields. If they are missing, the block is
   165     invalid and we must verify that we do not accept it.
   166  
   167     Since some tests mix valid and invalid blocks we need to check this for every block.
   168  
   169     If a block is invalid it does not necessarily fail the test, if it's invalidness is
   170     expected we are expected to ignore it and continue processing and then validate the
   171     post state.
   172  */
   173  func (t *BlockTest) insertBlocks(blockchain *core.BlockChain) ([]btBlock, error) {
   174  	validBlocks := make([]btBlock, 0)
   175  	// insert the test blocks, which will execute all transactions
   176  	for _, b := range t.json.Blocks {
   177  		cb, err := b.decode()
   178  		if err != nil {
   179  			if b.BlockHeader == nil {
   180  				continue // OK - block is supposed to be invalid, continue with next block
   181  			} else {
   182  				return nil, fmt.Errorf("Block RLP decoding failed when expected to succeed: %v", err)
   183  			}
   184  		}
   185  		// RLP decoding worked, try to insert into chain:
   186  		blocks := types.Blocks{cb}
   187  		i, err := blockchain.InsertChain(blocks)
   188  		if err != nil {
   189  			if b.BlockHeader == nil {
   190  				continue // OK - block is supposed to be invalid, continue with next block
   191  			} else {
   192  				return nil, fmt.Errorf("Block #%v insertion into chain failed: %v", blocks[i].Number(), err)
   193  			}
   194  		}
   195  		if b.BlockHeader == nil {
   196  			return nil, fmt.Errorf("Block insertion should have failed")
   197  		}
   198  
   199  		// validate RLP decoding by checking all values against test file JSON
   200  		if err = validateHeader(b.BlockHeader, cb.Header()); err != nil {
   201  			return nil, fmt.Errorf("Deserialised block header validation failed: %v", err)
   202  		}
   203  		validBlocks = append(validBlocks, b)
   204  	}
   205  	return validBlocks, nil
   206  }
   207  
   208  func validateHeader(h *btHeader, h2 *types.Header) error {
   209  	if h.Bloom != h2.Bloom {
   210  		return fmt.Errorf("Bloom: want: %x have: %x", h.Bloom, h2.Bloom)
   211  	}
   212  	if h.Coinbase != h2.Coinbase {
   213  		return fmt.Errorf("Coinbase: want: %x have: %x", h.Coinbase, h2.Coinbase)
   214  	}
   215  	if h.MixHash != h2.MixDigest {
   216  		return fmt.Errorf("MixHash: want: %x have: %x", h.MixHash, h2.MixDigest)
   217  	}
   218  	if h.Nonce != h2.Nonce {
   219  		return fmt.Errorf("Nonce: want: %x have: %x", h.Nonce, h2.Nonce)
   220  	}
   221  	if h.Number.Cmp(h2.Number) != 0 {
   222  		return fmt.Errorf("Number: want: %v have: %v", h.Number, h2.Number)
   223  	}
   224  	if h.ParentHash != h2.ParentHash {
   225  		return fmt.Errorf("Parent hash: want: %x have: %x", h.ParentHash, h2.ParentHash)
   226  	}
   227  	if h.ReceiptTrie != h2.ReceiptHash {
   228  		return fmt.Errorf("Receipt hash: want: %x have: %x", h.ReceiptTrie, h2.ReceiptHash)
   229  	}
   230  	if h.TransactionsTrie != h2.TxHash {
   231  		return fmt.Errorf("Tx hash: want: %x have: %x", h.TransactionsTrie, h2.TxHash)
   232  	}
   233  	if h.StateRoot != h2.Root {
   234  		return fmt.Errorf("State hash: want: %x have: %x", h.StateRoot, h2.Root)
   235  	}
   236  	if h.UncleHash != h2.UncleHash {
   237  		return fmt.Errorf("Uncle hash: want: %x have: %x", h.UncleHash, h2.UncleHash)
   238  	}
   239  	if !bytes.Equal(h.ExtraData, h2.Extra) {
   240  		return fmt.Errorf("Extra data: want: %x have: %x", h.ExtraData, h2.Extra)
   241  	}
   242  	if h.Difficulty.Cmp(h2.Difficulty) != 0 {
   243  		return fmt.Errorf("Difficulty: want: %v have: %v", h.Difficulty, h2.Difficulty)
   244  	}
   245  	if h.GasLimit != h2.GasLimit {
   246  		return fmt.Errorf("GasLimit: want: %d have: %d", h.GasLimit, h2.GasLimit)
   247  	}
   248  	if h.GasUsed != h2.GasUsed {
   249  		return fmt.Errorf("GasUsed: want: %d have: %d", h.GasUsed, h2.GasUsed)
   250  	}
   251  	if h.Timestamp != h2.Time {
   252  		return fmt.Errorf("Timestamp: want: %v have: %v", h.Timestamp, h2.Time)
   253  	}
   254  	return nil
   255  }
   256  
   257  func (t *BlockTest) validatePostState(statedb *state.StateDB) error {
   258  	// validate post state accounts in test file against what we have in state db
   259  	for addr, acct := range t.json.Post {
   260  		// address is indirectly verified by the other fields, as it's the db key
   261  		code2 := statedb.GetCode(addr)
   262  		balance2 := statedb.GetBalance(addr)
   263  		nonce2 := statedb.GetNonce(addr)
   264  		if !bytes.Equal(code2, acct.Code) {
   265  			return fmt.Errorf("account code mismatch for addr: %s want: %v have: %s", addr, acct.Code, hex.EncodeToString(code2))
   266  		}
   267  		if balance2.Cmp(acct.Balance) != 0 {
   268  			return fmt.Errorf("account balance mismatch for addr: %s, want: %d, have: %d", addr, acct.Balance, balance2)
   269  		}
   270  		if nonce2 != acct.Nonce {
   271  			return fmt.Errorf("account nonce mismatch for addr: %s want: %d have: %d", addr, acct.Nonce, nonce2)
   272  		}
   273  	}
   274  	return nil
   275  }
   276  
   277  func (t *BlockTest) validateImportedHeaders(cm *core.BlockChain, validBlocks []btBlock) error {
   278  	// to get constant lookup when verifying block headers by hash (some tests have many blocks)
   279  	bmap := make(map[common.Hash]btBlock, len(t.json.Blocks))
   280  	for _, b := range validBlocks {
   281  		bmap[b.BlockHeader.Hash] = b
   282  	}
   283  	// iterate over blocks backwards from HEAD and validate imported
   284  	// headers vs test file. some tests have reorgs, and we import
   285  	// block-by-block, so we can only validate imported headers after
   286  	// all blocks have been processed by BlockChain, as they may not
   287  	// be part of the longest chain until last block is imported.
   288  	for b := cm.CurrentBlock(); b != nil && b.NumberU64() != 0; b = cm.GetBlockByHash(b.Header().ParentHash) {
   289  		if err := validateHeader(bmap[b.Hash()].BlockHeader, b.Header()); err != nil {
   290  			return fmt.Errorf("Imported block header validation failed: %v", err)
   291  		}
   292  	}
   293  	return nil
   294  }
   295  
   296  func (bb *btBlock) decode() (*types.Block, error) {
   297  	data, err := hexutil.Decode(bb.Rlp)
   298  	if err != nil {
   299  		return nil, err
   300  	}
   301  	var b types.Block
   302  	err = rlp.DecodeBytes(data, &b)
   303  	return &b, err
   304  }