github.com/aaa256/atlantis@v0.0.0-20210707112435-42ee889287a2/tests/block_test_util.go (about)

     1  // Copyright 2015 The go-athereum Authors
     2  // This file is part of the go-athereum library.
     3  //
     4  // The go-athereum 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-athereum 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-athereum library. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  // Package tests implements execution of Atlantis 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/athereum/go-athereum/common"
    28  	"github.com/athereum/go-athereum/common/hexutil"
    29  	"github.com/athereum/go-athereum/common/math"
    30  	"github.com/athereum/go-athereum/consensus/athash"
    31  	"github.com/athereum/go-athereum/core"
    32  	"github.com/athereum/go-athereum/core/state"
    33  	"github.com/athereum/go-athereum/core/types"
    34  	"github.com/athereum/go-athereum/core/vm"
    35  	"github.com/athereum/go-athereum/athdb"
    36  	"github.com/athereum/go-athereum/params"
    37  	"github.com/athereum/go-athereum/rlp"
    38  )
    39  
    40  // A BlockTest checks handling of entire blocks.
    41  type BlockTest struct {
    42  	json btJSON
    43  }
    44  
    45  // UnmarshalJSON implements json.Unmarshaler interface.
    46  func (t *BlockTest) UnmarshalJSON(in []byte) error {
    47  	return json.Unmarshal(in, &t.json)
    48  }
    49  
    50  type btJSON struct {
    51  	Blocks    []btBlock             `json:"blocks"`
    52  	Genesis   btHeader              `json:"genesisBlockHeader"`
    53  	Pre       core.GenesisAlloc     `json:"pre"`
    54  	Post      core.GenesisAlloc     `json:"postState"`
    55  	BestBlock common.UnprefixedHash `json:"lastblockhash"`
    56  	Network   string                `json:"network"`
    57  }
    58  
    59  type btBlock struct {
    60  	BlockHeader  *btHeader
    61  	Rlp          string
    62  	UncleHeaders []*btHeader
    63  }
    64  
    65  //go:generate gencodec -type btHeader -field-override btHeaderMarshaling -out gen_btheader.go
    66  
    67  type btHeader struct {
    68  	Bloom            types.Bloom
    69  	Coinbase         common.Address
    70  	MixHash          common.Hash
    71  	Nonce            types.BlockNonce
    72  	Number           *big.Int
    73  	Hash             common.Hash
    74  	ParentHash       common.Hash
    75  	ReceiptTrie      common.Hash
    76  	StateRoot        common.Hash
    77  	TransactionsTrie common.Hash
    78  	UncleHash        common.Hash
    79  	ExtraData        []byte
    80  	Difficulty       *big.Int
    81  	GasLimit         uint64
    82  	GasUsed          uint64
    83  	Timestamp        *big.Int
    84  }
    85  
    86  type btHeaderMarshaling struct {
    87  	ExtraData  hexutil.Bytes
    88  	Number     *math.HexOrDecimal256
    89  	Difficulty *math.HexOrDecimal256
    90  	GasLimit   math.HexOrDecimal64
    91  	GasUsed    math.HexOrDecimal64
    92  	Timestamp  *math.HexOrDecimal256
    93  }
    94  
    95  func (t *BlockTest) Run() error {
    96  	config, ok := Forks[t.json.Network]
    97  	if !ok {
    98  		return UnsupportedForkError{t.json.Network}
    99  	}
   100  
   101  	// import pre accounts & construct test genesis block & state root
   102  	db := athdb.NewMemDatabase()
   103  	gblock, err := t.genesis(config).Commit(db)
   104  	if err != nil {
   105  		return err
   106  	}
   107  	if gblock.Hash() != t.json.Genesis.Hash {
   108  		return fmt.Errorf("genesis block hash doesn't match test: computed=%x, test=%x", gblock.Hash().Bytes()[:6], t.json.Genesis.Hash[:6])
   109  	}
   110  	if gblock.Root() != t.json.Genesis.StateRoot {
   111  		return fmt.Errorf("genesis block state root does not match test: computed=%x, test=%x", gblock.Root().Bytes()[:6], t.json.Genesis.StateRoot[:6])
   112  	}
   113  
   114  	chain, err := core.NewBlockChain(db, nil, config, athash.NewShared(), vm.Config{})
   115  	if err != nil {
   116  		return err
   117  	}
   118  	defer chain.Stop()
   119  
   120  	validBlocks, err := t.insertBlocks(chain)
   121  	if err != nil {
   122  		return err
   123  	}
   124  	cmlast := chain.CurrentBlock().Hash()
   125  	if common.Hash(t.json.BestBlock) != cmlast {
   126  		return fmt.Errorf("last block hash validation mismatch: want: %x, have: %x", t.json.BestBlock, cmlast)
   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,
   146  		GasUsed:    t.json.Genesis.GasUsed,
   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/athereum/tests/wiki/Blockchain-Tests-II
   155  
   156     Whather 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 != h2.GasLimit {
   239  		return fmt.Errorf("GasLimit: want: %d have: %d", h.GasLimit, h2.GasLimit)
   240  	}
   241  	if h.GasUsed != h2.GasUsed {
   242  		return fmt.Errorf("GasUsed: want: %d have: %d", 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  }