diff --git a/blockdag/dag.go b/blockdag/dag.go index 79efb9eaa..a45b57110 100644 --- a/blockdag/dag.go +++ b/blockdag/dag.go @@ -686,7 +686,19 @@ func (dag *BlockDAG) newFinalityPoint(newNode *blockNode) *blockNode { return currentNode } +// NextBlockFeeTransactionWithLock prepares the fee transaction for the next mined block +// +// This function CAN'T be called with the DAG lock not held. +func (dag *BlockDAG) NextBlockFeeTransactionWithLock() (*wire.MsgTx, error) { + dag.dagLock.RLock() + defer dag.dagLock.RUnlock() + + return dag.NextBlockFeeTransaction() +} + // NextBlockFeeTransaction prepares the fee transaction for the next mined block +// +// This function MUST be called with the DAG read-lock held func (dag *BlockDAG) NextBlockFeeTransaction() (*wire.MsgTx, error) { _, txsAcceptanceData, _, err := dag.virtual.blockNode.verifyAndBuildUTXO(dag, nil, true) if err != nil { @@ -1426,13 +1438,13 @@ func (dag *BlockDAG) locateHeaders(locator BlockLocator, hashStop *daghash.Hash, return headers } -// UTXORLock locks the DAG's UTXO set for reading. -func (dag *BlockDAG) UTXORLock() { +// RLock locks the DAG's UTXO set for reading. +func (dag *BlockDAG) RLock() { dag.dagLock.RLock() } -// UTXORUnlock unlocks the DAG's UTXO set for reading. -func (dag *BlockDAG) UTXORUnlock() { +// RUnlock unlocks the DAG's UTXO set for reading. +func (dag *BlockDAG) RUnlock() { dag.dagLock.RUnlock() } diff --git a/blockdag/difficulty.go b/blockdag/difficulty.go index edf6528be..2ce47fe1f 100644 --- a/blockdag/difficulty.go +++ b/blockdag/difficulty.go @@ -164,8 +164,6 @@ func (dag *BlockDAG) calcNextRequiredDifficulty(bluestParent *blockNode, newBloc // // This function is safe for concurrent access. func (dag *BlockDAG) CalcNextRequiredDifficulty(timestamp time.Time) (uint32, error) { - dag.dagLock.Lock() difficulty, err := dag.calcNextRequiredDifficulty(dag.selectedTip(), timestamp) - dag.dagLock.Unlock() return difficulty, err } diff --git a/blockdag/versionbits.go b/blockdag/versionbits.go index c1be96491..924803f6c 100644 --- a/blockdag/versionbits.go +++ b/blockdag/versionbits.go @@ -220,9 +220,7 @@ func (dag *BlockDAG) calcNextBlockVersion(prevNode *blockNode) (int32, error) { // // This function is safe for concurrent access. func (dag *BlockDAG) CalcNextBlockVersion() (int32, error) { - dag.dagLock.Lock() version, err := dag.calcNextBlockVersion(dag.selectedTip()) - dag.dagLock.Unlock() return version, err } diff --git a/mempool/mempool.go b/mempool/mempool.go index 6a7925743..ca0e2a1d9 100644 --- a/mempool/mempool.go +++ b/mempool/mempool.go @@ -607,8 +607,8 @@ func (mp *TxPool) RemoveDoubleSpends(tx *util.Tx) { // // This function MUST be called with the mempool lock held (for writes). func (mp *TxPool) addTransaction(tx *util.Tx, height int32, fee uint64, parentsInPool []*wire.OutPoint) *TxDesc { - mp.cfg.DAG.UTXORLock() - defer mp.cfg.DAG.UTXORUnlock() + mp.cfg.DAG.RLock() + defer mp.cfg.DAG.RUnlock() // Add the transaction to the pool and mark the referenced outpoints // as spent by the pool. txD := &TxDesc{ @@ -717,8 +717,8 @@ func (mp *TxPool) FetchTransaction(txID *daghash.TxID) (*util.Tx, error) { // // This function MUST be called with the mempool lock held (for writes). func (mp *TxPool) maybeAcceptTransaction(tx *util.Tx, isNew, rateLimit, rejectDupOrphans bool) ([]*daghash.TxID, *TxDesc, error) { - mp.cfg.DAG.UTXORLock() - defer mp.cfg.DAG.UTXORUnlock() + mp.cfg.DAG.RLock() + defer mp.cfg.DAG.RUnlock() txID := tx.ID() // Don't accept the transaction if it already exists in the pool. This diff --git a/mining/mining.go b/mining/mining.go index 2992b7f8b..22ab4be65 100644 --- a/mining/mining.go +++ b/mining/mining.go @@ -384,6 +384,17 @@ func NewBlkTmplGenerator(policy *Policy, params *dagconfig.Params, // | <= policy.BlockMinSize) | | // ----------------------------------- -- func (g *BlkTmplGenerator) NewBlockTemplate(payToAddress util.Address) (*BlockTemplate, error) { + g.dag.RLock() + isDagLocked := true + // We need to read-unlock the DAG before calling CheckConnectBlockTemplate + // Therefore the deferred function is only relevant in cases where an + // error is returned before calling CheckConnectBlockTemplate + defer func() { + if isDagLocked { + g.dag.RUnlock() + } + }() + // Extend the most recently known best block. nextBlockHeight := g.dag.Height() + 1 @@ -454,7 +465,6 @@ func (g *BlkTmplGenerator) NewBlockTemplate(payToAddress util.Address) (*BlockTe log.Debugf("Considering %d transactions for inclusion to new block", len(sourceTxns)) - for _, txDesc := range sourceTxns { // A block can't have more than one coinbase or contain // non-finalized transactions. @@ -672,6 +682,10 @@ func (g *BlkTmplGenerator) NewBlockTemplate(payToAddress util.Address) (*BlockTe // chain with no issues. block := util.NewBlock(&msgBlock) block.SetHeight(nextBlockHeight) + + g.dag.RUnlock() + isDagLocked = false + if err := g.dag.CheckConnectBlockTemplate(block); err != nil { return nil, err }