aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/chain.cpp7
-rw-r--r--src/chainparams.cpp1
-rw-r--r--src/checkpoints.cpp9
-rw-r--r--src/checkpoints.h3
-rw-r--r--src/compat/endian.h2
-rw-r--r--src/init.cpp129
-rw-r--r--src/main.cpp106
-rw-r--r--src/main.h9
-rw-r--r--src/qt/forms/rpcconsole.ui122
-rw-r--r--src/qt/guiutil.cpp13
-rw-r--r--src/qt/guiutil.h10
-rw-r--r--src/qt/peertablemodel.cpp5
-rw-r--r--src/qt/rpcconsole.cpp82
-rw-r--r--src/qt/rpcconsole.h8
-rw-r--r--src/rpcserver.cpp21
-rw-r--r--src/test/Checkpoints_tests.cpp16
-rw-r--r--src/test/alert_tests.cpp10
-rw-r--r--src/test/miner_tests.cpp1
-rw-r--r--src/test/rpc_tests.cpp3
-rw-r--r--src/test/univalue_tests.cpp6
-rw-r--r--src/test/util_tests.cpp44
-rw-r--r--src/univalue/univalue_read.cpp15
-rw-r--r--src/utilmoneystr.cpp4
-rw-r--r--src/utilmoneystr.h2
-rw-r--r--src/wallet/rpcdump.cpp9
-rw-r--r--src/wallet/rpcwallet.cpp18
26 files changed, 421 insertions, 234 deletions
diff --git a/src/chain.cpp b/src/chain.cpp
index 719256106e..5b8ce076c4 100644
--- a/src/chain.cpp
+++ b/src/chain.cpp
@@ -82,9 +82,10 @@ CBlockIndex* CBlockIndex::GetAncestor(int height)
while (heightWalk > height) {
int heightSkip = GetSkipHeight(heightWalk);
int heightSkipPrev = GetSkipHeight(heightWalk - 1);
- if (heightSkip == height ||
- (heightSkip > height && !(heightSkipPrev < heightSkip - 2 &&
- heightSkipPrev >= height))) {
+ if (pindexWalk->pskip != NULL &&
+ (heightSkip == height ||
+ (heightSkip > height && !(heightSkipPrev < heightSkip - 2 &&
+ heightSkipPrev >= height)))) {
// Only follow pskip if pprev->pskip isn't better than pskip->pprev.
pindexWalk = pindexWalk->pskip;
heightWalk = heightSkip;
diff --git a/src/chainparams.cpp b/src/chainparams.cpp
index 5f400b265c..7785417518 100644
--- a/src/chainparams.cpp
+++ b/src/chainparams.cpp
@@ -66,6 +66,7 @@ public:
*/
const char* pszTimestamp = "The Times 03/Jan/2009 Chancellor on brink of second bailout for banks";
CMutableTransaction txNew;
+ txNew.nVersion = 1;
txNew.vin.resize(1);
txNew.vout.resize(1);
txNew.vin[0].scriptSig = CScript() << 486604799 << CScriptNum(4) << vector<unsigned char>((const unsigned char*)pszTimestamp, (const unsigned char*)pszTimestamp + strlen(pszTimestamp));
diff --git a/src/checkpoints.cpp b/src/checkpoints.cpp
index 2024486139..87f4ad7f2e 100644
--- a/src/checkpoints.cpp
+++ b/src/checkpoints.cpp
@@ -24,15 +24,6 @@ namespace Checkpoints {
*/
static const double SIGCHECK_VERIFICATION_FACTOR = 5.0;
- bool CheckBlock(const CCheckpointData& data, int nHeight, const uint256& hash)
- {
- const MapCheckpoints& checkpoints = data.mapCheckpoints;
-
- MapCheckpoints::const_iterator i = checkpoints.find(nHeight);
- if (i == checkpoints.end()) return true;
- return hash == i->second;
- }
-
//! Guess how far we are in the verification process at the given block index
double GuessVerificationProgress(const CCheckpointData& data, CBlockIndex *pindex, bool fSigchecks) {
if (pindex==NULL)
diff --git a/src/checkpoints.h b/src/checkpoints.h
index a720f096c0..001e3cc801 100644
--- a/src/checkpoints.h
+++ b/src/checkpoints.h
@@ -26,9 +26,6 @@ struct CCheckpointData {
double fTransactionsPerDay;
};
-//! Returns true if block passes checkpoint checks
-bool CheckBlock(const CCheckpointData& data, int nHeight, const uint256& hash);
-
//! Return conservative estimate of total number of blocks, 0 if unknown
int GetTotalBlocksEstimate(const CCheckpointData& data);
diff --git a/src/compat/endian.h b/src/compat/endian.h
index 4d041d6554..9fec2a07fa 100644
--- a/src/compat/endian.h
+++ b/src/compat/endian.h
@@ -15,6 +15,8 @@
#if defined(HAVE_ENDIAN_H)
#include <endian.h>
+#elif defined(HAVE_SYS_ENDIAN_H)
+#include <sys/endian.h>
#endif
#if defined(WORDS_BIGENDIAN)
diff --git a/src/init.cpp b/src/init.cpp
index 02dca57031..b5f9a0310f 100644
--- a/src/init.cpp
+++ b/src/init.cpp
@@ -260,8 +260,10 @@ void OnRPCPreCommand(const CRPCCommand& cmd)
std::string HelpMessage(HelpMessageMode mode)
{
+ const bool showDebug = GetBoolArg("-help-debug", false);
// When adding new options to the categories, please keep and ensure alphabetical ordering.
+ // Do not translate _(...) -help-debug options, Many technical terms, and only a very small audience, so is unnecessary stress to translators.
string strUsage = HelpMessageGroup(_("Options:"));
strUsage += HelpMessageOpt("-?", _("This help message"));
strUsage += HelpMessageOpt("-alertnotify=<cmd>", _("Execute command when a relevant alert is received or we see a really long fork (%s in cmd is replaced by message)"));
@@ -318,7 +320,7 @@ std::string HelpMessage(HelpMessageMode mode)
strUsage += HelpMessageOpt("-timeout=<n>", strprintf(_("Specify connection timeout in milliseconds (minimum: 1, default: %d)"), DEFAULT_CONNECT_TIMEOUT));
#ifdef USE_UPNP
#if USE_UPNP
- strUsage += HelpMessageOpt("-upnp", _("Use UPnP to map the listening port (default: 1 when listening)"));
+ strUsage += HelpMessageOpt("-upnp", _("Use UPnP to map the listening port (default: 1 when listening and no -proxy)"));
#else
strUsage += HelpMessageOpt("-upnp", strprintf(_("Use UPnP to map the listening port (default: %u)"), 0));
#endif
@@ -326,14 +328,13 @@ std::string HelpMessage(HelpMessageMode mode)
strUsage += HelpMessageOpt("-whitebind=<addr>", _("Bind to given address and whitelist peers connecting to it. Use [host]:port notation for IPv6"));
strUsage += HelpMessageOpt("-whitelist=<netmask>", _("Whitelist peers connecting from the given netmask or IP address. Can be specified multiple times.") +
" " + _("Whitelisted peers cannot be DoS banned and their transactions are always relayed, even if they are already in the mempool, useful e.g. for a gateway"));
-
#ifdef ENABLE_WALLET
strUsage += HelpMessageGroup(_("Wallet options:"));
strUsage += HelpMessageOpt("-disablewallet", _("Do not load the wallet and disable wallet RPC calls"));
strUsage += HelpMessageOpt("-keypool=<n>", strprintf(_("Set key pool size to <n> (default: %u)"), 100));
- if (GetBoolArg("-help-debug", false))
- strUsage += HelpMessageOpt("-mintxfee=<amt>", strprintf(_("Fees (in BTC/Kb) smaller than this are considered zero fee for transaction creation (default: %s)"),
+ if (showDebug)
+ strUsage += HelpMessageOpt("-mintxfee=<amt>", strprintf("Fees (in BTC/Kb) smaller than this are considered zero fee for transaction creation (default: %s)",
FormatMoney(CWallet::minTxFee.GetFeePerK())));
strUsage += HelpMessageOpt("-paytxfee=<amt>", strprintf(_("Fee (in BTC/kB) to add to transactions you send (default: %s)"), FormatMoney(payTxFee.GetFeePerK())));
strUsage += HelpMessageOpt("-rescan", _("Rescan the block chain for missing wallet transactions") + " " + _("on startup"));
@@ -349,20 +350,19 @@ std::string HelpMessage(HelpMessageMode mode)
strUsage += HelpMessageOpt("-walletnotify=<cmd>", _("Execute command when a wallet transaction changes (%s in cmd is replaced by TxID)"));
strUsage += HelpMessageOpt("-zapwallettxes=<mode>", _("Delete all wallet transactions and only recover those parts of the blockchain through -rescan on startup") +
" " + _("(1 = keep tx meta data e.g. account owner and payment request information, 2 = drop tx meta data)"));
-
#endif
strUsage += HelpMessageGroup(_("Debugging/Testing options:"));
- if (GetBoolArg("-help-debug", false))
+ if (showDebug)
{
- strUsage += HelpMessageOpt("-checkpoints", strprintf(_("Only accept block chain matching built-in checkpoints (default: %u)"), 1));
- strUsage += HelpMessageOpt("-dblogsize=<n>", strprintf(_("Flush database activity from memory pool to disk log every <n> megabytes (default: %u)"), 100));
- strUsage += HelpMessageOpt("-disablesafemode", strprintf(_("Disable safemode, override a real safe mode event (default: %u)"), 0));
- strUsage += HelpMessageOpt("-testsafemode", strprintf(_("Force safe mode (default: %u)"), 0));
- strUsage += HelpMessageOpt("-dropmessagestest=<n>", _("Randomly drop 1 of every <n> network messages"));
- strUsage += HelpMessageOpt("-fuzzmessagestest=<n>", _("Randomly fuzz 1 of every <n> network messages"));
- strUsage += HelpMessageOpt("-flushwallet", strprintf(_("Run a thread to flush wallet periodically (default: %u)"), 1));
- strUsage += HelpMessageOpt("-stopafterblockimport", strprintf(_("Stop running after importing blocks from disk (default: %u)"), 0));
+ strUsage += HelpMessageOpt("-checkpoints", strprintf("Disable expensive verification for known chain history (default: %u)", 1));
+ strUsage += HelpMessageOpt("-dblogsize=<n>", strprintf("Flush database activity from memory pool to disk log every <n> megabytes (default: %u)", 100));
+ strUsage += HelpMessageOpt("-disablesafemode", strprintf("Disable safemode, override a real safe mode event (default: %u)", 0));
+ strUsage += HelpMessageOpt("-testsafemode", strprintf("Force safe mode (default: %u)", 0));
+ strUsage += HelpMessageOpt("-dropmessagestest=<n>", "Randomly drop 1 of every <n> network messages");
+ strUsage += HelpMessageOpt("-fuzzmessagestest=<n>", "Randomly fuzz 1 of every <n> network messages");
+ strUsage += HelpMessageOpt("-flushwallet", strprintf("Run a thread to flush wallet periodically (default: %u)", 1));
+ strUsage += HelpMessageOpt("-stopafterblockimport", strprintf("Stop running after importing blocks from disk (default: %u)", 0));
}
string debugCategories = "addrman, alert, bench, coindb, db, lock, rand, rpc, selectcoins, mempool, net, proxy, prune"; // Don't translate these and qt below
if (mode == HMM_BITCOIN_QT)
@@ -376,21 +376,20 @@ std::string HelpMessage(HelpMessageMode mode)
strUsage += HelpMessageOpt("-help-debug", _("Show all debugging options (usage: --help -help-debug)"));
strUsage += HelpMessageOpt("-logips", strprintf(_("Include IP addresses in debug output (default: %u)"), 0));
strUsage += HelpMessageOpt("-logtimestamps", strprintf(_("Prepend debug output with timestamp (default: %u)"), 1));
- if (GetBoolArg("-help-debug", false))
+ if (showDebug)
{
- strUsage += HelpMessageOpt("-limitfreerelay=<n>", strprintf(_("Continuously rate-limit free transactions to <n>*1000 bytes per minute (default: %u)"), 15));
- strUsage += HelpMessageOpt("-relaypriority", strprintf(_("Require high priority for relaying free or low-fee transactions (default: %u)"), 1));
- strUsage += HelpMessageOpt("-maxsigcachesize=<n>", strprintf(_("Limit size of signature cache to <n> entries (default: %u)"), 50000));
+ strUsage += HelpMessageOpt("-limitfreerelay=<n>", strprintf("Continuously rate-limit free transactions to <n>*1000 bytes per minute (default: %u)", 15));
+ strUsage += HelpMessageOpt("-relaypriority", strprintf("Require high priority for relaying free or low-fee transactions (default: %u)", 1));
+ strUsage += HelpMessageOpt("-maxsigcachesize=<n>", strprintf("Limit size of signature cache to <n> entries (default: %u)", 50000));
}
strUsage += HelpMessageOpt("-minrelaytxfee=<amt>", strprintf(_("Fees (in BTC/Kb) smaller than this are considered zero fee for relaying (default: %s)"), FormatMoney(::minRelayTxFee.GetFeePerK())));
strUsage += HelpMessageOpt("-printtoconsole", _("Send trace/debug info to console instead of debug.log file"));
- if (GetBoolArg("-help-debug", false))
+ if (showDebug)
{
- strUsage += HelpMessageOpt("-printpriority", strprintf(_("Log transaction priority and fee per kB when mining blocks (default: %u)"), 0));
- strUsage += HelpMessageOpt("-privdb", strprintf(_("Sets the DB_PRIVATE flag in the wallet db environment (default: %u)"), 1));
- strUsage += HelpMessageOpt("-regtest", _("Enter regression test mode, which uses a special chain in which blocks can be solved instantly.") + " " +
- _("This is intended for regression testing tools and app development.") + " " +
- _("In this mode -genproclimit controls how many blocks are generated immediately."));
+ strUsage += HelpMessageOpt("-printpriority", strprintf("Log transaction priority and fee per kB when mining blocks (default: %u)", 0));
+ strUsage += HelpMessageOpt("-privdb", strprintf("Sets the DB_PRIVATE flag in the wallet db environment (default: %u)", 1));
+ strUsage += HelpMessageOpt("-regtest", "Enter regression test mode, which uses a special chain in which blocks can be solved instantly. "
+ "This is intended for regression testing tools and app development.");
}
strUsage += HelpMessageOpt("-shrinkdebugfile", _("Shrink debug.log file on client startup (default: 1 when no -debug)"));
strUsage += HelpMessageOpt("-testnet", _("Use the test network"));
@@ -403,6 +402,8 @@ std::string HelpMessage(HelpMessageMode mode)
strUsage += HelpMessageOpt("-blockminsize=<n>", strprintf(_("Set minimum block size in bytes (default: %u)"), 0));
strUsage += HelpMessageOpt("-blockmaxsize=<n>", strprintf(_("Set maximum block size in bytes (default: %d)"), DEFAULT_BLOCK_MAX_SIZE));
strUsage += HelpMessageOpt("-blockprioritysize=<n>", strprintf(_("Set maximum size of high-priority/low-fee transactions in bytes (default: %d)"), DEFAULT_BLOCK_PRIORITY_SIZE));
+ if (showDebug)
+ strUsage += HelpMessageOpt("-blockversion=<n>", strprintf("Override block version to test forking scenarios (default: %d)", (int)CBlock::CURRENT_VERSION));
strUsage += HelpMessageGroup(_("RPC server options:"));
strUsage += HelpMessageOpt("-server", _("Accept command line and JSON-RPC commands"));
@@ -424,8 +425,8 @@ std::string HelpMessage(HelpMessageMode mode)
if (mode == HMM_BITCOIN_QT)
{
strUsage += HelpMessageGroup(_("UI Options:"));
- if (GetBoolArg("-help-debug", false)) {
- strUsage += HelpMessageOpt("-allowselfsignedrootcertificates", _("Allow self signed root certificates (default: 0)"));
+ if (showDebug) {
+ strUsage += HelpMessageOpt("-allowselfsignedrootcertificates", "Allow self signed root certificates (default: 0)");
}
strUsage += HelpMessageOpt("-choosedatadir", _("Choose data directory on startup (default: 0)"));
strUsage += HelpMessageOpt("-lang=<lang>", _("Set language, for example \"de_DE\" (default: system locale)"));
@@ -473,24 +474,43 @@ struct CImportingNow
// If we're using -prune with -reindex, then delete block files that will be ignored by the
// reindex. Since reindexing works by starting at block file 0 and looping until a blockfile
-// is missing, and since pruning works by deleting the oldest block file first, just check
-// for block file 0, and if it doesn't exist, delete all the block files in the
-// directory (since they won't be read by the reindex but will take up disk space).
-void DeleteAllBlockFiles()
+// is missing, do the same here to delete any later block files after a gap. Also delete all
+// rev files since they'll be rewritten by the reindex anyway. This ensures that vinfoBlockFile
+// is in sync with what's actually on disk by the time we start downloading, so that pruning
+// works correctly.
+void CleanupBlockRevFiles()
{
- if (boost::filesystem::exists(GetBlockPosFilename(CDiskBlockPos(0, 0), "blk")))
- return;
+ using namespace boost::filesystem;
+ map<string, path> mapBlockFiles;
+
+ // Glob all blk?????.dat and rev?????.dat files from the blocks directory.
+ // Remove the rev files immediately and insert the blk file paths into an
+ // ordered map keyed by block file index.
+ LogPrintf("Removing unusable blk?????.dat and rev?????.dat files for -reindex with -prune\n");
+ path blocksdir = GetDataDir() / "blocks";
+ for (directory_iterator it(blocksdir); it != directory_iterator(); it++) {
+ if (is_regular_file(*it) &&
+ it->path().filename().string().length() == 12 &&
+ it->path().filename().string().substr(8,4) == ".dat")
+ {
+ if (it->path().filename().string().substr(0,3) == "blk")
+ mapBlockFiles[it->path().filename().string().substr(3,5)] = it->path();
+ else if (it->path().filename().string().substr(0,3) == "rev")
+ remove(it->path());
+ }
+ }
- LogPrintf("Removing all blk?????.dat and rev?????.dat files for -reindex with -prune\n");
- boost::filesystem::path blocksdir = GetDataDir() / "blocks";
- for (boost::filesystem::directory_iterator it(blocksdir); it != boost::filesystem::directory_iterator(); it++) {
- if (is_regular_file(*it)) {
- if ((it->path().filename().string().length() == 12) &&
- (it->path().filename().string().substr(8,4) == ".dat") &&
- ((it->path().filename().string().substr(0,3) == "blk") ||
- (it->path().filename().string().substr(0,3) == "rev")))
- boost::filesystem::remove(it->path());
+ // Remove all block files that aren't part of a contiguous set starting at
+ // zero by walking the ordered map (keys are block file indices) by
+ // keeping a separate counter. Once we hit a gap (or if 0 doesn't exist)
+ // start removing block files.
+ int nContigCounter = 0;
+ BOOST_FOREACH(const PAIRTYPE(string, path)& item, mapBlockFiles) {
+ if (atoi(item.first) == nContigCounter) {
+ nContigCounter++;
+ continue;
}
+ remove(item.second);
}
}
@@ -714,16 +734,12 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
nMaxConnections = nFD - MIN_CORE_FILEDESCRIPTORS;
// if using block pruning, then disable txindex
- // also disable the wallet (for now, until SPV support is implemented in wallet)
if (GetArg("-prune", 0)) {
if (GetBoolArg("-txindex", false))
return InitError(_("Prune mode is incompatible with -txindex."));
#ifdef ENABLE_WALLET
- if (!GetBoolArg("-disablewallet", false)) {
- if (SoftSetBoolArg("-disablewallet", true))
- LogPrintf("%s : parameter interaction: -prune -> setting -disablewallet=1\n", __func__);
- else
- return InitError(_("Can't run with a wallet in prune mode."));
+ if (GetBoolArg("-rescan", false)) {
+ return InitError(_("Rescans are not possible in pruned mode. You will need to use -reindex which will download the whole blockchain again."));
}
#endif
}
@@ -1110,9 +1126,9 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
if (fReindex) {
pblocktree->WriteReindexing(true);
- //If we're reindexing in prune mode, wipe away all our block and undo data files
+ //If we're reindexing in prune mode, wipe away unusable block files and all undo data files
if (fPruneMode)
- DeleteAllBlockFiles();
+ CleanupBlockRevFiles();
}
if (!LoadBlockIndex()) {
@@ -1310,6 +1326,19 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
}
if (chainActive.Tip() && chainActive.Tip() != pindexRescan)
{
+ //We can't rescan beyond non-pruned blocks, stop and throw an error
+ //this might happen if a user uses a old wallet within a pruned node
+ // or if he ran -disablewallet for a longer time, then decided to re-enable
+ if (fPruneMode)
+ {
+ CBlockIndex *block = chainActive.Tip();
+ while (block && block->pprev && (block->pprev->nStatus & BLOCK_HAVE_DATA) && block->pprev->nTx > 0 && pindexRescan != block)
+ block = block->pprev;
+
+ if (pindexRescan != block)
+ return InitError(_("Prune: last wallet synchronisation goes beyond pruned data. You need to -reindex (download the whole blockchain again in case of pruned node)"));
+ }
+
uiInterface.InitMessage(_("Rescanning..."));
LogPrintf("Rescanning last %i blocks (from block %i)...\n", chainActive.Height() - pindexRescan->nHeight, pindexRescan->nHeight);
nStart = GetTimeMillis();
@@ -1396,7 +1425,7 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
// Monitor the chain, and alert if we get blocks much quicker or slower than expected
int64_t nPowTargetSpacing = Params().GetConsensus().nPowTargetSpacing;
CScheduler::Function f = boost::bind(&PartitionCheck, &IsInitialBlockDownload,
- boost::ref(cs_main), boost::cref(chainActive), nPowTargetSpacing);
+ boost::ref(cs_main), boost::cref(pindexBestHeader), nPowTargetSpacing);
scheduler.scheduleEvery(f, nPowTargetSpacing);
#ifdef ENABLE_WALLET
diff --git a/src/main.cpp b/src/main.cpp
index e9a5f7efd9..082ef6b6b2 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -1395,22 +1395,21 @@ bool CScriptCheck::operator()() {
return true;
}
-bool CheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsViewCache &inputs, bool fScriptChecks, unsigned int flags, bool cacheStore, std::vector<CScriptCheck> *pvChecks)
+int GetSpendHeight(const CCoinsViewCache& inputs)
{
- if (!tx.IsCoinBase())
- {
- if (pvChecks)
- pvChecks->reserve(tx.vin.size());
+ LOCK(cs_main);
+ CBlockIndex* pindexPrev = mapBlockIndex.find(inputs.GetBestBlock())->second;
+ return pindexPrev->nHeight + 1;
+}
+namespace Consensus {
+bool CheckTxInputs(const CTransaction& tx, CValidationState& state, const CCoinsViewCache& inputs, int nSpendHeight)
+{
// This doesn't trigger the DoS code on purpose; if it did, it would make it easier
// for an attacker to attempt to split the network.
if (!inputs.HaveInputs(tx))
return state.Invalid(error("CheckInputs(): %s inputs unavailable", tx.GetHash().ToString()));
- // While checking, GetBestBlock() refers to the parent block.
- // This is also true for mempool checks.
- CBlockIndex *pindexPrev = mapBlockIndex.find(inputs.GetBestBlock())->second;
- int nSpendHeight = pindexPrev->nHeight + 1;
CAmount nValueIn = 0;
CAmount nFees = 0;
for (unsigned int i = 0; i < tx.vin.size(); i++)
@@ -1449,6 +1448,19 @@ bool CheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsVi
if (!MoneyRange(nFees))
return state.DoS(100, error("CheckInputs(): nFees out of range"),
REJECT_INVALID, "bad-txns-fee-outofrange");
+ return true;
+}
+}// namespace Consensus
+
+bool CheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsViewCache &inputs, bool fScriptChecks, unsigned int flags, bool cacheStore, std::vector<CScriptCheck> *pvChecks)
+{
+ if (!tx.IsCoinBase())
+ {
+ if (!Consensus::CheckTxInputs(tx, state, inputs, GetSpendHeight(inputs)))
+ return false;
+
+ if (pvChecks)
+ pvChecks->reserve(tx.vin.size());
// The first loop above does all the inexpensive checks.
// Only if ALL inputs pass do we perform expensive ECDSA signature checks.
@@ -1711,9 +1723,10 @@ void ThreadScriptCheck() {
// we're being fed a bad chain (blocks being generated much
// too slowly or too quickly).
//
-void PartitionCheck(bool (*initialDownloadCheck)(), CCriticalSection& cs, const CChain& chain, int64_t nPowTargetSpacing)
+void PartitionCheck(bool (*initialDownloadCheck)(), CCriticalSection& cs, const CBlockIndex *const &bestHeader,
+ int64_t nPowTargetSpacing)
{
- if (initialDownloadCheck()) return;
+ if (bestHeader == NULL || initialDownloadCheck()) return;
static int64_t lastAlertTime = 0;
int64_t now = GetAdjustedTime();
@@ -1729,10 +1742,13 @@ void PartitionCheck(bool (*initialDownloadCheck)(), CCriticalSection& cs, const
int64_t startTime = GetAdjustedTime()-SPAN_SECONDS;
LOCK(cs);
- int h = chain.Height();
- while (h > 0 && chain[h]->GetBlockTime() >= startTime)
- --h;
- int nBlocks = chain.Height()-h;
+ const CBlockIndex* i = bestHeader;
+ int nBlocks = 0;
+ while (i->GetBlockTime() >= startTime) {
+ ++nBlocks;
+ i = i->pprev;
+ if (i == NULL) return; // Ran out of chain, we must not be fully sync'ed
+ }
// How likely is it to find that many by chance?
double p = boost::math::pdf(poisson, nBlocks);
@@ -1790,7 +1806,14 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
return true;
}
- bool fScriptChecks = (!fCheckpointsEnabled || pindex->nHeight >= Checkpoints::GetTotalBlocksEstimate(chainparams.Checkpoints()));
+ bool fScriptChecks = true;
+ if (fCheckpointsEnabled) {
+ CBlockIndex *pindexLastCheckpoint = Checkpoints::GetLastCheckpoint(chainparams.Checkpoints());
+ if (pindexLastCheckpoint && pindexLastCheckpoint->GetAncestor(pindex->nHeight) == pindex) {
+ // This block is an ancestor of a checkpoint: disable script checks
+ fScriptChecks = false;
+ }
+ }
// Do not allow blocks that contain transactions which 'overwrite' older transactions,
// unless those are already completely spent.
@@ -2712,18 +2735,23 @@ bool CheckBlock(const CBlock& block, CValidationState& state, bool fCheckPOW, bo
return true;
}
-bool ContextualCheckBlockHeader(const CBlockHeader& block, CValidationState& state, CBlockIndex * const pindexPrev)
+static bool CheckIndexAgainstCheckpoint(const CBlockIndex* pindexPrev, CValidationState& state, const CChainParams& chainparams, const uint256& hash)
{
- const CChainParams& chainParams = Params();
- const Consensus::Params& consensusParams = chainParams.GetConsensus();
- uint256 hash = block.GetHash();
- if (hash == consensusParams.hashGenesisBlock)
+ if (*pindexPrev->phashBlock == chainparams.GetConsensus().hashGenesisBlock)
return true;
- assert(pindexPrev);
-
int nHeight = pindexPrev->nHeight+1;
+ // Don't accept any forks from the main chain prior to last checkpoint
+ CBlockIndex* pcheckpoint = Checkpoints::GetLastCheckpoint(chainparams.Checkpoints());
+ if (pcheckpoint && nHeight < pcheckpoint->nHeight)
+ return state.DoS(100, error("%s: forked chain older than last checkpoint (height %d)", __func__, nHeight));
+ return true;
+}
+
+bool ContextualCheckBlockHeader(const CBlockHeader& block, CValidationState& state, CBlockIndex * const pindexPrev)
+{
+ const Consensus::Params& consensusParams = Params().GetConsensus();
// Check proof of work
if (block.nBits != GetNextWorkRequired(pindexPrev, &block, consensusParams))
return state.DoS(100, error("%s: incorrect proof of work", __func__),
@@ -2734,19 +2762,6 @@ bool ContextualCheckBlockHeader(const CBlockHeader& block, CValidationState& sta
return state.Invalid(error("%s: block's timestamp is too early", __func__),
REJECT_INVALID, "time-too-old");
- if(fCheckpointsEnabled)
- {
- // Check that the block chain matches the known block chain up to a checkpoint
- if (!Checkpoints::CheckBlock(chainParams.Checkpoints(), nHeight, hash))
- return state.DoS(100, error("%s: rejected by checkpoint lock-in at %d", __func__, nHeight),
- REJECT_CHECKPOINT, "checkpoint mismatch");
-
- // Don't accept any forks from the main chain prior to last checkpoint
- CBlockIndex* pcheckpoint = Checkpoints::GetLastCheckpoint(chainParams.Checkpoints());
- if (pcheckpoint && nHeight < pcheckpoint->nHeight)
- return state.DoS(100, error("%s: forked chain older than last checkpoint (height %d)", __func__, nHeight));
- }
-
// Reject block.nVersion=1 blocks when 95% (75% on testnet) of the network has upgraded:
if (block.nVersion < 2 && IsSuperMajority(2, pindexPrev, consensusParams.nMajorityRejectBlockOutdated, consensusParams))
return state.Invalid(error("%s: rejected nVersion=1 block", __func__),
@@ -2816,6 +2831,9 @@ bool AcceptBlockHeader(const CBlockHeader& block, CValidationState& state, CBloc
if (pindexPrev->nStatus & BLOCK_FAILED_MASK)
return state.DoS(100, error("%s: prev block invalid", __func__), REJECT_INVALID, "bad-prevblk");
}
+ assert(pindexPrev);
+ if (fCheckpointsEnabled && !CheckIndexAgainstCheckpoint(pindexPrev, state, chainparams, hash))
+ return error("%s: CheckIndexAgainstCheckpoint(): %s", __func__, state.GetRejectReason().c_str());
if (!ContextualCheckBlockHeader(block, state, pindexPrev))
return false;
@@ -2931,8 +2949,11 @@ bool ProcessNewBlock(CValidationState &state, CNode* pfrom, CBlock* pblock, bool
bool TestBlockValidity(CValidationState &state, const CBlock& block, CBlockIndex * const pindexPrev, bool fCheckPOW, bool fCheckMerkleRoot)
{
+ const CChainParams& chainparams = Params();
AssertLockHeld(cs_main);
- assert(pindexPrev == chainActive.Tip());
+ assert(pindexPrev && pindexPrev == chainActive.Tip());
+ if (fCheckpointsEnabled && !CheckIndexAgainstCheckpoint(pindexPrev, state, chainparams, block.GetHash()))
+ return error("%s: CheckIndexAgainstCheckpoint(): %s", __func__, state.GetRejectReason().c_str());
CCoinsViewCache viewNew(pcoinsTip);
CBlockIndex indexDummy(block);
@@ -3040,9 +3061,9 @@ void FindFilesToPrune(std::set<int>& setFilesToPrune)
if (nCurrentUsage + nBuffer < nPruneTarget) // are we below our target?
break;
- // don't prune files that could have a block within MIN_BLOCKS_TO_KEEP of the main chain's tip
+ // don't prune files that could have a block within MIN_BLOCKS_TO_KEEP of the main chain's tip but keep scanning
if (vinfoBlockFile[fileNumber].nHeightLast > nLastBlockWeCanPrune)
- break;
+ continue;
PruneOneBlockFile(fileNumber);
// Queue up the files for removal
@@ -4320,7 +4341,6 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
mempool.check(pcoinsTip);
RelayTransaction(tx);
vWorkQueue.push_back(inv.hash);
- vEraseQueue.push_back(inv.hash);
LogPrint("mempool", "AcceptToMemoryPool: peer=%d %s: accepted %s (poolsz %u)\n",
pfrom->id, pfrom->cleanSubVer,
@@ -4347,7 +4367,6 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
// anyone relaying LegitTxX banned)
CValidationState stateDummy;
- vEraseQueue.push_back(orphanHash);
if (setMisbehaving.count(fromPeer))
continue;
@@ -4356,6 +4375,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
LogPrint("mempool", " accepted orphan tx %s\n", orphanHash.ToString());
RelayTransaction(orphanTx);
vWorkQueue.push_back(orphanHash);
+ vEraseQueue.push_back(orphanHash);
}
else if (!fMissingInputs2)
{
@@ -4367,8 +4387,10 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
setMisbehaving.insert(fromPeer);
LogPrint("mempool", " invalid orphan tx %s\n", orphanHash.ToString());
}
- // too-little-fee orphan
+ // Has inputs but not accepted to mempool
+ // Probably non-standard or insufficient fee/priority
LogPrint("mempool", " removed orphan tx %s\n", orphanHash.ToString());
+ vEraseQueue.push_back(orphanHash);
}
mempool.check(pcoinsTip);
}
diff --git a/src/main.h b/src/main.h
index abaedae207..d87fec7868 100644
--- a/src/main.h
+++ b/src/main.h
@@ -186,7 +186,7 @@ bool SendMessages(CNode* pto, bool fSendTrickle);
/** Run an instance of the script checking thread */
void ThreadScriptCheck();
/** Try to detect Partition (network isolation) attacks against us */
-void PartitionCheck(bool (*initialDownloadCheck)(), CCriticalSection& cs, const CChain& chain, int64_t nPowTargetSpacing);
+void PartitionCheck(bool (*initialDownloadCheck)(), CCriticalSection& cs, const CBlockIndex *const &bestHeader, int64_t nPowTargetSpacing);
/** Check whether we are doing an initial block download (synchronizing from disk or network) */
bool IsInitialBlockDownload();
/** Format a string that describes several potential problems detected by the core */
@@ -487,4 +487,11 @@ extern CCoinsViewCache *pcoinsTip;
/** Global variable that points to the active block tree (protected by cs_main) */
extern CBlockTreeDB *pblocktree;
+/**
+ * Return the spend height, which is one more than the inputs.GetBestBlock().
+ * While checking, GetBestBlock() refers to the parent block. (protected by cs_main)
+ * This is also true for mempool checks.
+ */
+int GetSpendHeight(const CCoinsViewCache& inputs);
+
#endif // BITCOIN_MAIN_H
diff --git a/src/qt/forms/rpcconsole.ui b/src/qt/forms/rpcconsole.ui
index c1eb185501..7ae8237476 100644
--- a/src/qt/forms/rpcconsole.ui
+++ b/src/qt/forms/rpcconsole.ui
@@ -745,13 +745,36 @@
</property>
<layout class="QGridLayout" name="gridLayout_3">
<item row="0" column="0">
+ <widget class="QLabel" name="label_30">
+ <property name="text">
+ <string>Whitelisted</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="2">
+ <widget class="QLabel" name="peerWhitelisted">
+ <property name="cursor">
+ <cursorShape>IBeamCursor</cursorShape>
+ </property>
+ <property name="text">
+ <string>N/A</string>
+ </property>
+ <property name="textFormat">
+ <enum>Qt::PlainText</enum>
+ </property>
+ <property name="textInteractionFlags">
+ <set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="0">
<widget class="QLabel" name="label_23">
<property name="text">
<string>Direction</string>
</property>
</widget>
</item>
- <item row="0" column="2">
+ <item row="1" column="2">
<widget class="QLabel" name="peerDirection">
<property name="cursor">
<cursorShape>IBeamCursor</cursorShape>
@@ -767,14 +790,14 @@
</property>
</widget>
</item>
- <item row="1" column="0">
+ <item row="2" column="0">
<widget class="QLabel" name="label_21">
<property name="text">
<string>Version</string>
</property>
</widget>
</item>
- <item row="1" column="2">
+ <item row="2" column="2">
<widget class="QLabel" name="peerVersion">
<property name="cursor">
<cursorShape>IBeamCursor</cursorShape>
@@ -790,14 +813,14 @@
</property>
</widget>
</item>
- <item row="2" column="0">
+ <item row="3" column="0">
<widget class="QLabel" name="label_28">
<property name="text">
<string>User Agent</string>
</property>
</widget>
</item>
- <item row="2" column="2">
+ <item row="3" column="2">
<widget class="QLabel" name="peerSubversion">
<property name="cursor">
<cursorShape>IBeamCursor</cursorShape>
@@ -813,14 +836,14 @@
</property>
</widget>
</item>
- <item row="3" column="0">
+ <item row="4" column="0">
<widget class="QLabel" name="label_4">
<property name="text">
<string>Services</string>
</property>
</widget>
</item>
- <item row="3" column="2">
+ <item row="4" column="2">
<widget class="QLabel" name="peerServices">
<property name="cursor">
<cursorShape>IBeamCursor</cursorShape>
@@ -839,7 +862,7 @@
<item row="5" column="0">
<widget class="QLabel" name="label_29">
<property name="text">
- <string>Starting Height</string>
+ <string>Starting Block</string>
</property>
</widget>
</item>
@@ -862,7 +885,7 @@
<item row="6" column="0">
<widget class="QLabel" name="label_27">
<property name="text">
- <string>Sync Height</string>
+ <string>Synced Headers</string>
</property>
</widget>
</item>
@@ -883,13 +906,36 @@
</widget>
</item>
<item row="7" column="0">
+ <widget class="QLabel" name="label_25">
+ <property name="text">
+ <string>Synced Blocks</string>
+ </property>
+ </widget>
+ </item>
+ <item row="7" column="2">
+ <widget class="QLabel" name="peerCommonHeight">
+ <property name="cursor">
+ <cursorShape>IBeamCursor</cursorShape>
+ </property>
+ <property name="text">
+ <string>N/A</string>
+ </property>
+ <property name="textFormat">
+ <enum>Qt::PlainText</enum>
+ </property>
+ <property name="textInteractionFlags">
+ <set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
+ </property>
+ </widget>
+ </item>
+ <item row="8" column="0">
<widget class="QLabel" name="label_24">
<property name="text">
<string>Ban Score</string>
</property>
</widget>
</item>
- <item row="7" column="2">
+ <item row="8" column="2">
<widget class="QLabel" name="peerBanScore">
<property name="cursor">
<cursorShape>IBeamCursor</cursorShape>
@@ -905,14 +951,14 @@
</property>
</widget>
</item>
- <item row="8" column="0">
+ <item row="9" column="0">
<widget class="QLabel" name="label_22">
<property name="text">
<string>Connection Time</string>
</property>
</widget>
</item>
- <item row="8" column="2">
+ <item row="9" column="2">
<widget class="QLabel" name="peerConnTime">
<property name="cursor">
<cursorShape>IBeamCursor</cursorShape>
@@ -928,14 +974,14 @@
</property>
</widget>
</item>
- <item row="9" column="0">
+ <item row="10" column="0">
<widget class="QLabel" name="label_15">
<property name="text">
<string>Last Send</string>
</property>
</widget>
</item>
- <item row="9" column="2">
+ <item row="10" column="2">
<widget class="QLabel" name="peerLastSend">
<property name="cursor">
<cursorShape>IBeamCursor</cursorShape>
@@ -951,14 +997,14 @@
</property>
</widget>
</item>
- <item row="10" column="0">
+ <item row="11" column="0">
<widget class="QLabel" name="label_19">
<property name="text">
<string>Last Receive</string>
</property>
</widget>
</item>
- <item row="10" column="2">
+ <item row="11" column="2">
<widget class="QLabel" name="peerLastRecv">
<property name="cursor">
<cursorShape>IBeamCursor</cursorShape>
@@ -974,14 +1020,14 @@
</property>
</widget>
</item>
- <item row="11" column="0">
+ <item row="12" column="0">
<widget class="QLabel" name="label_18">
<property name="text">
<string>Bytes Sent</string>
</property>
</widget>
</item>
- <item row="11" column="2">
+ <item row="12" column="2">
<widget class="QLabel" name="peerBytesSent">
<property name="cursor">
<cursorShape>IBeamCursor</cursorShape>
@@ -997,14 +1043,14 @@
</property>
</widget>
</item>
- <item row="12" column="0">
+ <item row="13" column="0">
<widget class="QLabel" name="label_20">
<property name="text">
<string>Bytes Received</string>
</property>
</widget>
</item>
- <item row="12" column="2">
+ <item row="13" column="2">
<widget class="QLabel" name="peerBytesRecv">
<property name="cursor">
<cursorShape>IBeamCursor</cursorShape>
@@ -1020,14 +1066,14 @@
</property>
</widget>
</item>
- <item row="13" column="0">
+ <item row="14" column="0">
<widget class="QLabel" name="label_26">
<property name="text">
<string>Ping Time</string>
</property>
</widget>
</item>
- <item row="13" column="2">
+ <item row="14" column="2">
<widget class="QLabel" name="peerPingTime">
<property name="cursor">
<cursorShape>IBeamCursor</cursorShape>
@@ -1043,14 +1089,40 @@
</property>
</widget>
</item>
- <item row="14" column="0">
+ <item row="15" column="0">
+ <widget class="QLabel" name="peerPingWaitLabel">
+ <property name="toolTip">
+ <string>The duration of a currently outstanding ping.</string>
+ </property>
+ <property name="text">
+ <string>Ping Wait</string>
+ </property>
+ </widget>
+ </item>
+ <item row="15" column="2">
+ <widget class="QLabel" name="peerPingWait">
+ <property name="cursor">
+ <cursorShape>IBeamCursor</cursorShape>
+ </property>
+ <property name="text">
+ <string>N/A</string>
+ </property>
+ <property name="textFormat">
+ <enum>Qt::PlainText</enum>
+ </property>
+ <property name="textInteractionFlags">
+ <set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
+ </property>
+ </widget>
+ </item>
+ <item row="16" column="0">
<widget class="QLabel" name="label_timeoffset">
<property name="text">
<string>Time Offset</string>
</property>
</widget>
</item>
- <item row="14" column="2">
+ <item row="16" column="2">
<widget class="QLabel" name="timeoffset">
<property name="cursor">
<cursorShape>IBeamCursor</cursorShape>
@@ -1066,7 +1138,7 @@
</property>
</widget>
</item>
- <item row="15" column="1">
+ <item row="17" column="1">
<spacer name="verticalSpacer_3">
<property name="orientation">
<enum>Qt::Vertical</enum>
diff --git a/src/qt/guiutil.cpp b/src/qt/guiutil.cpp
index 4a1f728e18..581d2321bc 100644
--- a/src/qt/guiutil.cpp
+++ b/src/qt/guiutil.cpp
@@ -265,6 +265,19 @@ void copyEntryData(QAbstractItemView *view, int column, int role)
}
}
+QString getEntryData(QAbstractItemView *view, int column, int role)
+{
+ if(!view || !view->selectionModel())
+ return QString();
+ QModelIndexList selection = view->selectionModel()->selectedRows(column);
+
+ if(!selection.isEmpty()) {
+ // Return first item
+ return (selection.at(0).data(role).toString());
+ }
+ return QString();
+}
+
QString getSaveFileName(QWidget *parent, const QString &caption, const QString &dir,
const QString &filter,
QString *selectedSuffixOut)
diff --git a/src/qt/guiutil.h b/src/qt/guiutil.h
index bcbb540c37..55df64a256 100644
--- a/src/qt/guiutil.h
+++ b/src/qt/guiutil.h
@@ -64,6 +64,14 @@ namespace GUIUtil
*/
void copyEntryData(QAbstractItemView *view, int column, int role=Qt::EditRole);
+ /** Return a field of the currently selected entry as a QString. Does nothing if nothing
+ is selected.
+ @param[in] column Data column to extract from the model
+ @param[in] role Data role to extract from the model
+ @see TransactionView::copyLabel, TransactionView::copyAmount, TransactionView::copyAddress
+ */
+ QString getEntryData(QAbstractItemView *view, int column, int role);
+
void setClipboard(const QString& str);
/** Get save filename, mimics QFileDialog::getSaveFileName, except that it appends a default suffix
@@ -205,7 +213,7 @@ namespace GUIUtil
#else
typedef QProgressBar ProgressBar;
#endif
-
+
} // namespace GUIUtil
#endif // BITCOIN_QT_GUIUTIL_H
diff --git a/src/qt/peertablemodel.cpp b/src/qt/peertablemodel.cpp
index 220f273d02..f5904a4d8e 100644
--- a/src/qt/peertablemodel.cpp
+++ b/src/qt/peertablemodel.cpp
@@ -63,11 +63,12 @@ public:
#if QT_VERSION >= 0x040700
cachedNodeStats.reserve(vNodes.size());
#endif
- BOOST_FOREACH(CNode* pnode, vNodes)
+ foreach (CNode* pnode, vNodes)
{
CNodeCombinedStats stats;
stats.nodeStateStats.nMisbehavior = 0;
stats.nodeStateStats.nSyncHeight = -1;
+ stats.nodeStateStats.nCommonHeight = -1;
stats.fNodeStateStatsAvailable = false;
pnode->copyStats(stats.nodeStats);
cachedNodeStats.append(stats);
@@ -91,7 +92,7 @@ public:
// build index map
mapNodeRows.clear();
int row = 0;
- BOOST_FOREACH(CNodeCombinedStats &stats, cachedNodeStats)
+ foreach (const CNodeCombinedStats& stats, cachedNodeStats)
mapNodeRows.insert(std::pair<NodeId, int>(stats.nodeStats.nodeid, row++));
}
diff --git a/src/qt/rpcconsole.cpp b/src/qt/rpcconsole.cpp
index d7be531b2d..681617bd81 100644
--- a/src/qt/rpcconsole.cpp
+++ b/src/qt/rpcconsole.cpp
@@ -25,6 +25,7 @@
#endif
#include <QKeyEvent>
+#include <QMenu>
#include <QScrollBar>
#include <QThread>
#include <QTime>
@@ -205,7 +206,8 @@ RPCConsole::RPCConsole(QWidget *parent) :
ui(new Ui::RPCConsole),
clientModel(0),
historyPtr(0),
- cachedNodeid(-1)
+ cachedNodeid(-1),
+ contextMenu(0)
{
ui->setupUi(this);
GUIUtil::restoreWindowGeometry("nRPCConsoleWindow", this->size(), this);
@@ -305,10 +307,22 @@ void RPCConsole::setClientModel(ClientModel *model)
ui->peerWidget->setEditTriggers(QAbstractItemView::NoEditTriggers);
ui->peerWidget->setSelectionBehavior(QAbstractItemView::SelectRows);
ui->peerWidget->setSelectionMode(QAbstractItemView::SingleSelection);
+ ui->peerWidget->setContextMenuPolicy(Qt::CustomContextMenu);
ui->peerWidget->setColumnWidth(PeerTableModel::Address, ADDRESS_COLUMN_WIDTH);
ui->peerWidget->setColumnWidth(PeerTableModel::Subversion, SUBVERSION_COLUMN_WIDTH);
ui->peerWidget->setColumnWidth(PeerTableModel::Ping, PING_COLUMN_WIDTH);
+ // create context menu actions
+ QAction* disconnectAction = new QAction(tr("&Disconnect Node"), this);
+
+ // create context menu
+ contextMenu = new QMenu();
+ contextMenu->addAction(disconnectAction);
+
+ // context menu signals
+ connect(ui->peerWidget, SIGNAL(customContextMenuRequested(const QPoint&)), this, SLOT(showMenu(const QPoint&)));
+ connect(disconnectAction, SIGNAL(triggered()), this, SLOT(disconnectSelectedNode()));
+
// connect the peerWidget selection model to our peerSelected() handler
connect(ui->peerWidget->selectionModel(), SIGNAL(selectionChanged(const QItemSelection &, const QItemSelection &)),
this, SLOT(peerSelected(const QItemSelection &, const QItemSelection &)));
@@ -471,10 +485,10 @@ void RPCConsole::startExecutor()
void RPCConsole::on_tabWidget_currentChanged(int index)
{
- if(ui->tabWidget->widget(index) == ui->tab_console)
- {
+ if (ui->tabWidget->widget(index) == ui->tab_console)
ui->lineEdit->setFocus();
- }
+ else if (ui->tabWidget->widget(index) != ui->tab_peers)
+ clearSelectedNode();
}
void RPCConsole::on_openDebugLogfileButton_clicked()
@@ -544,12 +558,11 @@ void RPCConsole::peerLayoutChanged()
return;
// find the currently selected row
- int selectedRow;
+ int selectedRow = -1;
QModelIndexList selectedModelIndex = ui->peerWidget->selectionModel()->selectedIndexes();
- if (selectedModelIndex.isEmpty())
- selectedRow = -1;
- else
+ if (!selectedModelIndex.isEmpty()) {
selectedRow = selectedModelIndex.first().row();
+ }
// check if our detail node has a row in the table (it may not necessarily
// be at selectedRow since its position can change after a layout change)
@@ -559,9 +572,6 @@ void RPCConsole::peerLayoutChanged()
{
// detail node dissapeared from table (node disconnected)
fUnselect = true;
- cachedNodeid = -1;
- ui->detailWidget->hide();
- ui->peerHeading->setText(tr("Select a peer to view detailed information."));
}
else
{
@@ -576,10 +586,8 @@ void RPCConsole::peerLayoutChanged()
stats = clientModel->getPeerTableModel()->getNodeStats(detailNodeRow);
}
- if (fUnselect && selectedRow >= 0)
- {
- ui->peerWidget->selectionModel()->select(QItemSelection(selectedModelIndex.first(), selectedModelIndex.last()),
- QItemSelectionModel::Deselect);
+ if (fUnselect && selectedRow >= 0) {
+ clearSelectedNode();
}
if (fReselect)
@@ -597,7 +605,8 @@ void RPCConsole::updateNodeDetail(const CNodeCombinedStats *stats)
cachedNodeid = stats->nodeStats.nodeid;
// update the detail ui with latest node information
- QString peerAddrDetails(QString::fromStdString(stats->nodeStats.addrName));
+ QString peerAddrDetails(QString::fromStdString(stats->nodeStats.addrName) + " ");
+ peerAddrDetails += tr("(node id: %1)").arg(QString::number(stats->nodeStats.nodeid));
if (!stats->nodeStats.addrLocal.empty())
peerAddrDetails += "<br />" + tr("via %1").arg(QString::fromStdString(stats->nodeStats.addrLocal));
ui->peerHeading->setText(peerAddrDetails);
@@ -608,11 +617,13 @@ void RPCConsole::updateNodeDetail(const CNodeCombinedStats *stats)
ui->peerBytesRecv->setText(FormatBytes(stats->nodeStats.nRecvBytes));
ui->peerConnTime->setText(GUIUtil::formatDurationStr(GetTime() - stats->nodeStats.nTimeConnected));
ui->peerPingTime->setText(GUIUtil::formatPingTime(stats->nodeStats.dPingTime));
+ ui->peerPingWait->setText(GUIUtil::formatPingTime(stats->nodeStats.dPingWait));
ui->timeoffset->setText(GUIUtil::formatTimeOffset(stats->nodeStats.nTimeOffset));
- ui->peerVersion->setText(QString("%1").arg(stats->nodeStats.nVersion));
+ ui->peerVersion->setText(QString("%1").arg(QString::number(stats->nodeStats.nVersion)));
ui->peerSubversion->setText(QString::fromStdString(stats->nodeStats.cleanSubVer));
ui->peerDirection->setText(stats->nodeStats.fInbound ? tr("Inbound") : tr("Outbound"));
- ui->peerHeight->setText(QString("%1").arg(stats->nodeStats.nStartingHeight));
+ ui->peerHeight->setText(QString("%1").arg(QString::number(stats->nodeStats.nStartingHeight)));
+ ui->peerWhitelisted->setText(stats->nodeStats.fWhitelisted ? tr("Yes") : tr("No"));
// This check fails for example if the lock was busy and
// nodeStateStats couldn't be fetched.
@@ -625,9 +636,12 @@ void RPCConsole::updateNodeDetail(const CNodeCombinedStats *stats)
ui->peerSyncHeight->setText(QString("%1").arg(stats->nodeStateStats.nSyncHeight));
else
ui->peerSyncHeight->setText(tr("Unknown"));
- } else {
- ui->peerBanScore->setText(tr("Fetching..."));
- ui->peerSyncHeight->setText(tr("Fetching..."));
+
+ // Common height is init to -1
+ if (stats->nodeStateStats.nCommonHeight > -1)
+ ui->peerCommonHeight->setText(QString("%1").arg(stats->nodeStateStats.nCommonHeight));
+ else
+ ui->peerCommonHeight->setText(tr("Unknown"));
}
ui->detailWidget->show();
@@ -659,3 +673,29 @@ void RPCConsole::hideEvent(QHideEvent *event)
// stop PeerTableModel auto refresh
clientModel->getPeerTableModel()->stopAutoRefresh();
}
+
+void RPCConsole::showMenu(const QPoint& point)
+{
+ QModelIndex index = ui->peerWidget->indexAt(point);
+ if (index.isValid())
+ contextMenu->exec(QCursor::pos());
+}
+
+void RPCConsole::disconnectSelectedNode()
+{
+ // Get currently selected peer address
+ QString strNode = GUIUtil::getEntryData(ui->peerWidget, 0, PeerTableModel::Address);
+ // Find the node, disconnect it and clear the selected node
+ if (CNode *bannedNode = FindNode(strNode.toStdString())) {
+ bannedNode->CloseSocketDisconnect();
+ clearSelectedNode();
+ }
+}
+
+void RPCConsole::clearSelectedNode()
+{
+ ui->peerWidget->selectionModel()->clearSelection();
+ cachedNodeid = -1;
+ ui->detailWidget->hide();
+ ui->peerHeading->setText(tr("Select a peer to view detailed information."));
+}
diff --git a/src/qt/rpcconsole.h b/src/qt/rpcconsole.h
index 8737be35d1..a309df7ba7 100644
--- a/src/qt/rpcconsole.h
+++ b/src/qt/rpcconsole.h
@@ -19,6 +19,7 @@ namespace Ui {
}
QT_BEGIN_NAMESPACE
+class QMenu;
class QItemSelection;
QT_END_NAMESPACE
@@ -57,6 +58,8 @@ private slots:
void resizeEvent(QResizeEvent *event);
void showEvent(QShowEvent *event);
void hideEvent(QHideEvent *event);
+ /** Show custom context menu on Peers tab */
+ void showMenu(const QPoint& point);
public slots:
void clear();
@@ -73,6 +76,8 @@ public slots:
void peerSelected(const QItemSelection &selected, const QItemSelection &deselected);
/** Handle updated peer information */
void peerLayoutChanged();
+ /** Disconnect a selected node on the Peers tab */
+ void disconnectSelectedNode();
signals:
// For RPC command executor
@@ -85,6 +90,8 @@ private:
void setTrafficGraphRange(int mins);
/** show detailed information on ui about selected node */
void updateNodeDetail(const CNodeCombinedStats *stats);
+ /** clear the selected node */
+ void clearSelectedNode();
enum ColumnWidths
{
@@ -98,6 +105,7 @@ private:
QStringList history;
int historyPtr;
NodeId cachedNodeid;
+ QMenu *contextMenu;
};
#endif // BITCOIN_QT_RPCCONSOLE_H
diff --git a/src/rpcserver.cpp b/src/rpcserver.cpp
index e6bf008618..3894dd08bb 100644
--- a/src/rpcserver.cpp
+++ b/src/rpcserver.cpp
@@ -11,6 +11,7 @@
#include "sync.h"
#include "ui_interface.h"
#include "util.h"
+#include "utilmoneystr.h"
#include "utilstrencodings.h"
#ifdef ENABLE_WALLET
#include "wallet/wallet.h"
@@ -118,25 +119,21 @@ void RPCTypeCheckObj(const UniValue& o,
}
}
-static inline int64_t roundint64(double d)
-{
- return (int64_t)(d > 0 ? d + 0.5 : d - 0.5);
-}
-
CAmount AmountFromValue(const UniValue& value)
{
- double dAmount = value.get_real();
- if (dAmount <= 0.0 || dAmount > 21000000.0)
- throw JSONRPCError(RPC_TYPE_ERROR, "Invalid amount");
- CAmount nAmount = roundint64(dAmount * COIN);
- if (!MoneyRange(nAmount))
+ if (!value.isReal() && !value.isNum())
+ throw JSONRPCError(RPC_TYPE_ERROR, "Amount is not a number");
+ CAmount amount;
+ if (!ParseMoney(value.getValStr(), amount))
throw JSONRPCError(RPC_TYPE_ERROR, "Invalid amount");
- return nAmount;
+ if (!MoneyRange(amount))
+ throw JSONRPCError(RPC_TYPE_ERROR, "Amount out of range");
+ return amount;
}
UniValue ValueFromAmount(const CAmount& amount)
{
- return (double)amount / (double)COIN;
+ return UniValue(UniValue::VREAL, FormatMoney(amount));
}
uint256 ParseHashV(const UniValue& v, string strName)
diff --git a/src/test/Checkpoints_tests.cpp b/src/test/Checkpoints_tests.cpp
index 642ce13bcd..703cf307d1 100644
--- a/src/test/Checkpoints_tests.cpp
+++ b/src/test/Checkpoints_tests.cpp
@@ -21,21 +21,7 @@ BOOST_FIXTURE_TEST_SUITE(Checkpoints_tests, BasicTestingSetup)
BOOST_AUTO_TEST_CASE(sanity)
{
const Checkpoints::CCheckpointData& checkpoints = Params(CBaseChainParams::MAIN).Checkpoints();
- uint256 p11111 = uint256S("0x0000000069e244f73d78e8fd29ba2fd2ed618bd6fa2ee92559f542fdb26e7c1d");
- uint256 p134444 = uint256S("0x00000000000005b12ffd4cd315cd34ffd4a594f430ac814c91184a0d42d2b0fe");
- BOOST_CHECK(Checkpoints::CheckBlock(checkpoints, 11111, p11111));
- BOOST_CHECK(Checkpoints::CheckBlock(checkpoints, 134444, p134444));
-
-
- // Wrong hashes at checkpoints should fail:
- BOOST_CHECK(!Checkpoints::CheckBlock(checkpoints, 11111, p134444));
- BOOST_CHECK(!Checkpoints::CheckBlock(checkpoints, 134444, p11111));
-
- // ... but any hash not at a checkpoint should succeed:
- BOOST_CHECK(Checkpoints::CheckBlock(checkpoints, 11111+1, p134444));
- BOOST_CHECK(Checkpoints::CheckBlock(checkpoints, 134444+1, p11111));
-
BOOST_CHECK(Checkpoints::GetTotalBlocksEstimate(checkpoints) >= 134444);
-}
+}
BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/test/alert_tests.cpp b/src/test/alert_tests.cpp
index 22cb475e02..38dcc6023c 100644
--- a/src/test/alert_tests.cpp
+++ b/src/test/alert_tests.cpp
@@ -201,7 +201,6 @@ BOOST_AUTO_TEST_CASE(PartitionAlert)
{
// Test PartitionCheck
CCriticalSection csDummy;
- CChain chainDummy;
CBlockIndex indexDummy[100];
CChainParams& params = Params(CBaseChainParams::MAIN);
int64_t nPowTargetSpacing = params.GetConsensus().nPowTargetSpacing;
@@ -220,17 +219,16 @@ BOOST_AUTO_TEST_CASE(PartitionAlert)
// Other members don't matter, the partition check code doesn't
// use them
}
- chainDummy.SetTip(&indexDummy[99]);
// Test 1: chain with blocks every nPowTargetSpacing seconds,
// as normal, no worries:
- PartitionCheck(falseFunc, csDummy, chainDummy, nPowTargetSpacing);
+ PartitionCheck(falseFunc, csDummy, &indexDummy[99], nPowTargetSpacing);
BOOST_CHECK(strMiscWarning.empty());
// Test 2: go 3.5 hours without a block, expect a warning:
now += 3*60*60+30*60;
SetMockTime(now);
- PartitionCheck(falseFunc, csDummy, chainDummy, nPowTargetSpacing);
+ PartitionCheck(falseFunc, csDummy, &indexDummy[99], nPowTargetSpacing);
BOOST_CHECK(!strMiscWarning.empty());
BOOST_TEST_MESSAGE(std::string("Got alert text: ")+strMiscWarning);
strMiscWarning = "";
@@ -239,7 +237,7 @@ BOOST_AUTO_TEST_CASE(PartitionAlert)
// code:
now += 60*10;
SetMockTime(now);
- PartitionCheck(falseFunc, csDummy, chainDummy, nPowTargetSpacing);
+ PartitionCheck(falseFunc, csDummy, &indexDummy[99], nPowTargetSpacing);
BOOST_CHECK(strMiscWarning.empty());
// Test 4: get 2.5 times as many blocks as expected:
@@ -248,7 +246,7 @@ BOOST_AUTO_TEST_CASE(PartitionAlert)
int64_t quickSpacing = nPowTargetSpacing*2/5;
for (int i = 0; i < 100; i++) // Tweak chain timestamps:
indexDummy[i].nTime = now - (100-i)*quickSpacing;
- PartitionCheck(falseFunc, csDummy, chainDummy, nPowTargetSpacing);
+ PartitionCheck(falseFunc, csDummy, &indexDummy[99], nPowTargetSpacing);
BOOST_CHECK(!strMiscWarning.empty());
BOOST_TEST_MESSAGE(std::string("Got alert text: ")+strMiscWarning);
strMiscWarning = "";
diff --git a/src/test/miner_tests.cpp b/src/test/miner_tests.cpp
index 9e4fd8513e..212be0d2d6 100644
--- a/src/test/miner_tests.cpp
+++ b/src/test/miner_tests.cpp
@@ -74,6 +74,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
pblock->nVersion = 1;
pblock->nTime = chainActive.Tip()->GetMedianTimePast()+1;
CMutableTransaction txCoinbase(pblock->vtx[0]);
+ txCoinbase.nVersion = 1;
txCoinbase.vin[0].scriptSig = CScript();
txCoinbase.vin[0].scriptSig.push_back(blockinfo[i].extranonce);
txCoinbase.vin[0].scriptSig.push_back(chainActive.Height());
diff --git a/src/test/rpc_tests.cpp b/src/test/rpc_tests.cpp
index 0b33ddb086..08f988fdbf 100644
--- a/src/test/rpc_tests.cpp
+++ b/src/test/rpc_tests.cpp
@@ -131,6 +131,9 @@ static UniValue ValueFromString(const std::string &str)
BOOST_AUTO_TEST_CASE(rpc_parse_monetary_values)
{
+ BOOST_CHECK_THROW(AmountFromValue(ValueFromString("-0.00000001")), UniValue);
+ BOOST_CHECK_EQUAL(AmountFromValue(ValueFromString("0")), 0LL);
+ BOOST_CHECK_EQUAL(AmountFromValue(ValueFromString("0.00000000")), 0LL);
BOOST_CHECK_EQUAL(AmountFromValue(ValueFromString("0.00000001")), 1LL);
BOOST_CHECK_EQUAL(AmountFromValue(ValueFromString("0.17622195")), 17622195LL);
BOOST_CHECK_EQUAL(AmountFromValue(ValueFromString("0.5")), 50000000LL);
diff --git a/src/test/univalue_tests.cpp b/src/test/univalue_tests.cpp
index de84faca23..2c1d303f66 100644
--- a/src/test/univalue_tests.cpp
+++ b/src/test/univalue_tests.cpp
@@ -286,7 +286,7 @@ BOOST_AUTO_TEST_CASE(univalue_object)
}
static const char *json1 =
-"[1.10000000,{\"key1\":\"str\",\"key2\":800,\"key3\":{\"name\":\"martian\"}}]";
+"[1.10000000,{\"key1\":\"str\\u0000\",\"key2\":800,\"key3\":{\"name\":\"martian\"}}]";
BOOST_AUTO_TEST_CASE(univalue_readwrite)
{
@@ -306,7 +306,9 @@ BOOST_AUTO_TEST_CASE(univalue_readwrite)
BOOST_CHECK_EQUAL(obj.size(), 3);
BOOST_CHECK(obj["key1"].isStr());
- BOOST_CHECK_EQUAL(obj["key1"].getValStr(), "str");
+ std::string correctValue("str");
+ correctValue.push_back('\0');
+ BOOST_CHECK_EQUAL(obj["key1"].getValStr(), correctValue);
BOOST_CHECK(obj["key2"].isNum());
BOOST_CHECK_EQUAL(obj["key2"].getValStr(), "800");
BOOST_CHECK(obj["key3"].isObject());
diff --git a/src/test/util_tests.cpp b/src/test/util_tests.cpp
index 053cf3577d..5cb5894251 100644
--- a/src/test/util_tests.cpp
+++ b/src/test/util_tests.cpp
@@ -146,29 +146,27 @@ BOOST_AUTO_TEST_CASE(util_GetArg)
BOOST_AUTO_TEST_CASE(util_FormatMoney)
{
- BOOST_CHECK_EQUAL(FormatMoney(0, false), "0.00");
- BOOST_CHECK_EQUAL(FormatMoney((COIN/10000)*123456789, false), "12345.6789");
- BOOST_CHECK_EQUAL(FormatMoney(COIN, true), "+1.00");
- BOOST_CHECK_EQUAL(FormatMoney(-COIN, false), "-1.00");
- BOOST_CHECK_EQUAL(FormatMoney(-COIN, true), "-1.00");
-
- BOOST_CHECK_EQUAL(FormatMoney(COIN*100000000, false), "100000000.00");
- BOOST_CHECK_EQUAL(FormatMoney(COIN*10000000, false), "10000000.00");
- BOOST_CHECK_EQUAL(FormatMoney(COIN*1000000, false), "1000000.00");
- BOOST_CHECK_EQUAL(FormatMoney(COIN*100000, false), "100000.00");
- BOOST_CHECK_EQUAL(FormatMoney(COIN*10000, false), "10000.00");
- BOOST_CHECK_EQUAL(FormatMoney(COIN*1000, false), "1000.00");
- BOOST_CHECK_EQUAL(FormatMoney(COIN*100, false), "100.00");
- BOOST_CHECK_EQUAL(FormatMoney(COIN*10, false), "10.00");
- BOOST_CHECK_EQUAL(FormatMoney(COIN, false), "1.00");
- BOOST_CHECK_EQUAL(FormatMoney(COIN/10, false), "0.10");
- BOOST_CHECK_EQUAL(FormatMoney(COIN/100, false), "0.01");
- BOOST_CHECK_EQUAL(FormatMoney(COIN/1000, false), "0.001");
- BOOST_CHECK_EQUAL(FormatMoney(COIN/10000, false), "0.0001");
- BOOST_CHECK_EQUAL(FormatMoney(COIN/100000, false), "0.00001");
- BOOST_CHECK_EQUAL(FormatMoney(COIN/1000000, false), "0.000001");
- BOOST_CHECK_EQUAL(FormatMoney(COIN/10000000, false), "0.0000001");
- BOOST_CHECK_EQUAL(FormatMoney(COIN/100000000, false), "0.00000001");
+ BOOST_CHECK_EQUAL(FormatMoney(0), "0.00");
+ BOOST_CHECK_EQUAL(FormatMoney((COIN/10000)*123456789), "12345.6789");
+ BOOST_CHECK_EQUAL(FormatMoney(-COIN), "-1.00");
+
+ BOOST_CHECK_EQUAL(FormatMoney(COIN*100000000), "100000000.00");
+ BOOST_CHECK_EQUAL(FormatMoney(COIN*10000000), "10000000.00");
+ BOOST_CHECK_EQUAL(FormatMoney(COIN*1000000), "1000000.00");
+ BOOST_CHECK_EQUAL(FormatMoney(COIN*100000), "100000.00");
+ BOOST_CHECK_EQUAL(FormatMoney(COIN*10000), "10000.00");
+ BOOST_CHECK_EQUAL(FormatMoney(COIN*1000), "1000.00");
+ BOOST_CHECK_EQUAL(FormatMoney(COIN*100), "100.00");
+ BOOST_CHECK_EQUAL(FormatMoney(COIN*10), "10.00");
+ BOOST_CHECK_EQUAL(FormatMoney(COIN), "1.00");
+ BOOST_CHECK_EQUAL(FormatMoney(COIN/10), "0.10");
+ BOOST_CHECK_EQUAL(FormatMoney(COIN/100), "0.01");
+ BOOST_CHECK_EQUAL(FormatMoney(COIN/1000), "0.001");
+ BOOST_CHECK_EQUAL(FormatMoney(COIN/10000), "0.0001");
+ BOOST_CHECK_EQUAL(FormatMoney(COIN/100000), "0.00001");
+ BOOST_CHECK_EQUAL(FormatMoney(COIN/1000000), "0.000001");
+ BOOST_CHECK_EQUAL(FormatMoney(COIN/10000000), "0.0000001");
+ BOOST_CHECK_EQUAL(FormatMoney(COIN/100000000), "0.00000001");
}
BOOST_AUTO_TEST_CASE(util_ParseMoney)
diff --git a/src/univalue/univalue_read.cpp b/src/univalue/univalue_read.cpp
index 5cea778996..261771811d 100644
--- a/src/univalue/univalue_read.cpp
+++ b/src/univalue/univalue_read.cpp
@@ -188,25 +188,22 @@ enum jtokentype getJsonToken(string& tokenVal, unsigned int& consumed,
case 't': valStr += "\t"; break;
case 'u': {
- char buf[4] = {0,0,0,0};
- char *last = &buf[0];
unsigned int codepoint;
if (hatoui(raw + 1, raw + 1 + 4, codepoint) !=
raw + 1 + 4)
return JTOK_ERR;
if (codepoint <= 0x7f)
- *last = (char)codepoint;
+ valStr.push_back((char)codepoint);
else if (codepoint <= 0x7FF) {
- *last++ = (char)(0xC0 | (codepoint >> 6));
- *last = (char)(0x80 | (codepoint & 0x3F));
+ valStr.push_back((char)(0xC0 | (codepoint >> 6)));
+ valStr.push_back((char)(0x80 | (codepoint & 0x3F)));
} else if (codepoint <= 0xFFFF) {
- *last++ = (char)(0xE0 | (codepoint >> 12));
- *last++ = (char)(0x80 | ((codepoint >> 6) & 0x3F));
- *last = (char)(0x80 | (codepoint & 0x3F));
+ valStr.push_back((char)(0xE0 | (codepoint >> 12)));
+ valStr.push_back((char)(0x80 | ((codepoint >> 6) & 0x3F)));
+ valStr.push_back((char)(0x80 | (codepoint & 0x3F)));
}
- valStr += buf;
raw += 4;
break;
}
diff --git a/src/utilmoneystr.cpp b/src/utilmoneystr.cpp
index 2fbc048878..0f3203432f 100644
--- a/src/utilmoneystr.cpp
+++ b/src/utilmoneystr.cpp
@@ -11,7 +11,7 @@
using namespace std;
-string FormatMoney(const CAmount& n, bool fPlus)
+std::string FormatMoney(const CAmount& n)
{
// Note: not using straight sprintf here because we do NOT want
// localized number formatting.
@@ -29,8 +29,6 @@ string FormatMoney(const CAmount& n, bool fPlus)
if (n < 0)
str.insert((unsigned int)0, 1, '-');
- else if (fPlus && n > 0)
- str.insert((unsigned int)0, 1, '+');
return str;
}
diff --git a/src/utilmoneystr.h b/src/utilmoneystr.h
index cd9b04810d..99c3ba8306 100644
--- a/src/utilmoneystr.h
+++ b/src/utilmoneystr.h
@@ -14,7 +14,7 @@
#include "amount.h"
-std::string FormatMoney(const CAmount& n, bool fPlus=false);
+std::string FormatMoney(const CAmount& n);
bool ParseMoney(const std::string& str, CAmount& nRet);
bool ParseMoney(const char* pszIn, CAmount& nRet);
diff --git a/src/wallet/rpcdump.cpp b/src/wallet/rpcdump.cpp
index b682a42e23..5f800474a0 100644
--- a/src/wallet/rpcdump.cpp
+++ b/src/wallet/rpcdump.cpp
@@ -94,6 +94,9 @@ UniValue importprivkey(const UniValue& params, bool fHelp)
+ HelpExampleRpc("importprivkey", "\"mykey\", \"testing\", false")
);
+ if (fPruneMode)
+ throw JSONRPCError(RPC_WALLET_ERROR, "Importing keys is disabled in pruned mode");
+
LOCK2(cs_main, pwalletMain->cs_wallet);
EnsureWalletIsUnlocked();
@@ -166,6 +169,9 @@ UniValue importaddress(const UniValue& params, bool fHelp)
+ HelpExampleRpc("importaddress", "\"myaddress\", \"testing\", false")
);
+ if (fPruneMode)
+ throw JSONRPCError(RPC_WALLET_ERROR, "Importing addresses is disabled in pruned mode");
+
LOCK2(cs_main, pwalletMain->cs_wallet);
CScript script;
@@ -236,6 +242,9 @@ UniValue importwallet(const UniValue& params, bool fHelp)
+ HelpExampleRpc("importwallet", "\"test\"")
);
+ if (fPruneMode)
+ throw JSONRPCError(RPC_WALLET_ERROR, "Importing wallets is disabled in pruned mode");
+
LOCK2(cs_main, pwalletMain->cs_wallet);
EnsureWalletIsUnlocked();
diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp
index 479b7d606b..5404dd4aa0 100644
--- a/src/wallet/rpcwallet.cpp
+++ b/src/wallet/rpcwallet.cpp
@@ -414,6 +414,8 @@ UniValue sendtoaddress(const UniValue& params, bool fHelp)
// Amount
CAmount nAmount = AmountFromValue(params[1]);
+ if (nAmount <= 0)
+ throw JSONRPCError(RPC_TYPE_ERROR, "Invalid amount for send");
// Wallet comments
CWalletTx wtx;
@@ -731,12 +733,12 @@ UniValue getbalance(const UniValue& params, bool fHelp)
if (params[0].get_str() == "*") {
// Calculate total balance a different way from GetBalance()
// (GetBalance() sums up all unspent TxOuts)
- // getbalance and getbalance '*' 0 should return the same number
+ // getbalance and "getbalance * 1 true" should return the same number
CAmount nBalance = 0;
for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
{
const CWalletTx& wtx = (*it).second;
- if (!wtx.IsTrusted() || wtx.GetBlocksToMaturity() > 0)
+ if (!CheckFinalTx(wtx) || wtx.GetBlocksToMaturity() > 0 || wtx.GetDepthInMainChain() < 0)
continue;
CAmount allFee;
@@ -809,6 +811,8 @@ UniValue movecmd(const UniValue& params, bool fHelp)
string strFrom = AccountFromValue(params[0]);
string strTo = AccountFromValue(params[1]);
CAmount nAmount = AmountFromValue(params[2]);
+ if (nAmount <= 0)
+ throw JSONRPCError(RPC_TYPE_ERROR, "Invalid amount for send");
if (params.size() > 3)
// unused parameter, used to be nMinDepth, keep type-checking it though
(void)params[3].get_int();
@@ -888,6 +892,8 @@ UniValue sendfrom(const UniValue& params, bool fHelp)
if (!address.IsValid())
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Bitcoin address");
CAmount nAmount = AmountFromValue(params[2]);
+ if (nAmount <= 0)
+ throw JSONRPCError(RPC_TYPE_ERROR, "Invalid amount for send");
int nMinDepth = 1;
if (params.size() > 3)
nMinDepth = params[3].get_int();
@@ -987,6 +993,8 @@ UniValue sendmany(const UniValue& params, bool fHelp)
CScript scriptPubKey = GetScriptForDestination(address.Get());
CAmount nAmount = AmountFromValue(sendTo[name_]);
+ if (nAmount <= 0)
+ throw JSONRPCError(RPC_TYPE_ERROR, "Invalid amount for send");
totalAmount += nAmount;
bool fSubtractFeeFromAmount = false;
@@ -2168,9 +2176,7 @@ UniValue settxfee(const UniValue& params, bool fHelp)
LOCK2(cs_main, pwalletMain->cs_wallet);
// Amount
- CAmount nAmount = 0;
- if (params[0].get_real() != 0.0)
- nAmount = AmountFromValue(params[0]); // rejects 0.0 amounts
+ CAmount nAmount = AmountFromValue(params[0]);
payTxFee = CFeeRate(nAmount, 1000);
return true;
@@ -2354,4 +2360,4 @@ UniValue listunspent(const UniValue& params, bool fHelp)
}
return results;
-} \ No newline at end of file
+}