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