github.com/electroneum/electroneum-sc@v0.0.0-20230105223411-3bc1d078281e/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  
    28  	"github.com/electroneum/electroneum-sc/common"
    29  	"github.com/electroneum/electroneum-sc/common/hexutil"
    30  	"github.com/electroneum/electroneum-sc/common/math"
    31  	"github.com/electroneum/electroneum-sc/consensus"
    32  	"github.com/electroneum/electroneum-sc/consensus/ethash"
    33  	"github.com/electroneum/electroneum-sc/core"
    34  	"github.com/electroneum/electroneum-sc/core/rawdb"
    35  	"github.com/electroneum/electroneum-sc/core/state"
    36  	"github.com/electroneum/electroneum-sc/core/types"
    37  	"github.com/electroneum/electroneum-sc/core/vm"
    38  	"github.com/electroneum/electroneum-sc/params"
    39  	"github.com/electroneum/electroneum-sc/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  	ExpectException string
    65  	Rlp             string
    66  	UncleHeaders    []*btHeader
    67  }
    68  
    69  //go:generate go run github.com/fjl/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        uint64
    88  	BaseFeePerGas    *big.Int
    89  }
    90  
    91  type btHeaderMarshaling struct {
    92  	ExtraData     hexutil.Bytes
    93  	Number        *math.HexOrDecimal256
    94  	Difficulty    *math.HexOrDecimal256
    95  	GasLimit      math.HexOrDecimal64
    96  	GasUsed       math.HexOrDecimal64
    97  	Timestamp     math.HexOrDecimal64
    98  	BaseFeePerGas *math.HexOrDecimal256
    99  }
   100  
   101  func (t *BlockTest) Run(snapshotter bool) error {
   102  	config, ok := Forks[t.json.Network]
   103  	if !ok {
   104  		return UnsupportedForkError{t.json.Network}
   105  	}
   106  
   107  	// import pre accounts & construct test genesis block & state root
   108  	db := rawdb.NewMemoryDatabase()
   109  	gblock, err := t.genesis(config).Commit(db)
   110  	if err != nil {
   111  		return err
   112  	}
   113  	if gblock.Hash() != t.json.Genesis.Hash {
   114  		return fmt.Errorf("genesis block hash doesn't match test: computed=%x, test=%x", gblock.Hash().Bytes()[:6], t.json.Genesis.Hash[:6])
   115  	}
   116  	if gblock.Root() != t.json.Genesis.StateRoot {
   117  		return fmt.Errorf("genesis block state root does not match test: computed=%x, test=%x", gblock.Root().Bytes()[:6], t.json.Genesis.StateRoot[:6])
   118  	}
   119  	var engine consensus.Engine
   120  	if t.json.SealEngine == "NoProof" {
   121  		engine = ethash.NewFaker()
   122  	} else {
   123  		engine = ethash.NewShared()
   124  	}
   125  	cache := &core.CacheConfig{TrieCleanLimit: 0}
   126  	if snapshotter {
   127  		cache.SnapshotLimit = 1
   128  		cache.SnapshotWait = true
   129  	}
   130  	chain, err := core.NewBlockChain(db, cache, config, engine, vm.Config{}, nil, nil)
   131  	if err != nil {
   132  		return err
   133  	}
   134  	defer chain.Stop()
   135  
   136  	validBlocks, err := t.insertBlocks(chain)
   137  	if err != nil {
   138  		return err
   139  	}
   140  	cmlast := chain.CurrentBlock().Hash()
   141  	if common.Hash(t.json.BestBlock) != cmlast {
   142  		return fmt.Errorf("last block hash validation mismatch: want: %x, have: %x", t.json.BestBlock, cmlast)
   143  	}
   144  	newDB, err := chain.State()
   145  	if err != nil {
   146  		return err
   147  	}
   148  	if err = t.validatePostState(newDB); err != nil {
   149  		return fmt.Errorf("post state validation failed: %v", err)
   150  	}
   151  	// Cross-check the snapshot-to-hash against the trie hash
   152  	if snapshotter {
   153  		if err := chain.Snapshots().Verify(chain.CurrentBlock().Root()); err != nil {
   154  			return err
   155  		}
   156  	}
   157  	return t.validateImportedHeaders(chain, validBlocks)
   158  }
   159  
   160  func (t *BlockTest) genesis(config *params.ChainConfig) *core.Genesis {
   161  	return &core.Genesis{
   162  		Config:     config,
   163  		Nonce:      t.json.Genesis.Nonce.Uint64(),
   164  		Timestamp:  t.json.Genesis.Timestamp,
   165  		ParentHash: t.json.Genesis.ParentHash,
   166  		ExtraData:  t.json.Genesis.ExtraData,
   167  		GasLimit:   t.json.Genesis.GasLimit,
   168  		GasUsed:    t.json.Genesis.GasUsed,
   169  		Difficulty: t.json.Genesis.Difficulty,
   170  		Mixhash:    t.json.Genesis.MixHash,
   171  		Coinbase:   t.json.Genesis.Coinbase,
   172  		Alloc:      t.json.Pre,
   173  		BaseFee:    t.json.Genesis.BaseFeePerGas,
   174  	}
   175  }
   176  
   177  /*
   178  See https://github.com/ethereum/tests/wiki/Blockchain-Tests-II
   179  
   180  	Whether a block is valid or not is a bit subtle, it's defined by presence of
   181  	blockHeader, transactions and uncleHeaders fields. If they are missing, the block is
   182  	invalid and we must verify that we do not accept it.
   183  
   184  	Since some tests mix valid and invalid blocks we need to check this for every block.
   185  
   186  	If a block is invalid it does not necessarily fail the test, if it's invalidness is
   187  	expected we are expected to ignore it and continue processing and then validate the
   188  	post state.
   189  */
   190  func (t *BlockTest) insertBlocks(blockchain *core.BlockChain) ([]btBlock, error) {
   191  	validBlocks := make([]btBlock, 0)
   192  	// insert the test blocks, which will execute all transactions
   193  	for bi, b := range t.json.Blocks {
   194  		cb, err := b.decode()
   195  		if err != nil {
   196  			if b.BlockHeader == nil {
   197  				continue // OK - block is supposed to be invalid, continue with next block
   198  			} else {
   199  				return nil, fmt.Errorf("block RLP decoding failed when expected to succeed: %v", err)
   200  			}
   201  		}
   202  		// RLP decoding worked, try to insert into chain:
   203  		blocks := types.Blocks{cb}
   204  		i, err := blockchain.InsertChain(blocks)
   205  		if err != nil {
   206  			if b.BlockHeader == nil {
   207  				continue // OK - block is supposed to be invalid, continue with next block
   208  			} else {
   209  				return nil, fmt.Errorf("block #%v insertion into chain failed: %v", blocks[i].Number(), err)
   210  			}
   211  		}
   212  		if b.BlockHeader == nil {
   213  			if data, err := json.MarshalIndent(cb.Header(), "", "  "); err == nil {
   214  				fmt.Fprintf(os.Stderr, "block (index %d) insertion should have failed due to: %v:\n%v\n",
   215  					bi, b.ExpectException, string(data))
   216  			}
   217  			return nil, fmt.Errorf("block (index %d) insertion should have failed due to: %v",
   218  				bi, b.ExpectException)
   219  		}
   220  
   221  		// validate RLP decoding by checking all values against test file JSON
   222  		if err = validateHeader(b.BlockHeader, cb.Header()); err != nil {
   223  			return nil, fmt.Errorf("deserialised block header validation failed: %v", err)
   224  		}
   225  		validBlocks = append(validBlocks, b)
   226  	}
   227  	return validBlocks, nil
   228  }
   229  
   230  func validateHeader(h *btHeader, h2 *types.Header) error {
   231  	if h.Bloom != h2.Bloom {
   232  		return fmt.Errorf("bloom: want: %x have: %x", h.Bloom, h2.Bloom)
   233  	}
   234  	if h.Coinbase != h2.Coinbase {
   235  		return fmt.Errorf("coinbase: want: %x have: %x", h.Coinbase, h2.Coinbase)
   236  	}
   237  	if h.MixHash != h2.MixDigest {
   238  		return fmt.Errorf("MixHash: want: %x have: %x", h.MixHash, h2.MixDigest)
   239  	}
   240  	if h.Nonce != h2.Nonce {
   241  		return fmt.Errorf("nonce: want: %x have: %x", h.Nonce, h2.Nonce)
   242  	}
   243  	if h.Number.Cmp(h2.Number) != 0 {
   244  		return fmt.Errorf("number: want: %v have: %v", h.Number, h2.Number)
   245  	}
   246  	if h.ParentHash != h2.ParentHash {
   247  		return fmt.Errorf("parent hash: want: %x have: %x", h.ParentHash, h2.ParentHash)
   248  	}
   249  	if h.ReceiptTrie != h2.ReceiptHash {
   250  		return fmt.Errorf("receipt hash: want: %x have: %x", h.ReceiptTrie, h2.ReceiptHash)
   251  	}
   252  	if h.TransactionsTrie != h2.TxHash {
   253  		return fmt.Errorf("tx hash: want: %x have: %x", h.TransactionsTrie, h2.TxHash)
   254  	}
   255  	if h.StateRoot != h2.Root {
   256  		return fmt.Errorf("state hash: want: %x have: %x", h.StateRoot, h2.Root)
   257  	}
   258  	if h.UncleHash != h2.UncleHash {
   259  		return fmt.Errorf("uncle hash: want: %x have: %x", h.UncleHash, h2.UncleHash)
   260  	}
   261  	if !bytes.Equal(h.ExtraData, h2.Extra) {
   262  		return fmt.Errorf("extra data: want: %x have: %x", h.ExtraData, h2.Extra)
   263  	}
   264  	if h.Difficulty.Cmp(h2.Difficulty) != 0 {
   265  		return fmt.Errorf("difficulty: want: %v have: %v", h.Difficulty, h2.Difficulty)
   266  	}
   267  	if h.GasLimit != h2.GasLimit {
   268  		return fmt.Errorf("gasLimit: want: %d have: %d", h.GasLimit, h2.GasLimit)
   269  	}
   270  	if h.GasUsed != h2.GasUsed {
   271  		return fmt.Errorf("gasUsed: want: %d have: %d", h.GasUsed, h2.GasUsed)
   272  	}
   273  	if h.Timestamp != h2.Time {
   274  		return fmt.Errorf("timestamp: want: %v have: %v", h.Timestamp, h2.Time)
   275  	}
   276  	return nil
   277  }
   278  
   279  func (t *BlockTest) validatePostState(statedb *state.StateDB) error {
   280  	// validate post state accounts in test file against what we have in state db
   281  	for addr, acct := range t.json.Post {
   282  		// address is indirectly verified by the other fields, as it's the db key
   283  		code2 := statedb.GetCode(addr)
   284  		balance2 := statedb.GetBalance(addr)
   285  		nonce2 := statedb.GetNonce(addr)
   286  		if !bytes.Equal(code2, acct.Code) {
   287  			return fmt.Errorf("account code mismatch for addr: %s want: %v have: %s", addr, acct.Code, hex.EncodeToString(code2))
   288  		}
   289  		if balance2.Cmp(acct.Balance) != 0 {
   290  			return fmt.Errorf("account balance mismatch for addr: %s, want: %d, have: %d", addr, acct.Balance, balance2)
   291  		}
   292  		if nonce2 != acct.Nonce {
   293  			return fmt.Errorf("account nonce mismatch for addr: %s want: %d have: %d", addr, acct.Nonce, nonce2)
   294  		}
   295  	}
   296  	return nil
   297  }
   298  
   299  func (t *BlockTest) validateImportedHeaders(cm *core.BlockChain, validBlocks []btBlock) error {
   300  	// to get constant lookup when verifying block headers by hash (some tests have many blocks)
   301  	bmap := make(map[common.Hash]btBlock, len(t.json.Blocks))
   302  	for _, b := range validBlocks {
   303  		bmap[b.BlockHeader.Hash] = b
   304  	}
   305  	// iterate over blocks backwards from HEAD and validate imported
   306  	// headers vs test file. some tests have reorgs, and we import
   307  	// block-by-block, so we can only validate imported headers after
   308  	// all blocks have been processed by BlockChain, as they may not
   309  	// be part of the longest chain until last block is imported.
   310  	for b := cm.CurrentBlock(); b != nil && b.NumberU64() != 0; b = cm.GetBlockByHash(b.Header().ParentHash) {
   311  		if err := validateHeader(bmap[b.Hash()].BlockHeader, b.Header()); err != nil {
   312  			return fmt.Errorf("imported block header validation failed: %v", err)
   313  		}
   314  	}
   315  	return nil
   316  }
   317  
   318  func (bb *btBlock) decode() (*types.Block, error) {
   319  	data, err := hexutil.Decode(bb.Rlp)
   320  	if err != nil {
   321  		return nil, err
   322  	}
   323  	var b types.Block
   324  	err = rlp.DecodeBytes(data, &b)
   325  	return &b, err
   326  }