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