github.com/neatlab/neatio@v1.7.3-0.20220425043230-d903e92fcc75/chain/core/chain_makers.go (about) 1 package core 2 3 import ( 4 "fmt" 5 "math/big" 6 7 "github.com/neatlab/neatio/chain/consensus" 8 "github.com/neatlab/neatio/chain/core/state" 9 "github.com/neatlab/neatio/chain/core/types" 10 "github.com/neatlab/neatio/chain/core/vm" 11 "github.com/neatlab/neatio/neatdb" 12 "github.com/neatlab/neatio/params" 13 "github.com/neatlab/neatio/utilities/common" 14 ) 15 16 var ( 17 canonicalSeed = 1 18 forkSeed = 2 19 ) 20 21 type BlockGen struct { 22 i int 23 parent *types.Block 24 chain []*types.Block 25 chainReader consensus.ChainReader 26 header *types.Header 27 statedb *state.StateDB 28 29 gasPool *GasPool 30 txs []*types.Transaction 31 receipts []*types.Receipt 32 uncles []*types.Header 33 34 config *params.ChainConfig 35 engine consensus.Engine 36 } 37 38 func (b *BlockGen) SetCoinbase(addr common.Address) { 39 if b.gasPool != nil { 40 if len(b.txs) > 0 { 41 panic("coinbase must be set before adding transactions") 42 } 43 panic("coinbase can only be set once") 44 } 45 b.header.Coinbase = addr 46 b.gasPool = new(GasPool).AddGas(b.header.GasLimit) 47 } 48 49 func (b *BlockGen) SetExtra(data []byte) { 50 b.header.Extra = data 51 } 52 53 func (b *BlockGen) AddTx(tx *types.Transaction) { 54 b.AddTxWithChain(nil, tx) 55 } 56 57 func (b *BlockGen) AddTxWithChain(bc *BlockChain, tx *types.Transaction) { 58 if b.gasPool == nil { 59 b.SetCoinbase(common.Address{}) 60 } 61 b.statedb.Prepare(tx.Hash(), common.Hash{}, len(b.txs)) 62 receipt, err := ApplyTransaction(b.config, bc, &b.header.Coinbase, b.gasPool, b.statedb, b.header, tx, &b.header.GasUsed, vm.Config{}) 63 if err != nil { 64 panic(err) 65 } 66 b.txs = append(b.txs, tx) 67 b.receipts = append(b.receipts, receipt) 68 } 69 70 func (b *BlockGen) Number() *big.Int { 71 return new(big.Int).Set(b.header.Number) 72 } 73 74 func (b *BlockGen) AddUncheckedReceipt(receipt *types.Receipt) { 75 b.receipts = append(b.receipts, receipt) 76 } 77 78 func (b *BlockGen) TxNonce(addr common.Address) uint64 { 79 if !b.statedb.Exist(addr) { 80 panic("account does not exist") 81 } 82 return b.statedb.GetNonce(addr) 83 } 84 85 func (b *BlockGen) AddUncle(h *types.Header) { 86 b.uncles = append(b.uncles, h) 87 } 88 89 func (b *BlockGen) PrevBlock(index int) *types.Block { 90 if index >= b.i { 91 panic("block index out of range") 92 } 93 if index == -1 { 94 return b.parent 95 } 96 return b.chain[index] 97 } 98 99 func (b *BlockGen) OffsetTime(seconds int64) { 100 b.header.Time.Add(b.header.Time, new(big.Int).SetInt64(seconds)) 101 if b.header.Time.Cmp(b.parent.Header().Time) <= 0 { 102 panic("block time out of range") 103 } 104 b.header.Difficulty = b.engine.CalcDifficulty(b.chainReader, b.header.Time.Uint64(), b.parent.Header()) 105 } 106 107 func GenerateChain(config *params.ChainConfig, parent *types.Block, engine consensus.Engine, db neatdb.Database, n int, gen func(int, *BlockGen)) ([]*types.Block, []types.Receipts) { 108 if config == nil { 109 config = params.TestChainConfig 110 } 111 blocks, receipts := make(types.Blocks, n), make([]types.Receipts, n) 112 genblock := func(i int, parent *types.Block, statedb *state.StateDB) (*types.Block, types.Receipts) { 113 114 blockchain, _ := NewBlockChain(db, nil, config, engine, vm.Config{}, nil) 115 defer blockchain.Stop() 116 117 b := &BlockGen{i: i, parent: parent, chain: blocks, chainReader: blockchain, statedb: statedb, config: config, engine: engine} 118 b.header = makeHeader(b.chainReader, parent, statedb, b.engine) 119 120 if gen != nil { 121 gen(i, b) 122 } 123 124 if b.engine != nil { 125 block, _ := b.engine.Finalize(b.chainReader, b.header, statedb, b.txs, nil, b.uncles, b.receipts, nil) 126 127 root, err := statedb.Commit(config.IsEIP158(b.header.Number)) 128 if err != nil { 129 panic(fmt.Sprintf("state write error: %v", err)) 130 } 131 if err := statedb.Database().TrieDB().Commit(root, false); err != nil { 132 panic(fmt.Sprintf("trie write error: %v", err)) 133 } 134 return block, b.receipts 135 } 136 return nil, nil 137 } 138 for i := 0; i < n; i++ { 139 statedb, err := state.New(parent.Root(), state.NewDatabase(db)) 140 if err != nil { 141 panic(err) 142 } 143 block, receipt := genblock(i, parent, statedb) 144 blocks[i] = block 145 receipts[i] = receipt 146 parent = block 147 } 148 return blocks, receipts 149 } 150 151 func makeHeader(chain consensus.ChainReader, parent *types.Block, state *state.StateDB, engine consensus.Engine) *types.Header { 152 var time *big.Int 153 if parent.Time() == 0 { 154 time = big.NewInt(10) 155 } else { 156 time = new(big.Int).SetUint64(parent.Time() + 10) 157 } 158 159 return &types.Header{ 160 Root: state.IntermediateRoot(chain.Config().IsEIP158(parent.Number())), 161 ParentHash: parent.Hash(), 162 Coinbase: parent.Coinbase(), 163 Difficulty: engine.CalcDifficulty(chain, time.Uint64(), &types.Header{ 164 Number: parent.Number(), 165 Time: new(big.Int).Sub(time, big.NewInt(10)), 166 Difficulty: parent.Difficulty(), 167 UncleHash: parent.UncleHash(), 168 }), 169 GasLimit: CalcGasLimit(parent, parent.GasLimit(), parent.GasLimit()), 170 Number: new(big.Int).Add(parent.Number(), common.Big1), 171 Time: time, 172 } 173 } 174 175 func makeHeaderChain(parent *types.Header, n int, engine consensus.Engine, db neatdb.Database, seed int) []*types.Header { 176 blocks := makeBlockChain(types.NewBlockWithHeader(parent), n, engine, db, seed) 177 headers := make([]*types.Header, len(blocks)) 178 for i, block := range blocks { 179 headers[i] = block.Header() 180 } 181 return headers 182 } 183 184 func makeBlockChain(parent *types.Block, n int, engine consensus.Engine, db neatdb.Database, seed int) []*types.Block { 185 blocks, _ := GenerateChain(params.TestChainConfig, parent, engine, db, n, func(i int, b *BlockGen) { 186 b.SetCoinbase(common.Address{0: byte(seed), 19: byte(i)}) 187 }) 188 return blocks 189 }