diff --git a/blockmanager.go b/blockmanager.go index a296ee78..e02184cd 100644 --- a/blockmanager.go +++ b/blockmanager.go @@ -22,6 +22,7 @@ import ( "github.com/decred/dcrd/chaincfg/chainhash" "github.com/decred/dcrd/database" "github.com/decred/dcrd/dcrutil" + "github.com/decred/dcrd/fees" "github.com/decred/dcrd/mempool/v2" "github.com/decred/dcrd/wire" ) @@ -292,10 +293,51 @@ type headerNode struct { hash *chainhash.Hash } +// PeerNotifier provides an interface for server peer notifications. +type PeerNotifier interface { + // AnnounceNewTransactions generates and relays inventory vectors and + // notifies both websocket and getblocktemplate long poll clients of + // the passed transactions. + AnnounceNewTransactions(txns []*dcrutil.Tx) + + // UpdatePeerHeights updates the heights of all peers who have have + // announced the latest connected main chain block, or a recognized orphan. + UpdatePeerHeights(latestBlkHash *chainhash.Hash, latestHeight int64, updateSource *serverPeer) + + // RelayInventory relays the passed inventory vector to all connected peers + // that are not already known to have it. + RelayInventory(invVect *wire.InvVect, data interface{}, immediate bool) + + // TransactionConfirmed marks the provided single confirmation transaction + // as no longer needing rebroadcasting. + TransactionConfirmed(tx *dcrutil.Tx) +} + +// blockManangerConfig is a configuration struct for a blockManager. +type blockManagerConfig struct { + PeerNotifier PeerNotifier + TimeSource blockchain.MedianTimeSource + + // The following fields are for accessing the chain and its configuration. + Chain *blockchain.BlockChain + ChainParams *chaincfg.Params + + // The following fields provide access to the fee estimator, mempool and + // the background block template generator. + FeeEstimator *fees.Estimator + TxMemPool *mempool.TxPool + BgBlkTmplGenerator *BgBlkTmplGenerator + + // The following fields are blockManger callbacks. + NotifyWinningTickets func(*WinningTicketsNtfnData) + PruneRebroadcastInventory func() + RpcServer func() *rpcServer +} + // blockManager provides a concurrency safe block manager for handling all // incoming blocks. type blockManager struct { - server *server + cfg *blockManagerConfig started int32 shutdown int32 chain *blockchain.BlockChain @@ -368,7 +410,7 @@ func (b *blockManager) findNextHeaderCheckpoint(height int64) *chaincfg.Checkpoi if cfg.DisableCheckpoints { return nil } - checkpoints := b.server.chainParams.Checkpoints + checkpoints := b.chain.Checkpoints() if len(checkpoints) == 0 { return nil } @@ -613,7 +655,7 @@ func (b *blockManager) handleTxMsg(tmsg *txMsg) { // Process the transaction to include validation, insertion in the // memory pool, orphan handling, etc. allowOrphans := cfg.MaxOrphanTxs > 0 - acceptedTxs, err := b.server.txMemPool.ProcessTransaction(tmsg.tx, + acceptedTxs, err := b.cfg.TxMemPool.ProcessTransaction(tmsg.tx, allowOrphans, true, true) // Remove transaction from request maps. Either the mempool/chain @@ -649,7 +691,7 @@ func (b *blockManager) handleTxMsg(tmsg *txMsg) { return } - b.server.AnnounceNewTransactions(acceptedTxs) + b.cfg.PeerNotifier.AnnounceNewTransactions(acceptedTxs) } // current returns true if we believe we are synced with our peers, false if we @@ -732,7 +774,7 @@ func (b *blockManager) checkBlockForHiddenVotes(block *dcrutil.Block) { var oldTickets []*dcrutil.Tx var oldRevocations []*dcrutil.Tx oldVoteMap := make(map[chainhash.Hash]struct{}, - int(b.server.chainParams.TicketsPerBlock)) + int(b.cfg.ChainParams.TicketsPerBlock)) templateBlock := dcrutil.NewBlock(template.Block) // Add all the votes found in our template. Keep their @@ -768,12 +810,11 @@ func (b *blockManager) checkBlockForHiddenVotes(block *dcrutil.Block) { // Check the length of the reconstructed voter list for // integrity. votesTotal := len(newVotes) - if votesTotal > int(b.server.chainParams.TicketsPerBlock) { + if votesTotal > int(b.cfg.ChainParams.TicketsPerBlock) { bmgrLog.Warnf("error found while adding hidden votes "+ "from block %v to the old block template: %v max "+ "votes expected but %v votes found", block.Hash(), - int(b.server.chainParams.TicketsPerBlock), - votesTotal) + int(b.cfg.ChainParams.TicketsPerBlock), votesTotal) return } @@ -816,11 +857,9 @@ func (b *blockManager) checkBlockForHiddenVotes(block *dcrutil.Block) { } coinbase, err := createCoinbaseTx(b.chain.FetchSubsidyCache(), template.Block.Transactions[0].TxIn[0].SignatureScript, - opReturnPkScript, - int64(template.Block.Header.Height), + opReturnPkScript, int64(template.Block.Header.Height), cfg.miningAddrs[rand.Intn(len(cfg.miningAddrs))], - uint16(votesTotal), - b.server.chainParams) + uint16(votesTotal), b.cfg.ChainParams) if err != nil { bmgrLog.Errorf("failed to create coinbase while generating " + "block with extra found voters") @@ -966,7 +1005,7 @@ func (b *blockManager) handleBlockMsg(bmsg *blockMsg) { // votes in it that were hidden from the network and which // validate our parent block. We should bolt these new votes // into the tx tree stake of the old block template on parent. - svl := b.server.chainParams.StakeValidationHeight + svl := b.cfg.ChainParams.StakeValidationHeight if b.AggressiveMining && bmsg.block.Height() >= svl { b.checkBlockForHiddenVotes(bmsg.block) } @@ -974,7 +1013,7 @@ func (b *blockManager) handleBlockMsg(bmsg *blockMsg) { // Notify stake difficulty subscribers and prune invalidated // transactions. best := b.chain.BestSnapshot() - r := b.server.rpcServer + r := b.cfg.RpcServer() if r != nil { // Update registered websocket clients on the // current stake difficulty. @@ -985,9 +1024,8 @@ func (b *blockManager) handleBlockMsg(bmsg *blockMsg) { best.NextStakeDiff, }) } - b.server.txMemPool.PruneStakeTx(best.NextStakeDiff, - best.Height) - b.server.txMemPool.PruneExpiredTx() + b.cfg.TxMemPool.PruneStakeTx(best.NextStakeDiff, best.Height) + b.cfg.TxMemPool.PruneExpiredTx() // Update this peer's latest block height, for future // potential sync node candidancy. @@ -1000,9 +1038,8 @@ func (b *blockManager) handleBlockMsg(bmsg *blockMsg) { // Allow any clients performing long polling via the // getblocktemplate RPC to be notified when the new block causes // their old block template to become stale. - rpcServer := b.server.rpcServer - if rpcServer != nil { - rpcServer.gbtWorkState.NotifyBlockConnected(blockHash) + if r := b.cfg.RpcServer(); r != nil { + r.gbtWorkState.NotifyBlockConnected(blockHash) } } } @@ -1014,7 +1051,7 @@ func (b *blockManager) handleBlockMsg(bmsg *blockMsg) { if blkHashUpdate != nil && heightUpdate != 0 { bmsg.peer.UpdateLastBlockHeight(heightUpdate) if isOrphan || b.current() { - go b.server.UpdatePeerHeights(blkHashUpdate, heightUpdate, + go b.cfg.PeerNotifier.UpdatePeerHeights(blkHashUpdate, heightUpdate, bmsg.peer) } } @@ -1235,7 +1272,7 @@ func (b *blockManager) haveInventory(invVect *wire.InvVect) (bool, error) { case wire.InvTypeTx: // Ask the transaction memory pool if the transaction is known // to it in any form (main pool or orphan). - if b.server.txMemPool.HaveTransaction(&invVect.Hash) { + if b.cfg.TxMemPool.HaveTransaction(&invVect.Hash) { return true, nil } @@ -1290,7 +1327,6 @@ func (b *blockManager) handleInvMsg(imsg *invMsg) { if lastBlock != -1 && isCurrent { blkHeight, err := b.chain.BlockHeightByHash(&invVects[lastBlock].Hash) if err == nil { - imsg.peer.UpdateLastBlockHeight(blkHeight) } } @@ -1515,7 +1551,7 @@ out: // Notify stake difficulty subscribers and prune // invalidated transactions. best := b.chain.BestSnapshot() - r := b.server.rpcServer + r := b.cfg.RpcServer() if r != nil { r.ntfnMgr.NotifyStakeDifficulty( &StakeDifficultyNtfnData{ @@ -1524,9 +1560,9 @@ out: best.NextStakeDiff, }) } - b.server.txMemPool.PruneStakeTx(best.NextStakeDiff, + b.cfg.TxMemPool.PruneStakeTx(best.NextStakeDiff, best.Height) - b.server.txMemPool.PruneExpiredTx() + b.cfg.TxMemPool.PruneExpiredTx() } msg.reply <- forceReorganizationResponse{ @@ -1552,12 +1588,12 @@ out: continue } + r := b.cfg.RpcServer() onMainChain := !isOrphan && forkLen == 0 if onMainChain { // Notify stake difficulty subscribers and prune // invalidated transactions. best := b.chain.BestSnapshot() - r := b.server.rpcServer if r != nil { r.ntfnMgr.NotifyStakeDifficulty( &StakeDifficultyNtfnData{ @@ -1566,17 +1602,16 @@ out: best.NextStakeDiff, }) } - b.server.txMemPool.PruneStakeTx(best.NextStakeDiff, + b.cfg.TxMemPool.PruneStakeTx(best.NextStakeDiff, best.Height) - b.server.txMemPool.PruneExpiredTx() + b.cfg.TxMemPool.PruneExpiredTx() } // Allow any clients performing long polling via the // getblocktemplate RPC to be notified when the new block causes // their old block template to become stale. - rpcServer := b.server.rpcServer - if rpcServer != nil { - rpcServer.gbtWorkState.NotifyBlockConnected(msg.block.Hash()) + if r != nil { + r.gbtWorkState.NotifyBlockConnected(msg.block.Hash()) } msg.reply <- processBlockResponse{ @@ -1585,7 +1620,7 @@ out: } case processTransactionMsg: - acceptedTxs, err := b.server.txMemPool.ProcessTransaction(msg.tx, + acceptedTxs, err := b.cfg.TxMemPool.ProcessTransaction(msg.tx, msg.allowOrphans, msg.rateLimit, msg.allowHighFees) msg.reply <- processTransactionResponse{ acceptedTxs: acceptedTxs, @@ -1616,8 +1651,7 @@ out: msg.reply <- setParentTemplateResponse{} default: - bmgrLog.Warnf("Invalid message type in block "+ - "handler: %T", msg) + bmgrLog.Warnf("Invalid message type in block handler: %T", msg) } case <-b.quit: @@ -1667,9 +1701,10 @@ func isDoubleSpendOrDuplicateError(err error) bool { return false } -// handleNotifyMsg handles notifications from blockchain. It does things such -// as request orphan block parents and relay accepted blocks to connected peers. -func (b *blockManager) handleNotifyMsg(notification *blockchain.Notification) { +// handleBlockchainNotification handles notifications from blockchain. It does +// things such as request orphan block parents and relay accepted blocks to +// connected peers. +func (b *blockManager) handleBlockchainNotification(notification *blockchain.Notification) { switch notification.Type { // A block that intends to extend the main chain has passed all sanity and // contextual checks and the chain is believed to be current. Relay it to @@ -1686,7 +1721,7 @@ func (b *blockManager) handleNotifyMsg(notification *blockchain.Notification) { // Generate the inventory vector and relay it immediately. iv := wire.NewInvVect(wire.InvTypeBlock, block.Hash()) - b.server.RelayInventory(iv, block.MsgBlock().Header, true) + b.cfg.PeerNotifier.RelayInventory(iv, block.MsgBlock().Header, true) b.announcedBlockMtx.Lock() b.announcedBlock = block.Hash() b.announcedBlockMtx.Unlock() @@ -1738,10 +1773,10 @@ func (b *blockManager) handleNotifyMsg(notification *blockchain.Notification) { bestHeight := band.BestHeight blockHeight := int64(block.MsgBlock().Header.Height) reorgDepth := bestHeight - (blockHeight - band.ForkLen) - if b.server.rpcServer != nil && - blockHeight >= b.server.chainParams.StakeValidationHeight-1 && + if b.cfg.RpcServer() != nil && + blockHeight >= b.cfg.ChainParams.StakeValidationHeight-1 && reorgDepth < maxReorgDepthNotify && - blockHeight > b.server.chainParams.LatestCheckpointHeight() && + blockHeight > b.cfg.ChainParams.LatestCheckpointHeight() && !b.notifiedWinningTickets(blockHash) { // Obtain the winning tickets for this block. handleNotifyMsg @@ -1752,15 +1787,14 @@ func (b *blockManager) handleNotifyMsg(notification *blockchain.Notification) { bmgrLog.Errorf("Couldn't calculate winning tickets for "+ "accepted block %v: %v", blockHash, err.Error()) } else { - ntfnData := &WinningTicketsNtfnData{ + // Notify registered websocket clients of newly + // eligible tickets to vote on. + b.cfg.NotifyWinningTickets(&WinningTicketsNtfnData{ BlockHash: *blockHash, BlockHeight: blockHeight, Tickets: wt, - } + }) - // Notify registered websocket clients of newly - // eligible tickets to vote on. - b.server.rpcServer.ntfnMgr.NotifyWinningTickets(ntfnData) b.lotteryDataBroadcastMutex.Lock() b.lotteryDataBroadcast[*blockHash] = struct{}{} b.lotteryDataBroadcastMutex.Unlock() @@ -1775,32 +1809,32 @@ func (b *blockManager) handleNotifyMsg(notification *blockchain.Notification) { b.announcedBlockMtx.Unlock() if !sent { iv := wire.NewInvVect(wire.InvTypeBlock, blockHash) - b.server.RelayInventory(iv, block.MsgBlock().Header, true) + b.cfg.PeerNotifier.RelayInventory(iv, block.MsgBlock().Header, true) } // Inform the background block template generator about the accepted // block. - if b.server.bg != nil { - b.server.bg.BlockAccepted(block) + if b.cfg.BgBlkTmplGenerator != nil { + b.cfg.BgBlkTmplGenerator.BlockAccepted(block) } - if !b.server.feeEstimator.IsEnabled() { + if !b.cfg.FeeEstimator.IsEnabled() { // fee estimation can only start after we have performed an initial // sync, otherwise we'll start adding mempool transactions at the // wrong height. - b.server.feeEstimator.Enable(block.Height()) + b.cfg.FeeEstimator.Enable(block.Height()) } // A block has been connected to the main block chain. case blockchain.NTBlockConnected: blockSlice, ok := notification.Data.([]*dcrutil.Block) if !ok { - bmgrLog.Warnf("Chain connected notification is not a block slice.") + bmgrLog.Warnf("Block connected notification is not a block slice.") break } if len(blockSlice) != 2 { - bmgrLog.Warnf("Chain connected notification is wrong size slice.") + bmgrLog.Warnf("Block connected notification is wrong size slice.") break } @@ -1811,7 +1845,7 @@ func (b *blockManager) handleNotifyMsg(notification *blockchain.Notification) { // estimation. This must be done before attempting to remove // transactions from the mempool because the mempool will alert the // estimator of the txs that are leaving - b.server.feeEstimator.ProcessBlock(block) + b.cfg.FeeEstimator.ProcessBlock(block) // TODO: In the case the new tip disapproves the previous block, any // transactions the previous block contains in its regular tree which @@ -1837,22 +1871,19 @@ func (b *blockManager) handleNotifyMsg(notification *blockchain.Notification) { // // Also, in the case the RPC server is enabled, stop rebroadcasting any // transactions in the block that were setup to be rebroadcast. - txMemPool := b.server.txMemPool + txMemPool := b.cfg.TxMemPool handleConnectedBlockTxns := func(txns []*dcrutil.Tx) { for _, tx := range txns { txMemPool.RemoveTransaction(tx, false) txMemPool.RemoveDoubleSpends(tx) txMemPool.RemoveOrphan(tx) acceptedTxs := txMemPool.ProcessOrphans(tx) - b.server.AnnounceNewTransactions(acceptedTxs) + b.cfg.PeerNotifier.AnnounceNewTransactions(acceptedTxs) // Now that this block is in the blockchain, mark the // transaction (except the coinbase) as no longer needing // rebroadcasting. - if b.server.rpcServer != nil { - iv := wire.NewInvVect(wire.InvTypeTx, tx.Hash()) - b.server.RemoveRebroadcastInventory(iv) - } + b.cfg.PeerNotifier.TransactionConfirmed(tx) } } handleConnectedBlockTxns(block.Transactions()[1:]) @@ -1887,16 +1918,16 @@ func (b *blockManager) handleNotifyMsg(notification *blockchain.Notification) { } } - if r := b.server.rpcServer; r != nil { + if r := b.cfg.RpcServer(); r != nil { // Filter and update the rebroadcast inventory. - b.server.PruneRebroadcastInventory() + b.cfg.PruneRebroadcastInventory() // Notify registered websocket clients of incoming block. r.ntfnMgr.NotifyBlockConnected(block) } - if b.server.bg != nil { - b.server.bg.BlockConnected(block) + if b.cfg.BgBlkTmplGenerator != nil { + b.cfg.BgBlkTmplGenerator.BlockConnected(block) } // Stake tickets are spent or missed from the most recently connected block. @@ -1908,7 +1939,7 @@ func (b *blockManager) handleNotifyMsg(notification *blockchain.Notification) { break } - if r := b.server.rpcServer; r != nil { + if r := b.cfg.RpcServer(); r != nil { r.ntfnMgr.NotifySpentAndMissedTickets(tnd) } @@ -1921,7 +1952,7 @@ func (b *blockManager) handleNotifyMsg(notification *blockchain.Notification) { break } - if r := b.server.rpcServer; r != nil { + if r := b.cfg.RpcServer(); r != nil { r.ntfnMgr.NotifyNewTickets(tnd) } @@ -1929,12 +1960,12 @@ func (b *blockManager) handleNotifyMsg(notification *blockchain.Notification) { case blockchain.NTBlockDisconnected: blockSlice, ok := notification.Data.([]*dcrutil.Block) if !ok { - bmgrLog.Warnf("Chain disconnected notification is not a block slice.") + bmgrLog.Warnf("Block disconnected notification is not a block slice.") break } if len(blockSlice) != 2 { - bmgrLog.Warnf("Chain disconnected notification is wrong size slice.") + bmgrLog.Warnf("Block disconnected notification is wrong size slice.") break } @@ -1947,7 +1978,7 @@ func (b *blockManager) handleNotifyMsg(notification *blockchain.Notification) { // transactions and any that are now double spends from the transaction // pool. Transactions which depend on a confirmed transaction are NOT // removed recursively because they are still valid. - txMemPool := b.server.txMemPool + txMemPool := b.cfg.TxMemPool if !headerApprovesParent(&block.MsgBlock().Header) { for _, tx := range parentBlock.Transactions()[1:] { txMemPool.RemoveTransaction(tx, false) @@ -1990,17 +2021,14 @@ func (b *blockManager) handleNotifyMsg(notification *blockchain.Notification) { handleDisconnectedBlockTxns(block.Transactions()[1:]) handleDisconnectedBlockTxns(block.STransactions()) - if b.server.bg != nil { - b.server.bg.BlockDisconnected(block) + if b.cfg.BgBlkTmplGenerator != nil { + b.cfg.BgBlkTmplGenerator.BlockDisconnected(block) } - // Filter and update the rebroadcast inventory. - b.server.PruneRebroadcastInventory() - // Notify registered websocket clients. - if r := b.server.rpcServer; r != nil { + if r := b.cfg.RpcServer(); r != nil { // Filter and update the rebroadcast inventory. - b.server.PruneRebroadcastInventory() + b.cfg.PruneRebroadcastInventory() // Notify registered websocket clients. r.ntfnMgr.NotifyBlockDisconnected(block) @@ -2008,14 +2036,14 @@ func (b *blockManager) handleNotifyMsg(notification *blockchain.Notification) { // Chain reorganization has commenced. case blockchain.NTChainReorgStarted: - if b.server.bg != nil { - b.server.bg.ChainReorgStarted() + if b.cfg.BgBlkTmplGenerator != nil { + b.cfg.BgBlkTmplGenerator.ChainReorgStarted() } // Chain reorganization has concluded. case blockchain.NTChainReorgDone: - if b.server.bg != nil { - b.server.bg.ChainReorgDone() + if b.cfg.BgBlkTmplGenerator != nil { + b.cfg.BgBlkTmplGenerator.ChainReorgDone() } // The blockchain is reorganizing. @@ -2027,7 +2055,7 @@ func (b *blockManager) handleNotifyMsg(notification *blockchain.Notification) { } // Notify registered websocket clients. - if r := b.server.rpcServer; r != nil { + if r := b.cfg.RpcServer(); r != nil { r.ntfnMgr.NotifyReorganization(rd) } @@ -2194,7 +2222,7 @@ func (b *blockManager) requestFromPeer(p *serverPeer, blocks, txs []*chainhash.H // Ask the transaction memory pool if the transaction is known // to it in any form (main pool or orphan). - if b.server.txMemPool.HaveTransaction(vh) { + if b.cfg.TxMemPool.HaveTransaction(vh) { continue } @@ -2357,9 +2385,10 @@ func (b *blockManager) SetParentTemplate(bt *BlockTemplate) { // newBlockManager returns a new Decred block manager. // Use Start to begin processing asynchronous block and inv updates. -func newBlockManager(s *server, indexManager blockchain.IndexManager, interrupt <-chan struct{}) (*blockManager, error) { +func newBlockManager(config *blockManagerConfig) (*blockManager, error) { bm := blockManager{ - server: s, + cfg: config, + chain: config.Chain, rejectedTxns: make(map[chainhash.Hash]struct{}), requestedTxns: make(map[chainhash.Hash]struct{}), requestedBlocks: make(map[chainhash.Hash]struct{}), @@ -2370,20 +2399,6 @@ func newBlockManager(s *server, indexManager blockchain.IndexManager, interrupt quit: make(chan struct{}), } - // Create a new block chain instance with the appropriate configuration. - var err error - bm.chain, err = blockchain.New(&blockchain.Config{ - DB: s.db, - Interrupt: interrupt, - ChainParams: s.chainParams, - TimeSource: s.timeSource, - Notifications: bm.handleNotifyMsg, - SigCache: s.sigCache, - IndexManager: indexManager, - }) - if err != nil { - return nil, err - } best := bm.chain.BestSnapshot() bm.chain.DisableCheckpoints(cfg.DisableCheckpoints) if !cfg.DisableCheckpoints { @@ -2398,7 +2413,7 @@ func newBlockManager(s *server, indexManager blockchain.IndexManager, interrupt // Dump the blockchain here if asked for it, and quit. if cfg.DumpBlockchain != "" { - err = dumpBlockChain(bm.chain, best.Height) + err := dumpBlockChain(bm.chain, best.Height) if err != nil { return nil, err } diff --git a/mining.go b/mining.go index 6d8d2d62..08646c28 100644 --- a/mining.go +++ b/mining.go @@ -776,8 +776,8 @@ func deepCopyBlockTemplate(blockTemplate *BlockTemplate) *BlockTemplate { // miner. // Safe for concurrent access. func handleTooFewVoters(subsidyCache *blockchain.SubsidyCache, nextHeight int64, miningAddress dcrutil.Address, bm *blockManager) (*BlockTemplate, error) { - timeSource := bm.server.timeSource - stakeValidationHeight := bm.server.chainParams.StakeValidationHeight + timeSource := bm.cfg.TimeSource + stakeValidationHeight := bm.cfg.ChainParams.StakeValidationHeight curTemplate := bm.GetCurrentTemplate() // Check to see if we've fallen off the chain, for example if a @@ -807,7 +807,7 @@ func handleTooFewVoters(subsidyCache *blockchain.SubsidyCache, nextHeight int64, // If we're on testnet, the time since this last block // listed as the parent must be taken into consideration. - if bm.server.chainParams.ReduceMinDifficulty { + if bm.cfg.ChainParams.ReduceMinDifficulty { parentHash := cptCopy.Block.Header.PrevBlock requiredDifficulty, err := @@ -876,13 +876,9 @@ func handleTooFewVoters(subsidyCache *blockchain.SubsidyCache, nextHeight int64, if err != nil { return nil, err } - coinbaseTx, err := createCoinbaseTx(subsidyCache, - coinbaseScript, - opReturnPkScript, - topBlock.Height(), - miningAddress, - topBlock.MsgBlock().Header.Voters, - bm.server.chainParams) + coinbaseTx, err := createCoinbaseTx(subsidyCache, coinbaseScript, + opReturnPkScript, topBlock.Height(), miningAddress, + topBlock.MsgBlock().Header.Voters, bm.cfg.ChainParams) if err != nil { return nil, err } @@ -901,7 +897,7 @@ func handleTooFewVoters(subsidyCache *blockchain.SubsidyCache, nextHeight int64, // If we're on testnet, the time since this last block // listed as the parent must be taken into consideration. - if bm.server.chainParams.ReduceMinDifficulty { + if bm.cfg.ChainParams.ReduceMinDifficulty { parentHash := topBlock.MsgBlock().Header.PrevBlock requiredDifficulty, err := diff --git a/rpcserver.go b/rpcserver.go index f1a77608..90cdf04b 100644 --- a/rpcserver.go +++ b/rpcserver.go @@ -1392,7 +1392,7 @@ func handleEstimateStakeDiff(s *rpcServer, cmd interface{}, closeChan <-chan str c := cmd.(*dcrjson.EstimateStakeDiffCmd) // Minimum possible stake difficulty. - chain := s.server.blockManager.chain + chain := s.server.chain min, err := chain.EstimateNextStakeDifficulty(0, false) if err != nil { return nil, rpcInternalError(err.Error(), "Could not "+ @@ -1409,7 +1409,7 @@ func handleEstimateStakeDiff(s *rpcServer, cmd interface{}, closeChan <-chan str // The expected stake difficulty. Average the number of fresh stake // since the last retarget to get the number of tickets per block, // then use that to estimate the next stake difficulty. - bestHeight := s.server.blockManager.chain.BestSnapshot().Height + bestHeight := chain.BestSnapshot().Height lastAdjustment := (bestHeight / activeNetParams.StakeDiffWindowSize) * activeNetParams.StakeDiffWindowSize nextAdjustment := ((bestHeight / activeNetParams.StakeDiffWindowSize) + @@ -1525,7 +1525,7 @@ func handleExistsMissedTickets(s *rpcServer, cmd interface{}, closeChan <-chan s return nil, err } - exists := s.server.blockManager.chain.CheckMissedTickets(hashes) + exists := s.server.chain.CheckMissedTickets(hashes) if len(exists) != len(hashes) { return nil, rpcInvalidError("Invalid missed ticket count "+ "got %v, want %v", len(exists), len(hashes)) @@ -1551,7 +1551,7 @@ func handleExistsExpiredTickets(s *rpcServer, cmd interface{}, closeChan <-chan return nil, err } - exists := s.server.blockManager.chain.CheckExpiredTickets(hashes) + exists := s.server.chain.CheckExpiredTickets(hashes) if len(exists) != len(hashes) { return nil, rpcInvalidError("Invalid expired ticket count "+ "got %v, want %v", len(exists), len(hashes)) @@ -1577,7 +1577,7 @@ func handleExistsLiveTicket(s *rpcServer, cmd interface{}, closeChan <-chan stru return nil, rpcDecodeHexError(c.TxHash) } - return s.server.blockManager.chain.CheckLiveTicket(*hash), nil + return s.server.chain.CheckLiveTicket(*hash), nil } // handleExistsLiveTickets implements the existslivetickets command. @@ -1589,7 +1589,7 @@ func handleExistsLiveTickets(s *rpcServer, cmd interface{}, closeChan <-chan str return nil, err } - exists := s.server.blockManager.chain.CheckLiveTickets(hashes) + exists := s.server.chain.CheckLiveTickets(hashes) if len(exists) != len(hashes) { return nil, rpcInvalidError("Invalid live ticket count got "+ "%v, want %v", len(exists), len(hashes)) @@ -1809,7 +1809,7 @@ func handleGetBlock(s *rpcServer, cmd interface{}, closeChan <-chan struct{}) (i if err != nil { return nil, rpcDecodeHexError(c.Hash) } - blk, err := s.server.blockManager.chain.BlockByHash(hash) + blk, err := s.server.chain.BlockByHash(hash) if err != nil { return nil, &dcrjson.RPCError{ Code: dcrjson.ErrRPCBlockNotFound, @@ -2307,7 +2307,7 @@ func (state *gbtWorkState) updateBlockTemplate(s *rpcServer, useCoinbaseValue bo // generated. var msgBlock *wire.MsgBlock var targetDifficulty string - best := s.server.blockManager.chain.BestSnapshot() + best := s.server.chain.BestSnapshot() latestHash := best.Hash template := state.template if template == nil || state.prevHash == nil || @@ -2795,7 +2795,7 @@ func handleGetBlockTemplateRequest(s *rpcServer, request *dcrjson.TemplateReques } // No point in generating or accepting work before the chain is synced. - bestHeight := s.server.blockManager.chain.BestSnapshot().Height + bestHeight := s.server.chain.BestSnapshot().Height if bestHeight != 0 && !s.server.blockManager.IsCurrent() { return nil, &dcrjson.RPCError{ Code: dcrjson.ErrRPCClientInInitialDownload, @@ -2944,13 +2944,13 @@ func handleGetBlockTemplateProposal(s *rpcServer, request *dcrjson.TemplateReque block := dcrutil.NewBlock(&msgBlock) // Ensure the block is building from the expected previous block. - expectedPrevHash := &s.server.blockManager.chain.BestSnapshot().Hash + expectedPrevHash := &s.server.chain.BestSnapshot().Hash prevHash := &block.MsgBlock().Header.PrevBlock if *expectedPrevHash != *prevHash { return "bad-prevblk", nil } - err = s.server.blockManager.chain.CheckConnectBlockTemplate(block) + err = s.server.chain.CheckConnectBlockTemplate(block) if err != nil { if _, ok := err.(blockchain.RuleError); !ok { errStr := fmt.Sprintf("Failed to process block "+ @@ -3164,7 +3164,7 @@ func handleGetHeaders(s *rpcServer, cmd interface{}, closeChan <-chan struct{}) locators[i] = &blockLocators[i] } - chain := s.server.blockManager.chain + chain := s.server.chain headers := chain.LocateHeaders(locators, &hashStop) // Return the serialized block headers as hex-encoded strings. @@ -4040,7 +4040,7 @@ func handleGetWorkRequest(s *rpcServer) (interface{}, error) { // it has been at least one minute since the last template was // generated. lastTxUpdate := s.server.txMemPool.LastUpdated() - best := s.server.blockManager.chain.BestSnapshot() + best := s.server.chain.BestSnapshot() msgBlock := state.msgBlock // The current code pulls down a new template every second, however @@ -4338,7 +4338,7 @@ func handleGetWork(s *rpcServer, cmd interface{}, closeChan <-chan struct{}) (in } // No point in generating or accepting work before the chain is synced. - bestHeight := s.server.blockManager.chain.BestSnapshot().Height + bestHeight := s.server.chain.BestSnapshot().Height if bestHeight != 0 && !s.server.blockManager.IsCurrent() { return nil, &dcrjson.RPCError{ Code: dcrjson.ErrRPCClientInInitialDownload, @@ -4402,7 +4402,7 @@ func handleHelp(s *rpcServer, cmd interface{}, closeChan <-chan struct{}) (inter // handleLiveTickets implements the livetickets command. func handleLiveTickets(s *rpcServer, cmd interface{}, closeChan <-chan struct{}) (interface{}, error) { - lt, err := s.server.blockManager.chain.LiveTickets() + lt, err := s.server.chain.LiveTickets() if err != nil { return nil, rpcInternalError("Could not get live tickets "+ err.Error(), "") @@ -4418,7 +4418,7 @@ func handleLiveTickets(s *rpcServer, cmd interface{}, closeChan <-chan struct{}) // handleMissedTickets implements the missedtickets command. func handleMissedTickets(s *rpcServer, cmd interface{}, closeChan <-chan struct{}) (interface{}, error) { - mt, err := s.server.blockManager.chain.MissedTickets() + mt, err := s.server.chain.MissedTickets() if err != nil { return nil, rpcInternalError("Could not get missed tickets "+ err.Error(), "") @@ -4447,8 +4447,8 @@ func handlePing(s *rpcServer, cmd interface{}, closeChan <-chan struct{}) (inter // handleRebroadcastMissed implements the rebroadcastmissed command. func handleRebroadcastMissed(s *rpcServer, cmd interface{}, closeChan <-chan struct{}) (interface{}, error) { - best := s.server.blockManager.chain.BestSnapshot() - mt, err := s.server.blockManager.chain.MissedTickets() + best := s.server.chain.BestSnapshot() + mt, err := s.server.chain.MissedTickets() if err != nil { return nil, rpcInternalError("Could not get missed tickets "+ err.Error(), "") @@ -4476,7 +4476,7 @@ func handleRebroadcastMissed(s *rpcServer, cmd interface{}, closeChan <-chan str // handleRebroadcastWinners implements the rebroadcastwinners command. func handleRebroadcastWinners(s *rpcServer, cmd interface{}, closeChan <-chan struct{}) (interface{}, error) { - bestHeight := s.server.blockManager.chain.BestSnapshot().Height + bestHeight := s.server.chain.BestSnapshot().Height blocks, err := s.server.blockManager.TipGeneration() if err != nil { return nil, rpcInternalError("Could not get generation "+ @@ -4485,7 +4485,7 @@ func handleRebroadcastWinners(s *rpcServer, cmd interface{}, closeChan <-chan st for i := range blocks { winningTickets, _, _, err := - s.server.blockManager.chain.LotteryDataForBlock(&blocks[i]) + s.server.chain.LotteryDataForBlock(&blocks[i]) if err != nil { return nil, rpcInternalError("Lottery data for block "+ "failed: "+err.Error(), "") @@ -5051,7 +5051,7 @@ func handleSendRawTransaction(s *rpcServer, cmd interface{}, closeChan <-chan st // JSON-RPC error is returned to the client with the // deserialization error code (to match bitcoind behavior). if rErr, ok := err.(mempool.RuleError); ok { - err = fmt.Errorf("Rejected transaction %v: %v", tx.Hash(), + err = fmt.Errorf("rejected transaction %v: %v", tx.Hash(), err) rpcsLog.Debugf("%v", err) txRuleErr, ok := rErr.Err.(mempool.TxRuleError) @@ -5376,7 +5376,7 @@ func ticketFeeInfoForRange(s *rpcServer, start int64, end int64, txType stake.Tx func handleTicketFeeInfo(s *rpcServer, cmd interface{}, closeChan <-chan struct{}) (interface{}, error) { c := cmd.(*dcrjson.TicketFeeInfoCmd) - bestHeight := s.server.blockManager.chain.BestSnapshot().Height + bestHeight := s.server.chain.BestSnapshot().Height // Memory pool first. feeInfoMempool := feeInfoForMempool(s, stake.TxTypeSStx) @@ -5462,10 +5462,9 @@ func handleTicketsForAddress(s *rpcServer, cmd interface{}, closeChan <-chan str return nil, rpcInvalidError("Invalid address: %v", err) } - tickets, err := s.server.blockManager.chain.TicketsWithAddress(addr) + tickets, err := s.server.chain.TicketsWithAddress(addr) if err != nil { - return nil, rpcInternalError(err.Error(), - "Could not obtain tickets") + return nil, rpcInternalError(err.Error(), "could not obtain tickets") } ticketStrings := make([]string, len(tickets)) @@ -5487,15 +5486,14 @@ func handleTicketVWAP(s *rpcServer, cmd interface{}, closeChan <-chan struct{}) // The default VWAP is for the past WorkDiffWindows * WorkDiffWindowSize // many blocks. - bestHeight := s.server.blockManager.chain.BestSnapshot().Height + bestHeight := s.server.chain.BestSnapshot().Height var start uint32 if c.Start == nil { toEval := activeNetParams.WorkDiffWindows * activeNetParams.WorkDiffWindowSize startI64 := bestHeight - toEval - // Use 1 as the first block if there aren't - // enough blocks. + // Use 1 as the first block if there aren't enough blocks. if startI64 <= 0 { start = 1 } else { @@ -5544,7 +5542,7 @@ func handleTicketVWAP(s *rpcServer, cmd interface{}, closeChan <-chan struct{}) func handleTxFeeInfo(s *rpcServer, cmd interface{}, closeChan <-chan struct{}) (interface{}, error) { c := cmd.(*dcrjson.TxFeeInfoCmd) - bestHeight := s.server.blockManager.chain.BestSnapshot().Height + bestHeight := s.server.chain.BestSnapshot().Height // Memory pool first. feeInfoMempool := feeInfoForMempool(s, stake.TxTypeRegular) @@ -6432,7 +6430,7 @@ func newRPCServer(listenAddrs []string, generator *BlkTmplGenerator, s *server) rpc := rpcServer{ server: s, generator: generator, - chain: s.blockManager.chain, + chain: s.chain, statusLines: make(map[int]string), workState: newWorkState(), templatePool: make(map[[merkleRootPairSize]byte]*workStateBlockInfo), diff --git a/rpcwebsocket.go b/rpcwebsocket.go index de49c98c..d1096af5 100644 --- a/rpcwebsocket.go +++ b/rpcwebsocket.go @@ -2190,7 +2190,7 @@ func handleRescan(wsc *wsClient, icmd interface{}) (interface{}, error) { // Iterate over each block in the request and rescan. When a block // contains relevant transactions, add it to the response. - bc := wsc.server.server.blockManager.chain + bc := wsc.server.chain var lastBlockHash *chainhash.Hash for i := range blockHashes { block, err := bc.BlockByHash(&blockHashes[i]) diff --git a/server.go b/server.go index e404c70d..b2d4664d 100644 --- a/server.go +++ b/server.go @@ -194,6 +194,7 @@ type server struct { rpcServer *rpcServer blockManager *blockManager bg *BgBlkTmplGenerator + chain *blockchain.BlockChain txMemPool *mempool.TxPool feeEstimator *fees.Estimator cpuMiner *CPUMiner @@ -271,7 +272,7 @@ func newServerPeer(s *server, isPersistent bool) *serverPeer { // newestBlock returns the current best block hash and height using the format // required by the configuration for the peer package. func (sp *serverPeer) newestBlock() (*chainhash.Hash, int64, error) { - best := sp.server.blockManager.chain.BestSnapshot() + best := sp.server.chain.BestSnapshot() return &best.Hash, best.Height, nil } @@ -532,7 +533,7 @@ func (sp *serverPeer) OnGetMiningState(p *peer.Peer, msg *wire.MsgGetMiningState // Access the block manager and get the list of best blocks to mine on. bm := sp.server.blockManager mp := sp.server.txMemPool - best := bm.chain.BestSnapshot() + best := sp.server.chain.BestSnapshot() // Send out blank mining states if it's early in the blockchain. if best.Height < activeNetParams.StakeValidationHeight-1 { @@ -559,7 +560,7 @@ func (sp *serverPeer) OnGetMiningState(p *peer.Peer, msg *wire.MsgGetMiningState // per mining state message. There is nothing to send when there are no // eligible blocks. blockHashes := SortParentsByVotes(mp, best.Hash, children, - bm.server.chainParams) + bm.cfg.ChainParams) numBlocks := len(blockHashes) if numBlocks == 0 { return @@ -777,7 +778,7 @@ func (sp *serverPeer) OnGetBlocks(p *peer.Peer, msg *wire.MsgGetBlocks) { // Use the block after the genesis block if no other blocks in the // provided locator are known. This does mean the client will start // over with the genesis block if unknown block locators are provided. - chain := sp.server.blockManager.chain + chain := sp.server.chain hashList := chain.LocateBlocks(msg.BlockLocatorHashes, &msg.HashStop, wire.MaxBlocksPerMsg) @@ -818,7 +819,7 @@ func (sp *serverPeer) OnGetHeaders(p *peer.Peer, msg *wire.MsgGetHeaders) { // Use the block after the genesis block if no other blocks in the // provided locator are known. This does mean the client will start // over with the genesis block if unknown block locators are provided. - chain := sp.server.blockManager.chain + chain := sp.server.chain headers := chain.LocateHeaders(msg.BlockLocatorHashes, &msg.HashStop) // Send found headers to the requesting peer. @@ -892,7 +893,7 @@ func (sp *serverPeer) OnGetCFilter(p *peer.Peer, msg *wire.MsgGetCFilter) { // block was disconnected, or this has always been a sidechain block) build // the filter on the spot. if len(filterBytes) == 0 { - block, err := sp.server.blockManager.chain.BlockByHash(&msg.BlockHash) + block, err := sp.server.chain.BlockByHash(&msg.BlockHash) if err != nil { peerLog.Errorf("OnGetCFilter: failed to fetch non-mainchain "+ "block %v: %v", &msg.BlockHash, err) @@ -961,7 +962,7 @@ func (sp *serverPeer) OnGetCFHeaders(p *peer.Peer, msg *wire.MsgGetCFHeaders) { // Use the block after the genesis block if no other blocks in the provided // locator are known. This does mean the served filter headers will start // over at the genesis block if unknown block locators are provided. - chain := sp.server.blockManager.chain + chain := sp.server.chain hashList := chain.LocateBlocks(msg.BlockLocatorHashes, &msg.HashStop, wire.MaxCFHeadersPerMsg) if len(hashList) == 0 { @@ -1158,11 +1159,11 @@ func (s *server) PruneRebroadcastInventory() { // both websocket and getblocktemplate long poll clients of the passed // transactions. This function should be called whenever new transactions // are added to the mempool. -func (s *server) AnnounceNewTransactions(newTxs []*dcrutil.Tx) { +func (s *server) AnnounceNewTransactions(txns []*dcrutil.Tx) { // Generate and relay inventory vectors for all newly accepted // transactions into the memory pool due to the original being // accepted. - for _, tx := range newTxs { + for _, tx := range txns { // Generate the inventory vector and relay it. iv := wire.NewInvVect(wire.InvTypeTx, tx.Hash()) s.RelayInventory(iv, tx, false) @@ -1173,12 +1174,21 @@ func (s *server) AnnounceNewTransactions(newTxs []*dcrutil.Tx) { // Potentially notify any getblocktemplate long poll clients // about stale block templates due to the new transaction. - s.rpcServer.gbtWorkState.NotifyMempoolTx( - s.txMemPool.LastUpdated()) + s.rpcServer.gbtWorkState.NotifyMempoolTx(s.txMemPool.LastUpdated()) } } } +// TransactionConfirmed marks the provided single confirmation transaction as +// no longer needing rebroadcasting. +func (s *server) TransactionConfirmed(tx *dcrutil.Tx) { + // Rebroadcasting is only necessary when the RPC server is active. + if s.rpcServer != nil { + iv := wire.NewInvVect(wire.InvTypeTx, tx.Hash()) + s.RemoveRebroadcastInventory(iv) + } +} + // pushTxMsg sends a tx message for the provided transaction hash to the // connected peer. An error is returned if the transaction hash is not known. func (s *server) pushTxMsg(sp *serverPeer, hash *chainhash.Hash, doneChan chan<- struct{}, waitChan <-chan struct{}) error { @@ -1212,7 +1222,7 @@ func (s *server) pushTxMsg(sp *serverPeer, hash *chainhash.Hash, doneChan chan<- // pushBlockMsg sends a block message for the provided block hash to the // connected peer. An error is returned if the block hash is not known. func (s *server) pushBlockMsg(sp *serverPeer, hash *chainhash.Hash, doneChan chan<- struct{}, waitChan <-chan struct{}) error { - block, err := sp.server.blockManager.chain.BlockByHash(hash) + block, err := sp.server.chain.BlockByHash(hash) if err != nil { peerLog.Tracef("Unable to fetch requested block hash %v: %v", hash, err) @@ -1244,7 +1254,7 @@ func (s *server) pushBlockMsg(sp *serverPeer, hash *chainhash.Hash, doneChan cha // to trigger it to issue another getblocks message for the next // batch of inventory. if sendInv { - best := sp.server.blockManager.chain.BestSnapshot() + best := sp.server.chain.BestSnapshot() invMsg := wire.NewMsgInvSizeHint(1) iv := wire.NewInvVect(wire.InvTypeBlock, &best.Hash) invMsg.AddInvVect(iv) @@ -2016,9 +2026,9 @@ out: delete(pendingInvs, *msg) case broadcastPruneInventory: - best := s.blockManager.chain.BestSnapshot() + best := s.chain.BestSnapshot() nextStakeDiff, err := - s.blockManager.chain.CalcNextRequiredStakeDifficulty() + s.chain.CalcNextRequiredStakeDifficulty() if err != nil { srvrLog.Errorf("Failed to get next stake difficulty: %v", err) @@ -2058,7 +2068,7 @@ out: // ticket has been revived. if txType == stake.TxTypeSSRtx { refSStxHash := tx.MsgTx().TxIn[0].PreviousOutPoint.Hash - if !s.blockManager.chain.CheckLiveTicket(refSStxHash) { + if !s.chain.CheckLiveTicket(refSStxHash) { delete(pendingInvs, iv) srvrLog.Debugf("Pending revocation broadcast "+ "inventory for tx %v removed. "+ @@ -2534,11 +2544,24 @@ func newServer(listenAddrs []string, db database.DB, chainParams *chaincfg.Param if len(indexes) > 0 { indexManager = indexers.NewManager(db, indexes, chainParams) } - bm, err := newBlockManager(&s, indexManager, interrupt) + + // Create a new block chain instance with the appropriate configuration. + s.chain, err = blockchain.New(&blockchain.Config{ + DB: s.db, + Interrupt: interrupt, + ChainParams: s.chainParams, + TimeSource: s.timeSource, + Notifications: func(notification *blockchain.Notification) { + if s.blockManager != nil { + s.blockManager.handleBlockchainNotification(notification) + } + }, + SigCache: s.sigCache, + IndexManager: indexManager, + }) if err != nil { return nil, err } - s.blockManager = bm txC := mempool.Config{ Policy: mempool.Policy{ @@ -2552,23 +2575,23 @@ func newServer(listenAddrs []string, db database.DB, chainParams *chaincfg.Param MinRelayTxFee: cfg.minRelayTxFee, AllowOldVotes: cfg.AllowOldVotes, StandardVerifyFlags: func() (txscript.ScriptFlags, error) { - return standardScriptVerifyFlags(bm.chain) + return standardScriptVerifyFlags(s.chain) }, - AcceptSequenceLocks: bm.chain.IsFixSeqLocksAgendaActive, + AcceptSequenceLocks: s.chain.IsFixSeqLocksAgendaActive, }, ChainParams: chainParams, NextStakeDifficulty: func() (int64, error) { - return bm.chain.BestSnapshot().NextStakeDiff, nil + return s.chain.BestSnapshot().NextStakeDiff, nil }, - FetchUtxoView: bm.chain.FetchUtxoView, - BlockByHash: bm.chain.BlockByHash, - BestHash: func() *chainhash.Hash { return &bm.chain.BestSnapshot().Hash }, - BestHeight: func() int64 { return bm.chain.BestSnapshot().Height }, - CalcSequenceLock: bm.chain.CalcSequenceLock, - SubsidyCache: bm.chain.FetchSubsidyCache(), + FetchUtxoView: s.chain.FetchUtxoView, + BlockByHash: s.chain.BlockByHash, + BestHash: func() *chainhash.Hash { return &s.chain.BestSnapshot().Hash }, + BestHeight: func() int64 { return s.chain.BestSnapshot().Height }, + CalcSequenceLock: s.chain.CalcSequenceLock, + SubsidyCache: s.chain.FetchSubsidyCache(), SigCache: s.sigCache, PastMedianTime: func() time.Time { - return bm.chain.BestSnapshot().MedianTime + return s.chain.BestSnapshot().MedianTime }, AddrIndex: s.addrIndex, ExistsAddrIndex: s.existsAddrIndex, @@ -2581,6 +2604,27 @@ func newServer(listenAddrs []string, db database.DB, chainParams *chaincfg.Param }, } s.txMemPool = mempool.New(&txC) + s.blockManager, err = newBlockManager(&blockManagerConfig{ + PeerNotifier: &s, + Chain: s.chain, + ChainParams: s.chainParams, + TimeSource: s.timeSource, + FeeEstimator: s.feeEstimator, + TxMemPool: s.txMemPool, + BgBlkTmplGenerator: s.bg, + NotifyWinningTickets: func(wtnd *WinningTicketsNtfnData) { + if s.rpcServer != nil { + s.rpcServer.ntfnMgr.NotifyWinningTickets(wtnd) + } + }, + PruneRebroadcastInventory: s.PruneRebroadcastInventory, + RpcServer: func() *rpcServer { + return s.rpcServer + }, + }) + if err != nil { + return nil, err + } // Create the mining policy and block template generator based on the // configuration options. @@ -2594,7 +2638,7 @@ func newServer(listenAddrs []string, db database.DB, chainParams *chaincfg.Param TxMinFreeFee: cfg.minRelayTxFee, } tg := newBlkTmplGenerator(&policy, s.txMemPool, s.timeSource, s.sigCache, - s.chainParams, bm.chain, bm) + s.chainParams, s.chain, s.blockManager) // Create the background block template generator if the config has a // mining address. @@ -2607,9 +2651,9 @@ func newServer(listenAddrs []string, db database.DB, chainParams *chaincfg.Param PermitConnectionlessMining: cfg.SimNet, BlockTemplateGenerator: tg, MiningAddrs: cfg.miningAddrs, - ProcessBlock: bm.ProcessBlock, + ProcessBlock: s.blockManager.ProcessBlock, ConnectedCount: s.ConnectedCount, - IsCurrent: bm.IsCurrent, + IsCurrent: s.blockManager.IsCurrent, }) // Only setup a function to return new addresses to connect to when