mirror of
https://github.com/dashpay/dash.git
synced 2024-12-26 12:32:48 +01:00
fix: follow up backport bitcoin#16426
This commit is contained in:
parent
d5269332a4
commit
3f491fa7cb
@ -139,7 +139,7 @@ public:
|
|||||||
explicit ChainImpl(NodeContext& node) : m_node(node) {}
|
explicit ChainImpl(NodeContext& node) : m_node(node) {}
|
||||||
std::optional<int> getHeight() override
|
std::optional<int> getHeight() override
|
||||||
{
|
{
|
||||||
LOCK(cs_main);
|
LOCK(::cs_main);
|
||||||
int height = ::ChainActive().Height();
|
int height = ::ChainActive().Height();
|
||||||
if (height >= 0) {
|
if (height >= 0) {
|
||||||
return height;
|
return height;
|
||||||
@ -148,7 +148,7 @@ public:
|
|||||||
}
|
}
|
||||||
std::optional<int> getBlockHeight(const uint256& hash) override
|
std::optional<int> getBlockHeight(const uint256& hash) override
|
||||||
{
|
{
|
||||||
LOCK(cs_main);
|
LOCK(::cs_main);
|
||||||
CBlockIndex* block = LookupBlockIndex(hash);
|
CBlockIndex* block = LookupBlockIndex(hash);
|
||||||
if (block && ::ChainActive().Contains(block)) {
|
if (block && ::ChainActive().Contains(block)) {
|
||||||
return block->nHeight;
|
return block->nHeight;
|
||||||
@ -157,7 +157,7 @@ public:
|
|||||||
}
|
}
|
||||||
uint256 getBlockHash(int height) override
|
uint256 getBlockHash(int height) override
|
||||||
{
|
{
|
||||||
LOCK(cs_main);
|
LOCK(::cs_main);
|
||||||
CBlockIndex* block = ::ChainActive()[height];
|
CBlockIndex* block = ::ChainActive()[height];
|
||||||
assert(block != nullptr);
|
assert(block != nullptr);
|
||||||
return block->GetBlockHash();
|
return block->GetBlockHash();
|
||||||
|
@ -54,7 +54,7 @@ class Handler;
|
|||||||
//! internal workings of the bitcoin node, and not being very convenient to use.
|
//! internal workings of the bitcoin node, and not being very convenient to use.
|
||||||
//! Chain methods should be cleaned up and simplified over time. Examples:
|
//! Chain methods should be cleaned up and simplified over time. Examples:
|
||||||
//!
|
//!
|
||||||
//! * The initMessage() and showProgress() methods which the wallet uses to send
|
//! * The initMessages() and showProgress() methods which the wallet uses to send
|
||||||
//! notifications to the GUI should go away when GUI and wallet can directly
|
//! notifications to the GUI should go away when GUI and wallet can directly
|
||||||
//! communicate with each other without going through the node
|
//! communicate with each other without going through the node
|
||||||
//! (https://github.com/bitcoin/bitcoin/pull/15288#discussion_r253321096).
|
//! (https://github.com/bitcoin/bitcoin/pull/15288#discussion_r253321096).
|
||||||
|
@ -317,7 +317,7 @@ public:
|
|||||||
WalletValueMap value_map,
|
WalletValueMap value_map,
|
||||||
WalletOrderForm order_form) override
|
WalletOrderForm order_form) override
|
||||||
{
|
{
|
||||||
LOCK2(m_wallet->cs_wallet, cs_main);
|
LOCK(m_wallet->cs_wallet);
|
||||||
ReserveDestination m_dest(m_wallet.get());
|
ReserveDestination m_dest(m_wallet.get());
|
||||||
m_wallet->CommitTransaction(std::move(tx), std::move(value_map), std::move(order_form));
|
m_wallet->CommitTransaction(std::move(tx), std::move(value_map), std::move(order_form));
|
||||||
}
|
}
|
||||||
|
@ -238,10 +238,7 @@ static UniValue gobject_prepare(const JSONRPCRequest& request)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// -- send the tx to the network
|
// -- send the tx to the network
|
||||||
{
|
|
||||||
LOCK(cs_main);
|
|
||||||
wallet->CommitTransaction(tx, {}, {});
|
wallet->CommitTransaction(tx, {}, {});
|
||||||
}
|
|
||||||
|
|
||||||
LogPrint(BCLog::GOBJECT, "gobject_prepare -- GetDataAsPlainString = %s, hash = %s, txid = %s\n",
|
LogPrint(BCLog::GOBJECT, "gobject_prepare -- GetDataAsPlainString = %s, hash = %s, txid = %s\n",
|
||||||
govobj.GetDataAsPlainString(), govobj.GetHash().ToString(), tx->GetHash().ToString());
|
govobj.GetDataAsPlainString(), govobj.GetHash().ToString(), tx->GetHash().ToString());
|
||||||
|
@ -534,10 +534,7 @@ public:
|
|||||||
bilingual_str error;
|
bilingual_str error;
|
||||||
CCoinControl dummy;
|
CCoinControl dummy;
|
||||||
BOOST_CHECK(wallet->CreateTransaction({recipient}, tx, fee, changePos, error, dummy));
|
BOOST_CHECK(wallet->CreateTransaction({recipient}, tx, fee, changePos, error, dummy));
|
||||||
{
|
|
||||||
LOCK2(wallet->cs_wallet, cs_main);
|
|
||||||
wallet->CommitTransaction(tx, {}, {});
|
wallet->CommitTransaction(tx, {}, {});
|
||||||
}
|
|
||||||
CMutableTransaction blocktx;
|
CMutableTransaction blocktx;
|
||||||
{
|
{
|
||||||
LOCK(wallet->cs_wallet);
|
LOCK(wallet->cs_wallet);
|
||||||
@ -746,10 +743,7 @@ public:
|
|||||||
bilingual_str strError;
|
bilingual_str strError;
|
||||||
CCoinControl coinControl;
|
CCoinControl coinControl;
|
||||||
BOOST_CHECK(wallet->CreateTransaction(GetRecipients(vecEntries), tx, nFeeRet, nChangePosRet, strError, coinControl));
|
BOOST_CHECK(wallet->CreateTransaction(GetRecipients(vecEntries), tx, nFeeRet, nChangePosRet, strError, coinControl));
|
||||||
{
|
|
||||||
LOCK2(wallet->cs_wallet, cs_main);
|
|
||||||
wallet->CommitTransaction(tx, {}, {});
|
wallet->CommitTransaction(tx, {}, {});
|
||||||
}
|
|
||||||
CMutableTransaction blocktx;
|
CMutableTransaction blocktx;
|
||||||
{
|
{
|
||||||
LOCK(wallet->cs_wallet);
|
LOCK(wallet->cs_wallet);
|
||||||
@ -1087,10 +1081,7 @@ BOOST_FIXTURE_TEST_CASE(select_coins_grouped_by_addresses, ListCoinsTestingSetup
|
|||||||
tx1, fee, changePos, error, dummy));
|
tx1, fee, changePos, error, dummy));
|
||||||
BOOST_CHECK(wallet->CreateTransaction({CRecipient{GetScriptForRawPubKey({}), 1 * COIN, true /* subtract fee */}},
|
BOOST_CHECK(wallet->CreateTransaction({CRecipient{GetScriptForRawPubKey({}), 1 * COIN, true /* subtract fee */}},
|
||||||
tx2, fee, changePos, error, dummy));
|
tx2, fee, changePos, error, dummy));
|
||||||
{
|
|
||||||
LOCK2(wallet->cs_wallet, cs_main);
|
|
||||||
wallet->CommitTransaction(tx1, {}, {});
|
wallet->CommitTransaction(tx1, {}, {});
|
||||||
}
|
|
||||||
BOOST_CHECK_EQUAL(wallet->GetAvailableBalance(), 0);
|
BOOST_CHECK_EQUAL(wallet->GetAvailableBalance(), 0);
|
||||||
CreateAndProcessBlock({CMutableTransaction(*tx2)}, GetScriptForRawPubKey({}));
|
CreateAndProcessBlock({CMutableTransaction(*tx2)}, GetScriptForRawPubKey({}));
|
||||||
{
|
{
|
||||||
@ -1143,11 +1134,20 @@ BOOST_FIXTURE_TEST_CASE(wallet_disableprivkeys, TestChain100Setup)
|
|||||||
//! conditions if it's called the same time an incoming transaction shows up in
|
//! conditions if it's called the same time an incoming transaction shows up in
|
||||||
//! the mempool or a new block.
|
//! the mempool or a new block.
|
||||||
//!
|
//!
|
||||||
//! It isn't possible for a unit test to totally verify there aren't race
|
//! It isn't possible to verify there aren't race condition in every case, so
|
||||||
//! conditions without hooking into the implementation more, so this test just
|
//! this test just checks two specific cases and ensures that timing of
|
||||||
//! verifies that new transactions are detected during loading without any
|
//! notifications in these cases doesn't prevent the wallet from detecting
|
||||||
//! notifications at all, to infer that timing of notifications shouldn't
|
//! transactions.
|
||||||
//! matter. The test could be extended to cover other scenarios in the future.
|
//!
|
||||||
|
//! In the first case, block and mempool transactions are created before the
|
||||||
|
//! wallet is loaded, but notifications about these transactions are delayed
|
||||||
|
//! until after it is loaded. The notifications are superfluous in this case, so
|
||||||
|
//! the test verifies the transactions are detected before they arrive.
|
||||||
|
//!
|
||||||
|
//! In the second case, block and mempool transactions are created after the
|
||||||
|
//! wallet rescan and notifications are immediately synced, to verify the wallet
|
||||||
|
//! must already have a handler in place for them, and there's no gap after
|
||||||
|
//! rescanning where new transactions in new blocks could be lost.
|
||||||
BOOST_FIXTURE_TEST_CASE(CreateWalletFromFile, TestChain100Setup)
|
BOOST_FIXTURE_TEST_CASE(CreateWalletFromFile, TestChain100Setup)
|
||||||
{
|
{
|
||||||
gArgs.ForceSetArg("-unsafesqlitesync", "1");
|
gArgs.ForceSetArg("-unsafesqlitesync", "1");
|
||||||
@ -1159,6 +1159,7 @@ BOOST_FIXTURE_TEST_CASE(CreateWalletFromFile, TestChain100Setup)
|
|||||||
AddKey(*wallet, key);
|
AddKey(*wallet, key);
|
||||||
TestUnloadWallet(std::move(wallet));
|
TestUnloadWallet(std::move(wallet));
|
||||||
|
|
||||||
|
|
||||||
// Add log hook to detect AddToWallet events from rescans, blockConnected,
|
// Add log hook to detect AddToWallet events from rescans, blockConnected,
|
||||||
// and transactionAddedToMempool notifications
|
// and transactionAddedToMempool notifications
|
||||||
int addtx_count = 0;
|
int addtx_count = 0;
|
||||||
@ -1167,21 +1168,14 @@ BOOST_FIXTURE_TEST_CASE(CreateWalletFromFile, TestChain100Setup)
|
|||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
bool rescan_completed = false;
|
bool rescan_completed = false;
|
||||||
DebugLogHelper rescan_check("[default wallet] Rescan completed", [&](const std::string* s) {
|
DebugLogHelper rescan_check("[default wallet] Rescan completed", [&](const std::string* s) {
|
||||||
if (s) {
|
if (s) rescan_completed = true;
|
||||||
// For now, just assert that cs_main is being held during the
|
|
||||||
// rescan, ensuring that a new block couldn't be connected
|
|
||||||
// that the wallet would miss. After
|
|
||||||
// https://github.com/bitcoin/bitcoin/pull/16426 when cs_main is no
|
|
||||||
// longer held, the test can be extended to append a new block here
|
|
||||||
// and check it's handled correctly.
|
|
||||||
// AssertLockHeld(::cs_main);
|
|
||||||
rescan_completed = true;
|
|
||||||
}
|
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
// Block the queue to prevent the wallet receiving blockConnected and
|
// Block the queue to prevent the wallet receiving blockConnected and
|
||||||
// transactionAddedToMempool notifications, and create block and mempool
|
// transactionAddedToMempool notifications, and create block and mempool
|
||||||
// transactions paying to the wallet
|
// transactions paying to the wallet
|
||||||
@ -1196,27 +1190,52 @@ BOOST_FIXTURE_TEST_CASE(CreateWalletFromFile, TestChain100Setup)
|
|||||||
auto mempool_tx = TestSimpleSpend(*m_coinbase_txns[1], 0, coinbaseKey, GetScriptForRawPubKey(key.GetPubKey()));
|
auto mempool_tx = TestSimpleSpend(*m_coinbase_txns[1], 0, coinbaseKey, GetScriptForRawPubKey(key.GetPubKey()));
|
||||||
BOOST_CHECK(chain->broadcastTransaction(MakeTransactionRef(mempool_tx), error, DEFAULT_TRANSACTION_MAXFEE, false));
|
BOOST_CHECK(chain->broadcastTransaction(MakeTransactionRef(mempool_tx), error, DEFAULT_TRANSACTION_MAXFEE, false));
|
||||||
|
|
||||||
|
|
||||||
// Reload wallet and make sure new transactions are detected despite events
|
// Reload wallet and make sure new transactions are detected despite events
|
||||||
// being blocked
|
// being blocked
|
||||||
wallet = TestLoadWallet(*chain);
|
wallet = TestLoadWallet(*chain);
|
||||||
BOOST_CHECK(rescan_completed);
|
BOOST_CHECK(rescan_completed);
|
||||||
BOOST_CHECK_EQUAL(addtx_count, 2);
|
BOOST_CHECK_EQUAL(addtx_count, 2);
|
||||||
unsigned int block_tx_time, mempool_tx_time;
|
|
||||||
{
|
{
|
||||||
LOCK(wallet->cs_wallet);
|
LOCK(wallet->cs_wallet);
|
||||||
block_tx_time = wallet->mapWallet.at(block_tx.GetHash()).nTimeReceived;
|
BOOST_CHECK_EQUAL(wallet->mapWallet.count(block_tx.GetHash()), 1);
|
||||||
mempool_tx_time = wallet->mapWallet.at(mempool_tx.GetHash()).nTimeReceived;
|
BOOST_CHECK_EQUAL(wallet->mapWallet.count(mempool_tx.GetHash()), 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Unblock notification queue and make sure stale blockConnected and
|
// Unblock notification queue and make sure stale blockConnected and
|
||||||
// transactionAddedToMempool events are processed
|
// transactionAddedToMempool events are processed
|
||||||
promise.set_value();
|
promise.set_value();
|
||||||
SyncWithValidationInterfaceQueue();
|
SyncWithValidationInterfaceQueue();
|
||||||
BOOST_CHECK_EQUAL(addtx_count, 4);
|
BOOST_CHECK_EQUAL(addtx_count, 4);
|
||||||
|
|
||||||
|
TestUnloadWallet(std::move(wallet));
|
||||||
|
|
||||||
|
|
||||||
|
// Load wallet again, this time creating new block and mempool transactions
|
||||||
|
// paying to the wallet as the wallet finishes loading and syncing the
|
||||||
|
// queue so the events have to be handled immediately. Releasing the wallet
|
||||||
|
// lock during the sync is a little artificial but is needed to avoid a
|
||||||
|
// deadlock during the sync and simulates a new block notification happening
|
||||||
|
// as soon as possible.
|
||||||
|
addtx_count = 0;
|
||||||
|
auto handler = HandleLoadWallet([&](std::unique_ptr<interfaces::Wallet> wallet) EXCLUSIVE_LOCKS_REQUIRED(wallet->wallet()->cs_wallet) {
|
||||||
|
BOOST_CHECK(rescan_completed);
|
||||||
|
m_coinbase_txns.push_back(CreateAndProcessBlock({}, GetScriptForRawPubKey(coinbaseKey.GetPubKey())).vtx[0]);
|
||||||
|
block_tx = TestSimpleSpend(*m_coinbase_txns[2], 0, coinbaseKey, GetScriptForRawPubKey(key.GetPubKey()));
|
||||||
|
m_coinbase_txns.push_back(CreateAndProcessBlock({block_tx}, GetScriptForRawPubKey(coinbaseKey.GetPubKey())).vtx[0]);
|
||||||
|
mempool_tx = TestSimpleSpend(*m_coinbase_txns[3], 0, coinbaseKey, GetScriptForRawPubKey(key.GetPubKey()));
|
||||||
|
BOOST_CHECK(chain->broadcastTransaction(MakeTransactionRef(mempool_tx), error, DEFAULT_TRANSACTION_MAXFEE, false));
|
||||||
|
LEAVE_CRITICAL_SECTION(wallet->wallet()->cs_wallet);
|
||||||
|
SyncWithValidationInterfaceQueue();
|
||||||
|
ENTER_CRITICAL_SECTION(wallet->wallet()->cs_wallet);
|
||||||
|
});
|
||||||
|
wallet = TestLoadWallet(*chain);
|
||||||
|
BOOST_CHECK_EQUAL(addtx_count, 4);
|
||||||
{
|
{
|
||||||
LOCK(wallet->cs_wallet);
|
LOCK(wallet->cs_wallet);
|
||||||
BOOST_CHECK_EQUAL(block_tx_time, wallet->mapWallet.at(block_tx.GetHash()).nTimeReceived);
|
BOOST_CHECK_EQUAL(wallet->mapWallet.count(block_tx.GetHash()), 1);
|
||||||
BOOST_CHECK_EQUAL(mempool_tx_time, wallet->mapWallet.at(mempool_tx.GetHash()).nTimeReceived);
|
BOOST_CHECK_EQUAL(wallet->mapWallet.count(mempool_tx.GetHash()), 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
TestUnloadWallet(std::move(wallet));
|
TestUnloadWallet(std::move(wallet));
|
||||||
|
Loading…
Reference in New Issue
Block a user