func makeHeaderChain(parent *EvmHeader, n int, db ethdb.Database, seed int) []*EvmHeader {
	block := &EvmBlock{}
	block.EvmHeader = *parent
	blocks := makeBlockChain(block, n, db, seed)
	headers := make([]*EvmHeader, len(blocks))
	for i, block := range blocks {
		headers[i] = block.Header()
	}
	return headers
}
makeHeaderChain creates a deterministic chain of headers rooted at parent.
package evmcore
import (
	"fmt"
	"math/big"
	"time"
	"github.com/ethereum/go-ethereum/common"
	"github.com/ethereum/go-ethereum/core/state"
	"github.com/ethereum/go-ethereum/core/types"
	"github.com/ethereum/go-ethereum/core/vm"
	"github.com/ethereum/go-ethereum/ethdb"
	"github.com/ethereum/go-ethereum/params"
	"github.com/Fantom-foundation/go-opera/inter"
	"github.com/Fantom-foundation/go-opera/opera"
)
type BlockGen struct {
	i       int
	parent  *EvmBlock
	chain   []*EvmBlock
	header  *EvmHeader
	statedb *state.StateDB
	gasPool  *GasPool
	txs      []*types.Transaction
	receipts []*types.Receipt
	config *params.ChainConfig
}
type TestChain struct {
	headers map[common.Hash]*EvmHeader
}
func (tc *TestChain) GetHeader(hash common.Hash, number uint64) *EvmHeader {
	return tc.headers[hash]
}
func (b *BlockGen) SetCoinbase(addr common.Address) {
	if b.gasPool != nil {
		if len(b.txs) > 0 {
			panic("coinbase must be set before adding transactions")
		}
		panic("coinbase can only be set once")
	}
	b.header.Coinbase = addr
	b.gasPool = new(GasPool).AddGas(b.header.GasLimit)
}
func (b *BlockGen) AddTx(tx *types.Transaction) {
	b.AddTxWithChain(nil, tx)
}
func (b *BlockGen) AddTxWithChain(bc DummyChain, tx *types.Transaction) {
	if b.gasPool == nil {
		b.SetCoinbase(common.Address{})
	}
	msg, err := tx.AsMessage(types.MakeSigner(b.config, b.header.Number))
	if err != nil {
		panic(err)
	}
	b.statedb.Prepare(tx.Hash(), common.Hash{}, len(b.txs))
	blockContext := NewEVMBlockContext(b.header, bc, nil)
	vmenv := vm.NewEVM(blockContext, vm.TxContext{}, b.statedb, b.config, opera.DefaultVMConfig)
	receipt, _, _, err := applyTransaction(msg, b.config, b.gasPool, b.statedb, b.header, tx, &b.header.GasUsed, vmenv, func(log *types.Log, db *state.StateDB) {})
	if err != nil {
		panic(err)
	}
	b.txs = append(b.txs, tx)
	b.receipts = append(b.receipts, receipt)
}
func (b *BlockGen) GetBalance(addr common.Address) *big.Int {
	return b.statedb.GetBalance(addr)
}
func (b *BlockGen) AddUncheckedTx(tx *types.Transaction) {
	b.txs = append(b.txs, tx)
}
func (b *BlockGen) Number() *big.Int {
	return new(big.Int).Set(b.header.Number)
}
func (b *BlockGen) AddUncheckedReceipt(receipt *types.Receipt) {
	b.receipts = append(b.receipts, receipt)
}
func (b *BlockGen) TxNonce(addr common.Address) uint64 {
	if !b.statedb.Exist(addr) {
		panic("account does not exist")
	}
	return b.statedb.GetNonce(addr)
}
func (b *BlockGen) PrevBlock(index int) *EvmBlock {
	if index >= b.i {
		panic(fmt.Errorf("block index %d out of range (%d,%d)", index, -1, b.i))
	}
	if index == -1 {
		return b.parent
	}
	return b.chain[index]
}
func (b *BlockGen) OffsetTime(seconds int64) {
	b.header.Time += inter.Timestamp(seconds)
	if b.header.Time <= b.parent.Header().Time {
		panic("block time out of range")
	}
}
func GenerateChain(config *params.ChainConfig, parent *EvmBlock, db ethdb.Database, n int, gen func(int, *BlockGen)) ([]*EvmBlock, []types.Receipts, DummyChain) {
	if config == nil {
		config = params.AllEthashProtocolChanges
	}
	chain := &TestChain{
		headers: map[common.Hash]*EvmHeader{},
	}
	blocks, receipts := make([]*EvmBlock, n), make([]types.Receipts, n)
	genblock := func(i int, parent *EvmBlock, statedb *state.StateDB) (*EvmBlock, types.Receipts) {
		b := &BlockGen{i: i, chain: blocks, parent: parent, statedb: statedb, config: config}
		b.header = makeHeader(parent, statedb)
		if gen != nil {
			gen(i, b)
		}
		block := &EvmBlock{
			EvmHeader: *b.header,
		}
		root, err := flush(statedb, config.IsEIP158(b.header.Number))
		if err != nil {
			panic(fmt.Sprintf("state flush error: %v", err))
		}
		b.header = block.Header()
		block.Root = root
		return block, b.receipts
	}
	for i := 0; i < n; i++ {
		statedb, err := state.New(parent.Root, state.NewDatabase(db), nil)
		if err != nil {
			panic(err)
		}
		block, receipt := genblock(i, parent, statedb)
		blocks[i] = block
		receipts[i] = receipt
		parent = block
		chain.headers[block.Hash] = block.Header()
	}
	return blocks, receipts, chain
}
func makeHeader(parent *EvmBlock, state *state.StateDB) *EvmHeader {
	var t inter.Timestamp
	if parent.Time == 0 {
		t = 10
	} else {
		t = parent.Time + inter.Timestamp(10*time.Second)  
	}
	return &EvmHeader{
		ParentHash: parent.Hash,
		Coinbase:   parent.Coinbase,
		GasLimit:   parent.GasLimit,
		Number:     new(big.Int).Add(parent.Number, common.Big1),
		Time:       t,
	}
}