aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/chainparamsbase.cpp44
-rw-r--r--src/chainparamsbase.h5
-rw-r--r--src/httpserver.cpp42
-rw-r--r--src/init.cpp16
-rw-r--r--src/net_processing.cpp4
-rw-r--r--src/policy/fees.cpp13
-rw-r--r--src/policy/fees.h2
-rw-r--r--src/qt/README.md95
-rw-r--r--src/qt/bitcoin.cpp7
-rw-r--r--src/rpc/client.cpp1
-rw-r--r--src/rpc/mining.cpp48
-rw-r--r--src/rpc/misc.cpp12
-rw-r--r--src/script/ismine.cpp13
-rw-r--r--src/txmempool.h12
-rw-r--r--src/validation.cpp22
-rw-r--r--src/wallet/rpcdump.cpp29
-rw-r--r--src/wallet/rpcwallet.cpp18
-rw-r--r--src/wallet/test/wallet_tests.cpp18
-rw-r--r--src/wallet/wallet.cpp164
19 files changed, 288 insertions, 277 deletions
diff --git a/src/chainparamsbase.cpp b/src/chainparamsbase.cpp
index 89dd8549b9..a04258fd40 100644
--- a/src/chainparamsbase.cpp
+++ b/src/chainparamsbase.cpp
@@ -24,44 +24,6 @@ void AppendParamsHelpMessages(std::string& strUsage, bool debugHelp)
strUsage += HelpMessageOpt("-testnet", _("Use the test chain"));
}
-/**
- * Main network
- */
-class CBaseMainParams : public CBaseChainParams
-{
-public:
- CBaseMainParams()
- {
- nRPCPort = 8332;
- }
-};
-
-/**
- * Testnet (v3)
- */
-class CBaseTestNetParams : public CBaseChainParams
-{
-public:
- CBaseTestNetParams()
- {
- nRPCPort = 18332;
- strDataDir = "testnet3";
- }
-};
-
-/*
- * Regression test
- */
-class CBaseRegTestParams : public CBaseChainParams
-{
-public:
- CBaseRegTestParams()
- {
- nRPCPort = 18443;
- strDataDir = "regtest";
- }
-};
-
static std::unique_ptr<CBaseChainParams> globalChainBaseParams;
const CBaseChainParams& BaseParams()
@@ -73,11 +35,11 @@ const CBaseChainParams& BaseParams()
std::unique_ptr<CBaseChainParams> CreateBaseChainParams(const std::string& chain)
{
if (chain == CBaseChainParams::MAIN)
- return std::unique_ptr<CBaseChainParams>(new CBaseMainParams());
+ return MakeUnique<CBaseChainParams>("", 8332);
else if (chain == CBaseChainParams::TESTNET)
- return std::unique_ptr<CBaseChainParams>(new CBaseTestNetParams());
+ return MakeUnique<CBaseChainParams>("testnet3", 18332);
else if (chain == CBaseChainParams::REGTEST)
- return std::unique_ptr<CBaseChainParams>(new CBaseRegTestParams());
+ return MakeUnique<CBaseChainParams>("regtest", 18443);
else
throw std::runtime_error(strprintf("%s: Unknown chain %s.", __func__, chain));
}
diff --git a/src/chainparamsbase.h b/src/chainparamsbase.h
index b4d2bb4f08..2cb860380e 100644
--- a/src/chainparamsbase.h
+++ b/src/chainparamsbase.h
@@ -24,9 +24,10 @@ public:
const std::string& DataDir() const { return strDataDir; }
int RPCPort() const { return nRPCPort; }
-protected:
- CBaseChainParams() {}
+ CBaseChainParams() = delete;
+ CBaseChainParams(const std::string& data_dir, int rpc_port) : nRPCPort(rpc_port), strDataDir(data_dir) {}
+private:
int nRPCPort;
std::string strDataDir;
};
diff --git a/src/httpserver.cpp b/src/httpserver.cpp
index 73dce8d571..36db530c82 100644
--- a/src/httpserver.cpp
+++ b/src/httpserver.cpp
@@ -73,34 +73,13 @@ private:
std::deque<std::unique_ptr<WorkItem>> queue;
bool running;
size_t maxDepth;
- int numThreads;
-
- /** RAII object to keep track of number of running worker threads */
- class ThreadCounter
- {
- public:
- WorkQueue &wq;
- explicit ThreadCounter(WorkQueue &w): wq(w)
- {
- std::lock_guard<std::mutex> lock(wq.cs);
- wq.numThreads += 1;
- }
- ~ThreadCounter()
- {
- std::lock_guard<std::mutex> lock(wq.cs);
- wq.numThreads -= 1;
- wq.cond.notify_all();
- }
- };
public:
explicit WorkQueue(size_t _maxDepth) : running(true),
- maxDepth(_maxDepth),
- numThreads(0)
+ maxDepth(_maxDepth)
{
}
- /** Precondition: worker threads have all stopped
- * (call WaitExit)
+ /** Precondition: worker threads have all stopped (they have been joined).
*/
~WorkQueue()
{
@@ -119,7 +98,6 @@ public:
/** Thread function */
void Run()
{
- ThreadCounter count(*this);
while (true) {
std::unique_ptr<WorkItem> i;
{
@@ -141,13 +119,6 @@ public:
running = false;
cond.notify_all();
}
- /** Wait for worker threads to exit */
- void WaitExit()
- {
- std::unique_lock<std::mutex> lock(cs);
- while (numThreads > 0)
- cond.wait(lock);
- }
};
struct HTTPPathHandler
@@ -449,6 +420,7 @@ bool UpdateHTTPServerLogging(bool enable) {
std::thread threadHTTP;
std::future<bool> threadResult;
+static std::vector<std::thread> g_thread_http_workers;
bool StartHTTPServer()
{
@@ -460,8 +432,7 @@ bool StartHTTPServer()
threadHTTP = std::thread(std::move(task), eventBase, eventHTTP);
for (int i = 0; i < rpcThreads; i++) {
- std::thread rpc_worker(HTTPWorkQueueRun, workQueue);
- rpc_worker.detach();
+ g_thread_http_workers.emplace_back(HTTPWorkQueueRun, workQueue);
}
return true;
}
@@ -486,7 +457,10 @@ void StopHTTPServer()
LogPrint(BCLog::HTTP, "Stopping HTTP server\n");
if (workQueue) {
LogPrint(BCLog::HTTP, "Waiting for HTTP worker threads to exit\n");
- workQueue->WaitExit();
+ for (auto& thread: g_thread_http_workers) {
+ thread.join();
+ }
+ g_thread_http_workers.clear();
delete workQueue;
workQueue = nullptr;
}
diff --git a/src/init.cpp b/src/init.cpp
index ec2edd9cac..b28baba779 100644
--- a/src/init.cpp
+++ b/src/init.cpp
@@ -214,7 +214,7 @@ void Shutdown()
if (fFeeEstimatesInitialized)
{
- ::feeEstimator.FlushUnconfirmed(::mempool);
+ ::feeEstimator.FlushUnconfirmed();
fs::path est_path = GetDataDir() / FEE_ESTIMATES_FILENAME;
CAutoFile est_fileout(fsbridge::fopen(est_path, "wb"), SER_DISK, CLIENT_VERSION);
if (!est_fileout.IsNull())
@@ -1427,6 +1427,9 @@ bool AppInitMain()
pcoinsTip.reset();
pcoinsdbview.reset();
pcoinscatcher.reset();
+ // new CBlockTreeDB tries to delete the existing file, which
+ // fails if it's still open from the previous loop. Close it first:
+ pblocktree.reset();
pblocktree.reset(new CBlockTreeDB(nBlockTreeDBCache, false, fReset));
if (fReset) {
@@ -1647,12 +1650,19 @@ bool AppInitMain()
// Wait for genesis block to be processed
{
WaitableLock lock(cs_GenesisWait);
- while (!fHaveGenesis) {
- condvar_GenesisWait.wait(lock);
+ // We previously could hang here if StartShutdown() is called prior to
+ // ThreadImport getting started, so instead we just wait on a timer to
+ // check ShutdownRequested() regularly.
+ while (!fHaveGenesis && !ShutdownRequested()) {
+ condvar_GenesisWait.wait_for(lock, std::chrono::milliseconds(500));
}
uiInterface.NotifyBlockTip.disconnect(BlockNotifyGenesisWait);
}
+ if (ShutdownRequested()) {
+ return false;
+ }
+
// ********************************************************* Step 11: start node
int chain_active_height;
diff --git a/src/net_processing.cpp b/src/net_processing.cpp
index fc0ba82d8b..bf9307727a 100644
--- a/src/net_processing.cpp
+++ b/src/net_processing.cpp
@@ -1226,10 +1226,10 @@ void static ProcessGetData(CNode* pfrom, const Consensus::Params& consensusParam
}
} // release cs_main
- if (it != pfrom->vRecvGetData.end()) {
+ if (it != pfrom->vRecvGetData.end() && !pfrom->fPauseSend) {
const CInv &inv = *it;
- it++;
if (inv.type == MSG_BLOCK || inv.type == MSG_FILTERED_BLOCK || inv.type == MSG_CMPCT_BLOCK || inv.type == MSG_WITNESS_BLOCK) {
+ it++;
ProcessGetBlockData(pfrom, consensusParams, inv, connman, interruptMsgProc);
}
}
diff --git a/src/policy/fees.cpp b/src/policy/fees.cpp
index 9142f3706d..79b450e3e6 100644
--- a/src/policy/fees.cpp
+++ b/src/policy/fees.cpp
@@ -981,16 +981,17 @@ bool CBlockPolicyEstimator::Read(CAutoFile& filein)
return true;
}
-void CBlockPolicyEstimator::FlushUnconfirmed(CTxMemPool& pool) {
+void CBlockPolicyEstimator::FlushUnconfirmed() {
int64_t startclear = GetTimeMicros();
- std::vector<uint256> txids;
- pool.queryHashes(txids);
LOCK(cs_feeEstimator);
- for (auto& txid : txids) {
- removeTx(txid, false);
+ size_t num_entries = mapMemPoolTxs.size();
+ // Remove every entry in mapMemPoolTxs
+ while (!mapMemPoolTxs.empty()) {
+ auto mi = mapMemPoolTxs.begin();
+ removeTx(mi->first, false); // this calls erase() on mapMemPoolTxs
}
int64_t endclear = GetTimeMicros();
- LogPrint(BCLog::ESTIMATEFEE, "Recorded %u unconfirmed txs from mempool in %gs\n",txids.size(), (endclear - startclear)*0.000001);
+ LogPrint(BCLog::ESTIMATEFEE, "Recorded %u unconfirmed txs from mempool in %gs\n", num_entries, (endclear - startclear)*0.000001);
}
FeeFilterRounder::FeeFilterRounder(const CFeeRate& minIncrementalFee)
diff --git a/src/policy/fees.h b/src/policy/fees.h
index 96a842b7a1..5f69e989c1 100644
--- a/src/policy/fees.h
+++ b/src/policy/fees.h
@@ -223,7 +223,7 @@ public:
bool Read(CAutoFile& filein);
/** Empty mempool transactions on shutdown to record failure to confirm for txs still in mempool */
- void FlushUnconfirmed(CTxMemPool& pool);
+ void FlushUnconfirmed();
/** Calculation of highest target that estimates are tracked for */
unsigned int HighestTargetTracked(FeeEstimateHorizon horizon) const;
diff --git a/src/qt/README.md b/src/qt/README.md
new file mode 100644
index 0000000000..7ffea98170
--- /dev/null
+++ b/src/qt/README.md
@@ -0,0 +1,95 @@
+This directory contains the BitcoinQT graphical user interface (GUI). It uses the cross platform framework [QT](https://www1.qt.io/developers/).
+
+The current precise version for QT 5 is specified in [qt.mk](/depends/packages/qt.mk). QT 4 is also supported (see [#8263](https://github.com/bitcoin/bitcoin/issues/8263)).
+
+## Compile and run
+
+See build instructions ([OSX](/doc/build-osx.md), [Windows](/doc/build-windows.md), [Unix](/doc/build-unix.md), etc).
+
+To run:
+
+```sh
+./src/qt/bitcoin-qt
+```
+
+## Files and directories
+
+### forms
+
+Contains [Designer UI](http://doc.qt.io/qt-5.9/designer-using-a-ui-file.html) files. They are created with [Qt Creator](#use-qt-Creator-as IDE), but can be edited using any text editor.
+
+### locale
+
+Contains translations. They are periodically updated. The process is described [here](/doc/translation_process.md).
+
+### res
+
+Resources such as the icon.
+
+### test
+
+Tests.
+
+### bitcoingui.(h/cpp)
+
+Represents the main window of the Bitcoin UI.
+
+### \*model.(h/cpp)
+
+The model. When it has a corresponding controller, it generally inherits from [QAbstractTableModel](http://doc.qt.io/qt-5/qabstracttablemodel.html). Models that are used by controllers as helpers inherit from other QT classes like [QValidator](http://doc.qt.io/qt-5/qvalidator.html).
+
+ClientModel is used by the main application `bitcoingui` and several models like `peertablemodel`.
+
+### \*page.(h/cpp)
+
+A controller. `:NAMEpage.cpp` generally includes `:NAMEmodel.h` and `forms/:NAME.page.ui` with a similar `:NAME`.
+
+### \*dialog.(h/cpp)
+
+Various dialogs, e.g. to open a URL. Inherit from [QDialog](http://doc.qt.io/qt-4.8/qdialog.html).
+
+### paymentserver.(h/cpp)
+
+Used to process BIP21 and BIP70 (see https://github.com/bitcoin/bitcoin/pull/11622) payment URI / requests. Also handles URI based application switching (e.g. when following a bitcoin:... link from a browser).
+
+### walletview.(h/cpp)
+
+Represents the view to a single wallet.
+
+### Other .h/cpp files
+
+* UI elements like BitcoinAmountField, which inherit from QWidget.
+* `bitcoinstrings.cpp`: automatically generated
+* `bitcoinunits.(h/cpp)`: BTC / mBTC / etc handling
+* `callback.h`
+* `guiconstants.h`: UI colors, app name, etc
+* `guiutil.h`: several helper functions
+* `macdockiconhandler.(h/cpp)`
+* `macdockiconhandler.(h/cpp)`: display notifications in OSX
+
+## Contribute
+
+See [CONTRIBUTING.md](/CONTRIBUTING.md) for general guidelines. Specifically for QT:
+
+* don't change `local/bitcoin_en.ts`; this happens [automatically](/doc/translation_process.md#writing-code-with-translations)
+
+## Using Qt Creator as IDE
+
+You can use Qt Creator as an IDE. This is especially useful if you want to change
+the UI layout.
+
+Download and install the community edition of [Qt Creator](https://www.qt.io/download/).
+Uncheck everything except Qt Creator during the installation process.
+
+Instructions for OSX:
+
+1. Make sure you installed everything through Homebrew mentioned in the [OSX build instructions](/docs/build-osx.md)
+2. Use `./configure` with the `--enable-debug` flag
+3. In Qt Creator do "New Project" -> Import Project -> Import Existing Project
+4. Enter "bitcoin-qt" as project name, enter src/qt as location
+5. Leave the file selection as it is
+6. Confirm the "summary page"
+7. In the "Projects" tab select "Manage Kits..."
+8. Select the default "Desktop" kit and select "Clang (x86 64bit in /usr/bin)" as compiler
+9. Select LLDB as debugger (you might need to set the path to your installation)
+10. Start debugging with Qt Creator (you might need to the executable to "bitcoin-qt" under "Run", which is where you can also add command line arguments)
diff --git a/src/qt/bitcoin.cpp b/src/qt/bitcoin.cpp
index e567a177f9..e4c088d379 100644
--- a/src/qt/bitcoin.cpp
+++ b/src/qt/bitcoin.cpp
@@ -388,7 +388,6 @@ void BitcoinApplication::createWindow(const NetworkStyle *networkStyle)
pollShutdownTimer = new QTimer(window);
connect(pollShutdownTimer, SIGNAL(timeout()), window, SLOT(detectShutdown()));
- pollShutdownTimer->start(200);
}
void BitcoinApplication::createSplashScreen(const NetworkStyle *networkStyle)
@@ -515,14 +514,16 @@ void BitcoinApplication::initializeResult(bool success)
window, SLOT(message(QString,QString,unsigned int)));
QTimer::singleShot(100, paymentServer, SLOT(uiReady()));
#endif
+ pollShutdownTimer->start(200);
} else {
- quit(); // Exit main loop
+ Q_EMIT splashFinished(window); // Make sure splash screen doesn't stick around during shutdown
+ quit(); // Exit first main loop invocation
}
}
void BitcoinApplication::shutdownResult()
{
- quit(); // Exit main loop after shutdown finished
+ quit(); // Exit second main loop invocation after shutdown finished
}
void BitcoinApplication::handleRunawayException(const QString &message)
diff --git a/src/rpc/client.cpp b/src/rpc/client.cpp
index b88c1bccd5..99c1242d8a 100644
--- a/src/rpc/client.cpp
+++ b/src/rpc/client.cpp
@@ -114,7 +114,6 @@ static const CRPCConvertParam vRPCConvertParams[] =
{ "pruneblockchain", 0, "height" },
{ "keypoolrefill", 0, "newsize" },
{ "getrawmempool", 0, "verbose" },
- { "estimatefee", 0, "nblocks" },
{ "estimatesmartfee", 0, "conf_target" },
{ "estimaterawfee", 0, "conf_target" },
{ "estimaterawfee", 1, "threshold" },
diff --git a/src/rpc/mining.cpp b/src/rpc/mining.cpp
index c22d0ac377..69d0d12e86 100644
--- a/src/rpc/mining.cpp
+++ b/src/rpc/mining.cpp
@@ -201,7 +201,6 @@ UniValue getmininginfo(const JSONRPCRequest& request)
" \"pooledtx\": n (numeric) The size of the mempool\n"
" \"chain\": \"xxxx\", (string) current network name as defined in BIP70 (main, test, regtest)\n"
" \"warnings\": \"...\" (string) any network and blockchain warnings\n"
- " \"errors\": \"...\" (string) DEPRECATED. Same as warnings. Only shown when bitcoind is started with -deprecatedrpc=getmininginfo\n"
"}\n"
"\nExamples:\n"
+ HelpExampleCli("getmininginfo", "")
@@ -219,11 +218,7 @@ UniValue getmininginfo(const JSONRPCRequest& request)
obj.push_back(Pair("networkhashps", getnetworkhashps(request)));
obj.push_back(Pair("pooledtx", (uint64_t)mempool.size()));
obj.push_back(Pair("chain", Params().NetworkIDString()));
- if (IsDeprecatedRPCEnabled("getmininginfo")) {
- obj.push_back(Pair("errors", GetWarnings("statusbar")));
- } else {
- obj.push_back(Pair("warnings", GetWarnings("statusbar")));
- }
+ obj.push_back(Pair("warnings", GetWarnings("statusbar")));
return obj;
}
@@ -772,43 +767,8 @@ UniValue submitblock(const JSONRPCRequest& request)
UniValue estimatefee(const JSONRPCRequest& request)
{
- if (request.fHelp || request.params.size() != 1)
- throw std::runtime_error(
- "estimatefee nblocks\n"
- "\nDEPRECATED. Please use estimatesmartfee for more intelligent estimates."
- "\nEstimates the approximate fee per kilobyte needed for a transaction to begin\n"
- "confirmation within nblocks blocks. Uses virtual transaction size of transaction\n"
- "as defined in BIP 141 (witness data is discounted).\n"
- "\nArguments:\n"
- "1. nblocks (numeric, required)\n"
- "\nResult:\n"
- "n (numeric) estimated fee-per-kilobyte\n"
- "\n"
- "A negative value is returned if not enough transactions and blocks\n"
- "have been observed to make an estimate.\n"
- "-1 is always returned for nblocks == 1 as it is impossible to calculate\n"
- "a fee that is high enough to get reliably included in the next block.\n"
- "\nExample:\n"
- + HelpExampleCli("estimatefee", "6")
- );
-
- if (!IsDeprecatedRPCEnabled("estimatefee")) {
- throw JSONRPCError(RPC_METHOD_DEPRECATED, "estimatefee is deprecated and will be fully removed in v0.17. "
- "To use estimatefee in v0.16, restart bitcoind with -deprecatedrpc=estimatefee.\n"
- "Projects should transition to using estimatesmartfee before upgrading to v0.17");
- }
-
- RPCTypeCheck(request.params, {UniValue::VNUM});
-
- int nBlocks = request.params[0].get_int();
- if (nBlocks < 1)
- nBlocks = 1;
-
- CFeeRate feeRate = ::feeEstimator.estimateFee(nBlocks);
- if (feeRate == CFeeRate(0))
- return -1.0;
-
- return ValueFromAmount(feeRate.GetFeePerK());
+ throw JSONRPCError(RPC_METHOD_DEPRECATED, "estimatefee was removed in v0.17.\n"
+ "Clients should use estimatesmartfee.");
}
UniValue estimatesmartfee(const JSONRPCRequest& request)
@@ -986,7 +946,7 @@ static const CRPCCommand commands[] =
{ "generating", "generatetoaddress", &generatetoaddress, {"nblocks","address","maxtries"} },
- { "util", "estimatefee", &estimatefee, {"nblocks"} },
+ { "hidden", "estimatefee", &estimatefee, {} },
{ "util", "estimatesmartfee", &estimatesmartfee, {"conf_target", "estimate_mode"} },
{ "hidden", "estimaterawfee", &estimaterawfee, {"conf_target", "threshold"} },
diff --git a/src/rpc/misc.cpp b/src/rpc/misc.cpp
index c11dda22c4..e772f56534 100644
--- a/src/rpc/misc.cpp
+++ b/src/rpc/misc.cpp
@@ -262,9 +262,6 @@ UniValue createmultisig(const JSONRPCRequest& request)
std::string msg = "createmultisig nrequired [\"key\",...]\n"
"\nCreates a multi-signature address with n signature of m keys required.\n"
"It returns a json object with the address and redeemScript.\n"
- "DEPRECATION WARNING: Using addresses with createmultisig is deprecated. Clients must\n"
- "transition to using addmultisigaddress to create multisig addresses with addresses known\n"
- "to the wallet before upgrading to v0.17. To use the deprecated functionality, start bitcoind with -deprecatedrpc=createmultisig\n"
"\nArguments:\n"
"1. nrequired (numeric, required) The number of required signatures out of the n keys or addresses.\n"
"2. \"keys\" (string, required) A json array of hex-encoded public keys\n"
@@ -297,15 +294,8 @@ UniValue createmultisig(const JSONRPCRequest& request)
if (IsHex(keys[i].get_str()) && (keys[i].get_str().length() == 66 || keys[i].get_str().length() == 130)) {
pubkeys.push_back(HexToPubKey(keys[i].get_str()));
} else {
-#ifdef ENABLE_WALLET
- CWallet* const pwallet = GetWalletForJSONRPCRequest(request);
- if (IsDeprecatedRPCEnabled("createmultisig") && EnsureWalletIsAvailable(pwallet, false)) {
- pubkeys.push_back(AddrToPubKey(pwallet, keys[i].get_str()));
- } else
-#endif
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, strprintf("Invalid public key: %s\nNote that from v0.16, createmultisig no longer accepts addresses."
- " Clients must transition to using addmultisigaddress to create multisig addresses with addresses known to the wallet before upgrading to v0.17."
- " To use the deprecated functionality, start bitcoind with -deprecatedrpc=createmultisig", keys[i].get_str()));
+ " Users must use addmultisigaddress to create multisig addresses with addresses known to the wallet.", keys[i].get_str()));
}
}
diff --git a/src/script/ismine.cpp b/src/script/ismine.cpp
index d0dd272550..35d794b983 100644
--- a/src/script/ismine.cpp
+++ b/src/script/ismine.cpp
@@ -13,16 +13,13 @@
typedef std::vector<unsigned char> valtype;
-unsigned int HaveKeys(const std::vector<valtype>& pubkeys, const CKeyStore& keystore)
+static bool HaveKeys(const std::vector<valtype>& pubkeys, const CKeyStore& keystore)
{
- unsigned int nResult = 0;
- for (const valtype& pubkey : pubkeys)
- {
+ for (const valtype& pubkey : pubkeys) {
CKeyID keyID = CPubKey(pubkey).GetID();
- if (keystore.HaveKey(keyID))
- ++nResult;
+ if (!keystore.HaveKey(keyID)) return false;
}
- return nResult;
+ return true;
}
isminetype IsMine(const CKeyStore& keystore, const CScript& scriptPubKey, SigVersion sigversion)
@@ -140,7 +137,7 @@ isminetype IsMine(const CKeyStore &keystore, const CScript& scriptPubKey, bool&
}
}
}
- if (HaveKeys(keys, keystore) == keys.size())
+ if (HaveKeys(keys, keystore))
return ISMINE_SPENDABLE;
break;
}
diff --git a/src/txmempool.h b/src/txmempool.h
index d6f8e7094b..c6a1bf08ce 100644
--- a/src/txmempool.h
+++ b/src/txmempool.h
@@ -241,15 +241,18 @@ public:
/** \class CompareTxMemPoolEntryByScore
*
- * Sort by score of entry ((fee+delta)/size) in descending order
+ * Sort by feerate of entry (fee/size) in descending order
+ * This is only used for transaction relay, so we use GetFee()
+ * instead of GetModifiedFee() to avoid leaking prioritization
+ * information via the sort order.
*/
class CompareTxMemPoolEntryByScore
{
public:
bool operator()(const CTxMemPoolEntry& a, const CTxMemPoolEntry& b) const
{
- double f1 = (double)a.GetModifiedFee() * b.GetTxSize();
- double f2 = (double)b.GetModifiedFee() * a.GetTxSize();
+ double f1 = (double)a.GetFee() * b.GetTxSize();
+ double f2 = (double)b.GetFee() * a.GetTxSize();
if (f1 == f2) {
return b.GetTx().GetHash() < a.GetTx().GetHash();
}
@@ -379,8 +382,9 @@ public:
*
* mapTx is a boost::multi_index that sorts the mempool on 4 criteria:
* - transaction hash
- * - feerate [we use max(feerate of tx, feerate of tx with all descendants)]
+ * - descendant feerate [we use max(feerate of tx, feerate of tx with all descendants)]
* - time in mempool
+ * - ancestor feerate [we use min(feerate of tx, feerate of tx with all unconfirmed ancestors)]
*
* Note: the term "descendant" refers to in-mempool transactions that depend on
* this one, while "ancestor" refers to in-mempool transactions that a given
diff --git a/src/validation.cpp b/src/validation.cpp
index 6b02c0920c..371460a6f0 100644
--- a/src/validation.cpp
+++ b/src/validation.cpp
@@ -547,8 +547,10 @@ static bool AcceptToMemoryPoolWorker(const CChainParams& chainparams, CTxMemPool
const CTransaction& tx = *ptx;
const uint256 hash = tx.GetHash();
AssertLockHeld(cs_main);
- if (pfMissingInputs)
+ LOCK(pool.cs); // mempool "read lock" (held through GetMainSignals().TransactionAddedToMempool())
+ if (pfMissingInputs) {
*pfMissingInputs = false;
+ }
if (!CheckTransaction(tx, state))
return false; // state filled in by CheckTransaction
@@ -581,8 +583,6 @@ static bool AcceptToMemoryPoolWorker(const CChainParams& chainparams, CTxMemPool
// Check for conflicts with in-memory transactions
std::set<uint256> setConflicts;
- {
- LOCK(pool.cs); // protect pool.mapNextTx
for (const CTxIn &txin : tx.vin)
{
auto itConflicting = pool.mapNextTx.find(txin.prevout);
@@ -623,15 +623,12 @@ static bool AcceptToMemoryPoolWorker(const CChainParams& chainparams, CTxMemPool
}
}
}
- }
{
CCoinsView dummy;
CCoinsViewCache view(&dummy);
LockPoints lp;
- {
- LOCK(pool.cs);
CCoinsViewMemPool viewMemPool(pcoinsTip.get(), pool);
view.SetBackend(viewMemPool);
@@ -670,8 +667,6 @@ static bool AcceptToMemoryPoolWorker(const CChainParams& chainparams, CTxMemPool
if (!CheckSequenceLocks(tx, STANDARD_LOCKTIME_VERIFY_FLAGS, &lp))
return state.DoS(0, false, REJECT_NONSTANDARD, "non-BIP68-final");
- } // end LOCK(pool.cs)
-
CAmount nFees = 0;
if (!Consensus::CheckTxInputs(tx, state, view, GetSpendHeight(view), nFees)) {
return error("%s: Consensus::CheckTxInputs: %s, %s", __func__, tx.GetHash().ToString(), FormatStateMessage(state));
@@ -768,7 +763,6 @@ static bool AcceptToMemoryPoolWorker(const CChainParams& chainparams, CTxMemPool
// If we don't hold the lock allConflicting might be incomplete; the
// subsequent RemoveStaged() and addUnchecked() calls don't guarantee
// mempool consistency for us.
- LOCK(pool.cs);
const bool fReplacementTransaction = setConflicts.size();
if (fReplacementTransaction)
{
@@ -2582,9 +2576,6 @@ bool CChainState::ActivateBestChain(CValidationState &state, const CChainParams&
SyncWithValidationInterfaceQueue();
}
- if (ShutdownRequested())
- break;
-
const CBlockIndex *pindexFork;
bool fInitialDownload;
{
@@ -2631,6 +2622,13 @@ bool CChainState::ActivateBestChain(CValidationState &state, const CChainParams&
}
if (nStopAtHeight && pindexNewTip && pindexNewTip->nHeight >= nStopAtHeight) StartShutdown();
+
+ // We check shutdown only after giving ActivateBestChainStep a chance to run once so that we
+ // never shutdown before connecting the genesis block during LoadChainTip(). Previously this
+ // caused an assert() failure during shutdown in such cases as the UTXO DB flushing checks
+ // that the best block hash is non-null.
+ if (ShutdownRequested())
+ break;
} while (pindexNewTip != pindexMostWork);
CheckBlockIndex(chainparams.GetConsensus());
diff --git a/src/wallet/rpcdump.cpp b/src/wallet/rpcdump.cpp
index 0b021f9fe0..03fb824e7a 100644
--- a/src/wallet/rpcdump.cpp
+++ b/src/wallet/rpcdump.cpp
@@ -71,6 +71,28 @@ std::string DecodeDumpString(const std::string &str) {
return ret.str();
}
+bool GetWalletAddressesForKey(CWallet * const pwallet, const CKeyID &keyid, std::string &strAddr, std::string &strLabel)
+{
+ bool fLabelFound = false;
+ CKey key;
+ pwallet->GetKey(keyid, key);
+ for (const auto& dest : GetAllDestinationsForKey(key.GetPubKey())) {
+ if (pwallet->mapAddressBook.count(dest)) {
+ if (!strAddr.empty()) {
+ strAddr += ",";
+ }
+ strAddr += EncodeDestination(dest);
+ strLabel = EncodeDumpString(pwallet->mapAddressBook[dest].name);
+ fLabelFound = true;
+ }
+ }
+ if (!fLabelFound) {
+ strAddr = EncodeDestination(GetDestinationForKey(key.GetPubKey(), g_address_type));
+ }
+ return fLabelFound;
+}
+
+
UniValue importprivkey(const JSONRPCRequest& request)
{
CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
@@ -729,12 +751,13 @@ UniValue dumpwallet(const JSONRPCRequest& request)
for (std::vector<std::pair<int64_t, CKeyID> >::const_iterator it = vKeyBirth.begin(); it != vKeyBirth.end(); it++) {
const CKeyID &keyid = it->second;
std::string strTime = EncodeDumpTime(it->first);
- std::string strAddr = EncodeDestination(keyid);
+ std::string strAddr;
+ std::string strLabel;
CKey key;
if (pwallet->GetKey(keyid, key)) {
file << strprintf("%s %s ", CBitcoinSecret(key).ToString(), strTime);
- if (pwallet->mapAddressBook.count(keyid)) {
- file << strprintf("label=%s", EncodeDumpString(pwallet->mapAddressBook[keyid].name));
+ if (GetWalletAddressesForKey(pwallet, keyid, strAddr, strLabel)) {
+ file << strprintf("label=%s", strLabel);
} else if (keyid == masterKeyID) {
file << "hdmaster=1";
} else if (mapKeyPool.count(keyid)) {
diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp
index 33790d3490..261d9b37f5 100644
--- a/src/wallet/rpcwallet.cpp
+++ b/src/wallet/rpcwallet.cpp
@@ -1192,10 +1192,6 @@ UniValue addmultisigaddress(const JSONRPCRequest& request)
" \"address\":\"multisigaddress\", (string) The value of the new multisig address.\n"
" \"redeemScript\":\"script\" (string) The string value of the hex-encoded redemption script.\n"
"}\n"
- "\nResult (DEPRECATED. To see this result in v0.16 instead, please start bitcoind with -deprecatedrpc=addmultisigaddress).\n"
- " clients should transition to the new output api before upgrading to v0.17.\n"
- "\"address\" (string) A bitcoin address associated with the keys.\n"
-
"\nExamples:\n"
"\nAdd a multisig address from 2 addresses\n"
+ HelpExampleCli("addmultisigaddress", "2 \"[\\\"16sSauSf5pF2UkUwvKGq4qjNRzBZYqgEL5\\\",\\\"171sgjn4YtPu27adkKGrdDwzRTxnRkBfKV\\\"]\"") +
@@ -1238,11 +1234,6 @@ UniValue addmultisigaddress(const JSONRPCRequest& request)
CTxDestination dest = pwallet->AddAndGetDestinationForScript(inner, output_type);
pwallet->SetAddressBook(dest, strAccount, "send");
- // Return old style interface
- if (IsDeprecatedRPCEnabled("addmultisigaddress")) {
- return EncodeDestination(dest);
- }
-
UniValue result(UniValue::VOBJ);
result.pushKV("address", EncodeDestination(dest));
result.pushKV("redeemScript", HexStr(inner.begin(), inner.end()));
@@ -2193,14 +2184,14 @@ UniValue abandontransaction(const JSONRPCRequest& request)
return NullUniValue;
}
- if (request.fHelp || request.params.size() != 1)
+ if (request.fHelp || request.params.size() != 1) {
throw std::runtime_error(
"abandontransaction \"txid\"\n"
"\nMark in-wallet transaction <txid> as abandoned\n"
"This will mark this transaction and all its in-wallet descendants as abandoned which will allow\n"
"for their inputs to be respent. It can be used to replace \"stuck\" or evicted transactions.\n"
"It only works on transactions which are not included in a block and are not currently in the mempool.\n"
- "It has no effect on transactions which are already conflicted or abandoned.\n"
+ "It has no effect on transactions which are already abandoned.\n"
"\nArguments:\n"
"1. \"txid\" (string, required) The transaction id\n"
"\nResult:\n"
@@ -2208,6 +2199,7 @@ UniValue abandontransaction(const JSONRPCRequest& request)
+ HelpExampleCli("abandontransaction", "\"1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d\"")
+ HelpExampleRpc("abandontransaction", "\"1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d\"")
);
+ }
ObserveSafeMode();
@@ -3260,8 +3252,8 @@ UniValue bumpfee(const JSONRPCRequest& request)
"If the change output is not big enough to cover the increased fee, the command will currently fail\n"
"instead of adding new inputs to compensate. (A future implementation could improve this.)\n"
"The command will fail if the wallet or mempool contains a transaction that spends one of T's outputs.\n"
- "By default, the new fee will be calculated automatically using estimatefee.\n"
- "The user can specify a confirmation target for estimatefee.\n"
+ "By default, the new fee will be calculated automatically using estimatesmartfee.\n"
+ "The user can specify a confirmation target for estimatesmartfee.\n"
"Alternatively, the user can specify totalFee, or use RPC settxfee to set a higher fee rate.\n"
"At a minimum, the new fee rate must be high enough to pay an additional new relay fee (incrementalfee\n"
"returned by getnetworkinfo) to enter the node's mempool.\n"
diff --git a/src/wallet/test/wallet_tests.cpp b/src/wallet/test/wallet_tests.cpp
index f39471b871..161372784b 100644
--- a/src/wallet/test/wallet_tests.cpp
+++ b/src/wallet/test/wallet_tests.cpp
@@ -676,18 +676,24 @@ BOOST_FIXTURE_TEST_CASE(ListCoins, ListCoinsTestingSetup)
BOOST_CHECK_EQUAL(list.begin()->second.size(), 2);
// Lock both coins. Confirm number of available coins drops to 0.
- std::vector<COutput> available;
- wallet->AvailableCoins(available);
- BOOST_CHECK_EQUAL(available.size(), 2);
+ {
+ LOCK2(cs_main, wallet->cs_wallet);
+ std::vector<COutput> available;
+ wallet->AvailableCoins(available);
+ BOOST_CHECK_EQUAL(available.size(), 2);
+ }
for (const auto& group : list) {
for (const auto& coin : group.second) {
LOCK(wallet->cs_wallet);
wallet->LockCoin(COutPoint(coin.tx->GetHash(), coin.i));
}
}
- wallet->AvailableCoins(available);
- BOOST_CHECK_EQUAL(available.size(), 0);
-
+ {
+ LOCK2(cs_main, wallet->cs_wallet);
+ std::vector<COutput> available;
+ wallet->AvailableCoins(available);
+ BOOST_CHECK_EQUAL(available.size(), 0);
+ }
// Confirm ListCoins still returns same result as before, despite coins
// being locked.
list = wallet->ListCoins();
diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp
index 3b8ecce6da..513819606b 100644
--- a/src/wallet/wallet.cpp
+++ b/src/wallet/wallet.cpp
@@ -1078,7 +1078,7 @@ bool CWallet::TransactionCanBeAbandoned(const uint256& hashTx) const
{
LOCK2(cs_main, cs_wallet);
const CWalletTx* wtx = GetWalletTx(hashTx);
- return wtx && !wtx->isAbandoned() && wtx->GetDepthInMainChain() <= 0 && !wtx->InMempool();
+ return wtx && !wtx->isAbandoned() && wtx->GetDepthInMainChain() == 0 && !wtx->InMempool();
}
bool CWallet::AbandonTransaction(const uint256& hashTx)
@@ -1094,7 +1094,7 @@ bool CWallet::AbandonTransaction(const uint256& hashTx)
auto it = mapWallet.find(hashTx);
assert(it != mapWallet.end());
CWalletTx& origtx = it->second;
- if (origtx.GetDepthInMainChain() > 0 || origtx.InMempool()) {
+ if (origtx.GetDepthInMainChain() != 0 || origtx.InMempool()) {
return false;
}
@@ -2198,111 +2198,109 @@ CAmount CWallet::GetAvailableBalance(const CCoinControl* coinControl) const
void CWallet::AvailableCoins(std::vector<COutput> &vCoins, bool fOnlySafe, const CCoinControl *coinControl, const CAmount &nMinimumAmount, const CAmount &nMaximumAmount, const CAmount &nMinimumSumAmount, const uint64_t nMaximumCount, const int nMinDepth, const int nMaxDepth) const
{
+ AssertLockHeld(cs_main);
+ AssertLockHeld(cs_wallet);
+
vCoins.clear();
+ CAmount nTotal = 0;
+ for (const auto& entry : mapWallet)
{
- LOCK2(cs_main, cs_wallet);
+ const uint256& wtxid = entry.first;
+ const CWalletTx* pcoin = &entry.second;
- CAmount nTotal = 0;
+ if (!CheckFinalTx(*pcoin->tx))
+ continue;
- for (const auto& entry : mapWallet)
- {
- const uint256& wtxid = entry.first;
- const CWalletTx* pcoin = &entry.second;
+ if (pcoin->IsCoinBase() && pcoin->GetBlocksToMaturity() > 0)
+ continue;
- if (!CheckFinalTx(*pcoin->tx))
- continue;
+ int nDepth = pcoin->GetDepthInMainChain();
+ if (nDepth < 0)
+ continue;
- if (pcoin->IsCoinBase() && pcoin->GetBlocksToMaturity() > 0)
- continue;
+ // We should not consider coins which aren't at least in our mempool
+ // It's possible for these to be conflicted via ancestors which we may never be able to detect
+ if (nDepth == 0 && !pcoin->InMempool())
+ continue;
- int nDepth = pcoin->GetDepthInMainChain();
- if (nDepth < 0)
- continue;
+ bool safeTx = pcoin->IsTrusted();
+
+ // We should not consider coins from transactions that are replacing
+ // other transactions.
+ //
+ // Example: There is a transaction A which is replaced by bumpfee
+ // transaction B. In this case, we want to prevent creation of
+ // a transaction B' which spends an output of B.
+ //
+ // Reason: If transaction A were initially confirmed, transactions B
+ // and B' would no longer be valid, so the user would have to create
+ // a new transaction C to replace B'. However, in the case of a
+ // one-block reorg, transactions B' and C might BOTH be accepted,
+ // when the user only wanted one of them. Specifically, there could
+ // be a 1-block reorg away from the chain where transactions A and C
+ // were accepted to another chain where B, B', and C were all
+ // accepted.
+ if (nDepth == 0 && pcoin->mapValue.count("replaces_txid")) {
+ safeTx = false;
+ }
- // We should not consider coins which aren't at least in our mempool
- // It's possible for these to be conflicted via ancestors which we may never be able to detect
- if (nDepth == 0 && !pcoin->InMempool())
- continue;
+ // Similarly, we should not consider coins from transactions that
+ // have been replaced. In the example above, we would want to prevent
+ // creation of a transaction A' spending an output of A, because if
+ // transaction B were initially confirmed, conflicting with A and
+ // A', we wouldn't want to the user to create a transaction D
+ // intending to replace A', but potentially resulting in a scenario
+ // where A, A', and D could all be accepted (instead of just B and
+ // D, or just A and A' like the user would want).
+ if (nDepth == 0 && pcoin->mapValue.count("replaced_by_txid")) {
+ safeTx = false;
+ }
- bool safeTx = pcoin->IsTrusted();
-
- // We should not consider coins from transactions that are replacing
- // other transactions.
- //
- // Example: There is a transaction A which is replaced by bumpfee
- // transaction B. In this case, we want to prevent creation of
- // a transaction B' which spends an output of B.
- //
- // Reason: If transaction A were initially confirmed, transactions B
- // and B' would no longer be valid, so the user would have to create
- // a new transaction C to replace B'. However, in the case of a
- // one-block reorg, transactions B' and C might BOTH be accepted,
- // when the user only wanted one of them. Specifically, there could
- // be a 1-block reorg away from the chain where transactions A and C
- // were accepted to another chain where B, B', and C were all
- // accepted.
- if (nDepth == 0 && pcoin->mapValue.count("replaces_txid")) {
- safeTx = false;
- }
+ if (fOnlySafe && !safeTx) {
+ continue;
+ }
- // Similarly, we should not consider coins from transactions that
- // have been replaced. In the example above, we would want to prevent
- // creation of a transaction A' spending an output of A, because if
- // transaction B were initially confirmed, conflicting with A and
- // A', we wouldn't want to the user to create a transaction D
- // intending to replace A', but potentially resulting in a scenario
- // where A, A', and D could all be accepted (instead of just B and
- // D, or just A and A' like the user would want).
- if (nDepth == 0 && pcoin->mapValue.count("replaced_by_txid")) {
- safeTx = false;
- }
+ if (nDepth < nMinDepth || nDepth > nMaxDepth)
+ continue;
- if (fOnlySafe && !safeTx) {
+ for (unsigned int i = 0; i < pcoin->tx->vout.size(); i++) {
+ if (pcoin->tx->vout[i].nValue < nMinimumAmount || pcoin->tx->vout[i].nValue > nMaximumAmount)
continue;
- }
- if (nDepth < nMinDepth || nDepth > nMaxDepth)
+ if (coinControl && coinControl->HasSelected() && !coinControl->fAllowOtherInputs && !coinControl->IsSelected(COutPoint(entry.first, i)))
continue;
- for (unsigned int i = 0; i < pcoin->tx->vout.size(); i++) {
- if (pcoin->tx->vout[i].nValue < nMinimumAmount || pcoin->tx->vout[i].nValue > nMaximumAmount)
- continue;
-
- if (coinControl && coinControl->HasSelected() && !coinControl->fAllowOtherInputs && !coinControl->IsSelected(COutPoint(entry.first, i)))
- continue;
-
- if (IsLockedCoin(entry.first, i))
- continue;
-
- if (IsSpent(wtxid, i))
- continue;
+ if (IsLockedCoin(entry.first, i))
+ continue;
- isminetype mine = IsMine(pcoin->tx->vout[i]);
+ if (IsSpent(wtxid, i))
+ continue;
- if (mine == ISMINE_NO) {
- continue;
- }
+ isminetype mine = IsMine(pcoin->tx->vout[i]);
- bool fSpendableIn = ((mine & ISMINE_SPENDABLE) != ISMINE_NO) || (coinControl && coinControl->fAllowWatchOnly && (mine & ISMINE_WATCH_SOLVABLE) != ISMINE_NO);
- bool fSolvableIn = (mine & (ISMINE_SPENDABLE | ISMINE_WATCH_SOLVABLE)) != ISMINE_NO;
+ if (mine == ISMINE_NO) {
+ continue;
+ }
- vCoins.push_back(COutput(pcoin, i, nDepth, fSpendableIn, fSolvableIn, safeTx));
+ bool fSpendableIn = ((mine & ISMINE_SPENDABLE) != ISMINE_NO) || (coinControl && coinControl->fAllowWatchOnly && (mine & ISMINE_WATCH_SOLVABLE) != ISMINE_NO);
+ bool fSolvableIn = (mine & (ISMINE_SPENDABLE | ISMINE_WATCH_SOLVABLE)) != ISMINE_NO;
- // Checks the sum amount of all UTXO's.
- if (nMinimumSumAmount != MAX_MONEY) {
- nTotal += pcoin->tx->vout[i].nValue;
+ vCoins.push_back(COutput(pcoin, i, nDepth, fSpendableIn, fSolvableIn, safeTx));
- if (nTotal >= nMinimumSumAmount) {
- return;
- }
- }
+ // Checks the sum amount of all UTXO's.
+ if (nMinimumSumAmount != MAX_MONEY) {
+ nTotal += pcoin->tx->vout[i].nValue;
- // Checks the maximum number of UTXO's.
- if (nMaximumCount > 0 && vCoins.size() >= nMaximumCount) {
+ if (nTotal >= nMinimumSumAmount) {
return;
}
}
+
+ // Checks the maximum number of UTXO's.
+ if (nMaximumCount > 0 && vCoins.size() >= nMaximumCount) {
+ return;
+ }
}
}
}
@@ -2320,11 +2318,11 @@ std::map<CTxDestination, std::vector<COutput>> CWallet::ListCoins() const
// avoid adding some extra complexity to the Qt code.
std::map<CTxDestination, std::vector<COutput>> result;
-
std::vector<COutput> availableCoins;
- AvailableCoins(availableCoins);
LOCK2(cs_main, cs_wallet);
+ AvailableCoins(availableCoins);
+
for (auto& coin : availableCoins) {
CTxDestination address;
if (coin.fSpendable &&