github.com/neatio-net/neatio@v1.7.3-0.20231114194659-f4d7a2226baa/chain/core/chain_makers.go (about)

     1  package core
     2  
     3  import (
     4  	"fmt"
     5  	"math/big"
     6  
     7  	"github.com/neatio-net/neatio/chain/consensus"
     8  	"github.com/neatio-net/neatio/chain/core/state"
     9  	"github.com/neatio-net/neatio/chain/core/types"
    10  	"github.com/neatio-net/neatio/chain/core/vm"
    11  	"github.com/neatio-net/neatio/neatdb"
    12  	"github.com/neatio-net/neatio/params"
    13  	"github.com/neatio-net/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  }