github.com/neatlab/neatio@v1.7.3-0.20220425043230-d903e92fcc75/tests/block_test_util.go (about)

     1  package tests
     2  
     3  import (
     4  	"bytes"
     5  	"encoding/hex"
     6  	"encoding/json"
     7  	"fmt"
     8  	"math/big"
     9  
    10  	"github.com/neatlab/neatio/chain/core"
    11  	"github.com/neatlab/neatio/chain/core/rawdb"
    12  	"github.com/neatlab/neatio/chain/core/state"
    13  	"github.com/neatlab/neatio/chain/core/types"
    14  	"github.com/neatlab/neatio/chain/core/vm"
    15  	"github.com/neatlab/neatio/params"
    16  	"github.com/neatlab/neatio/utilities/common"
    17  	"github.com/neatlab/neatio/utilities/common/hexutil"
    18  	"github.com/neatlab/neatio/utilities/common/math"
    19  	"github.com/neatlab/neatio/utilities/rlp"
    20  )
    21  
    22  type BlockTest struct {
    23  	json btJSON
    24  }
    25  
    26  func (t *BlockTest) UnmarshalJSON(in []byte) error {
    27  	return json.Unmarshal(in, &t.json)
    28  }
    29  
    30  type btJSON struct {
    31  	Blocks    []btBlock             `json:"blocks"`
    32  	Genesis   btHeader              `json:"genesisBlockHeader"`
    33  	Pre       core.GenesisAlloc     `json:"pre"`
    34  	Post      core.GenesisAlloc     `json:"postState"`
    35  	BestBlock common.UnprefixedHash `json:"lastblockhash"`
    36  	Network   string                `json:"network"`
    37  }
    38  
    39  type btBlock struct {
    40  	BlockHeader  *btHeader
    41  	Rlp          string
    42  	UncleHeaders []*btHeader
    43  }
    44  
    45  //go:generate gencodec -type btHeader -field-override btHeaderMarshaling -out gen_btheader.go
    46  
    47  type btHeader struct {
    48  	Bloom            types.Bloom
    49  	Coinbase         common.Address
    50  	MixHash          common.Hash
    51  	Nonce            types.BlockNonce
    52  	Number           *big.Int
    53  	Hash             common.Hash
    54  	ParentHash       common.Hash
    55  	ReceiptTrie      common.Hash
    56  	StateRoot        common.Hash
    57  	TransactionsTrie common.Hash
    58  	UncleHash        common.Hash
    59  	ExtraData        []byte
    60  	Difficulty       *big.Int
    61  	GasLimit         uint64
    62  	GasUsed          uint64
    63  	Timestamp        *big.Int
    64  }
    65  
    66  type btHeaderMarshaling struct {
    67  	ExtraData  hexutil.Bytes
    68  	Number     *math.HexOrDecimal256
    69  	Difficulty *math.HexOrDecimal256
    70  	GasLimit   math.HexOrDecimal64
    71  	GasUsed    math.HexOrDecimal64
    72  	Timestamp  *math.HexOrDecimal256
    73  }
    74  
    75  func (t *BlockTest) Run() error {
    76  	config, ok := Forks[t.json.Network]
    77  	if !ok {
    78  		return UnsupportedForkError{t.json.Network}
    79  	}
    80  
    81  	db := rawdb.NewMemoryDatabase()
    82  	gblock, err := t.genesis(config).Commit(db)
    83  	if err != nil {
    84  		return err
    85  	}
    86  	if gblock.Hash() != t.json.Genesis.Hash {
    87  		return fmt.Errorf("genesis block hash doesn't match test: computed=%x, test=%x\n", gblock.Hash().Bytes()[:6], t.json.Genesis.Hash[:6])
    88  	}
    89  	if gblock.Root() != t.json.Genesis.StateRoot {
    90  		return fmt.Errorf("genesis block state root does not match test: computed=%x, test=%x", gblock.Root().Bytes()[:6], t.json.Genesis.StateRoot[:6])
    91  	}
    92  
    93  	chain, err := core.NewBlockChain(db, nil, config, nil, vm.Config{}, nil)
    94  	if err != nil {
    95  		return err
    96  	}
    97  	defer chain.Stop()
    98  
    99  	validBlocks, err := t.insertBlocks(chain)
   100  	if err != nil {
   101  		return err
   102  	}
   103  	cmlast := chain.CurrentBlock().Hash()
   104  	if common.Hash(t.json.BestBlock) != cmlast {
   105  		return fmt.Errorf("last block hash validation mismatch: want: %x, have: %x", t.json.BestBlock, cmlast)
   106  	}
   107  	newDB, err := chain.State()
   108  	if err != nil {
   109  		return err
   110  	}
   111  	if err = t.validatePostState(newDB); err != nil {
   112  		return fmt.Errorf("post state validation failed: %v", err)
   113  	}
   114  	return t.validateImportedHeaders(chain, validBlocks)
   115  }
   116  
   117  func (t *BlockTest) genesis(config *params.ChainConfig) *core.Genesis {
   118  	return &core.Genesis{
   119  		Config:     config,
   120  		Nonce:      t.json.Genesis.Nonce.Uint64(),
   121  		Timestamp:  t.json.Genesis.Timestamp.Uint64(),
   122  		ParentHash: t.json.Genesis.ParentHash,
   123  		ExtraData:  t.json.Genesis.ExtraData,
   124  		GasLimit:   t.json.Genesis.GasLimit,
   125  		GasUsed:    t.json.Genesis.GasUsed,
   126  		Difficulty: t.json.Genesis.Difficulty,
   127  		Mixhash:    t.json.Genesis.MixHash,
   128  		Coinbase:   t.json.Genesis.Coinbase,
   129  		Alloc:      t.json.Pre,
   130  	}
   131  }
   132  
   133  func (t *BlockTest) insertBlocks(blockchain *core.BlockChain) ([]btBlock, error) {
   134  	validBlocks := make([]btBlock, 0)
   135  	for _, b := range t.json.Blocks {
   136  		cb, err := b.decode()
   137  		if err != nil {
   138  			if b.BlockHeader == nil {
   139  				continue
   140  			} else {
   141  				return nil, fmt.Errorf("Block RLP decoding failed when expected to succeed: %v", err)
   142  			}
   143  		}
   144  		blocks := types.Blocks{cb}
   145  		i, err := blockchain.InsertChain(blocks)
   146  		if err != nil {
   147  			if b.BlockHeader == nil {
   148  				continue
   149  			} else {
   150  				return nil, fmt.Errorf("Block #%v insertion into chain failed: %v", blocks[i].Number(), err)
   151  			}
   152  		}
   153  		if b.BlockHeader == nil {
   154  			return nil, fmt.Errorf("Block insertion should have failed")
   155  		}
   156  
   157  		if err = validateHeader(b.BlockHeader, cb.Header()); err != nil {
   158  			return nil, fmt.Errorf("Deserialised block header validation failed: %v", err)
   159  		}
   160  		validBlocks = append(validBlocks, b)
   161  	}
   162  	return validBlocks, nil
   163  }
   164  
   165  func validateHeader(h *btHeader, h2 *types.Header) error {
   166  	if h.Bloom != h2.Bloom {
   167  		return fmt.Errorf("Bloom: want: %x have: %x", h.Bloom, h2.Bloom)
   168  	}
   169  	if h.Coinbase != h2.Coinbase {
   170  		return fmt.Errorf("Coinbase: want: %x have: %x", h.Coinbase, h2.Coinbase)
   171  	}
   172  	if h.MixHash != h2.MixDigest {
   173  		return fmt.Errorf("MixHash: want: %x have: %x", h.MixHash, h2.MixDigest)
   174  	}
   175  	if h.Nonce != h2.Nonce {
   176  		return fmt.Errorf("Nonce: want: %x have: %x", h.Nonce, h2.Nonce)
   177  	}
   178  	if h.Number.Cmp(h2.Number) != 0 {
   179  		return fmt.Errorf("Number: want: %v have: %v", h.Number, h2.Number)
   180  	}
   181  	if h.ParentHash != h2.ParentHash {
   182  		return fmt.Errorf("Parent hash: want: %x have: %x", h.ParentHash, h2.ParentHash)
   183  	}
   184  	if h.ReceiptTrie != h2.ReceiptHash {
   185  		return fmt.Errorf("Receipt hash: want: %x have: %x", h.ReceiptTrie, h2.ReceiptHash)
   186  	}
   187  	if h.TransactionsTrie != h2.TxHash {
   188  		return fmt.Errorf("Tx hash: want: %x have: %x", h.TransactionsTrie, h2.TxHash)
   189  	}
   190  	if h.StateRoot != h2.Root {
   191  		return fmt.Errorf("State hash: want: %x have: %x", h.StateRoot, h2.Root)
   192  	}
   193  	if h.UncleHash != h2.UncleHash {
   194  		return fmt.Errorf("Uncle hash: want: %x have: %x", h.UncleHash, h2.UncleHash)
   195  	}
   196  	if !bytes.Equal(h.ExtraData, h2.Extra) {
   197  		return fmt.Errorf("Extra data: want: %x have: %x", h.ExtraData, h2.Extra)
   198  	}
   199  	if h.Difficulty.Cmp(h2.Difficulty) != 0 {
   200  		return fmt.Errorf("Difficulty: want: %v have: %v", h.Difficulty, h2.Difficulty)
   201  	}
   202  	if h.GasLimit != h2.GasLimit {
   203  		return fmt.Errorf("GasLimit: want: %d have: %d", h.GasLimit, h2.GasLimit)
   204  	}
   205  	if h.GasUsed != h2.GasUsed {
   206  		return fmt.Errorf("GasUsed: want: %d have: %d", h.GasUsed, h2.GasUsed)
   207  	}
   208  	if h.Timestamp.Cmp(h2.Time) != 0 {
   209  		return fmt.Errorf("Timestamp: want: %v have: %v", h.Timestamp, h2.Time)
   210  	}
   211  	return nil
   212  }
   213  
   214  func (t *BlockTest) validatePostState(statedb *state.StateDB) error {
   215  	for addr, acct := range t.json.Post {
   216  		code2 := statedb.GetCode(addr)
   217  		balance2 := statedb.GetBalance(addr)
   218  		nonce2 := statedb.GetNonce(addr)
   219  		if !bytes.Equal(code2, acct.Code) {
   220  			return fmt.Errorf("account code mismatch for addr: %s want: %v have: %s", addr, acct.Code, hex.EncodeToString(code2))
   221  		}
   222  		if balance2.Cmp(acct.Balance) != 0 {
   223  			return fmt.Errorf("account balance mismatch for addr: %s, want: %d, have: %d", addr, acct.Balance, balance2)
   224  		}
   225  		if nonce2 != acct.Nonce {
   226  			return fmt.Errorf("account nonce mismatch for addr: %s want: %d have: %d", addr, acct.Nonce, nonce2)
   227  		}
   228  	}
   229  	return nil
   230  }
   231  
   232  func (t *BlockTest) validateImportedHeaders(cm *core.BlockChain, validBlocks []btBlock) error {
   233  	bmap := make(map[common.Hash]btBlock, len(t.json.Blocks))
   234  	for _, b := range validBlocks {
   235  		bmap[b.BlockHeader.Hash] = b
   236  	}
   237  	for b := cm.CurrentBlock(); b != nil && b.NumberU64() != 0; b = cm.GetBlockByHash(b.Header().ParentHash) {
   238  		if err := validateHeader(bmap[b.Hash()].BlockHeader, b.Header()); err != nil {
   239  			return fmt.Errorf("Imported block header validation failed: %v", err)
   240  		}
   241  	}
   242  	return nil
   243  }
   244  
   245  func (bb *btBlock) decode() (*types.Block, error) {
   246  	data, err := hexutil.Decode(bb.Rlp)
   247  	if err != nil {
   248  		return nil, err
   249  	}
   250  	var b types.Block
   251  	err = rlp.DecodeBytes(data, &b)
   252  	return &b, err
   253  }