Browse Source

Merge #13253: [0.16] Further Backports

acdf433822 Hold cs_main while calling UpdatedBlockTip() and ui.NotifyBlockTip (Jesse Cohen)
5ff571e90c [wallet] [tests] Test disallowed multiwallet params (John Newbery)
4c14e7b67c [wallet] Fix zapwallettxes/multiwallet interaction. (John Newbery)
4087dd08e7 RPC Docs: gettxout*: clarify bestblock and unspent counts (David A. Harding)
b8aacd660e [qa] Handle disconnect_node race (Suhas Daftuar)

Pull request description:

  Backports:
  - #13201 [qa] Handle disconnect_node race
  - #13184 RPC Docs: gettxout*: clarify bestblock and unspent counts
  - #13030 [bugfix] [wallet] Fix zapwallettxes/multiwallet interaction.
  - #12988 Hold cs_main while calling UpdatedBlockTip() signal

  to the 0.16 branch.

Tree-SHA512: 8f65002bbafaf9c436f89051b2d79bf6a668fbd07bd317c64af238ed4a7c8efe776864b739a7f2869f1e3daa16f2f4366a85f41b188f9c454879d2c7b309be50
0.16
Wladimir J. van der Laan 7 years ago
parent
commit
50b2c9e0df
No known key found for this signature in database
GPG Key ID: 1E4AED62986CD25D
  1. 8
      src/rpc/blockchain.cpp
  2. 17
      src/validation.cpp
  3. 4
      src/validationinterface.cpp
  4. 10
      src/wallet/init.cpp
  5. 9
      test/functional/test_framework/util.py
  6. 13
      test/functional/wallet_multiwallet.py

8
src/rpc/blockchain.cpp

@ -934,9 +934,9 @@ UniValue gettxoutsetinfo(const JSONRPCRequest& request)
"\nResult:\n" "\nResult:\n"
"{\n" "{\n"
" \"height\":n, (numeric) The current block height (index)\n" " \"height\":n, (numeric) The current block height (index)\n"
" \"bestblock\": \"hex\", (string) the best block hash hex\n" " \"bestblock\": \"hex\", (string) The hash of the block at the tip of the chain\n"
" \"transactions\": n, (numeric) The number of transactions\n" " \"transactions\": n, (numeric) The number of transactions with unspent outputs\n"
" \"txouts\": n, (numeric) The number of output transactions\n" " \"txouts\": n, (numeric) The number of unspent transaction outputs\n"
" \"bogosize\": n, (numeric) A meaningless metric for UTXO set size\n" " \"bogosize\": n, (numeric) A meaningless metric for UTXO set size\n"
" \"hash_serialized_2\": \"hash\", (string) The serialized hash\n" " \"hash_serialized_2\": \"hash\", (string) The serialized hash\n"
" \"disk_size\": n, (numeric) The estimated size of the chainstate on disk\n" " \"disk_size\": n, (numeric) The estimated size of the chainstate on disk\n"
@ -979,7 +979,7 @@ UniValue gettxout(const JSONRPCRequest& request)
" Note that an unspent output that is spent in the mempool won't appear.\n" " Note that an unspent output that is spent in the mempool won't appear.\n"
"\nResult:\n" "\nResult:\n"
"{\n" "{\n"
" \"bestblock\" : \"hash\", (string) the block hash\n" " \"bestblock\": \"hash\", (string) The hash of the block at the tip of the chain\n"
" \"confirmations\" : n, (numeric) The number of confirmations\n" " \"confirmations\" : n, (numeric) The number of confirmations\n"
" \"value\" : x.xxx, (numeric) The transaction value in " + CURRENCY_UNIT + "\n" " \"value\" : x.xxx, (numeric) The transaction value in " + CURRENCY_UNIT + "\n"
" \"scriptPubKey\" : { (json object)\n" " \"scriptPubKey\" : { (json object)\n"

17
src/validation.cpp

@ -2607,18 +2607,17 @@ bool CChainState::ActivateBestChain(CValidationState &state, const CChainParams&
assert(trace.pblock && trace.pindex); assert(trace.pblock && trace.pindex);
GetMainSignals().BlockConnected(trace.pblock, trace.pindex, trace.conflictedTxs); GetMainSignals().BlockConnected(trace.pblock, trace.pindex, trace.conflictedTxs);
} }
}
// When we reach this point, we switched to a new tip (stored in pindexNewTip).
// Notifications/callbacks that can run without cs_main
// Notify external listeners about the new tip. // Notify external listeners about the new tip.
GetMainSignals().UpdatedBlockTip(pindexNewTip, pindexFork, fInitialDownload); // Enqueue while holding cs_main to ensure that UpdatedBlockTip is called in the order in which blocks are connected
GetMainSignals().UpdatedBlockTip(pindexNewTip, pindexFork, fInitialDownload);
// Always notify the UI if a new block tip was connected // Always notify the UI if a new block tip was connected
if (pindexFork != pindexNewTip) { if (pindexFork != pindexNewTip) {
uiInterface.NotifyBlockTip(fInitialDownload, pindexNewTip); uiInterface.NotifyBlockTip(fInitialDownload, pindexNewTip);
}
} }
// When we reach this point, we switched to a new tip (stored in pindexNewTip).
if (nStopAtHeight && pindexNewTip && pindexNewTip->nHeight >= nStopAtHeight) StartShutdown(); if (nStopAtHeight && pindexNewTip && pindexNewTip->nHeight >= nStopAtHeight) StartShutdown();

4
src/validationinterface.cpp

@ -139,6 +139,10 @@ void CMainSignals::MempoolEntryRemoved(CTransactionRef ptx, MemPoolRemovalReason
} }
void CMainSignals::UpdatedBlockTip(const CBlockIndex *pindexNew, const CBlockIndex *pindexFork, bool fInitialDownload) { void CMainSignals::UpdatedBlockTip(const CBlockIndex *pindexNew, const CBlockIndex *pindexFork, bool fInitialDownload) {
// Dependencies exist that require UpdatedBlockTip events to be delivered in the order in which
// the chain actually updates. One way to ensure this is for the caller to invoke this signal
// in the same critical section where the chain is updated
m_internals->m_schedulerClient.AddToProcessQueue([pindexNew, pindexFork, fInitialDownload, this] { m_internals->m_schedulerClient.AddToProcessQueue([pindexNew, pindexFork, fInitialDownload, this] {
m_internals->UpdatedBlockTip(pindexNew, pindexFork, fInitialDownload); m_internals->UpdatedBlockTip(pindexNew, pindexFork, fInitialDownload);
}); });

10
src/wallet/init.cpp

@ -82,19 +82,19 @@ bool WalletParameterInteraction()
} }
} }
int zapwallettxes = gArgs.GetArg("-zapwallettxes", 0); bool zapwallettxes = gArgs.GetBoolArg("-zapwallettxes", false);
// -zapwallettxes implies dropping the mempool on startup // -zapwallettxes implies dropping the mempool on startup
if (zapwallettxes != 0 && gArgs.SoftSetBoolArg("-persistmempool", false)) { if (zapwallettxes && gArgs.SoftSetBoolArg("-persistmempool", false)) {
LogPrintf("%s: parameter interaction: -zapwallettxes=%s -> setting -persistmempool=0\n", __func__, zapwallettxes); LogPrintf("%s: parameter interaction: -zapwallettxes enabled -> setting -persistmempool=0\n", __func__);
} }
// -zapwallettxes implies a rescan // -zapwallettxes implies a rescan
if (zapwallettxes != 0) { if (zapwallettxes) {
if (is_multiwallet) { if (is_multiwallet) {
return InitError(strprintf("%s is only allowed with a single wallet file", "-zapwallettxes")); return InitError(strprintf("%s is only allowed with a single wallet file", "-zapwallettxes"));
} }
if (gArgs.SoftSetBoolArg("-rescan", true)) { if (gArgs.SoftSetBoolArg("-rescan", true)) {
LogPrintf("%s: parameter interaction: -zapwallettxes=%s -> setting -rescan=1\n", __func__, zapwallettxes); LogPrintf("%s: parameter interaction: -zapwallettxes enabled -> setting -rescan=1\n", __func__);
} }
} }

9
test/functional/test_framework/util.py

@ -335,7 +335,14 @@ def set_node_times(nodes, t):
def disconnect_nodes(from_connection, node_num): def disconnect_nodes(from_connection, node_num):
for peer_id in [peer['id'] for peer in from_connection.getpeerinfo() if "testnode%d" % node_num in peer['subver']]: for peer_id in [peer['id'] for peer in from_connection.getpeerinfo() if "testnode%d" % node_num in peer['subver']]:
from_connection.disconnectnode(nodeid=peer_id) try:
from_connection.disconnectnode(nodeid=peer_id)
except JSONRPCException as e:
# If this node is disconnected between calculating the peer id
# and issuing the disconnect, don't worry about it.
# This avoids a race condition if we're mass-disconnecting peers.
if e.error['code'] != -29: # RPC_CLIENT_NODE_NOT_CONNECTED
raise
# wait to disconnect # wait to disconnect
wait_until(lambda: [peer['id'] for peer in from_connection.getpeerinfo() if "testnode%d" % node_num in peer['subver']] == [], timeout=5) wait_until(lambda: [peer['id'] for peer in from_connection.getpeerinfo() if "testnode%d" % node_num in peer['subver']] == [], timeout=5)

13
test/functional/wallet_multiwallet.py

@ -56,6 +56,19 @@ class MultiWalletTest(BitcoinTestFramework):
open(not_a_dir, 'a').close() open(not_a_dir, 'a').close()
self.assert_start_raises_init_error(0, ['-walletdir=' + not_a_dir], 'Error: Specified -walletdir "' + not_a_dir + '" is not a directory') self.assert_start_raises_init_error(0, ['-walletdir=' + not_a_dir], 'Error: Specified -walletdir "' + not_a_dir + '" is not a directory')
self.log.info("Do not allow -zapwallettxes with multiwallet")
self.assert_start_raises_init_error(0, ['-zapwallettxes', '-wallet=w1', '-wallet=w2'], "Error: -zapwallettxes is only allowed with a single wallet file")
self.assert_start_raises_init_error(0, ['-zapwallettxes=1', '-wallet=w1', '-wallet=w2'], "Error: -zapwallettxes is only allowed with a single wallet file")
self.assert_start_raises_init_error(0, ['-zapwallettxes=2', '-wallet=w1', '-wallet=w2'], "Error: -zapwallettxes is only allowed with a single wallet file")
self.log.info("Do not allow -salvagewallet with multiwallet")
self.assert_start_raises_init_error(0, ['-salvagewallet', '-wallet=w1', '-wallet=w2'], "Error: -salvagewallet is only allowed with a single wallet file")
self.assert_start_raises_init_error(0, ['-salvagewallet=1', '-wallet=w1', '-wallet=w2'], "Error: -salvagewallet is only allowed with a single wallet file")
self.log.info("Do not allow -upgradewallet with multiwallet")
self.assert_start_raises_init_error(0, ['-upgradewallet', '-wallet=w1', '-wallet=w2'], "Error: -upgradewallet is only allowed with a single wallet file")
self.assert_start_raises_init_error(0, ['-upgradewallet=1', '-wallet=w1', '-wallet=w2'], "Error: -upgradewallet is only allowed with a single wallet file")
# if wallets/ doesn't exist, datadir should be the default wallet dir # if wallets/ doesn't exist, datadir should be the default wallet dir
wallet_dir2 = data_dir('walletdir') wallet_dir2 = data_dir('walletdir')
os.rename(wallet_dir(), wallet_dir2) os.rename(wallet_dir(), wallet_dir2)

Loading…
Cancel
Save