aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorSuhas Daftuar <sdaftuar@chaincode.com>2015-12-16 14:57:54 -0500
committerSuhas Daftuar <sdaftuar@gmail.com>2016-01-19 08:30:04 -0500
commiteaa8d2754b48b62cdd07255fc3028feecad0c095 (patch)
treeb8d312d93e9ec123af0ba08034ab5df18ce6f2e7 /src
parentf9fd4c2884849bc667da3da8bf5f78f33dd01f1c (diff)
RPC: indicate which transactions are replaceable
Add "bip125-replaceable" output field to listtransactions and gettransaction which indicates if an unconfirmed transaction, or any unconfirmed parent, is signaling opt-in RBF according to BIP 125.
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am2
-rw-r--r--src/policy/rbf.cpp46
-rw-r--r--src/policy/rbf.h20
-rw-r--r--src/wallet/rpcwallet.cpp22
4 files changed, 90 insertions, 0 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index 5da1a873de..5d7fbb13d2 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 \
@@ -239,6 +240,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/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/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp
index a977b5abd6..f7a1ca0fef 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));
}
@@ -1439,6 +1457,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 +1727,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"