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