github.com/linapex/ethereum-go-chinese@v0.0.0-20190316121929-f8b7a73c3fa1/core/chain_makers.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:35</date>
    10  //</624450078500720640>
    11  
    12  
    13  package core
    14  
    15  import (
    16  	"fmt"
    17  	"math/big"
    18  
    19  	"github.com/ethereum/go-ethereum/common"
    20  	"github.com/ethereum/go-ethereum/consensus"
    21  	"github.com/ethereum/go-ethereum/consensus/misc"
    22  	"github.com/ethereum/go-ethereum/core/state"
    23  	"github.com/ethereum/go-ethereum/core/types"
    24  	"github.com/ethereum/go-ethereum/core/vm"
    25  	"github.com/ethereum/go-ethereum/ethdb"
    26  	"github.com/ethereum/go-ethereum/params"
    27  )
    28  
    29  //blockgen为测试创建块。
    30  //有关详细说明,请参阅GenerateChain。
    31  type BlockGen struct {
    32  	i       int
    33  	parent  *types.Block
    34  	chain   []*types.Block
    35  	header  *types.Header
    36  	statedb *state.StateDB
    37  
    38  	gasPool  *GasPool
    39  	txs      []*types.Transaction
    40  	receipts []*types.Receipt
    41  	uncles   []*types.Header
    42  
    43  	config *params.ChainConfig
    44  	engine consensus.Engine
    45  }
    46  
    47  //setcoinbase设置生成块的coinbase。
    48  //最多只能调用一次。
    49  func (b *BlockGen) SetCoinbase(addr common.Address) {
    50  	if b.gasPool != nil {
    51  		if len(b.txs) > 0 {
    52  			panic("coinbase must be set before adding transactions")
    53  		}
    54  		panic("coinbase can only be set once")
    55  	}
    56  	b.header.Coinbase = addr
    57  	b.gasPool = new(GasPool).AddGas(b.header.GasLimit)
    58  }
    59  
    60  //setextra设置所生成块的额外数据字段。
    61  func (b *BlockGen) SetExtra(data []byte) {
    62  	b.header.Extra = data
    63  }
    64  
    65  //setnonce设置所生成块的nonce字段。
    66  func (b *BlockGen) SetNonce(nonce types.BlockNonce) {
    67  	b.header.Nonce = nonce
    68  }
    69  
    70  //addtx将事务添加到生成的块中。如果没有Coinbase
    71  //设置后,块的coinbase设置为零地址。
    72  //
    73  //如果无法执行事务,则addtx将暂停。除了
    74  //协议规定的限制(气体限制等),有一些
    75  //对交易内容的进一步限制
    76  //补充。值得注意的是,依赖blockhash指令的合同代码
    77  //在执行过程中会恐慌。
    78  func (b *BlockGen) AddTx(tx *types.Transaction) {
    79  	b.AddTxWithChain(nil, tx)
    80  }
    81  
    82  //addtxwithchain向生成的块添加事务。如果没有Coinbase
    83  //设置后,块的coinbase设置为零地址。
    84  //
    85  //如果无法执行事务,则addtxwithchain将暂停。除了
    86  //协议规定的限制(气体限制等),有一些
    87  //对交易内容的进一步限制
    88  //补充。如果合同代码依赖于blockhash指令,
    89  //将返回链中的块。
    90  func (b *BlockGen) AddTxWithChain(bc *BlockChain, tx *types.Transaction) {
    91  	if b.gasPool == nil {
    92  		b.SetCoinbase(common.Address{})
    93  	}
    94  	b.statedb.Prepare(tx.Hash(), common.Hash{}, len(b.txs))
    95  	receipt, _, err := ApplyTransaction(b.config, bc, &b.header.Coinbase, b.gasPool, b.statedb, b.header, tx, &b.header.GasUsed, vm.Config{})
    96  	if err != nil {
    97  		panic(err)
    98  	}
    99  	b.txs = append(b.txs, tx)
   100  	b.receipts = append(b.receipts, receipt)
   101  }
   102  
   103  //number返回正在生成的块的块号。
   104  func (b *BlockGen) Number() *big.Int {
   105  	return new(big.Int).Set(b.header.Number)
   106  }
   107  
   108  //addUncheckedReceipt强制将收据添加到块,而不使用
   109  //支持事务。
   110  //
   111  //添加取消选中的收据在实际使用时会导致共识失败。
   112  //链处理。这最好与原始块插入结合使用。
   113  func (b *BlockGen) AddUncheckedReceipt(receipt *types.Receipt) {
   114  	b.receipts = append(b.receipts, receipt)
   115  }
   116  
   117  //txnonce返回的下一个有效事务nonce
   118  //账户地址如果帐户不存在,它会恐慌。
   119  func (b *BlockGen) TxNonce(addr common.Address) uint64 {
   120  	if !b.statedb.Exist(addr) {
   121  		panic("account does not exist")
   122  	}
   123  	return b.statedb.GetNonce(addr)
   124  }
   125  
   126  //AddUncle向生成的块添加一个叔叔头。
   127  func (b *BlockGen) AddUncle(h *types.Header) {
   128  	b.uncles = append(b.uncles, h)
   129  }
   130  
   131  //prevblock按数字返回以前生成的块。它恐慌,如果
   132  //num大于或等于正在生成的块的数目。
   133  //对于索引-1,prevblock返回给generatechain的父块。
   134  func (b *BlockGen) PrevBlock(index int) *types.Block {
   135  	if index >= b.i {
   136  		panic(fmt.Errorf("block index %d out of range (%d,%d)", index, -1, b.i))
   137  	}
   138  	if index == -1 {
   139  		return b.parent
   140  	}
   141  	return b.chain[index]
   142  }
   143  
   144  //offsettime修改块的时间实例,隐式更改其
   145  //相关难度。在没有分叉的情况下测试场景很有用
   146  //直接与链条长度相连。
   147  func (b *BlockGen) OffsetTime(seconds int64) {
   148  	b.header.Time.Add(b.header.Time, new(big.Int).SetInt64(seconds))
   149  	if b.header.Time.Cmp(b.parent.Header().Time) <= 0 {
   150  		panic("block time out of range")
   151  	}
   152  	chainreader := &fakeChainReader{config: b.config}
   153  	b.header.Difficulty = b.engine.CalcDifficulty(chainreader, b.header.Time.Uint64(), b.parent.Header())
   154  }
   155  
   156  //GenerateChain创建一个由n个块组成的链。第一个街区
   157  //父级将是提供的父级。数据库用于存储
   158  //中间状态,应包含父级的状态trie。
   159  //
   160  //使用新的块生成器调用generator函数
   161  //每一个街区。任何添加到生成器的事务和叔叔
   162  //成为区块的一部分。如果gen为零,则块将为空。
   163  //他们的硬币库将是零地址。
   164  //
   165  //GenerateChain创建的块不包含有效的工作证明
   166  //价值观。将它们插入区块链需要使用fakepow或
   167  //类似的非验证性工作实施证明。
   168  func GenerateChain(config *params.ChainConfig, parent *types.Block, engine consensus.Engine, db ethdb.Database, n int, gen func(int, *BlockGen)) ([]*types.Block, []types.Receipts) {
   169  	if config == nil {
   170  		config = params.TestChainConfig
   171  	}
   172  	blocks, receipts := make(types.Blocks, n), make([]types.Receipts, n)
   173  	chainreader := &fakeChainReader{config: config}
   174  	genblock := func(i int, parent *types.Block, statedb *state.StateDB) (*types.Block, types.Receipts) {
   175  		b := &BlockGen{i: i, chain: blocks, parent: parent, statedb: statedb, config: config, engine: engine}
   176  		b.header = makeHeader(chainreader, parent, statedb, b.engine)
   177  
   178  //根据任何硬分叉规格改变状态并阻塞
   179  		if daoBlock := config.DAOForkBlock; daoBlock != nil {
   180  			limit := new(big.Int).Add(daoBlock, params.DAOForkExtraRange)
   181  			if b.header.Number.Cmp(daoBlock) >= 0 && b.header.Number.Cmp(limit) < 0 {
   182  				if config.DAOForkSupport {
   183  					b.header.Extra = common.CopyBytes(params.DAOForkBlockExtra)
   184  				}
   185  			}
   186  		}
   187  		if config.DAOForkSupport && config.DAOForkBlock != nil && config.DAOForkBlock.Cmp(b.header.Number) == 0 {
   188  			misc.ApplyDAOHardFork(statedb)
   189  		}
   190  //对块执行任何用户修改
   191  		if gen != nil {
   192  			gen(i, b)
   193  		}
   194  		if b.engine != nil {
   195  //敲定并密封块
   196  			block, _ := b.engine.Finalize(chainreader, b.header, statedb, b.txs, b.uncles, b.receipts)
   197  
   198  //将状态更改写入数据库
   199  			root, err := statedb.Commit(config.IsEIP158(b.header.Number))
   200  			if err != nil {
   201  				panic(fmt.Sprintf("state write error: %v", err))
   202  			}
   203  			if err := statedb.Database().TrieDB().Commit(root, false); err != nil {
   204  				panic(fmt.Sprintf("trie write error: %v", err))
   205  			}
   206  			return block, b.receipts
   207  		}
   208  		return nil, nil
   209  	}
   210  	for i := 0; i < n; i++ {
   211  		statedb, err := state.New(parent.Root(), state.NewDatabase(db))
   212  		if err != nil {
   213  			panic(err)
   214  		}
   215  		block, receipt := genblock(i, parent, statedb)
   216  		blocks[i] = block
   217  		receipts[i] = receipt
   218  		parent = block
   219  	}
   220  	return blocks, receipts
   221  }
   222  
   223  func makeHeader(chain consensus.ChainReader, parent *types.Block, state *state.StateDB, engine consensus.Engine) *types.Header {
   224  	var time *big.Int
   225  	if parent.Time() == nil {
   226  		time = big.NewInt(10)
   227  	} else {
   228  time = new(big.Int).Add(parent.Time(), big.NewInt(10)) //阻塞时间固定为10秒
   229  	}
   230  
   231  	return &types.Header{
   232  		Root:       state.IntermediateRoot(chain.Config().IsEIP158(parent.Number())),
   233  		ParentHash: parent.Hash(),
   234  		Coinbase:   parent.Coinbase(),
   235  		Difficulty: engine.CalcDifficulty(chain, time.Uint64(), &types.Header{
   236  			Number:     parent.Number(),
   237  			Time:       new(big.Int).Sub(time, big.NewInt(10)),
   238  			Difficulty: parent.Difficulty(),
   239  			UncleHash:  parent.UncleHash(),
   240  		}),
   241  		GasLimit: CalcGasLimit(parent, parent.GasLimit(), parent.GasLimit()),
   242  		Number:   new(big.Int).Add(parent.Number(), common.Big1),
   243  		Time:     time,
   244  	}
   245  }
   246  
   247  //MakeHeaderChain创建一个以父级为根的具有确定性的头链。
   248  func makeHeaderChain(parent *types.Header, n int, engine consensus.Engine, db ethdb.Database, seed int) []*types.Header {
   249  	blocks := makeBlockChain(types.NewBlockWithHeader(parent), n, engine, db, seed)
   250  	headers := make([]*types.Header, len(blocks))
   251  	for i, block := range blocks {
   252  		headers[i] = block.Header()
   253  	}
   254  	return headers
   255  }
   256  
   257  //makeBlockchain创建了一个基于父级的确定性块链。
   258  func makeBlockChain(parent *types.Block, n int, engine consensus.Engine, db ethdb.Database, seed int) []*types.Block {
   259  	blocks, _ := GenerateChain(params.TestChainConfig, parent, engine, db, n, func(i int, b *BlockGen) {
   260  		b.SetCoinbase(common.Address{0: byte(seed), 19: byte(i)})
   261  	})
   262  	return blocks
   263  }
   264  
   265  type fakeChainReader struct {
   266  	config  *params.ChainConfig
   267  	genesis *types.Block
   268  }
   269  
   270  //config返回链配置。
   271  func (cr *fakeChainReader) Config() *params.ChainConfig {
   272  	return cr.config
   273  }
   274  
   275  func (cr *fakeChainReader) CurrentHeader() *types.Header                            { return nil }
   276  func (cr *fakeChainReader) GetHeaderByNumber(number uint64) *types.Header           { return nil }
   277  func (cr *fakeChainReader) GetHeaderByHash(hash common.Hash) *types.Header          { return nil }
   278  func (cr *fakeChainReader) GetHeader(hash common.Hash, number uint64) *types.Header { return nil }
   279  func (cr *fakeChainReader) GetBlock(hash common.Hash, number uint64) *types.Block   { return nil }
   280