aboutsummaryrefslogtreecommitdiff
path: root/src/wallet
diff options
context:
space:
mode:
Diffstat (limited to 'src/wallet')
-rw-r--r--src/wallet/crypter.cpp2
-rw-r--r--src/wallet/crypter.h2
-rw-r--r--src/wallet/db.cpp4
-rw-r--r--src/wallet/db.h2
-rw-r--r--src/wallet/rpcdump.cpp4
-rw-r--r--src/wallet/rpcwallet.cpp245
-rw-r--r--src/wallet/rpcwallet.h10
-rw-r--r--src/wallet/test/wallet_tests.cpp35
-rw-r--r--src/wallet/wallet.cpp191
-rw-r--r--src/wallet/wallet.h194
-rw-r--r--src/wallet/wallet_ismine.cpp2
-rw-r--r--src/wallet/wallet_ismine.h4
-rw-r--r--src/wallet/walletdb.cpp10
-rw-r--r--src/wallet/walletdb.h2
14 files changed, 491 insertions, 216 deletions
diff --git a/src/wallet/crypter.cpp b/src/wallet/crypter.cpp
index c86ad9758e..95aa4c2593 100644
--- a/src/wallet/crypter.cpp
+++ b/src/wallet/crypter.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2009-2013 The Bitcoin Core developers
+// Copyright (c) 2009-2015 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/wallet/crypter.h b/src/wallet/crypter.h
index 70aeb76723..eb06a7866a 100644
--- a/src/wallet/crypter.h
+++ b/src/wallet/crypter.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2009-2014 The Bitcoin Core developers
+// Copyright (c) 2009-2015 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/wallet/db.cpp b/src/wallet/db.cpp
index 4b9dbebddd..50b0f40a6a 100644
--- a/src/wallet/db.cpp
+++ b/src/wallet/db.cpp
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2014 The Bitcoin Core developers
+// Copyright (c) 2009-2015 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -205,7 +205,7 @@ bool CDBEnv::Salvage(const std::string& strFile, bool fAggressive, std::vector<C
std::string keyHex, valueHex;
while (!strDump.eof() && keyHex != "DATA=END") {
getline(strDump, keyHex);
- if (keyHex != "DATA_END") {
+ if (keyHex != "DATA=END") {
getline(strDump, valueHex);
vResult.push_back(make_pair(ParseHex(keyHex), ParseHex(valueHex)));
}
diff --git a/src/wallet/db.h b/src/wallet/db.h
index 7f58d03f08..01b8c71a04 100644
--- a/src/wallet/db.h
+++ b/src/wallet/db.h
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2014 The Bitcoin Core developers
+// Copyright (c) 2009-2015 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/wallet/rpcdump.cpp b/src/wallet/rpcdump.cpp
index c431fc4013..9ec28e7b91 100644
--- a/src/wallet/rpcdump.cpp
+++ b/src/wallet/rpcdump.cpp
@@ -1,10 +1,10 @@
-// Copyright (c) 2009-2014 The Bitcoin Core developers
+// Copyright (c) 2009-2015 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include "base58.h"
#include "chain.h"
-#include "rpcserver.h"
+#include "rpc/server.h"
#include "init.h"
#include "main.h"
#include "script/script.h"
diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp
index db60e498dd..857a3a77e2 100644
--- a/src/wallet/rpcwallet.cpp
+++ b/src/wallet/rpcwallet.cpp
@@ -1,5 +1,5 @@
// Copyright (c) 2010 Satoshi Nakamoto
-// Copyright (c) 2009-2014 The Bitcoin Core developers
+// Copyright (c) 2009-2015 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -11,7 +11,8 @@
#include "main.h"
#include "net.h"
#include "netbase.h"
-#include "rpcserver.h"
+#include "policy/rbf.h"
+#include "rpc/server.h"
#include "timedata.h"
#include "util.h"
#include "utilmoneystr.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));
}
@@ -92,7 +110,7 @@ UniValue getnewaddress(const UniValue& params, bool fHelp)
{
if (!EnsureWalletIsAvailable(fHelp))
return NullUniValue;
-
+
if (fHelp || params.size() > 1)
throw runtime_error(
"getnewaddress ( \"account\" )\n"
@@ -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");
@@ -171,7 +188,7 @@ UniValue getaccountaddress(const UniValue& params, bool fHelp)
{
if (!EnsureWalletIsAvailable(fHelp))
return NullUniValue;
-
+
if (fHelp || params.size() != 1)
throw runtime_error(
"getaccountaddress \"account\"\n"
@@ -203,7 +220,7 @@ UniValue getrawchangeaddress(const UniValue& params, bool fHelp)
{
if (!EnsureWalletIsAvailable(fHelp))
return NullUniValue;
-
+
if (fHelp || params.size() > 1)
throw runtime_error(
"getrawchangeaddress\n"
@@ -238,7 +255,7 @@ UniValue setaccount(const UniValue& params, bool fHelp)
{
if (!EnsureWalletIsAvailable(fHelp))
return NullUniValue;
-
+
if (fHelp || params.size() < 1 || params.size() > 2)
throw runtime_error(
"setaccount \"bitcoinaddress\" \"account\"\n"
@@ -284,7 +301,7 @@ UniValue getaccount(const UniValue& params, bool fHelp)
{
if (!EnsureWalletIsAvailable(fHelp))
return NullUniValue;
-
+
if (fHelp || params.size() != 1)
throw runtime_error(
"getaccount \"bitcoinaddress\"\n"
@@ -316,7 +333,7 @@ UniValue getaddressesbyaccount(const UniValue& params, bool fHelp)
{
if (!EnsureWalletIsAvailable(fHelp))
return NullUniValue;
-
+
if (fHelp || params.size() != 1)
throw runtime_error(
"getaddressesbyaccount \"account\"\n"
@@ -384,15 +401,15 @@ UniValue sendtoaddress(const UniValue& params, bool fHelp)
{
if (!EnsureWalletIsAvailable(fHelp))
return NullUniValue;
-
+
if (fHelp || params.size() < 2 || params.size() > 5)
throw runtime_error(
"sendtoaddress \"bitcoinaddress\" amount ( \"comment\" \"comment-to\" subtractfeefromamount )\n"
- "\nSend an amount to a given address. The amount is a real and is rounded to the nearest 0.00000001\n"
+ "\nSend an amount to a given address.\n"
+ HelpRequiringPassphrase() +
"\nArguments:\n"
"1. \"bitcoinaddress\" (string, required) The bitcoin address to send to.\n"
- "2. \"amount\" (numeric, required) The amount in " + CURRENCY_UNIT + " to send. eg 0.1\n"
+ "2. \"amount\" (numeric or string, required) The amount in " + CURRENCY_UNIT + " to send. eg 0.1\n"
"3. \"comment\" (string, optional) A comment used to store what the transaction is for. \n"
" This is not part of the transaction, just kept in your wallet.\n"
"4. \"comment-to\" (string, optional) A comment to store the name of the person or organization \n"
@@ -442,7 +459,7 @@ UniValue listaddressgroupings(const UniValue& params, bool fHelp)
{
if (!EnsureWalletIsAvailable(fHelp))
return NullUniValue;
-
+
if (fHelp)
throw runtime_error(
"listaddressgroupings\n"
@@ -493,7 +510,7 @@ UniValue signmessage(const UniValue& params, bool fHelp)
{
if (!EnsureWalletIsAvailable(fHelp))
return NullUniValue;
-
+
if (fHelp || params.size() != 2)
throw runtime_error(
"signmessage \"bitcoinaddress\" \"message\"\n"
@@ -549,7 +566,7 @@ UniValue getreceivedbyaddress(const UniValue& params, bool fHelp)
{
if (!EnsureWalletIsAvailable(fHelp))
return NullUniValue;
-
+
if (fHelp || params.size() < 1 || params.size() > 2)
throw runtime_error(
"getreceivedbyaddress \"bitcoinaddress\" ( minconf )\n"
@@ -607,7 +624,7 @@ UniValue getreceivedbyaccount(const UniValue& params, bool fHelp)
{
if (!EnsureWalletIsAvailable(fHelp))
return NullUniValue;
-
+
if (fHelp || params.size() < 1 || params.size() > 2)
throw runtime_error(
"getreceivedbyaccount \"account\" ( minconf )\n"
@@ -696,7 +713,7 @@ UniValue getbalance(const UniValue& params, bool fHelp)
{
if (!EnsureWalletIsAvailable(fHelp))
return NullUniValue;
-
+
if (fHelp || params.size() > 3)
throw runtime_error(
"getbalance ( \"account\" minconf includeWatchonly )\n"
@@ -771,7 +788,7 @@ UniValue getunconfirmedbalance(const UniValue &params, bool fHelp)
{
if (!EnsureWalletIsAvailable(fHelp))
return NullUniValue;
-
+
if (fHelp || params.size() > 0)
throw runtime_error(
"getunconfirmedbalance\n"
@@ -787,7 +804,7 @@ UniValue movecmd(const UniValue& params, bool fHelp)
{
if (!EnsureWalletIsAvailable(fHelp))
return NullUniValue;
-
+
if (fHelp || params.size() < 3 || params.size() > 5)
throw runtime_error(
"move \"fromaccount\" \"toaccount\" amount ( minconf \"comment\" )\n"
@@ -860,17 +877,16 @@ UniValue sendfrom(const UniValue& params, bool fHelp)
{
if (!EnsureWalletIsAvailable(fHelp))
return NullUniValue;
-
+
if (fHelp || params.size() < 3 || params.size() > 6)
throw runtime_error(
"sendfrom \"fromaccount\" \"tobitcoinaddress\" amount ( minconf \"comment\" \"comment-to\" )\n"
- "\nDEPRECATED (use sendtoaddress). Sent an amount from an account to a bitcoin address.\n"
- "The amount is a real and is rounded to the nearest 0.00000001."
+ "\nDEPRECATED (use sendtoaddress). Sent an amount from an account to a bitcoin address."
+ HelpRequiringPassphrase() + "\n"
"\nArguments:\n"
"1. \"fromaccount\" (string, required) The name of the account to send funds from. May be the default account using \"\".\n"
"2. \"tobitcoinaddress\" (string, required) The bitcoin address to send funds to.\n"
- "3. amount (numeric, required) The amount in " + CURRENCY_UNIT + " (transaction fee is added on top).\n"
+ "3. amount (numeric or string, required) The amount in " + CURRENCY_UNIT + " (transaction fee is added on top).\n"
"4. minconf (numeric, optional, default=1) Only use funds with at least this many confirmations.\n"
"5. \"comment\" (string, optional) A comment used to store what the transaction is for. \n"
" This is not part of the transaction, just kept in your wallet.\n"
@@ -925,7 +941,7 @@ UniValue sendmany(const UniValue& params, bool fHelp)
{
if (!EnsureWalletIsAvailable(fHelp))
return NullUniValue;
-
+
if (fHelp || params.size() < 2 || params.size() > 5)
throw runtime_error(
"sendmany \"fromaccount\" {\"address\":amount,...} ( minconf \"comment\" [\"address\",...] )\n"
@@ -935,7 +951,7 @@ UniValue sendmany(const UniValue& params, bool fHelp)
"1. \"fromaccount\" (string, required) DEPRECATED. The account to send the funds from. Should be \"\" for the default account\n"
"2. \"amounts\" (string, required) A json object with addresses and amounts\n"
" {\n"
- " \"address\":amount (numeric) The bitcoin address is the key, the numeric amount in " + CURRENCY_UNIT + " is the value\n"
+ " \"address\":amount (numeric or string) The bitcoin address is the key, the numeric amount (can be string) in " + CURRENCY_UNIT + " is the value\n"
" ,...\n"
" }\n"
"3. minconf (numeric, optional, default=1) Only use the balance confirmed at least this many times.\n"
@@ -1032,14 +1048,14 @@ UniValue sendmany(const UniValue& params, bool fHelp)
return wtx.GetHash().GetHex();
}
-// Defined in rpcmisc.cpp
+// Defined in rpc/misc.cpp
extern CScript _createmultisig_redeemScript(const UniValue& params);
UniValue addmultisigaddress(const UniValue& params, bool fHelp)
{
if (!EnsureWalletIsAvailable(fHelp))
return NullUniValue;
-
+
if (fHelp || params.size() < 2 || params.size() > 3)
{
string msg = "addmultisigaddress nrequired [\"key\",...] ( \"account\" )\n"
@@ -1222,7 +1238,7 @@ UniValue listreceivedbyaddress(const UniValue& params, bool fHelp)
{
if (!EnsureWalletIsAvailable(fHelp))
return NullUniValue;
-
+
if (fHelp || params.size() > 3)
throw runtime_error(
"listreceivedbyaddress ( minconf includeempty includeWatchonly)\n"
@@ -1260,7 +1276,7 @@ UniValue listreceivedbyaccount(const UniValue& params, bool fHelp)
{
if (!EnsureWalletIsAvailable(fHelp))
return NullUniValue;
-
+
if (fHelp || params.size() > 3)
throw runtime_error(
"listreceivedbyaccount ( minconf includeempty includeWatchonly)\n"
@@ -1395,7 +1411,7 @@ UniValue listtransactions(const UniValue& params, bool fHelp)
{
if (!EnsureWalletIsAvailable(fHelp))
return NullUniValue;
-
+
if (fHelp || params.size() > 4)
throw runtime_error(
"listtransactions ( \"account\" count from includeWatchonly)\n"
@@ -1424,7 +1440,7 @@ UniValue listtransactions(const UniValue& params, bool fHelp)
" 'send' category of transactions.\n"
" \"confirmations\": n, (numeric) The number of confirmations for the transaction. Available for 'send' and \n"
" 'receive' category of transactions. Negative confirmations indicate the\n"
- " transation conflicts with the block chain\n"
+ " transaction conflicts with the block chain\n"
" \"trusted\": xxx (bool) Whether we consider the outputs of this unconfirmed transaction safe to spend.\n"
" \"blockhash\": \"hashvalue\", (string) The block hash containing the transaction. Available for 'send' and 'receive'\n"
" category of transactions.\n"
@@ -1440,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"
@@ -1519,7 +1537,7 @@ UniValue listaccounts(const UniValue& params, bool fHelp)
{
if (!EnsureWalletIsAvailable(fHelp))
return NullUniValue;
-
+
if (fHelp || params.size() > 2)
throw runtime_error(
"listaccounts ( minconf includeWatchonly)\n"
@@ -1598,7 +1616,7 @@ UniValue listsinceblock(const UniValue& params, bool fHelp)
{
if (!EnsureWalletIsAvailable(fHelp))
return NullUniValue;
-
+
if (fHelp)
throw runtime_error(
"listsinceblock ( \"blockhash\" target-confirmations includeWatchonly)\n"
@@ -1690,7 +1708,7 @@ UniValue gettransaction(const UniValue& params, bool fHelp)
{
if (!EnsureWalletIsAvailable(fHelp))
return NullUniValue;
-
+
if (fHelp || params.size() < 1 || params.size() > 2)
throw runtime_error(
"gettransaction \"txid\" ( includeWatchonly )\n"
@@ -1708,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"
@@ -1764,12 +1784,46 @@ UniValue gettransaction(const UniValue& params, bool fHelp)
return entry;
}
+UniValue abandontransaction(const UniValue& params, bool fHelp)
+{
+ if (!EnsureWalletIsAvailable(fHelp))
+ return NullUniValue;
+
+ if (fHelp || params.size() != 1)
+ throw runtime_error(
+ "abandontransaction \"txid\"\n"
+ "\nMark in-wallet transaction <txid> as abandoned\n"
+ "This will mark this transaction and all its in-wallet descendants as abandoned which will allow\n"
+ "for their inputs to be respent. It can be used to replace \"stuck\" or evicted transactions.\n"
+ "It only works on transactions which are not included in a block and are not currently in the mempool.\n"
+ "It has no effect on transactions which are already conflicted or abandoned.\n"
+ "\nArguments:\n"
+ "1. \"txid\" (string, required) The transaction id\n"
+ "\nResult:\n"
+ "\nExamples:\n"
+ + HelpExampleCli("abandontransaction", "\"1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d\"")
+ + HelpExampleRpc("abandontransaction", "\"1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d\"")
+ );
+
+ LOCK2(cs_main, pwalletMain->cs_wallet);
+
+ uint256 hash;
+ hash.SetHex(params[0].get_str());
+
+ if (!pwalletMain->mapWallet.count(hash))
+ throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid or non-wallet transaction id");
+ if (!pwalletMain->AbandonTransaction(hash))
+ throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Transaction not eligible for abandonment");
+
+ return NullUniValue;
+}
+
UniValue backupwallet(const UniValue& params, bool fHelp)
{
if (!EnsureWalletIsAvailable(fHelp))
return NullUniValue;
-
+
if (fHelp || params.size() != 1)
throw runtime_error(
"backupwallet \"destination\"\n"
@@ -1795,7 +1849,7 @@ UniValue keypoolrefill(const UniValue& params, bool fHelp)
{
if (!EnsureWalletIsAvailable(fHelp))
return NullUniValue;
-
+
if (fHelp || params.size() > 1)
throw runtime_error(
"keypoolrefill ( newsize )\n"
@@ -1839,7 +1893,7 @@ UniValue walletpassphrase(const UniValue& params, bool fHelp)
{
if (!EnsureWalletIsAvailable(fHelp))
return NullUniValue;
-
+
if (pwalletMain->IsCrypted() && (fHelp || params.size() != 2))
throw runtime_error(
"walletpassphrase \"passphrase\" timeout\n"
@@ -1899,7 +1953,7 @@ UniValue walletpassphrasechange(const UniValue& params, bool fHelp)
{
if (!EnsureWalletIsAvailable(fHelp))
return NullUniValue;
-
+
if (pwalletMain->IsCrypted() && (fHelp || params.size() != 2))
throw runtime_error(
"walletpassphrasechange \"oldpassphrase\" \"newpassphrase\"\n"
@@ -1945,7 +1999,7 @@ UniValue walletlock(const UniValue& params, bool fHelp)
{
if (!EnsureWalletIsAvailable(fHelp))
return NullUniValue;
-
+
if (pwalletMain->IsCrypted() && (fHelp || params.size() != 0))
throw runtime_error(
"walletlock\n"
@@ -1984,7 +2038,7 @@ UniValue encryptwallet(const UniValue& params, bool fHelp)
{
if (!EnsureWalletIsAvailable(fHelp))
return NullUniValue;
-
+
if (!pwalletMain->IsCrypted() && (fHelp || params.size() != 1))
throw runtime_error(
"encryptwallet \"passphrase\"\n"
@@ -2041,7 +2095,7 @@ UniValue lockunspent(const UniValue& params, bool fHelp)
{
if (!EnsureWalletIsAvailable(fHelp))
return NullUniValue;
-
+
if (fHelp || params.size() < 1 || params.size() > 2)
throw runtime_error(
"lockunspent unlock [{\"txid\":\"txid\",\"vout\":n},...]\n"
@@ -2125,7 +2179,7 @@ UniValue listlockunspent(const UniValue& params, bool fHelp)
{
if (!EnsureWalletIsAvailable(fHelp))
return NullUniValue;
-
+
if (fHelp || params.size() > 0)
throw runtime_error(
"listlockunspent\n"
@@ -2174,13 +2228,13 @@ UniValue settxfee(const UniValue& params, bool fHelp)
{
if (!EnsureWalletIsAvailable(fHelp))
return NullUniValue;
-
+
if (fHelp || params.size() < 1 || params.size() > 1)
throw runtime_error(
"settxfee amount\n"
"\nSet the transaction fee per kB. Overwrites the paytxfee parameter.\n"
"\nArguments:\n"
- "1. amount (numeric, required) The transaction fee in " + CURRENCY_UNIT + "/kB rounded to the nearest 0.00000001\n"
+ "1. amount (numeric or sting, required) The transaction fee in " + CURRENCY_UNIT + "/kB\n"
"\nResult\n"
"true|false (boolean) Returns true if successful\n"
"\nExamples:\n"
@@ -2201,7 +2255,7 @@ UniValue getwalletinfo(const UniValue& params, bool fHelp)
{
if (!EnsureWalletIsAvailable(fHelp))
return NullUniValue;
-
+
if (fHelp || params.size() != 0)
throw runtime_error(
"getwalletinfo\n"
@@ -2243,7 +2297,7 @@ UniValue resendwallettransactions(const UniValue& params, bool fHelp)
{
if (!EnsureWalletIsAvailable(fHelp))
return NullUniValue;
-
+
if (fHelp || params.size() != 0)
throw runtime_error(
"resendwallettransactions\n"
@@ -2268,7 +2322,7 @@ UniValue listunspent(const UniValue& params, bool fHelp)
{
if (!EnsureWalletIsAvailable(fHelp))
return NullUniValue;
-
+
if (fHelp || params.size() > 3)
throw runtime_error(
"listunspent ( minconf maxconf [\"address\",...] )\n"
@@ -2442,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/test/wallet_tests.cpp b/src/wallet/test/wallet_tests.cpp
index 8b9292bd14..e84d588026 100644
--- a/src/wallet/test/wallet_tests.cpp
+++ b/src/wallet/test/wallet_tests.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2012-2014 The Bitcoin Core developers
+// Copyright (c) 2012-2015 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -328,4 +328,37 @@ BOOST_AUTO_TEST_CASE(coin_selection_tests)
empty_wallet();
}
+BOOST_AUTO_TEST_CASE(ApproximateBestSubset)
+{
+ CoinSet setCoinsRet;
+ CAmount nValueRet;
+
+ LOCK(wallet.cs_wallet);
+
+ empty_wallet();
+
+ // Test vValue sort order
+ for (int i = 0; i < 1000; i++)
+ add_coin(1000 * COIN);
+ add_coin(3 * COIN);
+
+ BOOST_CHECK(wallet.SelectCoinsMinConf(1003 * COIN, 1, 6, vCoins, setCoinsRet, nValueRet));
+ BOOST_CHECK_EQUAL(nValueRet, 1003 * COIN);
+ BOOST_CHECK_EQUAL(setCoinsRet.size(), 2U);
+
+ empty_wallet();
+
+ // Test trimming
+ for (int i = 0; i < 100; i++)
+ add_coin(10 * COIN);
+ for (int i = 0; i < 100; i++)
+ add_coin(1000 * COIN);
+
+ BOOST_CHECK(wallet.SelectCoinsMinConf(100001 * COIN, 1, 6, vCoins, setCoinsRet, nValueRet));
+ // We need all 100 larger coins and exactly one small coin.
+ // Superfluous small coins must be trimmed from the set:
+ BOOST_CHECK_EQUAL(nValueRet, 100010 * COIN);
+ BOOST_CHECK_EQUAL(setCoinsRet.size(), 101);
+}
+
BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp
index d23d54e678..65defc30aa 100644
--- a/src/wallet/wallet.cpp
+++ b/src/wallet/wallet.cpp
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2014 The Bitcoin Core developers
+// Copyright (c) 2009-2015 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -37,7 +37,6 @@ using namespace std;
* Settings
*/
CFeeRate payTxFee(DEFAULT_TRANSACTION_FEE);
-CAmount maxTxFee = DEFAULT_TRANSACTION_MAXFEE;
unsigned int nTxConfirmTarget = DEFAULT_TX_CONFIRM_TARGET;
bool bSpendZeroConfChange = DEFAULT_SPEND_ZEROCONF_CHANGE;
bool fSendFreeTransactions = DEFAULT_SEND_FREE_TRANSACTIONS;
@@ -47,6 +46,14 @@ bool fSendFreeTransactions = DEFAULT_SEND_FREE_TRANSACTIONS;
* Override with -mintxfee
*/
CFeeRate CWallet::minTxFee = CFeeRate(DEFAULT_TRANSACTION_MINFEE);
+/**
+ * If fee estimation does not have enough data to provide estimates, use this fee instead.
+ * Has no effect if not using fee estimation
+ * Override with -fallbackfee
+ */
+CFeeRate CWallet::fallbackFee = CFeeRate(DEFAULT_FALLBACK_FEE);
+
+const uint256 CMerkleTx::ABANDON_HASH(uint256S("0000000000000000000000000000000000000000000000000000000000000001"));
/** @defgroup mapWallet
*
@@ -455,8 +462,11 @@ bool CWallet::IsSpent(const uint256& hash, unsigned int n) const
{
const uint256& wtxid = it->second;
std::map<uint256, CWalletTx>::const_iterator mit = mapWallet.find(wtxid);
- if (mit != mapWallet.end() && mit->second.GetDepthInMainChain() >= 0)
- return true; // Spent
+ if (mit != mapWallet.end()) {
+ int depth = mit->second.GetDepthInMainChain();
+ if (depth > 0 || (depth == 0 && !mit->second.isAbandoned()))
+ return true; // Spent
+ }
}
return false;
}
@@ -610,7 +620,7 @@ bool CWallet::AddToWallet(const CWalletTx& wtxIn, bool fFromLoadWallet, CWalletD
BOOST_FOREACH(const CTxIn& txin, wtx.vin) {
if (mapWallet.count(txin.prevout.hash)) {
CWalletTx& prevtx = mapWallet[txin.prevout.hash];
- if (prevtx.nIndex == -1 && !prevtx.hashBlock.IsNull()) {
+ if (prevtx.nIndex == -1 && !prevtx.hashUnset()) {
MarkConflicted(prevtx.hashBlock, wtx.GetHash());
}
}
@@ -631,7 +641,7 @@ bool CWallet::AddToWallet(const CWalletTx& wtxIn, bool fFromLoadWallet, CWalletD
wtxOrdered.insert(make_pair(wtx.nOrderPos, TxPair(&wtx, (CAccountingEntry*)0)));
wtx.nTimeSmart = wtx.nTimeReceived;
- if (!wtxIn.hashBlock.IsNull())
+ if (!wtxIn.hashUnset())
{
if (mapBlockIndex.count(wtxIn.hashBlock))
{
@@ -681,7 +691,13 @@ bool CWallet::AddToWallet(const CWalletTx& wtxIn, bool fFromLoadWallet, CWalletD
if (!fInsertedNew)
{
// Merge
- if (!wtxIn.hashBlock.IsNull() && wtxIn.hashBlock != wtx.hashBlock)
+ if (!wtxIn.hashUnset() && wtxIn.hashBlock != wtx.hashBlock)
+ {
+ wtx.hashBlock = wtxIn.hashBlock;
+ fUpdated = true;
+ }
+ // If no longer abandoned, update
+ if (wtxIn.hashBlock.IsNull() && wtx.isAbandoned())
{
wtx.hashBlock = wtxIn.hashBlock;
fUpdated = true;
@@ -768,30 +784,93 @@ bool CWallet::AddToWalletIfInvolvingMe(const CTransaction& tx, const CBlock* pbl
return false;
}
+bool CWallet::AbandonTransaction(const uint256& hashTx)
+{
+ LOCK2(cs_main, cs_wallet);
+
+ // Do not flush the wallet here for performance reasons
+ CWalletDB walletdb(strWalletFile, "r+", false);
+
+ std::set<uint256> todo;
+ std::set<uint256> done;
+
+ // Can't mark abandoned if confirmed or in mempool
+ assert(mapWallet.count(hashTx));
+ CWalletTx& origtx = mapWallet[hashTx];
+ if (origtx.GetDepthInMainChain() > 0 || origtx.InMempool()) {
+ return false;
+ }
+
+ todo.insert(hashTx);
+
+ while (!todo.empty()) {
+ uint256 now = *todo.begin();
+ todo.erase(now);
+ done.insert(now);
+ assert(mapWallet.count(now));
+ CWalletTx& wtx = mapWallet[now];
+ int currentconfirm = wtx.GetDepthInMainChain();
+ // If the orig tx was not in block, none of its spends can be
+ assert(currentconfirm <= 0);
+ // if (currentconfirm < 0) {Tx and spends are already conflicted, no need to abandon}
+ if (currentconfirm == 0 && !wtx.isAbandoned()) {
+ // If the orig tx was not in block/mempool, none of its spends can be in mempool
+ assert(!wtx.InMempool());
+ wtx.nIndex = -1;
+ wtx.setAbandoned();
+ wtx.MarkDirty();
+ wtx.WriteToDisk(&walletdb);
+ NotifyTransactionChanged(this, wtx.GetHash(), CT_UPDATED);
+ // Iterate over all its outputs, and mark transactions in the wallet that spend them abandoned too
+ TxSpends::const_iterator iter = mapTxSpends.lower_bound(COutPoint(hashTx, 0));
+ while (iter != mapTxSpends.end() && iter->first.hash == now) {
+ if (!done.count(iter->second)) {
+ todo.insert(iter->second);
+ }
+ iter++;
+ }
+ // If a transaction changes 'conflicted' state, that changes the balance
+ // available of the outputs it spends. So force those to be recomputed
+ BOOST_FOREACH(const CTxIn& txin, wtx.vin)
+ {
+ if (mapWallet.count(txin.prevout.hash))
+ mapWallet[txin.prevout.hash].MarkDirty();
+ }
+ }
+ }
+
+ return true;
+}
+
void CWallet::MarkConflicted(const uint256& hashBlock, const uint256& hashTx)
{
LOCK2(cs_main, cs_wallet);
- CBlockIndex* pindex;
- assert(mapBlockIndex.count(hashBlock));
- pindex = mapBlockIndex[hashBlock];
int conflictconfirms = 0;
- if (chainActive.Contains(pindex)) {
- conflictconfirms = -(chainActive.Height() - pindex->nHeight + 1);
+ if (mapBlockIndex.count(hashBlock)) {
+ CBlockIndex* pindex = mapBlockIndex[hashBlock];
+ if (chainActive.Contains(pindex)) {
+ conflictconfirms = -(chainActive.Height() - pindex->nHeight + 1);
+ }
}
- assert(conflictconfirms < 0);
+ // If number of conflict confirms cannot be determined, this means
+ // that the block is still unknown or not yet part of the main chain,
+ // for example when loading the wallet during a reindex. Do nothing in that
+ // case.
+ if (conflictconfirms >= 0)
+ return;
// Do not flush the wallet here for performance reasons
CWalletDB walletdb(strWalletFile, "r+", false);
- std::deque<uint256> todo;
+ std::set<uint256> todo;
std::set<uint256> done;
- todo.push_back(hashTx);
+ todo.insert(hashTx);
while (!todo.empty()) {
- uint256 now = todo.front();
- todo.pop_front();
+ uint256 now = *todo.begin();
+ todo.erase(now);
done.insert(now);
assert(mapWallet.count(now));
CWalletTx& wtx = mapWallet[now];
@@ -807,15 +886,22 @@ void CWallet::MarkConflicted(const uint256& hashBlock, const uint256& hashTx)
TxSpends::const_iterator iter = mapTxSpends.lower_bound(COutPoint(now, 0));
while (iter != mapTxSpends.end() && iter->first.hash == now) {
if (!done.count(iter->second)) {
- todo.push_back(iter->second);
+ todo.insert(iter->second);
}
iter++;
}
+ // If a transaction changes 'conflicted' state, that changes the balance
+ // available of the outputs it spends. So force those to be recomputed
+ BOOST_FOREACH(const CTxIn& txin, wtx.vin)
+ {
+ if (mapWallet.count(txin.prevout.hash))
+ mapWallet[txin.prevout.hash].MarkDirty();
+ }
}
}
}
-void CWallet::SyncTransaction(const CTransaction& tx, const CBlock* pblock)
+void CWallet::SyncTransaction(const CTransaction& tx, const CBlockIndex *pindex, const CBlock* pblock)
{
LOCK2(cs_main, cs_wallet);
@@ -969,7 +1055,7 @@ int CWalletTx::GetRequestCount() const
if (IsCoinBase())
{
// Generated block
- if (!hashBlock.IsNull())
+ if (!hashUnset())
{
map<uint256, int>::const_iterator mi = pwallet->mapRequestCount.find(hashBlock);
if (mi != pwallet->mapRequestCount.end())
@@ -985,7 +1071,7 @@ int CWalletTx::GetRequestCount() const
nRequests = (*mi).second;
// How about the block it's in?
- if (nRequests == 0 && !hashBlock.IsNull())
+ if (nRequests == 0 && !hashUnset())
{
map<uint256, int>::const_iterator mi = pwallet->mapRequestCount.find(hashBlock);
if (mi != pwallet->mapRequestCount.end())
@@ -1034,7 +1120,8 @@ void CWalletTx::GetAmounts(list<COutputEntry>& listReceived,
// In either case, we need to get the destination address
CTxDestination address;
- if (!ExtractDestination(txout.scriptPubKey, address))
+
+ if (!ExtractDestination(txout.scriptPubKey, address) && !txout.scriptPubKey.IsUnspendable())
{
LogPrintf("CWalletTx::GetAmounts: Unknown transaction type found, txid %s\n",
this->GetHash().ToString());
@@ -1158,7 +1245,7 @@ void CWallet::ReacceptWalletTransactions()
int nDepth = wtx.GetDepthInMainChain();
- if (!wtx.IsCoinBase() && nDepth == 0) {
+ if (!wtx.IsCoinBase() && (nDepth == 0 && !wtx.isAbandoned())) {
mapSorted.insert(std::make_pair(wtx.nOrderPos, &wtx));
}
}
@@ -1169,7 +1256,7 @@ void CWallet::ReacceptWalletTransactions()
CWalletTx& wtx = *(item.second);
LOCK(mempool.cs);
- wtx.AcceptToMemoryPool(false);
+ wtx.AcceptToMemoryPool(false, maxTxFee);
}
}
@@ -1178,7 +1265,7 @@ bool CWalletTx::RelayWalletTransaction()
assert(pwallet->GetBroadcastTransactions());
if (!IsCoinBase())
{
- if (GetDepthInMainChain() == 0) {
+ if (GetDepthInMainChain() == 0 && !isAbandoned()) {
LogPrintf("Relaying wtx %s\n", GetHash().ToString());
RelayTransaction((CTransaction)*this);
return true;
@@ -1359,6 +1446,15 @@ CAmount CWalletTx::GetChange() const
return nChangeCached;
}
+bool CWalletTx::InMempool() const
+{
+ LOCK(mempool.cs);
+ if (mempool.exists(GetHash())) {
+ return true;
+ }
+ return false;
+}
+
bool CWalletTx::IsTrusted() const
{
// Quick answer in most cases
@@ -1373,12 +1469,8 @@ bool CWalletTx::IsTrusted() const
return false;
// Don't trust unconfirmed transactions from us unless they are in the mempool.
- {
- LOCK(mempool.cs);
- if (!mempool.exists(GetHash())) {
- return false;
- }
- }
+ if (!InMempool())
+ return false;
// Trusted if all inputs are from us and are in the mempool:
BOOST_FOREACH(const CTxIn& txin, vin)
@@ -1632,6 +1724,16 @@ static void ApproximateBestSubset(vector<pair<CAmount, pair<const CWalletTx*,uns
}
}
}
+
+ //Reduces the approximate best subset by removing any inputs that are smaller than the surplus of nTotal beyond nTargetValue.
+ for (unsigned int i = 0; i < vValue.size(); i++)
+ {
+ if (vfBest[i] && (nBest - vValue[i].first) >= nTargetValue )
+ {
+ vfBest[i] = false;
+ nBest -= vValue[i].first;
+ }
+ }
}
bool CWallet::SelectCoinsMinConf(const CAmount& nTargetValue, int nConfMine, int nConfTheirs, vector<COutput> vCoins,
@@ -1701,7 +1803,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;
@@ -2170,7 +2273,7 @@ bool CWallet::CommitTransaction(CWalletTx& wtxNew, CReserveKey& reservekey)
if (fBroadcastTransactions)
{
// Broadcast
- if (!wtxNew.AcceptToMemoryPool(false))
+ if (!wtxNew.AcceptToMemoryPool(false, maxTxFee))
{
// This must not fail. The transaction has already been signed and recorded.
LogPrintf("CommitTransaction(): Error: Transaction not valid\n");
@@ -2207,14 +2310,12 @@ CAmount CWallet::GetMinimumFee(unsigned int nTxBytes, unsigned int nConfirmTarge
if (nFeeNeeded == 0) {
int estimateFoundTarget = nConfirmTarget;
nFeeNeeded = pool.estimateSmartFee(nConfirmTarget, &estimateFoundTarget).GetFee(nTxBytes);
- // ... unless we don't have enough mempool data for our desired target
- // so we make sure we're paying at least minTxFee
- if (nFeeNeeded == 0 || (unsigned int)estimateFoundTarget > nConfirmTarget)
- nFeeNeeded = std::max(nFeeNeeded, GetRequiredFee(nTxBytes));
- }
- // prevent user from paying a non-sense fee (like 1 satoshi): 0 < fee < minRelayFee
- if (nFeeNeeded < ::minRelayTxFee.GetFee(nTxBytes))
- nFeeNeeded = ::minRelayTxFee.GetFee(nTxBytes);
+ // ... unless we don't have enough mempool data for estimatefee, then use fallbackFee
+ if (nFeeNeeded == 0)
+ nFeeNeeded = fallbackFee.GetFee(nTxBytes);
+ }
+ // prevent user from paying a fee below minRelayTxFee or minTxFee
+ nFeeNeeded = std::max(nFeeNeeded, GetRequiredFee(nTxBytes));
// But always obey the maximum
if (nFeeNeeded > maxTxFee)
nFeeNeeded = maxTxFee;
@@ -2904,8 +3005,9 @@ int CMerkleTx::SetMerkleBranch(const CBlock& block)
int CMerkleTx::GetDepthInMainChain(const CBlockIndex* &pindexRet) const
{
- if (hashBlock.IsNull())
+ if (hashUnset())
return 0;
+
AssertLockHeld(cs_main);
// Find the block it claims to be in
@@ -2928,9 +3030,8 @@ int CMerkleTx::GetBlocksToMaturity() const
}
-bool CMerkleTx::AcceptToMemoryPool(bool fLimitFree, bool fRejectAbsurdFee)
+bool CMerkleTx::AcceptToMemoryPool(bool fLimitFree, CAmount nAbsurdFee)
{
CValidationState state;
- return ::AcceptToMemoryPool(mempool, state, *this, fLimitFree, NULL, false, fRejectAbsurdFee);
+ return ::AcceptToMemoryPool(mempool, state, *this, fLimitFree, NULL, false, nAbsurdFee);
}
-
diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h
index 859788893c..990b27c7ce 100644
--- a/src/wallet/wallet.h
+++ b/src/wallet/wallet.h
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2014 The Bitcoin Core developers
+// Copyright (c) 2009-2015 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -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>
@@ -31,7 +32,6 @@
* Settings
*/
extern CFeeRate payTxFee;
-extern CAmount maxTxFee;
extern unsigned int nTxConfirmTarget;
extern bool bSpendZeroConfChange;
extern bool fSendFreeTransactions;
@@ -39,12 +39,10 @@ extern bool fSendFreeTransactions;
static const unsigned int DEFAULT_KEYPOOL_SIZE = 100;
//! -paytxfee default
static const CAmount DEFAULT_TRANSACTION_FEE = 0;
-//! -paytxfee will warn if called with a higher fee than this amount (in satoshis) per KB
-static const CAmount nHighTransactionFeeWarning = 0.01 * COIN;
+//! -fallbackfee default
+static const CAmount DEFAULT_FALLBACK_FEE = 20000;
//! -mintxfee default
static const CAmount DEFAULT_TRANSACTION_MINFEE = 1000;
-//! -maxtxfee default
-static const CAmount DEFAULT_TRANSACTION_MAXFEE = 0.1 * COIN;
//! minimum change amount
static const CAmount MIN_CHANGE = CENT;
//! Default for -spendzeroconfchange
@@ -53,13 +51,10 @@ static const bool DEFAULT_SPEND_ZEROCONF_CHANGE = true;
static const bool DEFAULT_SEND_FREE_TRANSACTIONS = false;
//! -txconfirmtarget default
static const unsigned int DEFAULT_TX_CONFIRM_TARGET = 2;
-//! -maxtxfee will warn if called with a higher fee than this amount (in satoshis)
-static const CAmount nHighTransactionMaxFeeWarning = 100 * nHighTransactionFeeWarning;
//! Largest (in bytes) free transaction we're willing to create
static const unsigned int MAX_FREE_TRANSACTION_CREATE_SIZE = 1000;
static const bool DEFAULT_WALLETBROADCAST = true;
-class CAccountingEntry;
class CBlockIndex;
class CCoinControl;
class COutput;
@@ -155,6 +150,10 @@ struct COutputEntry
/** A transaction with a merkle branch linking it to the block chain. */
class CMerkleTx : public CTransaction
{
+private:
+ /** Constant used in hashBlock to indicate tx has been abandoned */
+ static const uint256 ABANDON_HASH;
+
public:
uint256 hashBlock;
@@ -205,7 +204,11 @@ public:
int GetDepthInMainChain() const { const CBlockIndex *pindexRet; return GetDepthInMainChain(pindexRet); }
bool IsInMainChain() const { const CBlockIndex *pindexRet; return GetDepthInMainChain(pindexRet) > 0; }
int GetBlocksToMaturity() const;
- bool AcceptToMemoryPool(bool fLimitFree=true, bool fRejectAbsurdFee=true);
+ /** Pass this transaction to the mempool. Fails if absolute fee exceeds absurd fee. */
+ bool AcceptToMemoryPool(bool fLimitFree, const CAmount nAbsurdFee);
+ bool hashUnset() const { return (hashBlock.IsNull() || hashBlock == ABANDON_HASH); }
+ bool isAbandoned() const { return (hashBlock == ABANDON_HASH); }
+ void setAbandoned() { hashBlock = ABANDON_HASH; }
};
/**
@@ -384,6 +387,7 @@ public:
// True if only scriptSigs are different
bool IsEquivalentTo(const CWalletTx& tx) const;
+ bool InMempool() const;
bool IsTrusted() const;
bool WriteToDisk(CWalletDB *pwalletdb);
@@ -444,6 +448,86 @@ public:
}
};
+/**
+ * Internal transfers.
+ * Database key is acentry<account><counter>.
+ */
+class CAccountingEntry
+{
+public:
+ std::string strAccount;
+ CAmount nCreditDebit;
+ int64_t nTime;
+ std::string strOtherAccount;
+ std::string strComment;
+ mapValue_t mapValue;
+ int64_t nOrderPos; //! position in ordered transaction list
+ uint64_t nEntryNo;
+
+ CAccountingEntry()
+ {
+ SetNull();
+ }
+
+ void SetNull()
+ {
+ nCreditDebit = 0;
+ nTime = 0;
+ strAccount.clear();
+ strOtherAccount.clear();
+ strComment.clear();
+ nOrderPos = -1;
+ nEntryNo = 0;
+ }
+
+ ADD_SERIALIZE_METHODS;
+
+ template <typename Stream, typename Operation>
+ inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
+ if (!(nType & SER_GETHASH))
+ READWRITE(nVersion);
+ //! Note: strAccount is serialized as part of the key, not here.
+ READWRITE(nCreditDebit);
+ READWRITE(nTime);
+ READWRITE(LIMITED_STRING(strOtherAccount, 65536));
+
+ if (!ser_action.ForRead())
+ {
+ WriteOrderPos(nOrderPos, mapValue);
+
+ if (!(mapValue.empty() && _ssExtra.empty()))
+ {
+ CDataStream ss(nType, nVersion);
+ ss.insert(ss.begin(), '\0');
+ ss << mapValue;
+ ss.insert(ss.end(), _ssExtra.begin(), _ssExtra.end());
+ strComment.append(ss.str());
+ }
+ }
+
+ READWRITE(LIMITED_STRING(strComment, 65536));
+
+ size_t nSepPos = strComment.find("\0", 0, 1);
+ if (ser_action.ForRead())
+ {
+ mapValue.clear();
+ if (std::string::npos != nSepPos)
+ {
+ CDataStream ss(std::vector<char>(strComment.begin() + nSepPos + 1, strComment.end()), nType, nVersion);
+ ss >> mapValue;
+ _ssExtra = std::vector<char>(ss.begin(), ss.end());
+ }
+ ReadOrderPos(nOrderPos, mapValue);
+ }
+ if (std::string::npos != nSepPos)
+ strComment.erase(nSepPos);
+
+ mapValue.erase("n");
+ }
+
+private:
+ std::vector<char> _ssExtra;
+};
/**
@@ -485,7 +569,6 @@ private:
/* Mark a transaction (and its in-wallet descendants) as conflicting with a particular block. */
void MarkConflicted(const uint256& hashBlock, const uint256& hashTx);
-
void SyncMetaData(std::pair<TxSpends::iterator, TxSpends::iterator>);
public:
@@ -635,7 +718,7 @@ public:
void MarkDirty();
bool AddToWallet(const CWalletTx& wtxIn, bool fFromLoadWallet, CWalletDB* pwalletdb);
- void SyncTransaction(const CTransaction& tx, const CBlock* pblock);
+ void SyncTransaction(const CTransaction& tx, const CBlockIndex *pindex, const CBlock* pblock);
bool AddToWalletIfInvolvingMe(const CTransaction& tx, const CBlock* pblock, bool fUpdate);
int ScanForWalletTransactions(CBlockIndex* pindexStart, bool fUpdate = false);
void ReacceptWalletTransactions();
@@ -665,6 +748,7 @@ public:
bool AddAccountingEntry(const CAccountingEntry&, CWalletDB & pwalletdb);
static CFeeRate minTxFee;
+ static CFeeRate fallbackFee;
/**
* Estimate the minimum fee considering user set parameters
* and the required fee
@@ -782,6 +866,9 @@ public:
bool GetBroadcastTransactions() const { return fBroadcastTransactions; }
/** Set whether this wallet broadcasts transactions. */
void SetBroadcastTransactions(bool broadcast) { fBroadcastTransactions = broadcast; }
+
+ /* Mark a transaction (and it in-wallet descendants) as abandoned so its inputs may be respent. */
+ bool AbandonTransaction(const uint256& hashTx);
};
/** A key allocated from the key pool. */
@@ -839,87 +926,4 @@ public:
}
};
-
-
-/**
- * Internal transfers.
- * Database key is acentry<account><counter>.
- */
-class CAccountingEntry
-{
-public:
- std::string strAccount;
- CAmount nCreditDebit;
- int64_t nTime;
- std::string strOtherAccount;
- std::string strComment;
- mapValue_t mapValue;
- int64_t nOrderPos; //! position in ordered transaction list
- uint64_t nEntryNo;
-
- CAccountingEntry()
- {
- SetNull();
- }
-
- void SetNull()
- {
- nCreditDebit = 0;
- nTime = 0;
- strAccount.clear();
- strOtherAccount.clear();
- strComment.clear();
- nOrderPos = -1;
- nEntryNo = 0;
- }
-
- ADD_SERIALIZE_METHODS;
-
- template <typename Stream, typename Operation>
- inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
- if (!(nType & SER_GETHASH))
- READWRITE(nVersion);
- //! Note: strAccount is serialized as part of the key, not here.
- READWRITE(nCreditDebit);
- READWRITE(nTime);
- READWRITE(LIMITED_STRING(strOtherAccount, 65536));
-
- if (!ser_action.ForRead())
- {
- WriteOrderPos(nOrderPos, mapValue);
-
- if (!(mapValue.empty() && _ssExtra.empty()))
- {
- CDataStream ss(nType, nVersion);
- ss.insert(ss.begin(), '\0');
- ss << mapValue;
- ss.insert(ss.end(), _ssExtra.begin(), _ssExtra.end());
- strComment.append(ss.str());
- }
- }
-
- READWRITE(LIMITED_STRING(strComment, 65536));
-
- size_t nSepPos = strComment.find("\0", 0, 1);
- if (ser_action.ForRead())
- {
- mapValue.clear();
- if (std::string::npos != nSepPos)
- {
- CDataStream ss(std::vector<char>(strComment.begin() + nSepPos + 1, strComment.end()), nType, nVersion);
- ss >> mapValue;
- _ssExtra = std::vector<char>(ss.begin(), ss.end());
- }
- ReadOrderPos(nOrderPos, mapValue);
- }
- if (std::string::npos != nSepPos)
- strComment.erase(nSepPos);
-
- mapValue.erase("n");
- }
-
-private:
- std::vector<char> _ssExtra;
-};
-
#endif // BITCOIN_WALLET_WALLET_H
diff --git a/src/wallet/wallet_ismine.cpp b/src/wallet/wallet_ismine.cpp
index d27b1531e3..ebda5cc53d 100644
--- a/src/wallet/wallet_ismine.cpp
+++ b/src/wallet/wallet_ismine.cpp
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2014 The Bitcoin Core developers
+// Copyright (c) 2009-2015 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/wallet/wallet_ismine.h b/src/wallet/wallet_ismine.h
index 9f45f76c6b..51afd1b140 100644
--- a/src/wallet/wallet_ismine.h
+++ b/src/wallet/wallet_ismine.h
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2014 The Bitcoin Core developers
+// Copyright (c) 2009-2015 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -17,7 +17,7 @@ class CScript;
enum isminetype
{
ISMINE_NO = 0,
- //! Indicates that we dont know how to create a scriptSig that would solve this if we were given the appropriate private keys
+ //! Indicates that we don't know how to create a scriptSig that would solve this if we were given the appropriate private keys
ISMINE_WATCH_UNSOLVABLE = 1,
//! Indicates that we know how to create a scriptSig that would solve this if we were given the appropriate private keys
ISMINE_WATCH_SOLVABLE = 2,
diff --git a/src/wallet/walletdb.cpp b/src/wallet/walletdb.cpp
index e2e827d816..67511976df 100644
--- a/src/wallet/walletdb.cpp
+++ b/src/wallet/walletdb.cpp
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2014 The Bitcoin Core developers
+// Copyright (c) 2009-2015 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -15,6 +15,7 @@
#include "utiltime.h"
#include "wallet/wallet.h"
+#include <boost/version.hpp>
#include <boost/filesystem.hpp>
#include <boost/foreach.hpp>
#include <boost/scoped_ptr.hpp>
@@ -960,8 +961,13 @@ bool CWalletDB::Recover(CDBEnv& dbenv, const std::string& filename, bool fOnlyKe
CDataStream ssKey(row.first, SER_DISK, CLIENT_VERSION);
CDataStream ssValue(row.second, SER_DISK, CLIENT_VERSION);
string strType, strErr;
- bool fReadOK = ReadKeyValue(&dummyWallet, ssKey, ssValue,
+ bool fReadOK;
+ {
+ // Required in LoadKeyMetadata():
+ LOCK(dummyWallet.cs_wallet);
+ fReadOK = ReadKeyValue(&dummyWallet, ssKey, ssValue,
wss, strType, strErr);
+ }
if (!IsKeyType(strType))
continue;
if (!fReadOK)
diff --git a/src/wallet/walletdb.h b/src/wallet/walletdb.h
index 77f7958814..8da33dead2 100644
--- a/src/wallet/walletdb.h
+++ b/src/wallet/walletdb.h
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2013 The Bitcoin Core developers
+// Copyright (c) 2009-2015 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.