github.com/linapex/ethereum-dpos-chinese@v0.0.0-20190316121959-b78b3a4a1ece/tests/block_test_util.go (about)

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