From 3911752697b6718fd8014146776378c465a8e88e Mon Sep 17 00:00:00 2001 From: BJ4 Date: Fri, 9 Nov 2018 12:08:17 +0800 Subject: app: fix core test --- core/blockchain.go | 78 ++++++++++++++++++++++++++++++++++++++++++++++- core/blockchain_test.go | 38 +++++++++++++++++------ core/chain_makers_test.go | 6 ++-- core/dao_test.go | 1 + core/evm.go | 9 +++++- core/genesis_test.go | 6 ++-- core/tx_pool_test.go | 43 ++++++++++++++------------ 7 files changed, 144 insertions(+), 37 deletions(-) (limited to 'core') diff --git a/core/blockchain.go b/core/blockchain.go index c44d2633a..79e0b2a02 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -203,7 +203,83 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, chainConfig *par addressCounter: make(map[uint32]map[common.Address]uint64), chainLastHeight: make(map[uint32]uint64), } - bc.SetValidator(NewDexonBlockValidator(chainConfig, bc, engine)) + bc.SetValidator(NewBlockValidator(chainConfig, bc, engine)) + bc.SetProcessor(NewStateProcessor(chainConfig, bc, engine)) + + var err error + bc.hc, err = NewHeaderChain(db, chainConfig, engine, bc.getProcInterrupt) + if err != nil { + return nil, err + } + bc.genesisBlock = bc.GetBlockByNumber(0) + if bc.genesisBlock == nil { + return nil, ErrNoGenesis + } + if err := bc.loadLastState(); err != nil { + return nil, err + } + // Check the current state of the block hashes and make sure that we do not have any of the bad blocks in our chain + for hash := range BadHashes { + if header := bc.GetHeaderByHash(hash); header != nil { + // get the canonical block corresponding to the offending header's number + headerByNumber := bc.GetHeaderByNumber(header.Number.Uint64()) + // make sure the headerByNumber (if present) is in our current canonical chain + if headerByNumber != nil && headerByNumber.Hash() == header.Hash() { + log.Error("Found bad hash, rewinding chain", "number", header.Number, "hash", header.ParentHash) + bc.SetHead(header.Number.Uint64() - 1) + log.Error("Chain rewind was successful, resuming normal operation") + } + } + } + + // Set genesis round height mapping. + bc.roundHeightMap.Store(0, 0) + + // Take ownership of this particular state + go bc.update() + return bc, nil +} + +func NewBlockChainWithDexonValidator(db ethdb.Database, cacheConfig *CacheConfig, chainConfig *params.ChainConfig, engine consensus.Engine, vmConfig vm.Config, shouldPreserve func(block *types.Block) bool) (*BlockChain, error) { + if cacheConfig == nil { + cacheConfig = &CacheConfig{ + TrieNodeLimit: 256 * 1024 * 1024, + TrieTimeLimit: 5 * time.Minute, + } + } + bodyCache, _ := lru.New(bodyCacheLimit) + bodyRLPCache, _ := lru.New(bodyCacheLimit) + receiptsCache, _ := lru.New(receiptsCacheLimit) + blockCache, _ := lru.New(blockCacheLimit) + futureBlocks, _ := lru.New(maxFutureBlocks) + badBlocks, _ := lru.New(badBlockLimit) + + bc := &BlockChain{ + chainConfig: chainConfig, + cacheConfig: cacheConfig, + db: db, + triegc: prque.New(nil), + stateCache: state.NewDatabase(db), + quit: make(chan struct{}), + bodyCache: bodyCache, + bodyRLPCache: bodyRLPCache, + receiptsCache: receiptsCache, + blockCache: blockCache, + futureBlocks: futureBlocks, + engine: engine, + vmConfig: vmConfig, + badBlocks: badBlocks, + pendingBlocks: make(map[uint64]struct { + block *types.Block + receipts types.Receipts + }), + confirmedBlocks: make(map[uint32]map[coreCommon.Hash]*blockInfo), + addressNonce: make(map[uint32]map[common.Address]uint64), + addressCost: make(map[uint32]map[common.Address]*big.Int), + addressCounter: make(map[uint32]map[common.Address]uint64), + chainLastHeight: make(map[uint32]uint64), + } + bc.SetValidator(NewBlockValidator(chainConfig, bc, engine)) bc.SetProcessor(NewStateProcessor(chainConfig, bc, engine)) var err error diff --git a/core/blockchain_test.go b/core/blockchain_test.go index 72b21034b..bbaaf5e6d 100644 --- a/core/blockchain_test.go +++ b/core/blockchain_test.go @@ -47,10 +47,13 @@ var ( // header only chain. func newCanonical(engine consensus.Engine, n int, full bool) (ethdb.Database, *BlockChain, error) { var ( - db = ethdb.NewMemDatabase() - genesis = new(Genesis).MustCommit(db) + db = ethdb.NewMemDatabase() + g = new(Genesis) ) + g.Config = params.TestnetChainConfig + genesis := g.MustCommit(db) + // Initialize a fresh chain with only a genesis block blockchain, _ := NewBlockChain(db, nil, params.AllEthashProtocolChanges, engine, vm.Config{}, nil) // Create and inject the requested chain @@ -1275,9 +1278,13 @@ func TestEIP155Transition(t *testing.T) { Config: ¶ms.ChainConfig{ChainID: big.NewInt(1), EIP155Block: big.NewInt(2), HomesteadBlock: new(big.Int)}, Alloc: GenesisAlloc{address: {Balance: funds}, deleteAddr: {Balance: new(big.Int)}}, } - genesis = gspec.MustCommit(db) ) + dexConf := new(params.DexconConfig) + dexConf.BlockReward = new(big.Int) + gspec.Config.Dexcon = dexConf + genesis := gspec.MustCommit(db) + blockchain, _ := NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil) defer blockchain.Stop() @@ -1383,8 +1390,10 @@ func TestEIP161AccountRemoval(t *testing.T) { }, Alloc: GenesisAlloc{address: {Balance: funds}}, } - genesis = gspec.MustCommit(db) ) + + gspec.Config.Dexcon = params.TestChainConfig.Dexcon + genesis := gspec.MustCommit(db) blockchain, _ := NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil) defer blockchain.Stop() @@ -1442,7 +1451,10 @@ func TestBlockchainHeaderchainReorgConsistency(t *testing.T) { engine := ethash.NewFaker() db := ethdb.NewMemDatabase() - genesis := new(Genesis).MustCommit(db) + gspec := &Genesis{ + Config: params.TestnetChainConfig, + } + genesis := gspec.MustCommit(db) blocks, _ := GenerateChain(params.TestChainConfig, genesis, engine, db, 64, func(i int, b *BlockGen) { b.SetCoinbase(common.Address{1}) }) // Generate a bunch of fork blocks, each side forking from the canonical chain @@ -1458,7 +1470,7 @@ func TestBlockchainHeaderchainReorgConsistency(t *testing.T) { // Import the canonical and fork chain side by side, verifying the current block // and current header consistency diskdb := ethdb.NewMemDatabase() - new(Genesis).MustCommit(diskdb) + gspec.MustCommit(diskdb) chain, err := NewBlockChain(diskdb, nil, params.TestChainConfig, engine, vm.Config{}, nil) if err != nil { @@ -1487,7 +1499,10 @@ func TestTrieForkGC(t *testing.T) { engine := ethash.NewFaker() db := ethdb.NewMemDatabase() - genesis := new(Genesis).MustCommit(db) + gspec := &Genesis{ + Config: params.TestnetChainConfig, + } + genesis := gspec.MustCommit(db) blocks, _ := GenerateChain(params.TestChainConfig, genesis, engine, db, 2*triesInMemory, func(i int, b *BlockGen) { b.SetCoinbase(common.Address{1}) }) // Generate a bunch of fork blocks, each side forking from the canonical chain @@ -1502,7 +1517,7 @@ func TestTrieForkGC(t *testing.T) { } // Import the canonical and fork chain side by side, forcing the trie cache to cache both diskdb := ethdb.NewMemDatabase() - new(Genesis).MustCommit(diskdb) + gspec.MustCommit(diskdb) chain, err := NewBlockChain(diskdb, nil, params.TestChainConfig, engine, vm.Config{}, nil) if err != nil { @@ -1533,7 +1548,10 @@ func TestLargeReorgTrieGC(t *testing.T) { engine := ethash.NewFaker() db := ethdb.NewMemDatabase() - genesis := new(Genesis).MustCommit(db) + gspec := &Genesis{ + Config: params.TestnetChainConfig, + } + genesis := gspec.MustCommit(db) shared, _ := GenerateChain(params.TestChainConfig, genesis, engine, db, 64, func(i int, b *BlockGen) { b.SetCoinbase(common.Address{1}) }) original, _ := GenerateChain(params.TestChainConfig, shared[len(shared)-1], engine, db, 2*triesInMemory, func(i int, b *BlockGen) { b.SetCoinbase(common.Address{2}) }) @@ -1541,7 +1559,7 @@ func TestLargeReorgTrieGC(t *testing.T) { // Import the shared chain and the original canonical one diskdb := ethdb.NewMemDatabase() - new(Genesis).MustCommit(diskdb) + gspec.MustCommit(diskdb) chain, err := NewBlockChain(diskdb, nil, params.TestChainConfig, engine, vm.Config{}, nil) if err != nil { diff --git a/core/chain_makers_test.go b/core/chain_makers_test.go index c240ed824..cb01ae0c9 100644 --- a/core/chain_makers_test.go +++ b/core/chain_makers_test.go @@ -42,7 +42,7 @@ func ExampleGenerateChain() { // Ensure that key1 has some funds in the genesis block. gspec := &Genesis{ - Config: ¶ms.ChainConfig{HomesteadBlock: new(big.Int)}, + Config: ¶ms.ChainConfig{HomesteadBlock: new(big.Int), Dexcon: params.TestChainConfig.Dexcon}, Alloc: GenesisAlloc{addr1: {Balance: big.NewInt(1000000)}}, } genesis := gspec.MustCommit(db) @@ -160,7 +160,7 @@ func ExampleGenerateChainWithRoundChange() { // This call generates a chain of 1000 blocks. The function runs for // each block and adds different features to gen based on the // block index. - chain, _ := GenerateChainWithRoundChange(gspec.Config, genesis, ethash.NewFaker(), db, 1000, func(i int, gen *BlockGen) { + chain, _ := GenerateChainWithRoundChange(gspec.Config, genesis, ethash.NewFaker(), db, 5, func(i int, gen *BlockGen) { switch i { case 0: // In block 1, addr1 sends addr2 some ether. @@ -189,7 +189,7 @@ func ExampleGenerateChainWithRoundChange() { }, nodeSet, 30) // Import the chain. This runs all block validation rules. - blockchain, _ := NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vm.Config{}) + blockchain, _ := NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil) defer blockchain.Stop() if i, err := blockchain.InsertChain(chain); err != nil { diff --git a/core/dao_test.go b/core/dao_test.go index f7b8d8576..785aab5f2 100644 --- a/core/dao_test.go +++ b/core/dao_test.go @@ -34,6 +34,7 @@ func TestDAOForkRangeExtradata(t *testing.T) { // Generate a common prefix for both pro-forkers and non-forkers db := ethdb.NewMemDatabase() gspec := new(Genesis) + gspec.Config = params.TestChainConfig genesis := gspec.MustCommit(db) prefix, _ := GenerateChain(params.TestChainConfig, genesis, ethash.NewFaker(), db, int(forkBlock.Int64()-1), func(i int, gen *BlockGen) {}) diff --git a/core/evm.go b/core/evm.go index 7e25e1d52..5e8cf9063 100644 --- a/core/evm.go +++ b/core/evm.go @@ -18,6 +18,7 @@ package core import ( "math/big" + "reflect" "sync" "github.com/dexon-foundation/dexon/common" @@ -48,6 +49,12 @@ func NewEVMContext(msg Message, header *types.Header, chain ChainContext, author } else { beneficiary = *author } + + var roundHeight sync.Map + if !reflect.ValueOf(chain).IsNil() { + roundHeight = chain.GetRoundHeightMap() + } + return vm.Context{ CanTransfer: CanTransfer, Transfer: Transfer, @@ -58,7 +65,7 @@ func NewEVMContext(msg Message, header *types.Header, chain ChainContext, author Time: new(big.Int).SetUint64(header.Time), Randomness: header.Randomness, Difficulty: new(big.Int).Set(header.Difficulty), - RoundHeight: chain.GetRoundHeightMap(), + RoundHeight: roundHeight, GasLimit: header.GasLimit, GasPrice: new(big.Int).Set(msg.GasPrice()), } diff --git a/core/genesis_test.go b/core/genesis_test.go index 48cfd0db5..288883af2 100644 --- a/core/genesis_test.go +++ b/core/genesis_test.go @@ -43,16 +43,16 @@ func TestDefaultGenesisBlock(t *testing.T) { func TestSetupGenesis(t *testing.T) { var ( - customghash = common.HexToHash("0x89c99d90b79719238d2645c7642f2c9295246e80775b38cfd162b696817fbd50") + customghash = common.HexToHash("0xb6ba0591a77fc67883bb23a0463ecacede39e63176ec65fd137466c4cda91af5") customg = Genesis{ - Config: ¶ms.ChainConfig{HomesteadBlock: big.NewInt(3)}, + Config: ¶ms.ChainConfig{HomesteadBlock: big.NewInt(3), Dexcon: params.TestChainConfig.Dexcon}, Alloc: GenesisAlloc{ {1}: {Balance: big.NewInt(1), Storage: map[common.Hash]common.Hash{{1}: {1}}}, }, } oldcustomg = customg ) - oldcustomg.Config = ¶ms.ChainConfig{HomesteadBlock: big.NewInt(2)} + oldcustomg.Config = ¶ms.ChainConfig{HomesteadBlock: big.NewInt(2), Dexcon: params.TestChainConfig.Dexcon} tests := []struct { name string fn func(ethdb.Database) (*params.ChainConfig, common.Hash, error) diff --git a/core/tx_pool_test.go b/core/tx_pool_test.go index 0ef926d1d..2cc6c7903 100644 --- a/core/tx_pool_test.go +++ b/core/tx_pool_test.go @@ -47,6 +47,7 @@ func init() { type testBlockChain struct { statedb *state.StateDB gasLimit uint64 + chainHeadFeed *event.Feed blockConfirmedFeed *event.Feed } @@ -64,6 +65,10 @@ func (bc *testBlockChain) StateAt(common.Hash) (*state.StateDB, error) { return bc.statedb, nil } +func (bc *testBlockChain) SubscribeChainHeadEvent(ch chan<- ChainHeadEvent) event.Subscription { + return bc.chainHeadFeed.Subscribe(ch) +} + func (bc *testBlockChain) SubscribeBlockConfirmedEvent(ch chan<- BlockConfirmedEvent) event.Subscription { return bc.blockConfirmedFeed.Subscribe(ch) } @@ -79,7 +84,7 @@ func pricedTransaction(nonce uint64, gaslimit uint64, gasprice *big.Int, key *ec func setupTxPool() (*TxPool, *ecdsa.PrivateKey) { statedb, _ := state.New(common.Hash{}, state.NewDatabase(ethdb.NewMemDatabase())) - blockchain := &testBlockChain{statedb, 1000000, new(event.Feed)} + blockchain := &testBlockChain{statedb, 1000000, new(event.Feed), new(event.Feed)} key, _ := crypto.GenerateKey() pool := NewTxPool(testTxPoolConfig, params.TestChainConfig, blockchain) @@ -187,7 +192,7 @@ func TestStateChangeDuringTransactionPoolReset(t *testing.T) { // setup pool with 2 transaction in it statedb.SetBalance(address, new(big.Int).SetUint64(params.Ether)) - blockchain := &testChain{&testBlockChain{statedb, 1000000000, new(event.Feed)}, address, &trigger} + blockchain := &testChain{&testBlockChain{statedb, 1000000000, new(event.Feed), new(event.Feed)}, address, &trigger} tx0 := transaction(0, 100000, key) tx1 := transaction(1, 100000, key) @@ -338,7 +343,7 @@ func TestTransactionChainFork(t *testing.T) { statedb, _ := state.New(common.Hash{}, state.NewDatabase(ethdb.NewMemDatabase())) statedb.AddBalance(addr, big.NewInt(100000000000000)) - pool.chain = &testBlockChain{statedb, 1000000, new(event.Feed)} + pool.chain = &testBlockChain{statedb, 1000000, new(event.Feed), new(event.Feed)} pool.lockedReset(nil, nil) } resetState() @@ -367,7 +372,7 @@ func TestTransactionDoubleNonce(t *testing.T) { statedb, _ := state.New(common.Hash{}, state.NewDatabase(ethdb.NewMemDatabase())) statedb.AddBalance(addr, big.NewInt(100000000000000)) - pool.chain = &testBlockChain{statedb, 1000000, new(event.Feed)} + pool.chain = &testBlockChain{statedb, 1000000, new(event.Feed), new(event.Feed)} pool.lockedReset(nil, nil) } resetState() @@ -555,7 +560,7 @@ func TestTransactionPostponing(t *testing.T) { // Create the pool to test the postponing with statedb, _ := state.New(common.Hash{}, state.NewDatabase(ethdb.NewMemDatabase())) - blockchain := &testBlockChain{statedb, 1000000, new(event.Feed)} + blockchain := &testBlockChain{statedb, 1000000, new(event.Feed), new(event.Feed)} pool := NewTxPool(testTxPoolConfig, params.TestChainConfig, blockchain) defer pool.Stop() @@ -770,7 +775,7 @@ func testTransactionQueueGlobalLimiting(t *testing.T, nolocals bool) { // Create the pool to test the limit enforcement with statedb, _ := state.New(common.Hash{}, state.NewDatabase(ethdb.NewMemDatabase())) - blockchain := &testBlockChain{statedb, 1000000, new(event.Feed)} + blockchain := &testBlockChain{statedb, 1000000, new(event.Feed), new(event.Feed)} config := testTxPoolConfig config.NoLocals = nolocals @@ -858,7 +863,7 @@ func testTransactionQueueTimeLimiting(t *testing.T, nolocals bool) { // Create the pool to test the non-expiration enforcement statedb, _ := state.New(common.Hash{}, state.NewDatabase(ethdb.NewMemDatabase())) - blockchain := &testBlockChain{statedb, 1000000, new(event.Feed)} + blockchain := &testBlockChain{statedb, 1000000, new(event.Feed), new(event.Feed)} config := testTxPoolConfig config.Lifetime = time.Second @@ -1012,7 +1017,7 @@ func TestTransactionPendingGlobalLimiting(t *testing.T) { // Create the pool to test the limit enforcement with statedb, _ := state.New(common.Hash{}, state.NewDatabase(ethdb.NewMemDatabase())) - blockchain := &testBlockChain{statedb, 1000000, new(event.Feed)} + blockchain := &testBlockChain{statedb, 1000000, new(event.Feed), new(event.Feed)} config := testTxPoolConfig config.GlobalSlots = config.AccountSlots * 10 @@ -1058,7 +1063,7 @@ func TestTransactionCapClearsFromAll(t *testing.T) { // Create the pool to test the limit enforcement with statedb, _ := state.New(common.Hash{}, state.NewDatabase(ethdb.NewMemDatabase())) - blockchain := &testBlockChain{statedb, 1000000, new(event.Feed)} + blockchain := &testBlockChain{statedb, 1000000, new(event.Feed), new(event.Feed)} config := testTxPoolConfig config.AccountSlots = 2 @@ -1092,7 +1097,7 @@ func TestTransactionPendingMinimumAllowance(t *testing.T) { // Create the pool to test the limit enforcement with statedb, _ := state.New(common.Hash{}, state.NewDatabase(ethdb.NewMemDatabase())) - blockchain := &testBlockChain{statedb, 1000000, new(event.Feed)} + blockchain := &testBlockChain{statedb, 1000000, new(event.Feed), new(event.Feed)} config := testTxPoolConfig config.GlobalSlots = 1 @@ -1140,7 +1145,7 @@ func TestTransactionPoolRepricing(t *testing.T) { // Create the pool to test the pricing enforcement with statedb, _ := state.New(common.Hash{}, state.NewDatabase(ethdb.NewMemDatabase())) - blockchain := &testBlockChain{statedb, 1000000, new(event.Feed)} + blockchain := &testBlockChain{statedb, 1000000, new(event.Feed), new(event.Feed)} pool := NewTxPool(testTxPoolConfig, params.TestChainConfig, blockchain) defer pool.Stop() @@ -1261,7 +1266,7 @@ func TestTransactionPoolRepricingKeepsLocals(t *testing.T) { // Create the pool to test the pricing enforcement with statedb, _ := state.New(common.Hash{}, state.NewDatabase(ethdb.NewMemDatabase())) - blockchain := &testBlockChain{statedb, 1000000, new(event.Feed)} + blockchain := &testBlockChain{statedb, 1000000, new(event.Feed), new(event.Feed)} pool := NewTxPool(testTxPoolConfig, params.TestChainConfig, blockchain) defer pool.Stop() @@ -1323,7 +1328,7 @@ func TestTransactionPoolUnderpricing(t *testing.T) { // Create the pool to test the pricing enforcement with statedb, _ := state.New(common.Hash{}, state.NewDatabase(ethdb.NewMemDatabase())) - blockchain := &testBlockChain{statedb, 1000000, new(event.Feed)} + blockchain := &testBlockChain{statedb, 1000000, new(event.Feed), new(event.Feed)} config := testTxPoolConfig config.GlobalSlots = 2 @@ -1429,7 +1434,7 @@ func TestTransactionPoolStableUnderpricing(t *testing.T) { // Create the pool to test the pricing enforcement with statedb, _ := state.New(common.Hash{}, state.NewDatabase(ethdb.NewMemDatabase())) - blockchain := &testBlockChain{statedb, 1000000, new(event.Feed)} + blockchain := &testBlockChain{statedb, 1000000, new(event.Feed), new(event.Feed)} config := testTxPoolConfig config.GlobalSlots = 128 @@ -1495,7 +1500,7 @@ func TestTransactionReplacement(t *testing.T) { // Create the pool to test the pricing enforcement with statedb, _ := state.New(common.Hash{}, state.NewDatabase(ethdb.NewMemDatabase())) - blockchain := &testBlockChain{statedb, 1000000, new(event.Feed)} + blockchain := &testBlockChain{statedb, 1000000, new(event.Feed), new(event.Feed)} pool := NewTxPool(testTxPoolConfig, params.TestChainConfig, blockchain) defer pool.Stop() @@ -1589,7 +1594,7 @@ func testTransactionJournaling(t *testing.T, nolocals bool) { // Create the original pool to inject transaction into the journal statedb, _ := state.New(common.Hash{}, state.NewDatabase(ethdb.NewMemDatabase())) - blockchain := &testBlockChain{statedb, 1000000, new(event.Feed)} + blockchain := &testBlockChain{statedb, 1000000, new(event.Feed), new(event.Feed)} config := testTxPoolConfig config.NoLocals = nolocals @@ -1631,7 +1636,7 @@ func testTransactionJournaling(t *testing.T, nolocals bool) { // Terminate the old pool, bump the local nonce, create a new pool and ensure relevant transaction survive pool.Stop() statedb.SetNonce(crypto.PubkeyToAddress(local.PublicKey), 1) - blockchain = &testBlockChain{statedb, 1000000, new(event.Feed)} + blockchain = &testBlockChain{statedb, 1000000, new(event.Feed), new(event.Feed)} pool = NewTxPool(config, params.TestChainConfig, blockchain) @@ -1658,7 +1663,7 @@ func testTransactionJournaling(t *testing.T, nolocals bool) { pool.Stop() statedb.SetNonce(crypto.PubkeyToAddress(local.PublicKey), 1) - blockchain = &testBlockChain{statedb, 1000000, new(event.Feed)} + blockchain = &testBlockChain{statedb, 1000000, new(event.Feed), new(event.Feed)} pool = NewTxPool(config, params.TestChainConfig, blockchain) pending, queued = pool.Stats() @@ -1687,7 +1692,7 @@ func TestTransactionStatusCheck(t *testing.T) { // Create the pool to test the status retrievals with statedb, _ := state.New(common.Hash{}, state.NewDatabase(ethdb.NewMemDatabase())) - blockchain := &testBlockChain{statedb, 1000000, new(event.Feed)} + blockchain := &testBlockChain{statedb, 1000000, new(event.Feed), new(event.Feed)} pool := NewTxPool(testTxPoolConfig, params.TestChainConfig, blockchain) defer pool.Stop() -- cgit v1.2.3