aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am3
-rw-r--r--src/coins.cpp10
-rw-r--r--src/coins.h2
-rw-r--r--src/init.cpp4
-rw-r--r--src/main.cpp24
-rw-r--r--src/main.h3
-rw-r--r--src/net.cpp54
-rw-r--r--src/policy/rbf.cpp46
-rw-r--r--src/policy/rbf.h20
-rw-r--r--src/qt/receivecoinsdialog.cpp1
-rw-r--r--src/qt/receivecoinsdialog.h2
-rw-r--r--src/qt/recentrequeststablemodel.cpp9
-rw-r--r--src/qt/rpcconsole.cpp4
-rw-r--r--src/rpcserver.cpp67
-rw-r--r--src/rpcserver.h50
-rw-r--r--src/test/test_bitcoin.cpp1
-rw-r--r--src/wallet/rpcwallet.cpp120
-rw-r--r--src/wallet/rpcwallet.h10
-rw-r--r--src/wallet/wallet.cpp3
-rw-r--r--src/wallet/wallet.h1
20 files changed, 275 insertions, 159 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index 5da1a873de..948d12424f 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -122,6 +122,7 @@ BITCOIN_CORE_H = \
noui.h \
policy/fees.h \
policy/policy.h \
+ policy/rbf.h \
pow.h \
prevector.h \
primitives/block.h \
@@ -164,6 +165,7 @@ BITCOIN_CORE_H = \
version.h \
wallet/crypter.h \
wallet/db.h \
+ wallet/rpcwallet.h \
wallet/wallet.h \
wallet/wallet_ismine.h \
wallet/walletdb.h \
@@ -239,6 +241,7 @@ libbitcoin_wallet_a_SOURCES = \
wallet/wallet.cpp \
wallet/wallet_ismine.cpp \
wallet/walletdb.cpp \
+ policy/rbf.cpp \
$(BITCOIN_CORE_H)
# crypto primitives library
diff --git a/src/coins.cpp b/src/coins.cpp
index 4d1dbdea4e..877fb8b26c 100644
--- a/src/coins.cpp
+++ b/src/coins.cpp
@@ -117,11 +117,17 @@ CCoinsModifier CCoinsViewCache::ModifyCoins(const uint256 &txid) {
return CCoinsModifier(*this, ret.first, cachedCoinUsage);
}
-CCoinsModifier CCoinsViewCache::ModifyNewCoins(const uint256 &txid) {
+// ModifyNewCoins has to know whether the new outputs its creating are for a
+// coinbase or not. If they are for a coinbase, it can not mark them as fresh.
+// This is to ensure that the historical duplicate coinbases before BIP30 was
+// in effect will still be properly overwritten when spent.
+CCoinsModifier CCoinsViewCache::ModifyNewCoins(const uint256 &txid, bool coinbase) {
assert(!hasModifier);
std::pair<CCoinsMap::iterator, bool> ret = cacheCoins.insert(std::make_pair(txid, CCoinsCacheEntry()));
ret.first->second.coins.Clear();
- ret.first->second.flags = CCoinsCacheEntry::FRESH;
+ if (!coinbase) {
+ ret.first->second.flags = CCoinsCacheEntry::FRESH;
+ }
ret.first->second.flags |= CCoinsCacheEntry::DIRTY;
return CCoinsModifier(*this, ret.first, 0);
}
diff --git a/src/coins.h b/src/coins.h
index eab94ec1b4..d297cae1aa 100644
--- a/src/coins.h
+++ b/src/coins.h
@@ -435,7 +435,7 @@ public:
* would not properly overwrite the first coinbase of the pair. Simultaneous modifications
* are not allowed.
*/
- CCoinsModifier ModifyNewCoins(const uint256 &txid);
+ CCoinsModifier ModifyNewCoins(const uint256 &txid, bool coinbase);
/**
* Push the modifications applied to this cache to its base.
diff --git a/src/init.cpp b/src/init.cpp
index 0a0e587763..7aecf93516 100644
--- a/src/init.cpp
+++ b/src/init.cpp
@@ -367,6 +367,7 @@ std::string HelpMessage(HelpMessageMode mode)
strUsage += HelpMessageOpt("-onion=<ip:port>", strprintf(_("Use separate SOCKS5 proxy to reach peers via Tor hidden services (default: %s)"), "-proxy"));
strUsage += HelpMessageOpt("-onlynet=<net>", _("Only connect to nodes in network <net> (ipv4, ipv6 or onion)"));
strUsage += HelpMessageOpt("-permitbaremultisig", strprintf(_("Relay non-P2SH multisig (default: %u)"), DEFAULT_PERMIT_BAREMULTISIG));
+ strUsage += HelpMessageOpt("-permitrbf", strprintf(_("Permit transaction replacement (default: %u)"), DEFAULT_PERMIT_REPLACEMENT));
strUsage += HelpMessageOpt("-peerbloomfilters", strprintf(_("Support filtering of blocks and transaction with bloom filters (default: %u)"), 1));
if (showDebug)
strUsage += HelpMessageOpt("-enforcenodebloom", strprintf("Enforce minimum protocol version to limit use of bloom filters (default: %u)", 0));
@@ -935,6 +936,8 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
#ifdef ENABLE_WALLET
bool fDisableWallet = GetBoolArg("-disablewallet", false);
+ if (!fDisableWallet)
+ walletRegisterRPCCommands();
#endif
nConnectTimeout = GetArg("-timeout", DEFAULT_CONNECT_TIMEOUT);
@@ -1027,6 +1030,7 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
nLocalServices |= NODE_BLOOM;
nMaxTipAge = GetArg("-maxtipage", DEFAULT_MAX_TIP_AGE);
+ fPermitReplacement = GetBoolArg("-permitrbf", DEFAULT_PERMIT_REPLACEMENT);
// ********************************************************* Step 4: application initialization: dir lock, daemonize, pidfile, debug log
diff --git a/src/main.cpp b/src/main.cpp
index 9870beecc7..c8ea62758b 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -78,6 +78,7 @@ bool fAlerts = DEFAULT_ALERTS;
/* If the tip is older than this (in seconds), the node is considered to be in initial block download.
*/
int64_t nMaxTipAge = DEFAULT_MAX_TIP_AGE;
+bool fPermitReplacement = DEFAULT_PERMIT_REPLACEMENT;
/** Fees smaller than this (in satoshi) are considered zero fee (for relaying, mining and transaction creation) */
CFeeRate minRelayTxFee = CFeeRate(DEFAULT_MIN_RELAY_TX_FEE);
@@ -868,12 +869,15 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState &state, const C
// unconfirmed ancestors anyway; doing otherwise is hopelessly
// insecure.
bool fReplacementOptOut = true;
- BOOST_FOREACH(const CTxIn &txin, ptxConflicting->vin)
+ if (fPermitReplacement)
{
- if (txin.nSequence < std::numeric_limits<unsigned int>::max()-1)
+ BOOST_FOREACH(const CTxIn &txin, ptxConflicting->vin)
{
- fReplacementOptOut = false;
- break;
+ if (txin.nSequence < std::numeric_limits<unsigned int>::max()-1)
+ {
+ fReplacementOptOut = false;
+ break;
+ }
}
}
if (fReplacementOptOut)
@@ -1542,17 +1546,9 @@ void UpdateCoins(const CTransaction& tx, CValidationState &state, CCoinsViewCach
undo.nVersion = coins->nVersion;
}
}
- // add outputs
- inputs.ModifyNewCoins(tx.GetHash())->FromTx(tx, nHeight);
- }
- else {
- // add outputs for coinbase tx
- // In this case call the full ModifyCoins which will do a database
- // lookup to be sure the coins do not already exist otherwise we do not
- // know whether to mark them fresh or not. We want the duplicate coinbases
- // before BIP30 to still be properly overwritten.
- inputs.ModifyCoins(tx.GetHash())->FromTx(tx, nHeight);
}
+ // add outputs
+ inputs.ModifyNewCoins(tx.GetHash(), tx.IsCoinBase())->FromTx(tx, nHeight);
}
void UpdateCoins(const CTransaction& tx, CValidationState &state, CCoinsViewCache &inputs, int nHeight)
diff --git a/src/main.h b/src/main.h
index 228877641d..98069a225d 100644
--- a/src/main.h
+++ b/src/main.h
@@ -107,6 +107,8 @@ static const bool DEFAULT_TXINDEX = false;
static const unsigned int DEFAULT_BANSCORE_THRESHOLD = 100;
static const bool DEFAULT_TESTSAFEMODE = false;
+/** Default for -permitrbf */
+static const bool DEFAULT_PERMIT_REPLACEMENT = true;
/** Maximum number of headers to announce when relaying blocks with headers message.*/
static const unsigned int MAX_BLOCKS_TO_ANNOUNCE = 8;
@@ -139,6 +141,7 @@ extern size_t nCoinCacheUsage;
extern CFeeRate minRelayTxFee;
extern bool fAlerts;
extern int64_t nMaxTipAge;
+extern bool fPermitReplacement;
/** Best header we've seen so far (used for getheaders queries' starting points). */
extern CBlockIndex *pindexBestHeader;
diff --git a/src/net.cpp b/src/net.cpp
index db8f97abc2..48e9e10157 100644
--- a/src/net.cpp
+++ b/src/net.cpp
@@ -38,7 +38,7 @@
#include <math.h>
-// Dump addresses to peers.dat every 15 minutes (900s)
+// Dump addresses to peers.dat and banlist.dat every 15 minutes (900s)
#define DUMP_ADDRESSES_INTERVAL 900
#if !defined(HAVE_MSG_NOSIGNAL) && !defined(MSG_NOSIGNAL)
@@ -573,11 +573,13 @@ void CNode::SweepBanned()
banmap_t::iterator it = setBanned.begin();
while(it != setBanned.end())
{
+ CSubNet subNet = (*it).first;
CBanEntry banEntry = (*it).second;
if(now > banEntry.nBanUntil)
{
setBanned.erase(it++);
setBannedIsDirty = true;
+ LogPrint("net", "%s: Removed banned node ip/subnet from banlist.dat: %s\n", __func__, subNet.ToString());
}
else
++it;
@@ -1492,12 +1494,7 @@ void DumpAddresses()
void DumpData()
{
DumpAddresses();
-
- if (CNode::BannedSetIsDirty())
- {
- DumpBanlist();
- CNode::SetBannedSetDirty(false);
- }
+ DumpBanlist();
}
void static ProcessOneShot()
@@ -1938,31 +1935,36 @@ void static Discover(boost::thread_group& threadGroup)
void StartNode(boost::thread_group& threadGroup, CScheduler& scheduler)
{
uiInterface.InitMessage(_("Loading addresses..."));
- // Load addresses for peers.dat
+ // Load addresses from peers.dat
int64_t nStart = GetTimeMillis();
{
CAddrDB adb;
- if (!adb.Read(addrman))
+ if (adb.Read(addrman))
+ LogPrintf("Loaded %i addresses from peers.dat %dms\n", addrman.size(), GetTimeMillis() - nStart);
+ else
LogPrintf("Invalid or missing peers.dat; recreating\n");
}
- //try to read stored banlist
+ uiInterface.InitMessage(_("Loading banlist..."));
+ // Load addresses from banlist.dat
+ nStart = GetTimeMillis();
CBanDB bandb;
banmap_t banmap;
- if (!bandb.Read(banmap))
+ if (bandb.Read(banmap)) {
+ CNode::SetBanned(banmap); // thread save setter
+ CNode::SetBannedSetDirty(false); // no need to write down, just read data
+ CNode::SweepBanned(); // sweep out unused entries
+
+ LogPrint("net", "Loaded %d banned node ips/subnets from banlist.dat %dms\n",
+ banmap.size(), GetTimeMillis() - nStart);
+ } else
LogPrintf("Invalid or missing banlist.dat; recreating\n");
- CNode::SetBanned(banmap); //thread save setter
- CNode::SetBannedSetDirty(false); //no need to write down just read or nonexistent data
- CNode::SweepBanned(); //sweap out unused entries
-
- LogPrintf("Loaded %i addresses from peers.dat %dms\n",
- addrman.size(), GetTimeMillis() - nStart);
fAddressesInitialized = true;
if (semOutbound == NULL) {
// initialize semaphore
- int nMaxOutbound = min(MAX_OUTBOUND_CONNECTIONS, nMaxConnections);
+ int nMaxOutbound = std::min(MAX_OUTBOUND_CONNECTIONS, nMaxConnections);
semOutbound = new CSemaphore(nMaxOutbound);
}
@@ -2609,30 +2611,34 @@ bool CBanDB::Read(banmap_t& banSet)
// ... verify the network matches ours
if (memcmp(pchMsgTmp, Params().MessageStart(), sizeof(pchMsgTmp)))
return error("%s: Invalid network magic number", __func__);
-
+
// de-serialize address data into one CAddrMan object
ssBanlist >> banSet;
}
catch (const std::exception& e) {
return error("%s: Deserialize or I/O error - %s", __func__, e.what());
}
-
+
return true;
}
void DumpBanlist()
{
- int64_t nStart = GetTimeMillis();
+ CNode::SweepBanned(); // clean unused entries (if bantime has expired)
- CNode::SweepBanned(); //clean unused entries (if bantime has expired)
+ if (!CNode::BannedSetIsDirty())
+ return;
+
+ int64_t nStart = GetTimeMillis();
CBanDB bandb;
banmap_t banmap;
CNode::GetBanned(banmap);
- bandb.Write(banmap);
+ if (bandb.Write(banmap))
+ CNode::SetBannedSetDirty(false);
LogPrint("net", "Flushed %d banned node ips/subnets to banlist.dat %dms\n",
- banmap.size(), GetTimeMillis() - nStart);
+ banmap.size(), GetTimeMillis() - nStart);
}
int64_t PoissonNextSend(int64_t nNow, int average_interval_seconds) {
diff --git a/src/policy/rbf.cpp b/src/policy/rbf.cpp
new file mode 100644
index 0000000000..98b1a1ba4c
--- /dev/null
+++ b/src/policy/rbf.cpp
@@ -0,0 +1,46 @@
+// Copyright (c) 2016 The Bitcoin developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#include "policy/rbf.h"
+
+bool SignalsOptInRBF(const CTransaction &tx)
+{
+ BOOST_FOREACH(const CTxIn &txin, tx.vin) {
+ if (txin.nSequence < std::numeric_limits<unsigned int>::max()-1) {
+ return true;
+ }
+ }
+ return false;
+}
+
+bool IsRBFOptIn(const CTxMemPoolEntry &entry, CTxMemPool &pool)
+{
+ AssertLockHeld(pool.cs);
+
+ CTxMemPool::setEntries setAncestors;
+
+ // First check the transaction itself.
+ if (SignalsOptInRBF(entry.GetTx())) {
+ return true;
+ }
+
+ // If this transaction is not in our mempool, then we can't be sure
+ // we will know about all its inputs.
+ if (!pool.exists(entry.GetTx().GetHash())) {
+ throw std::runtime_error("Cannot determine RBF opt-in signal for non-mempool transaction\n");
+ }
+
+ // If all the inputs have nSequence >= maxint-1, it still might be
+ // signaled for RBF if any unconfirmed parents have signaled.
+ uint64_t noLimit = std::numeric_limits<uint64_t>::max();
+ std::string dummy;
+ pool.CalculateMemPoolAncestors(entry, setAncestors, noLimit, noLimit, noLimit, noLimit, dummy, false);
+
+ BOOST_FOREACH(CTxMemPool::txiter it, setAncestors) {
+ if (SignalsOptInRBF(it->GetTx())) {
+ return true;
+ }
+ }
+ return false;
+}
diff --git a/src/policy/rbf.h b/src/policy/rbf.h
new file mode 100644
index 0000000000..925ce0d9bd
--- /dev/null
+++ b/src/policy/rbf.h
@@ -0,0 +1,20 @@
+// Copyright (c) 2016 The Bitcoin developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#ifndef BITCOIN_POLICY_RBF_H
+#define BITCOIN_POLICY_RBF_H
+
+#include "txmempool.h"
+
+// Check whether the sequence numbers on this transaction are signaling
+// opt-in to replace-by-fee, according to BIP 125
+bool SignalsOptInRBF(const CTransaction &tx);
+
+// Determine whether an in-mempool transaction is signaling opt-in to RBF
+// according to BIP 125
+// This involves checking sequence numbers of the transaction, as well
+// as the sequence numbers of all in-mempool ancestors.
+bool IsRBFOptIn(const CTxMemPoolEntry &entry, CTxMemPool &pool);
+
+#endif // BITCOIN_POLICY_RBF_H
diff --git a/src/qt/receivecoinsdialog.cpp b/src/qt/receivecoinsdialog.cpp
index b1f82023bc..0b355837ab 100644
--- a/src/qt/receivecoinsdialog.cpp
+++ b/src/qt/receivecoinsdialog.cpp
@@ -82,6 +82,7 @@ void ReceiveCoinsDialog::setModel(WalletModel *model)
tableView->setSelectionMode(QAbstractItemView::ContiguousSelection);
tableView->setColumnWidth(RecentRequestsTableModel::Date, DATE_COLUMN_WIDTH);
tableView->setColumnWidth(RecentRequestsTableModel::Label, LABEL_COLUMN_WIDTH);
+ tableView->setColumnWidth(RecentRequestsTableModel::Amount, AMOUNT_MINIMUM_COLUMN_WIDTH);
connect(tableView->selectionModel(),
SIGNAL(selectionChanged(QItemSelection, QItemSelection)), this,
diff --git a/src/qt/receivecoinsdialog.h b/src/qt/receivecoinsdialog.h
index 543854a2f4..226fd65cfa 100644
--- a/src/qt/receivecoinsdialog.h
+++ b/src/qt/receivecoinsdialog.h
@@ -36,7 +36,7 @@ public:
enum ColumnWidths {
DATE_COLUMN_WIDTH = 130,
LABEL_COLUMN_WIDTH = 120,
- AMOUNT_MINIMUM_COLUMN_WIDTH = 160,
+ AMOUNT_MINIMUM_COLUMN_WIDTH = 180,
MINIMUM_COLUMN_WIDTH = 130
};
diff --git a/src/qt/recentrequeststablemodel.cpp b/src/qt/recentrequeststablemodel.cpp
index ef9422506a..2335d6b282 100644
--- a/src/qt/recentrequeststablemodel.cpp
+++ b/src/qt/recentrequeststablemodel.cpp
@@ -83,7 +83,7 @@ QVariant RecentRequestsTableModel::data(const QModelIndex &index, int role) cons
}
case Amount:
if (rec->recipient.amount == 0 && role == Qt::DisplayRole)
- return tr("(no amount)");
+ return tr("(no amount requested)");
else if (role == Qt::EditRole)
return BitcoinUnits::format(walletModel->getOptionsModel()->getDisplayUnit(), rec->recipient.amount, false, BitcoinUnits::separatorNever);
else
@@ -125,12 +125,7 @@ void RecentRequestsTableModel::updateAmountColumnTitle()
/** Gets title for amount column including current display unit if optionsModel reference available. */
QString RecentRequestsTableModel::getAmountTitle()
{
- QString amountTitle = tr("Amount");
- if (this->walletModel->getOptionsModel() != NULL)
- {
- amountTitle += " ("+BitcoinUnits::name(this->walletModel->getOptionsModel()->getDisplayUnit()) + ")";
- }
- return amountTitle;
+ return (this->walletModel->getOptionsModel() != NULL) ? tr("Requested") + " ("+BitcoinUnits::name(this->walletModel->getOptionsModel()->getDisplayUnit()) + ")" : "";
}
QModelIndex RecentRequestsTableModel::index(int row, int column, const QModelIndex &parent) const
diff --git a/src/qt/rpcconsole.cpp b/src/qt/rpcconsole.cpp
index 7178bc00e6..fb36020317 100644
--- a/src/qt/rpcconsole.cpp
+++ b/src/qt/rpcconsole.cpp
@@ -474,7 +474,11 @@ void RPCConsole::clear()
// Set default style sheet
QFontInfo fixedFontInfo(GUIUtil::fixedPitchFont());
// Try to make fixed font adequately large on different OS
+#ifdef WIN32
+ QString ptSize = QString("%1pt").arg(QFontInfo(QFont()).pointSize() * 10 / 8);
+#else
QString ptSize = QString("%1pt").arg(QFontInfo(QFont()).pointSize() * 8.5 / 9);
+#endif
ui->messagesWidget->document()->setDefaultStyleSheet(
QString(
"table { }"
diff --git a/src/rpcserver.cpp b/src/rpcserver.cpp
index 53c368b271..b638598f76 100644
--- a/src/rpcserver.cpp
+++ b/src/rpcserver.cpp
@@ -309,9 +309,6 @@ static const CRPCCommand vRPCCommands[] =
{ "rawtransactions", "getrawtransaction", &getrawtransaction, true },
{ "rawtransactions", "sendrawtransaction", &sendrawtransaction, false },
{ "rawtransactions", "signrawtransaction", &signrawtransaction, false }, /* uses wallet if enabled */
-#ifdef ENABLE_WALLET
- { "rawtransactions", "fundrawtransaction", &fundrawtransaction, false },
-#endif
/* Utility functions */
{ "util", "createmultisig", &createmultisig, true },
@@ -326,54 +323,6 @@ static const CRPCCommand vRPCCommands[] =
{ "hidden", "invalidateblock", &invalidateblock, true },
{ "hidden", "reconsiderblock", &reconsiderblock, true },
{ "hidden", "setmocktime", &setmocktime, true },
-#ifdef ENABLE_WALLET
- { "hidden", "resendwallettransactions", &resendwallettransactions, true},
-#endif
-
-#ifdef ENABLE_WALLET
- /* Wallet */
- { "wallet", "addmultisigaddress", &addmultisigaddress, true },
- { "wallet", "backupwallet", &backupwallet, true },
- { "wallet", "dumpprivkey", &dumpprivkey, true },
- { "wallet", "dumpwallet", &dumpwallet, true },
- { "wallet", "encryptwallet", &encryptwallet, true },
- { "wallet", "getaccountaddress", &getaccountaddress, true },
- { "wallet", "getaccount", &getaccount, true },
- { "wallet", "getaddressesbyaccount", &getaddressesbyaccount, true },
- { "wallet", "getbalance", &getbalance, false },
- { "wallet", "getnewaddress", &getnewaddress, true },
- { "wallet", "getrawchangeaddress", &getrawchangeaddress, true },
- { "wallet", "getreceivedbyaccount", &getreceivedbyaccount, false },
- { "wallet", "getreceivedbyaddress", &getreceivedbyaddress, false },
- { "wallet", "gettransaction", &gettransaction, false },
- { "wallet", "abandontransaction", &abandontransaction, false },
- { "wallet", "getunconfirmedbalance", &getunconfirmedbalance, false },
- { "wallet", "getwalletinfo", &getwalletinfo, false },
- { "wallet", "importprivkey", &importprivkey, true },
- { "wallet", "importwallet", &importwallet, true },
- { "wallet", "importaddress", &importaddress, true },
- { "wallet", "importpubkey", &importpubkey, true },
- { "wallet", "keypoolrefill", &keypoolrefill, true },
- { "wallet", "listaccounts", &listaccounts, false },
- { "wallet", "listaddressgroupings", &listaddressgroupings, false },
- { "wallet", "listlockunspent", &listlockunspent, false },
- { "wallet", "listreceivedbyaccount", &listreceivedbyaccount, false },
- { "wallet", "listreceivedbyaddress", &listreceivedbyaddress, false },
- { "wallet", "listsinceblock", &listsinceblock, false },
- { "wallet", "listtransactions", &listtransactions, false },
- { "wallet", "listunspent", &listunspent, false },
- { "wallet", "lockunspent", &lockunspent, true },
- { "wallet", "move", &movecmd, false },
- { "wallet", "sendfrom", &sendfrom, false },
- { "wallet", "sendmany", &sendmany, false },
- { "wallet", "sendtoaddress", &sendtoaddress, false },
- { "wallet", "setaccount", &setaccount, true },
- { "wallet", "settxfee", &settxfee, true },
- { "wallet", "signmessage", &signmessage, true },
- { "wallet", "walletlock", &walletlock, true },
- { "wallet", "walletpassphrasechange", &walletpassphrasechange, true },
- { "wallet", "walletpassphrase", &walletpassphrase, true },
-#endif // ENABLE_WALLET
};
CRPCTable::CRPCTable()
@@ -396,6 +345,20 @@ const CRPCCommand *CRPCTable::operator[](const std::string &name) const
return (*it).second;
}
+bool CRPCTable::appendCommand(const std::string& name, const CRPCCommand* pcmd)
+{
+ if (IsRPCRunning())
+ return false;
+
+ // don't allow overwriting for now
+ map<string, const CRPCCommand*>::const_iterator it = mapCommands.find(name);
+ if (it != mapCommands.end())
+ return false;
+
+ mapCommands[name] = pcmd;
+ return true;
+}
+
bool StartRPC()
{
LogPrint("rpc", "Starting RPC\n");
@@ -573,4 +536,4 @@ void RPCRunLater(const std::string& name, boost::function<void(void)> func, int6
deadlineTimers.insert(std::make_pair(name, boost::shared_ptr<RPCTimerBase>(timerInterface->NewTimer(func, nSeconds*1000))));
}
-const CRPCTable tableRPC;
+CRPCTable tableRPC;
diff --git a/src/rpcserver.h b/src/rpcserver.h
index 29f5036580..219d0422dc 100644
--- a/src/rpcserver.h
+++ b/src/rpcserver.h
@@ -144,9 +144,17 @@ public:
* @throws an exception (UniValue) when an error happens.
*/
UniValue execute(const std::string &method, const UniValue &params) const;
+
+
+ /**
+ * Appends a CRPCCommand to the dispatch table.
+ * Returns false if RPC server is already running (dump concurrency protection).
+ * Commands cannot be overwritten (returns false).
+ */
+ bool appendCommand(const std::string& name, const CRPCCommand* pcmd);
};
-extern const CRPCTable tableRPC;
+extern CRPCTable tableRPC;
/**
* Utilities: convert hex-encoded Values
@@ -178,13 +186,6 @@ extern UniValue setban(const UniValue& params, bool fHelp);
extern UniValue listbanned(const UniValue& params, bool fHelp);
extern UniValue clearbanned(const UniValue& params, bool fHelp);
-extern UniValue dumpprivkey(const UniValue& params, bool fHelp); // in rpcdump.cpp
-extern UniValue importprivkey(const UniValue& params, bool fHelp);
-extern UniValue importaddress(const UniValue& params, bool fHelp);
-extern UniValue importpubkey(const UniValue& params, bool fHelp);
-extern UniValue dumpwallet(const UniValue& params, bool fHelp);
-extern UniValue importwallet(const UniValue& params, bool fHelp);
-
extern UniValue getgenerate(const UniValue& params, bool fHelp); // in rpcmining.cpp
extern UniValue setgenerate(const UniValue& params, bool fHelp);
extern UniValue generate(const UniValue& params, bool fHelp);
@@ -198,45 +199,13 @@ extern UniValue estimatepriority(const UniValue& params, bool fHelp);
extern UniValue estimatesmartfee(const UniValue& params, bool fHelp);
extern UniValue estimatesmartpriority(const UniValue& params, bool fHelp);
-extern UniValue getnewaddress(const UniValue& params, bool fHelp); // in rpcwallet.cpp
-extern UniValue getaccountaddress(const UniValue& params, bool fHelp);
-extern UniValue getrawchangeaddress(const UniValue& params, bool fHelp);
-extern UniValue setaccount(const UniValue& params, bool fHelp);
-extern UniValue getaccount(const UniValue& params, bool fHelp);
-extern UniValue getaddressesbyaccount(const UniValue& params, bool fHelp);
-extern UniValue sendtoaddress(const UniValue& params, bool fHelp);
-extern UniValue signmessage(const UniValue& params, bool fHelp);
extern UniValue verifymessage(const UniValue& params, bool fHelp);
-extern UniValue getreceivedbyaddress(const UniValue& params, bool fHelp);
-extern UniValue getreceivedbyaccount(const UniValue& params, bool fHelp);
-extern UniValue getbalance(const UniValue& params, bool fHelp);
-extern UniValue getunconfirmedbalance(const UniValue& params, bool fHelp);
-extern UniValue movecmd(const UniValue& params, bool fHelp);
-extern UniValue sendfrom(const UniValue& params, bool fHelp);
-extern UniValue sendmany(const UniValue& params, bool fHelp);
-extern UniValue addmultisigaddress(const UniValue& params, bool fHelp);
extern UniValue createmultisig(const UniValue& params, bool fHelp);
-extern UniValue listreceivedbyaddress(const UniValue& params, bool fHelp);
-extern UniValue listreceivedbyaccount(const UniValue& params, bool fHelp);
-extern UniValue listtransactions(const UniValue& params, bool fHelp);
-extern UniValue listaddressgroupings(const UniValue& params, bool fHelp);
-extern UniValue listaccounts(const UniValue& params, bool fHelp);
-extern UniValue listsinceblock(const UniValue& params, bool fHelp);
-extern UniValue gettransaction(const UniValue& params, bool fHelp);
-extern UniValue abandontransaction(const UniValue& params, bool fHelp);
-extern UniValue backupwallet(const UniValue& params, bool fHelp);
-extern UniValue keypoolrefill(const UniValue& params, bool fHelp);
-extern UniValue walletpassphrase(const UniValue& params, bool fHelp);
-extern UniValue walletpassphrasechange(const UniValue& params, bool fHelp);
-extern UniValue walletlock(const UniValue& params, bool fHelp);
-extern UniValue encryptwallet(const UniValue& params, bool fHelp);
extern UniValue validateaddress(const UniValue& params, bool fHelp);
extern UniValue getinfo(const UniValue& params, bool fHelp);
-extern UniValue getwalletinfo(const UniValue& params, bool fHelp);
extern UniValue getblockchaininfo(const UniValue& params, bool fHelp);
extern UniValue getnetworkinfo(const UniValue& params, bool fHelp);
extern UniValue setmocktime(const UniValue& params, bool fHelp);
-extern UniValue resendwallettransactions(const UniValue& params, bool fHelp);
extern UniValue getrawtransaction(const UniValue& params, bool fHelp); // in rcprawtransaction.cpp
extern UniValue listunspent(const UniValue& params, bool fHelp);
@@ -245,7 +214,6 @@ extern UniValue listlockunspent(const UniValue& params, bool fHelp);
extern UniValue createrawtransaction(const UniValue& params, bool fHelp);
extern UniValue decoderawtransaction(const UniValue& params, bool fHelp);
extern UniValue decodescript(const UniValue& params, bool fHelp);
-extern UniValue fundrawtransaction(const UniValue& params, bool fHelp);
extern UniValue signrawtransaction(const UniValue& params, bool fHelp);
extern UniValue sendrawtransaction(const UniValue& params, bool fHelp);
extern UniValue gettxoutproof(const UniValue& params, bool fHelp);
diff --git a/src/test/test_bitcoin.cpp b/src/test/test_bitcoin.cpp
index f81050b15d..0416d0c926 100644
--- a/src/test/test_bitcoin.cpp
+++ b/src/test/test_bitcoin.cpp
@@ -54,6 +54,7 @@ TestingSetup::TestingSetup(const std::string& chainName) : BasicTestingSetup(cha
const CChainParams& chainparams = Params();
#ifdef ENABLE_WALLET
bitdb.MakeMock();
+ walletRegisterRPCCommands();
#endif
ClearDatadirCache();
pathTemp = GetTempPath() / strprintf("test_bitcoin_%lu_%i", (unsigned long)GetTime(), (int)(GetRand(100000)));
diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp
index a977b5abd6..8b56a0a3d0 100644
--- a/src/wallet/rpcwallet.cpp
+++ b/src/wallet/rpcwallet.cpp
@@ -11,6 +11,7 @@
#include "main.h"
#include "net.h"
#include "netbase.h"
+#include "policy/rbf.h"
#include "rpcserver.h"
#include "timedata.h"
#include "util.h"
@@ -76,6 +77,23 @@ void WalletTxToJSON(const CWalletTx& wtx, UniValue& entry)
entry.push_back(Pair("walletconflicts", conflicts));
entry.push_back(Pair("time", wtx.GetTxTime()));
entry.push_back(Pair("timereceived", (int64_t)wtx.nTimeReceived));
+
+ // Add opt-in RBF status
+ std::string rbfStatus = "no";
+ if (confirms <= 0) {
+ LOCK(mempool.cs);
+ if (!mempool.exists(hash)) {
+ if (SignalsOptInRBF(wtx)) {
+ rbfStatus = "yes";
+ } else {
+ rbfStatus = "unknown";
+ }
+ } else if (IsRBFOptIn(*mempool.mapTx.find(hash), mempool)) {
+ rbfStatus = "yes";
+ }
+ }
+ entry.push_back(Pair("bip125-replaceable", rbfStatus));
+
BOOST_FOREACH(const PAIRTYPE(string,string)& item, wtx.mapValue)
entry.push_back(Pair(item.first, item.second));
}
@@ -137,26 +155,25 @@ CBitcoinAddress GetAccountAddress(string strAccount, bool bForceNew=false)
CAccount account;
walletdb.ReadAccount(strAccount, account);
- bool bKeyUsed = false;
-
- // Check if the current key has been used
- if (account.vchPubKey.IsValid())
- {
- CScript scriptPubKey = GetScriptForDestination(account.vchPubKey.GetID());
- for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin();
- it != pwalletMain->mapWallet.end() && account.vchPubKey.IsValid();
- ++it)
- {
- const CWalletTx& wtx = (*it).second;
- BOOST_FOREACH(const CTxOut& txout, wtx.vout)
- if (txout.scriptPubKey == scriptPubKey)
- bKeyUsed = true;
+ if (!bForceNew) {
+ if (!account.vchPubKey.IsValid())
+ bForceNew = true;
+ else {
+ // Check if the current key has been used
+ CScript scriptPubKey = GetScriptForDestination(account.vchPubKey.GetID());
+ for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin();
+ it != pwalletMain->mapWallet.end() && account.vchPubKey.IsValid();
+ ++it)
+ BOOST_FOREACH(const CTxOut& txout, (*it).second.vout)
+ if (txout.scriptPubKey == scriptPubKey) {
+ bForceNew = true;
+ break;
+ }
}
}
// Generate a new key
- if (!account.vchPubKey.IsValid() || bForceNew || bKeyUsed)
- {
+ if (bForceNew) {
if (!pwalletMain->GetKeyFromPool(account.vchPubKey))
throw JSONRPCError(RPC_WALLET_KEYPOOL_RAN_OUT, "Error: Keypool ran out, please call keypoolrefill first");
@@ -1439,6 +1456,8 @@ UniValue listtransactions(const UniValue& params, bool fHelp)
" \"otheraccount\": \"accountname\", (string) For the 'move' category of transactions, the account the funds came \n"
" from (for receiving funds, positive amounts), or went to (for sending funds,\n"
" negative amounts).\n"
+ " \"bip125-replaceable\": \"yes|no|unknown\" (string) Whether this transaction could be replaced due to BIP125 (replace-by-fee);\n"
+ " may be unknown for unconfirmed transactions not in the mempool\n"
" }\n"
"]\n"
@@ -1707,6 +1726,8 @@ UniValue gettransaction(const UniValue& params, bool fHelp)
" \"txid\" : \"transactionid\", (string) The transaction id.\n"
" \"time\" : ttt, (numeric) The transaction time in seconds since epoch (1 Jan 1970 GMT)\n"
" \"timereceived\" : ttt, (numeric) The time received in seconds since epoch (1 Jan 1970 GMT)\n"
+ " \"bip125-replaceable\": \"yes|no|unknown\" (string) Whether this transaction could be replaced due to BIP125 (replace-by-fee);\n"
+ " may be unknown for unconfirmed transactions not in the mempool\n"
" \"details\" : [\n"
" {\n"
" \"account\" : \"accountname\", (string) DEPRECATED. The account name involved in the transaction, can be \"\" for the default account.\n"
@@ -2475,3 +2496,70 @@ UniValue fundrawtransaction(const UniValue& params, bool fHelp)
return result;
}
+
+extern UniValue dumpprivkey(const UniValue& params, bool fHelp); // in rpcdump.cpp
+extern UniValue importprivkey(const UniValue& params, bool fHelp);
+extern UniValue importaddress(const UniValue& params, bool fHelp);
+extern UniValue importpubkey(const UniValue& params, bool fHelp);
+extern UniValue dumpwallet(const UniValue& params, bool fHelp);
+extern UniValue importwallet(const UniValue& params, bool fHelp);
+
+const CRPCCommand vWalletRPCCommands[] =
+{ // category name actor (function) okSafeMode
+ // --------------------- ------------------------ ----------------------- ----------
+ { "rawtransactions", "fundrawtransaction", &fundrawtransaction, false },
+ { "hidden", "resendwallettransactions", &resendwallettransactions, true },
+ { "wallet", "abandontransaction", &abandontransaction, false },
+ { "wallet", "addmultisigaddress", &addmultisigaddress, true },
+ { "wallet", "backupwallet", &backupwallet, true },
+ { "wallet", "dumpprivkey", &dumpprivkey, true },
+ { "wallet", "dumpwallet", &dumpwallet, true },
+ { "wallet", "encryptwallet", &encryptwallet, true },
+ { "wallet", "getaccountaddress", &getaccountaddress, true },
+ { "wallet", "getaccount", &getaccount, true },
+ { "wallet", "getaddressesbyaccount", &getaddressesbyaccount, true },
+ { "wallet", "getbalance", &getbalance, false },
+ { "wallet", "getnewaddress", &getnewaddress, true },
+ { "wallet", "getrawchangeaddress", &getrawchangeaddress, true },
+ { "wallet", "getreceivedbyaccount", &getreceivedbyaccount, false },
+ { "wallet", "getreceivedbyaddress", &getreceivedbyaddress, false },
+ { "wallet", "gettransaction", &gettransaction, false },
+ { "wallet", "getunconfirmedbalance", &getunconfirmedbalance, false },
+ { "wallet", "getwalletinfo", &getwalletinfo, false },
+ { "wallet", "importprivkey", &importprivkey, true },
+ { "wallet", "importwallet", &importwallet, true },
+ { "wallet", "importaddress", &importaddress, true },
+ { "wallet", "importpubkey", &importpubkey, true },
+ { "wallet", "keypoolrefill", &keypoolrefill, true },
+ { "wallet", "listaccounts", &listaccounts, false },
+ { "wallet", "listaddressgroupings", &listaddressgroupings, false },
+ { "wallet", "listlockunspent", &listlockunspent, false },
+ { "wallet", "listreceivedbyaccount", &listreceivedbyaccount, false },
+ { "wallet", "listreceivedbyaddress", &listreceivedbyaddress, false },
+ { "wallet", "listsinceblock", &listsinceblock, false },
+ { "wallet", "listtransactions", &listtransactions, false },
+ { "wallet", "listunspent", &listunspent, false },
+ { "wallet", "lockunspent", &lockunspent, true },
+ { "wallet", "move", &movecmd, false },
+ { "wallet", "sendfrom", &sendfrom, false },
+ { "wallet", "sendmany", &sendmany, false },
+ { "wallet", "sendtoaddress", &sendtoaddress, false },
+ { "wallet", "setaccount", &setaccount, true },
+ { "wallet", "settxfee", &settxfee, true },
+ { "wallet", "signmessage", &signmessage, true },
+ { "wallet", "walletlock", &walletlock, true },
+ { "wallet", "walletpassphrasechange", &walletpassphrasechange, true },
+ { "wallet", "walletpassphrase", &walletpassphrase, true },
+};
+
+void walletRegisterRPCCommands()
+{
+ unsigned int vcidx;
+ for (vcidx = 0; vcidx < ARRAYLEN(vWalletRPCCommands); vcidx++)
+ {
+ const CRPCCommand *pcmd;
+
+ pcmd = &vWalletRPCCommands[vcidx];
+ tableRPC.appendCommand(pcmd->name, pcmd);
+ }
+}
diff --git a/src/wallet/rpcwallet.h b/src/wallet/rpcwallet.h
new file mode 100644
index 0000000000..42e8021afa
--- /dev/null
+++ b/src/wallet/rpcwallet.h
@@ -0,0 +1,10 @@
+// Copyright (c) 2016 The Bitcoin Core developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#ifndef BITCOIN_WALLET_RPCWALLET_H
+#define BITCOIN_WALLET_RPCWALLET_H
+
+void walletRegisterRPCCommands();
+
+#endif //BITCOIN_WALLET_RPCWALLET_H
diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp
index cbc71aa16b..5b8bd55498 100644
--- a/src/wallet/wallet.cpp
+++ b/src/wallet/wallet.cpp
@@ -1799,7 +1799,8 @@ bool CWallet::SelectCoinsMinConf(const CAmount& nTargetValue, int nConfMine, int
}
// Solve subset sum by stochastic approximation
- sort(vValue.rbegin(), vValue.rend(), CompareValueOnly());
+ std::sort(vValue.begin(), vValue.end(), CompareValueOnly());
+ std::reverse(vValue.begin(), vValue.end());
vector<char> vfBest;
CAmount nBest;
diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h
index 2176a5ff66..ffc7dcbd2c 100644
--- a/src/wallet/wallet.h
+++ b/src/wallet/wallet.h
@@ -15,6 +15,7 @@
#include "wallet/crypter.h"
#include "wallet/wallet_ismine.h"
#include "wallet/walletdb.h"
+#include "wallet/rpcwallet.h"
#include <algorithm>
#include <map>