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