From 3dd263a9b9cb6fbff8ce0b7e5347c572b019fe26 Mon Sep 17 00:00:00 2001 From: "James C. Owens" Date: Thu, 30 Nov 2023 14:07:50 -0500 Subject: [PATCH] Implement lock for GridcoinConnectBlock to queued txindex write. --- src/gridcoin/voting/result.cpp | 17 ++++++++++--- src/main.cpp | 1 + src/main.h | 1 + src/validation.cpp | 45 ++++++++++++++++++++-------------- 4 files changed, 43 insertions(+), 21 deletions(-) diff --git a/src/gridcoin/voting/result.cpp b/src/gridcoin/voting/result.cpp index ef523a2cd3..51047e546a 100644 --- a/src/gridcoin/voting/result.cpp +++ b/src/gridcoin/voting/result.cpp @@ -864,6 +864,7 @@ class VoteCounter { CTransaction tx; + /* bool read_tx_success = false; // This is very ugly. In testing for implement poll expiration reminders PR2716, there is an issue with ReadDiskTx @@ -884,11 +885,21 @@ class VoteCounter } } - if (!read_tx_success) { - LogPrintf("WARN: %s: failed to read vote tx after 10 tries", __func__); - throw InvalidVoteError(); + if (!read_tx_success) { + LogPrintf("WARN: %s: failed to read vote tx after 10 tries", __func__); + throw InvalidVoteError(); + } + */ + + { + LOCK(cs_tx_val_commit_to_disk); + + if (!m_txdb.ReadDiskTx(txid, tx)) { + LogPrintf("WARN: %s: failed to read vote tx.", __func__); + } } + if (tx.nTime < m_poll.m_timestamp) { LogPrintf("WARN: %s: tx earlier than poll", __func__); throw InvalidVoteError(); diff --git a/src/main.cpp b/src/main.cpp index 4fbe0e2740..137a345a12 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -62,6 +62,7 @@ CCriticalSection cs_setpwalletRegistered; set setpwalletRegistered; CCriticalSection cs_main; +CCriticalSection cs_tx_val_commit_to_disk; CTxMemPool mempool; diff --git a/src/main.h b/src/main.h index 336333f4a3..5af4e3e47a 100644 --- a/src/main.h +++ b/src/main.h @@ -75,6 +75,7 @@ typedef std::unordered_map BlockMap; extern CScript COINBASE_FLAGS; extern CCriticalSection cs_main; +extern CCriticalSection cs_tx_val_commit_to_disk; extern BlockMap mapBlockIndex; extern CBlockIndex* pindexGenesisBlock; extern unsigned int nStakeMinAge; diff --git a/src/validation.cpp b/src/validation.cpp index d9b12eb165..e397f59962 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -1641,30 +1641,39 @@ bool ConnectBlock(CBlock& block, CTxDB& txdb, CBlockIndex* pindex, bool fJustChe mapQueuedChanges[hashTx] = CTxIndex(posThisTx, tx.vout.size()); } - if (IsResearchAgeEnabled(pindex->nHeight) - && !GridcoinConnectBlock(block, pindex, txdb, stake_value_in, nStakeReward, nFees)) { - return false; - } + // This lock protects the time period between the GridcoinConnectBlock, which also connects validated transaction contracts + // and causes contract handlers to fire, and the committing of the txindex changes to disk below. Any contract handlers that + // generate signals whose downstream handlers make use of transaction data on disk via leveldb (txdb) on another thread need + // to take this lock to ensure that the write to leveldb and the access of the transaction data by the signal handlers is + // appropriately serialized. + LOCK(cs_tx_val_commit_to_disk); + + if (IsResearchAgeEnabled(pindex->nHeight) + && !GridcoinConnectBlock(block, pindex, txdb, stake_value_in, nStakeReward, nFees)) + { + return false; + } - pindex->nMoneySupply = ReturnCurrentMoneySupply(pindex) + nValueOut - nValueIn; + pindex->nMoneySupply = ReturnCurrentMoneySupply(pindex) + nValueOut - nValueIn; - if (!txdb.WriteBlockIndex(CDiskBlockIndex(pindex))) - return error("%s: WriteBlockIndex for pindex failed", __func__); + if (!txdb.WriteBlockIndex(CDiskBlockIndex(pindex))) + return error("%s: WriteBlockIndex for pindex failed", __func__); - if (!OutOfSyncByAge()) - { - fColdBoot = false; - } + if (!OutOfSyncByAge()) + { + fColdBoot = false; + } - if (fJustCheck) - return true; + if (fJustCheck) + return true; - // Write queued txindex changes - for (const auto& [hash, index] : mapQueuedChanges) - { - if (!txdb.UpdateTxIndex(hash, index)) - return error("%s: UpdateTxIndex failed", __func__); + // Write queued txindex changes + for (const auto& [hash, index] : mapQueuedChanges) + { + if (!txdb.UpdateTxIndex(hash, index)) + return error("%s: UpdateTxIndex failed", __func__); + } } // Update block index on disk without changing it in memory.