github.com/codingfuture/orig-energi3@v0.8.4/tests/block_test_util.go (about)

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