github.com/linapex/ethereum-go-chinese@v0.0.0-20190316121929-f8b7a73c3fa1/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 19:16:45</date>
    10  //</624450121920155648>
    11  
    12  
    13  //包测试实现了以太坊JSON测试的执行。
    14  package tests
    15  
    16  import (
    17  	"bytes"
    18  	"encoding/hex"
    19  	"encoding/json"
    20  	"fmt"
    21  	"math/big"
    22  
    23  	"github.com/ethereum/go-ethereum/common"
    24  	"github.com/ethereum/go-ethereum/common/hexutil"
    25  	"github.com/ethereum/go-ethereum/common/math"
    26  	"github.com/ethereum/go-ethereum/consensus"
    27  	"github.com/ethereum/go-ethereum/consensus/ethash"
    28  	"github.com/ethereum/go-ethereum/core"
    29  	"github.com/ethereum/go-ethereum/core/state"
    30  	"github.com/ethereum/go-ethereum/core/types"
    31  	"github.com/ethereum/go-ethereum/core/vm"
    32  	"github.com/ethereum/go-ethereum/ethdb"
    33  	"github.com/ethereum/go-ethereum/params"
    34  	"github.com/ethereum/go-ethereum/rlp"
    35  )
    36  
    37  //块测试检查整个块的处理。
    38  type BlockTest struct {
    39  	json btJSON
    40  }
    41  
    42  //unmashaljson实现json.unmasheler接口。
    43  func (t *BlockTest) UnmarshalJSON(in []byte) error {
    44  	return json.Unmarshal(in, &t.json)
    45  }
    46  
    47  type btJSON struct {
    48  	Blocks     []btBlock             `json:"blocks"`
    49  	Genesis    btHeader              `json:"genesisBlockHeader"`
    50  	Pre        core.GenesisAlloc     `json:"pre"`
    51  	Post       core.GenesisAlloc     `json:"postState"`
    52  	BestBlock  common.UnprefixedHash `json:"lastblockhash"`
    53  	Network    string                `json:"network"`
    54  	SealEngine string                `json:"sealEngine"`
    55  }
    56  
    57  type btBlock struct {
    58  	BlockHeader  *btHeader
    59  	Rlp          string
    60  	UncleHeaders []*btHeader
    61  }
    62  
    63  //go:生成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  //导入预帐户并构建测试Genesis块和状态根
   100  	db := ethdb.NewMemDatabase()
   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", 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  	var engine consensus.Engine
   112  	if t.json.SealEngine == "NoProof" {
   113  		engine = ethash.NewFaker()
   114  	} else {
   115  		engine = ethash.NewShared()
   116  	}
   117  	chain, err := core.NewBlockChain(db, &core.CacheConfig{TrieCleanLimit: 0}, config, engine, vm.Config{}, nil)
   118  	if err != nil {
   119  		return err
   120  	}
   121  	defer chain.Stop()
   122  
   123  	validBlocks, err := t.insertBlocks(chain)
   124  	if err != nil {
   125  		return err
   126  	}
   127  	cmlast := chain.CurrentBlock().Hash()
   128  	if common.Hash(t.json.BestBlock) != cmlast {
   129  		return fmt.Errorf("last block hash validation mismatch: want: %x, have: %x", t.json.BestBlock, cmlast)
   130  	}
   131  	newDB, err := chain.State()
   132  	if err != nil {
   133  		return err
   134  	}
   135  	if err = t.validatePostState(newDB); err != nil {
   136  		return fmt.Errorf("post state validation failed: %v", err)
   137  	}
   138  	return t.validateImportedHeaders(chain, validBlocks)
   139  }
   140  
   141  func (t *BlockTest) genesis(config *params.ChainConfig) *core.Genesis {
   142  	return &core.Genesis{
   143  		Config:     config,
   144  		Nonce:      t.json.Genesis.Nonce.Uint64(),
   145  		Timestamp:  t.json.Genesis.Timestamp.Uint64(),
   146  		ParentHash: t.json.Genesis.ParentHash,
   147  		ExtraData:  t.json.Genesis.ExtraData,
   148  		GasLimit:   t.json.Genesis.GasLimit,
   149  		GasUsed:    t.json.Genesis.GasUsed,
   150  		Difficulty: t.json.Genesis.Difficulty,
   151  		Mixhash:    t.json.Genesis.MixHash,
   152  		Coinbase:   t.json.Genesis.Coinbase,
   153  		Alloc:      t.json.Pre,
   154  	}
   155  }
   156  
   157  /*参见https://github.com/ethereum/tests/wiki/blockback-tests-ii
   158  
   159     一个块是否有效有点微妙,它是通过存在
   160     BlockHeader、Transactions和UncleHeaders字段。如果他们不见了,这个街区就是
   161     无效,我们必须确认我们不接受它。
   162  
   163     由于一些测试混合了有效和无效的块,我们需要为每个块检查这一点。
   164  
   165     如果一个块是无效的,它不一定会通过测试,如果它的无效性是
   166     期望我们忽略它并继续处理,然后验证
   167     后状态。
   168  **/
   169  
   170  func (t *BlockTest) insertBlocks(blockchain *core.BlockChain) ([]btBlock, error) {
   171  	validBlocks := make([]btBlock, 0)
   172  //插入将执行所有事务的测试块
   173  	for _, b := range t.json.Blocks {
   174  		cb, err := b.decode()
   175  		if err != nil {
   176  			if b.BlockHeader == nil {
   177  continue //好-块应该无效,继续下一个块
   178  			} else {
   179  				return nil, fmt.Errorf("Block RLP decoding failed when expected to succeed: %v", err)
   180  			}
   181  		}
   182  //RLP解码成功,尝试插入链:
   183  		blocks := types.Blocks{cb}
   184  		i, err := blockchain.InsertChain(blocks)
   185  		if err != nil {
   186  			if b.BlockHeader == nil {
   187  continue //好-块应该无效,继续下一个块
   188  			} else {
   189  				return nil, fmt.Errorf("Block #%v insertion into chain failed: %v", blocks[i].Number(), err)
   190  			}
   191  		}
   192  		if b.BlockHeader == nil {
   193  			return nil, fmt.Errorf("Block insertion should have failed")
   194  		}
   195  
   196  //通过检查测试文件json的所有值来验证rlp解码
   197  		if err = validateHeader(b.BlockHeader, cb.Header()); err != nil {
   198  			return nil, fmt.Errorf("Deserialised block header validation failed: %v", err)
   199  		}
   200  		validBlocks = append(validBlocks, b)
   201  	}
   202  	return validBlocks, nil
   203  }
   204  
   205  func validateHeader(h *btHeader, h2 *types.Header) error {
   206  	if h.Bloom != h2.Bloom {
   207  		return fmt.Errorf("Bloom: want: %x have: %x", h.Bloom, h2.Bloom)
   208  	}
   209  	if h.Coinbase != h2.Coinbase {
   210  		return fmt.Errorf("Coinbase: want: %x have: %x", h.Coinbase, h2.Coinbase)
   211  	}
   212  	if h.MixHash != h2.MixDigest {
   213  		return fmt.Errorf("MixHash: want: %x have: %x", h.MixHash, h2.MixDigest)
   214  	}
   215  	if h.Nonce != h2.Nonce {
   216  		return fmt.Errorf("Nonce: want: %x have: %x", h.Nonce, h2.Nonce)
   217  	}
   218  	if h.Number.Cmp(h2.Number) != 0 {
   219  		return fmt.Errorf("Number: want: %v have: %v", h.Number, h2.Number)
   220  	}
   221  	if h.ParentHash != h2.ParentHash {
   222  		return fmt.Errorf("Parent hash: want: %x have: %x", h.ParentHash, h2.ParentHash)
   223  	}
   224  	if h.ReceiptTrie != h2.ReceiptHash {
   225  		return fmt.Errorf("Receipt hash: want: %x have: %x", h.ReceiptTrie, h2.ReceiptHash)
   226  	}
   227  	if h.TransactionsTrie != h2.TxHash {
   228  		return fmt.Errorf("Tx hash: want: %x have: %x", h.TransactionsTrie, h2.TxHash)
   229  	}
   230  	if h.StateRoot != h2.Root {
   231  		return fmt.Errorf("State hash: want: %x have: %x", h.StateRoot, h2.Root)
   232  	}
   233  	if h.UncleHash != h2.UncleHash {
   234  		return fmt.Errorf("Uncle hash: want: %x have: %x", h.UncleHash, h2.UncleHash)
   235  	}
   236  	if !bytes.Equal(h.ExtraData, h2.Extra) {
   237  		return fmt.Errorf("Extra data: want: %x have: %x", h.ExtraData, h2.Extra)
   238  	}
   239  	if h.Difficulty.Cmp(h2.Difficulty) != 0 {
   240  		return fmt.Errorf("Difficulty: want: %v have: %v", h.Difficulty, h2.Difficulty)
   241  	}
   242  	if h.GasLimit != h2.GasLimit {
   243  		return fmt.Errorf("GasLimit: want: %d have: %d", h.GasLimit, h2.GasLimit)
   244  	}
   245  	if h.GasUsed != h2.GasUsed {
   246  		return fmt.Errorf("GasUsed: want: %d have: %d", h.GasUsed, h2.GasUsed)
   247  	}
   248  	if h.Timestamp.Cmp(h2.Time) != 0 {
   249  		return fmt.Errorf("Timestamp: want: %v have: %v", h.Timestamp, h2.Time)
   250  	}
   251  	return nil
   252  }
   253  
   254  func (t *BlockTest) validatePostState(statedb *state.StateDB) error {
   255  //根据状态数据库中的内容验证测试文件中的状态后帐户
   256  	for addr, acct := range t.json.Post {
   257  //地址由其他字段间接验证,因为它是db键
   258  		code2 := statedb.GetCode(addr)
   259  		balance2 := statedb.GetBalance(addr)
   260  		nonce2 := statedb.GetNonce(addr)
   261  		if !bytes.Equal(code2, acct.Code) {
   262  			return fmt.Errorf("account code mismatch for addr: %s want: %v have: %s", addr, acct.Code, hex.EncodeToString(code2))
   263  		}
   264  		if balance2.Cmp(acct.Balance) != 0 {
   265  			return fmt.Errorf("account balance mismatch for addr: %s, want: %d, have: %d", addr, acct.Balance, balance2)
   266  		}
   267  		if nonce2 != acct.Nonce {
   268  			return fmt.Errorf("account nonce mismatch for addr: %s want: %d have: %d", addr, acct.Nonce, nonce2)
   269  		}
   270  	}
   271  	return nil
   272  }
   273  
   274  func (t *BlockTest) validateImportedHeaders(cm *core.BlockChain, validBlocks []btBlock) error {
   275  //通过哈希验证块头时获取常量查找(某些测试有许多块)
   276  	bmap := make(map[common.Hash]btBlock, len(t.json.Blocks))
   277  	for _, b := range validBlocks {
   278  		bmap[b.BlockHeader.Hash] = b
   279  	}
   280  //从头部向后迭代块并验证导入的
   281  //头与测试文件。有些测试有REORG,我们导入
   282  //逐块,因此我们只能在
   283  //所有块都已由区块链处理,因为它们可能不是
   284  //成为最长链的一部分,直到导入最后一个块。
   285  	for b := cm.CurrentBlock(); b != nil && b.NumberU64() != 0; b = cm.GetBlockByHash(b.Header().ParentHash) {
   286  		if err := validateHeader(bmap[b.Hash()].BlockHeader, b.Header()); err != nil {
   287  			return fmt.Errorf("Imported block header validation failed: %v", err)
   288  		}
   289  	}
   290  	return nil
   291  }
   292  
   293  func (bb *btBlock) decode() (*types.Block, error) {
   294  	data, err := hexutil.Decode(bb.Rlp)
   295  	if err != nil {
   296  		return nil, err
   297  	}
   298  	var b types.Block
   299  	err = rlp.DecodeBytes(data, &b)
   300  	return &b, err
   301  }
   302