aboutsummaryrefslogtreecommitdiff
path: root/src/wallet
diff options
context:
space:
mode:
Diffstat (limited to 'src/wallet')
-rw-r--r--src/wallet/rpcdump.cpp8
-rw-r--r--src/wallet/rpcwallet.cpp33
-rw-r--r--src/wallet/test/accounting_tests.cpp4
-rw-r--r--src/wallet/test/crypto_tests.cpp32
-rw-r--r--src/wallet/test/wallet_tests.cpp78
-rw-r--r--src/wallet/wallet.cpp240
-rw-r--r--src/wallet/wallet.h46
-rw-r--r--src/wallet/walletdb.cpp2
8 files changed, 246 insertions, 197 deletions
diff --git a/src/wallet/rpcdump.cpp b/src/wallet/rpcdump.cpp
index bb5337c4ad..008a4ece19 100644
--- a/src/wallet/rpcdump.cpp
+++ b/src/wallet/rpcdump.cpp
@@ -6,7 +6,7 @@
#include "chain.h"
#include "rpc/server.h"
#include "init.h"
-#include "main.h"
+#include "validation.h"
#include "script/script.h"
#include "script/standard.h"
#include "sync.h"
@@ -267,11 +267,11 @@ UniValue importprunedfunds(const JSONRPCRequest& request)
"2. \"txoutproof\" (string, required) The hex output from gettxoutproof that contains the transaction\n"
);
- CTransaction tx;
+ CMutableTransaction tx;
if (!DecodeHexTx(tx, request.params[0].get_str()))
throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed");
uint256 hashTx = tx.GetHash();
- CWalletTx wtx(pwalletMain,tx);
+ CWalletTx wtx(pwalletMain, MakeTransactionRef(std::move(tx)));
CDataStream ssMB(ParseHexV(request.params[1], "proof"), SER_NETWORK, PROTOCOL_VERSION);
CMerkleBlock merkleBlock;
@@ -304,7 +304,7 @@ UniValue importprunedfunds(const JSONRPCRequest& request)
LOCK2(cs_main, pwalletMain->cs_wallet);
- if (pwalletMain->IsMine(tx)) {
+ if (pwalletMain->IsMine(wtx)) {
pwalletMain->AddToWallet(wtx, false);
return NullUniValue;
}
diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp
index 5a22e0278d..5a4fcc743c 100644
--- a/src/wallet/rpcwallet.cpp
+++ b/src/wallet/rpcwallet.cpp
@@ -9,7 +9,7 @@
#include "consensus/validation.h"
#include "core_io.h"
#include "init.h"
-#include "main.h"
+#include "validation.h"
#include "net.h"
#include "policy/rbf.h"
#include "rpc/server.h"
@@ -362,7 +362,7 @@ static void SendMoney(const CTxDestination &address, CAmount nValue, bool fSubtr
CRecipient recipient = {scriptPubKey, nValue, fSubtractFeeFromAmount};
vecSend.push_back(recipient);
if (!pwalletMain->CreateTransaction(vecSend, wtxNew, reservekey, nFeeRequired, nChangePosRet, strError)) {
- if (!fSubtractFeeFromAmount && nValue + nFeeRequired > pwalletMain->GetBalance())
+ if (!fSubtractFeeFromAmount && nValue + nFeeRequired > curBalance)
strError = strprintf("Error: This transaction requires a transaction fee of at least %s", FormatMoney(nFeeRequired));
throw JSONRPCError(RPC_WALLET_ERROR, strError);
}
@@ -583,10 +583,10 @@ UniValue getreceivedbyaddress(const JSONRPCRequest& request)
for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
{
const CWalletTx& wtx = (*it).second;
- if (wtx.IsCoinBase() || !CheckFinalTx(wtx))
+ if (wtx.IsCoinBase() || !CheckFinalTx(*wtx.tx))
continue;
- BOOST_FOREACH(const CTxOut& txout, wtx.vout)
+ BOOST_FOREACH(const CTxOut& txout, wtx.tx->vout)
if (txout.scriptPubKey == scriptPubKey)
if (wtx.GetDepthInMainChain() >= nMinDepth)
nAmount += txout.nValue;
@@ -637,10 +637,10 @@ UniValue getreceivedbyaccount(const JSONRPCRequest& request)
for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
{
const CWalletTx& wtx = (*it).second;
- if (wtx.IsCoinBase() || !CheckFinalTx(wtx))
+ if (wtx.IsCoinBase() || !CheckFinalTx(*wtx.tx))
continue;
- BOOST_FOREACH(const CTxOut& txout, wtx.vout)
+ BOOST_FOREACH(const CTxOut& txout, wtx.tx->vout)
{
CTxDestination address;
if (ExtractDestination(txout.scriptPubKey, address) && IsMine(*pwalletMain, address) && setAddress.count(address))
@@ -1149,14 +1149,14 @@ UniValue ListReceived(const UniValue& params, bool fByAccounts)
{
const CWalletTx& wtx = (*it).second;
- if (wtx.IsCoinBase() || !CheckFinalTx(wtx))
+ if (wtx.IsCoinBase() || !CheckFinalTx(*wtx.tx))
continue;
int nDepth = wtx.GetDepthInMainChain();
if (nDepth < nMinDepth)
continue;
- BOOST_FOREACH(const CTxOut& txout, wtx.vout)
+ BOOST_FOREACH(const CTxOut& txout, wtx.tx->vout)
{
CTxDestination address;
if (!ExtractDestination(txout.scriptPubKey, address))
@@ -1780,7 +1780,7 @@ UniValue gettransaction(const JSONRPCRequest& request)
CAmount nCredit = wtx.GetCredit(filter);
CAmount nDebit = wtx.GetDebit(filter);
CAmount nNet = nCredit - nDebit;
- CAmount nFee = (wtx.IsFromMe(filter) ? wtx.GetValueOut() - nDebit : 0);
+ CAmount nFee = (wtx.IsFromMe(filter) ? wtx.tx->GetValueOut() - nDebit : 0);
entry.push_back(Pair("amount", ValueFromAmount(nNet - nFee)));
if (wtx.IsFromMe(filter))
@@ -1792,7 +1792,7 @@ UniValue gettransaction(const JSONRPCRequest& request)
ListTransactions(wtx, "*", 0, false, details, filter);
entry.push_back(Pair("details", details));
- string strHex = EncodeHexTx(static_cast<CTransaction>(wtx));
+ string strHex = EncodeHexTx(static_cast<CTransaction>(wtx), RPCSerializationFlags());
entry.push_back(Pair("hex", strHex));
return entry;
@@ -2420,7 +2420,7 @@ UniValue listunspent(const JSONRPCRequest& request)
continue;
CTxDestination address;
- const CScript& scriptPubKey = out.tx->vout[out.i].scriptPubKey;
+ const CScript& scriptPubKey = out.tx->tx->vout[out.i].scriptPubKey;
bool fValidAddress = ExtractDestination(scriptPubKey, address);
if (setAddress.size() && (!fValidAddress || !setAddress.count(address)))
@@ -2445,7 +2445,7 @@ UniValue listunspent(const JSONRPCRequest& request)
}
entry.push_back(Pair("scriptPubKey", HexStr(scriptPubKey.begin(), scriptPubKey.end())));
- entry.push_back(Pair("amount", ValueFromAmount(out.tx->vout[out.i].nValue)));
+ entry.push_back(Pair("amount", ValueFromAmount(out.tx->tx->vout[out.i].nValue)));
entry.push_back(Pair("confirmations", out.nDepth));
entry.push_back(Pair("spendable", out.fSpendable));
entry.push_back(Pair("solvable", out.fSolvable));
@@ -2557,17 +2557,16 @@ UniValue fundrawtransaction(const JSONRPCRequest& request)
}
// parse hex string from parameter
- CTransaction origTx;
- if (!DecodeHexTx(origTx, request.params[0].get_str(), true))
+ CMutableTransaction tx;
+ if (!DecodeHexTx(tx, request.params[0].get_str(), true))
throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed");
- if (origTx.vout.size() == 0)
+ if (tx.vout.size() == 0)
throw JSONRPCError(RPC_INVALID_PARAMETER, "TX must have at least one output");
- if (changePosition != -1 && (changePosition < 0 || (unsigned int)changePosition > origTx.vout.size()))
+ if (changePosition != -1 && (changePosition < 0 || (unsigned int)changePosition > tx.vout.size()))
throw JSONRPCError(RPC_INVALID_PARAMETER, "changePosition out of bounds");
- CMutableTransaction tx(origTx);
CAmount nFeeOut;
string strFailReason;
diff --git a/src/wallet/test/accounting_tests.cpp b/src/wallet/test/accounting_tests.cpp
index a833be13d0..eb14d176bd 100644
--- a/src/wallet/test/accounting_tests.cpp
+++ b/src/wallet/test/accounting_tests.cpp
@@ -86,7 +86,7 @@ BOOST_AUTO_TEST_CASE(acc_orderupgrade)
{
CMutableTransaction tx(wtx);
--tx.nLockTime; // Just to change the hash :)
- *static_cast<CTransaction*>(&wtx) = CTransaction(tx);
+ wtx.SetTx(MakeTransactionRef(std::move(tx)));
}
pwalletMain->AddToWallet(wtx);
vpwtx.push_back(&pwalletMain->mapWallet[wtx.GetHash()]);
@@ -96,7 +96,7 @@ BOOST_AUTO_TEST_CASE(acc_orderupgrade)
{
CMutableTransaction tx(wtx);
--tx.nLockTime; // Just to change the hash :)
- *static_cast<CTransaction*>(&wtx) = CTransaction(tx);
+ wtx.SetTx(MakeTransactionRef(std::move(tx)));
}
pwalletMain->AddToWallet(wtx);
vpwtx.push_back(&pwalletMain->mapWallet[wtx.GetHash()]);
diff --git a/src/wallet/test/crypto_tests.cpp b/src/wallet/test/crypto_tests.cpp
index ce35c53c48..c64c76244e 100644
--- a/src/wallet/test/crypto_tests.cpp
+++ b/src/wallet/test/crypto_tests.cpp
@@ -42,15 +42,19 @@ bool OldEncrypt(const CKeyingMaterial& vchPlaintext, std::vector<unsigned char>
int nCLen = nLen + AES_BLOCK_SIZE, nFLen = 0;
vchCiphertext = std::vector<unsigned char> (nCLen);
- EVP_CIPHER_CTX ctx;
+ EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();
+
+ if (!ctx) return false;
bool fOk = true;
- EVP_CIPHER_CTX_init(&ctx);
- if (fOk) fOk = EVP_EncryptInit_ex(&ctx, EVP_aes_256_cbc(), NULL, chKey, chIV) != 0;
- if (fOk) fOk = EVP_EncryptUpdate(&ctx, &vchCiphertext[0], &nCLen, &vchPlaintext[0], nLen) != 0;
- if (fOk) fOk = EVP_EncryptFinal_ex(&ctx, (&vchCiphertext[0]) + nCLen, &nFLen) != 0;
- EVP_CIPHER_CTX_cleanup(&ctx);
+ EVP_CIPHER_CTX_init(ctx);
+ if (fOk) fOk = EVP_EncryptInit_ex(ctx, EVP_aes_256_cbc(), NULL, chKey, chIV) != 0;
+ if (fOk) fOk = EVP_EncryptUpdate(ctx, &vchCiphertext[0], &nCLen, &vchPlaintext[0], nLen) != 0;
+ if (fOk) fOk = EVP_EncryptFinal_ex(ctx, (&vchCiphertext[0]) + nCLen, &nFLen) != 0;
+ EVP_CIPHER_CTX_cleanup(ctx);
+
+ EVP_CIPHER_CTX_free(ctx);
if (!fOk) return false;
@@ -66,15 +70,19 @@ bool OldDecrypt(const std::vector<unsigned char>& vchCiphertext, CKeyingMaterial
vchPlaintext = CKeyingMaterial(nPLen);
- EVP_CIPHER_CTX ctx;
+ EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();
+
+ if (!ctx) return false;
bool fOk = true;
- EVP_CIPHER_CTX_init(&ctx);
- if (fOk) fOk = EVP_DecryptInit_ex(&ctx, EVP_aes_256_cbc(), NULL, chKey, chIV) != 0;
- if (fOk) fOk = EVP_DecryptUpdate(&ctx, &vchPlaintext[0], &nPLen, &vchCiphertext[0], nLen) != 0;
- if (fOk) fOk = EVP_DecryptFinal_ex(&ctx, (&vchPlaintext[0]) + nPLen, &nFLen) != 0;
- EVP_CIPHER_CTX_cleanup(&ctx);
+ EVP_CIPHER_CTX_init(ctx);
+ if (fOk) fOk = EVP_DecryptInit_ex(ctx, EVP_aes_256_cbc(), NULL, chKey, chIV) != 0;
+ if (fOk) fOk = EVP_DecryptUpdate(ctx, &vchPlaintext[0], &nPLen, &vchCiphertext[0], nLen) != 0;
+ if (fOk) fOk = EVP_DecryptFinal_ex(ctx, (&vchPlaintext[0]) + nPLen, &nFLen) != 0;
+ EVP_CIPHER_CTX_cleanup(ctx);
+
+ EVP_CIPHER_CTX_free(ctx);
if (!fOk) return false;
diff --git a/src/wallet/test/wallet_tests.cpp b/src/wallet/test/wallet_tests.cpp
index acf980c784..9465d88067 100644
--- a/src/wallet/test/wallet_tests.cpp
+++ b/src/wallet/test/wallet_tests.cpp
@@ -42,7 +42,7 @@ static void add_coin(const CAmount& nValue, int nAge = 6*24, bool fIsFromMe = fa
// so stop vin being empty, and cache a non-zero Debit to fake out IsFromMe()
tx.vin.resize(1);
}
- CWalletTx* wtx = new CWalletTx(&wallet, tx);
+ CWalletTx* wtx = new CWalletTx(&wallet, MakeTransactionRef(std::move(tx)));
if (fIsFromMe)
{
wtx->fDebitCached = true;
@@ -78,24 +78,24 @@ BOOST_AUTO_TEST_CASE(coin_selection_tests)
empty_wallet();
// with an empty wallet we can't even pay one cent
- BOOST_CHECK(!wallet.SelectCoinsMinConf( 1 * CENT, 1, 6, vCoins, setCoinsRet, nValueRet));
+ BOOST_CHECK(!wallet.SelectCoinsMinConf( 1 * CENT, 1, 6, 0, vCoins, setCoinsRet, nValueRet));
add_coin(1*CENT, 4); // add a new 1 cent coin
// with a new 1 cent coin, we still can't find a mature 1 cent
- BOOST_CHECK(!wallet.SelectCoinsMinConf( 1 * CENT, 1, 6, vCoins, setCoinsRet, nValueRet));
+ BOOST_CHECK(!wallet.SelectCoinsMinConf( 1 * CENT, 1, 6, 0, vCoins, setCoinsRet, nValueRet));
// but we can find a new 1 cent
- BOOST_CHECK( wallet.SelectCoinsMinConf( 1 * CENT, 1, 1, vCoins, setCoinsRet, nValueRet));
+ BOOST_CHECK( wallet.SelectCoinsMinConf( 1 * CENT, 1, 1, 0, vCoins, setCoinsRet, nValueRet));
BOOST_CHECK_EQUAL(nValueRet, 1 * CENT);
add_coin(2*CENT); // add a mature 2 cent coin
// we can't make 3 cents of mature coins
- BOOST_CHECK(!wallet.SelectCoinsMinConf( 3 * CENT, 1, 6, vCoins, setCoinsRet, nValueRet));
+ BOOST_CHECK(!wallet.SelectCoinsMinConf( 3 * CENT, 1, 6, 0, vCoins, setCoinsRet, nValueRet));
// we can make 3 cents of new coins
- BOOST_CHECK( wallet.SelectCoinsMinConf( 3 * CENT, 1, 1, vCoins, setCoinsRet, nValueRet));
+ BOOST_CHECK( wallet.SelectCoinsMinConf( 3 * CENT, 1, 1, 0, vCoins, setCoinsRet, nValueRet));
BOOST_CHECK_EQUAL(nValueRet, 3 * CENT);
add_coin(5*CENT); // add a mature 5 cent coin,
@@ -105,33 +105,33 @@ BOOST_AUTO_TEST_CASE(coin_selection_tests)
// now we have new: 1+10=11 (of which 10 was self-sent), and mature: 2+5+20=27. total = 38
// we can't make 38 cents only if we disallow new coins:
- BOOST_CHECK(!wallet.SelectCoinsMinConf(38 * CENT, 1, 6, vCoins, setCoinsRet, nValueRet));
+ BOOST_CHECK(!wallet.SelectCoinsMinConf(38 * CENT, 1, 6, 0, vCoins, setCoinsRet, nValueRet));
// we can't even make 37 cents if we don't allow new coins even if they're from us
- BOOST_CHECK(!wallet.SelectCoinsMinConf(38 * CENT, 6, 6, vCoins, setCoinsRet, nValueRet));
+ BOOST_CHECK(!wallet.SelectCoinsMinConf(38 * CENT, 6, 6, 0, vCoins, setCoinsRet, nValueRet));
// but we can make 37 cents if we accept new coins from ourself
- BOOST_CHECK( wallet.SelectCoinsMinConf(37 * CENT, 1, 6, vCoins, setCoinsRet, nValueRet));
+ BOOST_CHECK( wallet.SelectCoinsMinConf(37 * CENT, 1, 6, 0, vCoins, setCoinsRet, nValueRet));
BOOST_CHECK_EQUAL(nValueRet, 37 * CENT);
// and we can make 38 cents if we accept all new coins
- BOOST_CHECK( wallet.SelectCoinsMinConf(38 * CENT, 1, 1, vCoins, setCoinsRet, nValueRet));
+ BOOST_CHECK( wallet.SelectCoinsMinConf(38 * CENT, 1, 1, 0, vCoins, setCoinsRet, nValueRet));
BOOST_CHECK_EQUAL(nValueRet, 38 * CENT);
// try making 34 cents from 1,2,5,10,20 - we can't do it exactly
- BOOST_CHECK( wallet.SelectCoinsMinConf(34 * CENT, 1, 1, vCoins, setCoinsRet, nValueRet));
+ BOOST_CHECK( wallet.SelectCoinsMinConf(34 * CENT, 1, 1, 0, vCoins, setCoinsRet, nValueRet));
BOOST_CHECK_EQUAL(nValueRet, 35 * CENT); // but 35 cents is closest
BOOST_CHECK_EQUAL(setCoinsRet.size(), 3U); // the best should be 20+10+5. it's incredibly unlikely the 1 or 2 got included (but possible)
// when we try making 7 cents, the smaller coins (1,2,5) are enough. We should see just 2+5
- BOOST_CHECK( wallet.SelectCoinsMinConf( 7 * CENT, 1, 1, vCoins, setCoinsRet, nValueRet));
+ BOOST_CHECK( wallet.SelectCoinsMinConf( 7 * CENT, 1, 1, 0, vCoins, setCoinsRet, nValueRet));
BOOST_CHECK_EQUAL(nValueRet, 7 * CENT);
BOOST_CHECK_EQUAL(setCoinsRet.size(), 2U);
// when we try making 8 cents, the smaller coins (1,2,5) are exactly enough.
- BOOST_CHECK( wallet.SelectCoinsMinConf( 8 * CENT, 1, 1, vCoins, setCoinsRet, nValueRet));
+ BOOST_CHECK( wallet.SelectCoinsMinConf( 8 * CENT, 1, 1, 0, vCoins, setCoinsRet, nValueRet));
BOOST_CHECK(nValueRet == 8 * CENT);
BOOST_CHECK_EQUAL(setCoinsRet.size(), 3U);
// when we try making 9 cents, no subset of smaller coins is enough, and we get the next bigger coin (10)
- BOOST_CHECK( wallet.SelectCoinsMinConf( 9 * CENT, 1, 1, vCoins, setCoinsRet, nValueRet));
+ BOOST_CHECK( wallet.SelectCoinsMinConf( 9 * CENT, 1, 1, 0, vCoins, setCoinsRet, nValueRet));
BOOST_CHECK_EQUAL(nValueRet, 10 * CENT);
BOOST_CHECK_EQUAL(setCoinsRet.size(), 1U);
@@ -145,30 +145,30 @@ BOOST_AUTO_TEST_CASE(coin_selection_tests)
add_coin(30*CENT); // now we have 6+7+8+20+30 = 71 cents total
// check that we have 71 and not 72
- BOOST_CHECK( wallet.SelectCoinsMinConf(71 * CENT, 1, 1, vCoins, setCoinsRet, nValueRet));
- BOOST_CHECK(!wallet.SelectCoinsMinConf(72 * CENT, 1, 1, vCoins, setCoinsRet, nValueRet));
+ BOOST_CHECK( wallet.SelectCoinsMinConf(71 * CENT, 1, 1, 0, vCoins, setCoinsRet, nValueRet));
+ BOOST_CHECK(!wallet.SelectCoinsMinConf(72 * CENT, 1, 1, 0, vCoins, setCoinsRet, nValueRet));
// now try making 16 cents. the best smaller coins can do is 6+7+8 = 21; not as good at the next biggest coin, 20
- BOOST_CHECK( wallet.SelectCoinsMinConf(16 * CENT, 1, 1, vCoins, setCoinsRet, nValueRet));
+ BOOST_CHECK( wallet.SelectCoinsMinConf(16 * CENT, 1, 1, 0, vCoins, setCoinsRet, nValueRet));
BOOST_CHECK_EQUAL(nValueRet, 20 * CENT); // we should get 20 in one coin
BOOST_CHECK_EQUAL(setCoinsRet.size(), 1U);
add_coin( 5*CENT); // now we have 5+6+7+8+20+30 = 75 cents total
// now if we try making 16 cents again, the smaller coins can make 5+6+7 = 18 cents, better than the next biggest coin, 20
- BOOST_CHECK( wallet.SelectCoinsMinConf(16 * CENT, 1, 1, vCoins, setCoinsRet, nValueRet));
+ BOOST_CHECK( wallet.SelectCoinsMinConf(16 * CENT, 1, 1, 0, vCoins, setCoinsRet, nValueRet));
BOOST_CHECK_EQUAL(nValueRet, 18 * CENT); // we should get 18 in 3 coins
BOOST_CHECK_EQUAL(setCoinsRet.size(), 3U);
add_coin( 18*CENT); // now we have 5+6+7+8+18+20+30
// and now if we try making 16 cents again, the smaller coins can make 5+6+7 = 18 cents, the same as the next biggest coin, 18
- BOOST_CHECK( wallet.SelectCoinsMinConf(16 * CENT, 1, 1, vCoins, setCoinsRet, nValueRet));
+ BOOST_CHECK( wallet.SelectCoinsMinConf(16 * CENT, 1, 1, 0, vCoins, setCoinsRet, nValueRet));
BOOST_CHECK_EQUAL(nValueRet, 18 * CENT); // we should get 18 in 1 coin
BOOST_CHECK_EQUAL(setCoinsRet.size(), 1U); // because in the event of a tie, the biggest coin wins
// now try making 11 cents. we should get 5+6
- BOOST_CHECK( wallet.SelectCoinsMinConf(11 * CENT, 1, 1, vCoins, setCoinsRet, nValueRet));
+ BOOST_CHECK( wallet.SelectCoinsMinConf(11 * CENT, 1, 1, 0, vCoins, setCoinsRet, nValueRet));
BOOST_CHECK_EQUAL(nValueRet, 11 * CENT);
BOOST_CHECK_EQUAL(setCoinsRet.size(), 2U);
@@ -177,11 +177,11 @@ BOOST_AUTO_TEST_CASE(coin_selection_tests)
add_coin( 2*COIN);
add_coin( 3*COIN);
add_coin( 4*COIN); // now we have 5+6+7+8+18+20+30+100+200+300+400 = 1094 cents
- BOOST_CHECK( wallet.SelectCoinsMinConf(95 * CENT, 1, 1, vCoins, setCoinsRet, nValueRet));
+ BOOST_CHECK( wallet.SelectCoinsMinConf(95 * CENT, 1, 1, 0, vCoins, setCoinsRet, nValueRet));
BOOST_CHECK_EQUAL(nValueRet, 1 * COIN); // we should get 1 BTC in 1 coin
BOOST_CHECK_EQUAL(setCoinsRet.size(), 1U);
- BOOST_CHECK( wallet.SelectCoinsMinConf(195 * CENT, 1, 1, vCoins, setCoinsRet, nValueRet));
+ BOOST_CHECK( wallet.SelectCoinsMinConf(195 * CENT, 1, 1, 0, vCoins, setCoinsRet, nValueRet));
BOOST_CHECK_EQUAL(nValueRet, 2 * COIN); // we should get 2 BTC in 1 coin
BOOST_CHECK_EQUAL(setCoinsRet.size(), 1U);
@@ -196,14 +196,14 @@ BOOST_AUTO_TEST_CASE(coin_selection_tests)
// try making 1 * MIN_CHANGE from the 1.5 * MIN_CHANGE
// we'll get change smaller than MIN_CHANGE whatever happens, so can expect MIN_CHANGE exactly
- BOOST_CHECK( wallet.SelectCoinsMinConf(MIN_CHANGE, 1, 1, vCoins, setCoinsRet, nValueRet));
+ BOOST_CHECK( wallet.SelectCoinsMinConf(MIN_CHANGE, 1, 1, 0, vCoins, setCoinsRet, nValueRet));
BOOST_CHECK_EQUAL(nValueRet, MIN_CHANGE);
// but if we add a bigger coin, small change is avoided
add_coin(1111*MIN_CHANGE);
// try making 1 from 0.1 + 0.2 + 0.3 + 0.4 + 0.5 + 1111 = 1112.5
- BOOST_CHECK( wallet.SelectCoinsMinConf(1 * MIN_CHANGE, 1, 1, vCoins, setCoinsRet, nValueRet));
+ BOOST_CHECK( wallet.SelectCoinsMinConf(1 * MIN_CHANGE, 1, 1, 0, vCoins, setCoinsRet, nValueRet));
BOOST_CHECK_EQUAL(nValueRet, 1 * MIN_CHANGE); // we should get the exact amount
// if we add more small coins:
@@ -211,7 +211,7 @@ BOOST_AUTO_TEST_CASE(coin_selection_tests)
add_coin(MIN_CHANGE * 7 / 10);
// and try again to make 1.0 * MIN_CHANGE
- BOOST_CHECK( wallet.SelectCoinsMinConf(1 * MIN_CHANGE, 1, 1, vCoins, setCoinsRet, nValueRet));
+ BOOST_CHECK( wallet.SelectCoinsMinConf(1 * MIN_CHANGE, 1, 1, 0, vCoins, setCoinsRet, nValueRet));
BOOST_CHECK_EQUAL(nValueRet, 1 * MIN_CHANGE); // we should get the exact amount
// run the 'mtgox' test (see http://blockexplorer.com/tx/29a3efd3ef04f9153d47a990bd7b048a4b2d213daaa5fb8ed670fb85f13bdbcf)
@@ -220,7 +220,7 @@ BOOST_AUTO_TEST_CASE(coin_selection_tests)
for (int j = 0; j < 20; j++)
add_coin(50000 * COIN);
- BOOST_CHECK( wallet.SelectCoinsMinConf(500000 * COIN, 1, 1, vCoins, setCoinsRet, nValueRet));
+ BOOST_CHECK( wallet.SelectCoinsMinConf(500000 * COIN, 1, 1, 0, vCoins, setCoinsRet, nValueRet));
BOOST_CHECK_EQUAL(nValueRet, 500000 * COIN); // we should get the exact amount
BOOST_CHECK_EQUAL(setCoinsRet.size(), 10U); // in ten coins
@@ -233,7 +233,7 @@ BOOST_AUTO_TEST_CASE(coin_selection_tests)
add_coin(MIN_CHANGE * 6 / 10);
add_coin(MIN_CHANGE * 7 / 10);
add_coin(1111 * MIN_CHANGE);
- BOOST_CHECK( wallet.SelectCoinsMinConf(1 * MIN_CHANGE, 1, 1, vCoins, setCoinsRet, nValueRet));
+ BOOST_CHECK( wallet.SelectCoinsMinConf(1 * MIN_CHANGE, 1, 1, 0, vCoins, setCoinsRet, nValueRet));
BOOST_CHECK_EQUAL(nValueRet, 1111 * MIN_CHANGE); // we get the bigger coin
BOOST_CHECK_EQUAL(setCoinsRet.size(), 1U);
@@ -243,7 +243,7 @@ BOOST_AUTO_TEST_CASE(coin_selection_tests)
add_coin(MIN_CHANGE * 6 / 10);
add_coin(MIN_CHANGE * 8 / 10);
add_coin(1111 * MIN_CHANGE);
- BOOST_CHECK( wallet.SelectCoinsMinConf(MIN_CHANGE, 1, 1, vCoins, setCoinsRet, nValueRet));
+ BOOST_CHECK( wallet.SelectCoinsMinConf(MIN_CHANGE, 1, 1, 0, vCoins, setCoinsRet, nValueRet));
BOOST_CHECK_EQUAL(nValueRet, MIN_CHANGE); // we should get the exact amount
BOOST_CHECK_EQUAL(setCoinsRet.size(), 2U); // in two coins 0.4+0.6
@@ -254,22 +254,22 @@ BOOST_AUTO_TEST_CASE(coin_selection_tests)
add_coin(MIN_CHANGE * 100);
// trying to make 100.01 from these three coins
- BOOST_CHECK(wallet.SelectCoinsMinConf(MIN_CHANGE * 10001 / 100, 1, 1, vCoins, setCoinsRet, nValueRet));
+ BOOST_CHECK(wallet.SelectCoinsMinConf(MIN_CHANGE * 10001 / 100, 1, 1, 0, vCoins, setCoinsRet, nValueRet));
BOOST_CHECK_EQUAL(nValueRet, MIN_CHANGE * 10105 / 100); // we should get all coins
BOOST_CHECK_EQUAL(setCoinsRet.size(), 3U);
// but if we try to make 99.9, we should take the bigger of the two small coins to avoid small change
- BOOST_CHECK(wallet.SelectCoinsMinConf(MIN_CHANGE * 9990 / 100, 1, 1, vCoins, setCoinsRet, nValueRet));
+ BOOST_CHECK(wallet.SelectCoinsMinConf(MIN_CHANGE * 9990 / 100, 1, 1, 0, vCoins, setCoinsRet, nValueRet));
BOOST_CHECK_EQUAL(nValueRet, 101 * MIN_CHANGE);
BOOST_CHECK_EQUAL(setCoinsRet.size(), 2U);
// test with many inputs
for (CAmount amt=1500; amt < COIN; amt*=10) {
empty_wallet();
- // Create 676 inputs (= MAX_STANDARD_TX_SIZE / 148 bytes per input)
+ // Create 676 inputs (= (old MAX_STANDARD_TX_SIZE == 100000) / 148 bytes per input)
for (uint16_t j = 0; j < 676; j++)
add_coin(amt);
- BOOST_CHECK(wallet.SelectCoinsMinConf(2000, 1, 1, vCoins, setCoinsRet, nValueRet));
+ BOOST_CHECK(wallet.SelectCoinsMinConf(2000, 1, 1, 0, vCoins, setCoinsRet, nValueRet));
if (amt - 2000 < MIN_CHANGE) {
// needs more than one input:
uint16_t returnSize = std::ceil((2000.0 + MIN_CHANGE)/amt);
@@ -291,8 +291,8 @@ BOOST_AUTO_TEST_CASE(coin_selection_tests)
// picking 50 from 100 coins doesn't depend on the shuffle,
// but does depend on randomness in the stochastic approximation code
- BOOST_CHECK(wallet.SelectCoinsMinConf(50 * COIN, 1, 6, vCoins, setCoinsRet , nValueRet));
- BOOST_CHECK(wallet.SelectCoinsMinConf(50 * COIN, 1, 6, vCoins, setCoinsRet2, nValueRet));
+ BOOST_CHECK(wallet.SelectCoinsMinConf(50 * COIN, 1, 6, 0, vCoins, setCoinsRet , nValueRet));
+ BOOST_CHECK(wallet.SelectCoinsMinConf(50 * COIN, 1, 6, 0, vCoins, setCoinsRet2, nValueRet));
BOOST_CHECK(!equal_sets(setCoinsRet, setCoinsRet2));
int fails = 0;
@@ -300,8 +300,8 @@ BOOST_AUTO_TEST_CASE(coin_selection_tests)
{
// selecting 1 from 100 identical coins depends on the shuffle; this test will fail 1% of the time
// run the test RANDOM_REPEATS times and only complain if all of them fail
- BOOST_CHECK(wallet.SelectCoinsMinConf(COIN, 1, 6, vCoins, setCoinsRet , nValueRet));
- BOOST_CHECK(wallet.SelectCoinsMinConf(COIN, 1, 6, vCoins, setCoinsRet2, nValueRet));
+ BOOST_CHECK(wallet.SelectCoinsMinConf(COIN, 1, 6, 0, vCoins, setCoinsRet , nValueRet));
+ BOOST_CHECK(wallet.SelectCoinsMinConf(COIN, 1, 6, 0, vCoins, setCoinsRet2, nValueRet));
if (equal_sets(setCoinsRet, setCoinsRet2))
fails++;
}
@@ -321,8 +321,8 @@ BOOST_AUTO_TEST_CASE(coin_selection_tests)
{
// selecting 1 from 100 identical coins depends on the shuffle; this test will fail 1% of the time
// run the test RANDOM_REPEATS times and only complain if all of them fail
- BOOST_CHECK(wallet.SelectCoinsMinConf(90*CENT, 1, 6, vCoins, setCoinsRet , nValueRet));
- BOOST_CHECK(wallet.SelectCoinsMinConf(90*CENT, 1, 6, vCoins, setCoinsRet2, nValueRet));
+ BOOST_CHECK(wallet.SelectCoinsMinConf(90*CENT, 1, 6, 0, vCoins, setCoinsRet , nValueRet));
+ BOOST_CHECK(wallet.SelectCoinsMinConf(90*CENT, 1, 6, 0, vCoins, setCoinsRet2, nValueRet));
if (equal_sets(setCoinsRet, setCoinsRet2))
fails++;
}
@@ -346,7 +346,7 @@ BOOST_AUTO_TEST_CASE(ApproximateBestSubset)
add_coin(1000 * COIN);
add_coin(3 * COIN);
- BOOST_CHECK(wallet.SelectCoinsMinConf(1003 * COIN, 1, 6, vCoins, setCoinsRet, nValueRet));
+ BOOST_CHECK(wallet.SelectCoinsMinConf(1003 * COIN, 1, 6, 0, vCoins, setCoinsRet, nValueRet));
BOOST_CHECK_EQUAL(nValueRet, 1003 * COIN);
BOOST_CHECK_EQUAL(setCoinsRet.size(), 2U);
}
diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp
index f88da978d4..c25e8be13c 100644
--- a/src/wallet/wallet.cpp
+++ b/src/wallet/wallet.cpp
@@ -13,7 +13,7 @@
#include "consensus/validation.h"
#include "key.h"
#include "keystore.h"
-#include "main.h"
+#include "validation.h"
#include "net.h"
#include "policy/policy.h"
#include "primitives/block.h"
@@ -75,7 +75,7 @@ struct CompareValueOnly
std::string COutput::ToString() const
{
- return strprintf("COutput(%s, %d, %d) [%s]", tx->GetHash().ToString(), i, nDepth, FormatMoney(tx->vout[i].nValue));
+ return strprintf("COutput(%s, %d, %d) [%s]", tx->GetHash().ToString(), i, nDepth, FormatMoney(tx->tx->vout[i].nValue));
}
const CWalletTx* CWallet::GetWalletTx(const uint256& hash) const
@@ -400,7 +400,7 @@ set<uint256> CWallet::GetConflicts(const uint256& txid) const
std::pair<TxSpends::const_iterator, TxSpends::const_iterator> range;
- BOOST_FOREACH(const CTxIn& txin, wtx.vin)
+ BOOST_FOREACH(const CTxIn& txin, wtx.tx->vin)
{
if (mapTxSpends.count(txin.prevout) <= 1)
continue; // No conflict if zero or one spends
@@ -552,7 +552,7 @@ void CWallet::AddToSpends(const uint256& wtxid)
if (thisTx.IsCoinBase()) // Coinbases don't spend anything!
return;
- BOOST_FOREACH(const CTxIn& txin, thisTx.vin)
+ BOOST_FOREACH(const CTxIn& txin, thisTx.tx->vin)
AddToSpends(txin.prevout, wtxid);
}
@@ -795,7 +795,7 @@ bool CWallet::GetAccountPubkey(CPubKey &pubKey, std::string strAccount, bool bFo
for (map<uint256, CWalletTx>::iterator it = mapWallet.begin();
it != mapWallet.end() && account.vchPubKey.IsValid();
++it)
- BOOST_FOREACH(const CTxOut& txout, (*it).second.vout)
+ BOOST_FOREACH(const CTxOut& txout, (*it).second.tx->vout)
if (txout.scriptPubKey == scriptPubKey) {
bForceNew = true;
break;
@@ -954,7 +954,7 @@ bool CWallet::LoadToWallet(const CWalletTx& wtxIn)
wtx.BindWallet(this);
wtxOrdered.insert(make_pair(wtx.nOrderPos, TxPair(&wtx, (CAccountingEntry*)0)));
AddToSpends(hash);
- BOOST_FOREACH(const CTxIn& txin, wtx.vin) {
+ BOOST_FOREACH(const CTxIn& txin, wtx.tx->vin) {
if (mapWallet.count(txin.prevout.hash)) {
CWalletTx& prevtx = mapWallet[txin.prevout.hash];
if (prevtx.nIndex == -1 && !prevtx.hashUnset()) {
@@ -993,7 +993,7 @@ bool CWallet::AddToWalletIfInvolvingMe(const CTransaction& tx, const CBlockIndex
if (fExisted && !fUpdate) return false;
if (fExisted || IsMine(tx) || IsFromMe(tx))
{
- CWalletTx wtx(this,tx);
+ CWalletTx wtx(this, MakeTransactionRef(tx));
// Get merkle branch if transaction was found in a block
if (posInBlock != -1)
@@ -1009,8 +1009,7 @@ 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);
+ CWalletDB walletdb(strWalletFile, "r+");
std::set<uint256> todo;
std::set<uint256> done;
@@ -1052,7 +1051,7 @@ bool CWallet::AbandonTransaction(const uint256& hashTx)
}
// 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)
+ BOOST_FOREACH(const CTxIn& txin, wtx.tx->vin)
{
if (mapWallet.count(txin.prevout.hash))
mapWallet[txin.prevout.hash].MarkDirty();
@@ -1113,7 +1112,7 @@ void CWallet::MarkConflicted(const uint256& hashBlock, const uint256& hashTx)
}
// 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)
+ BOOST_FOREACH(const CTxIn& txin, wtx.tx->vin)
{
if (mapWallet.count(txin.prevout.hash))
mapWallet[txin.prevout.hash].MarkDirty();
@@ -1148,8 +1147,8 @@ isminetype CWallet::IsMine(const CTxIn &txin) const
if (mi != mapWallet.end())
{
const CWalletTx& prev = (*mi).second;
- if (txin.prevout.n < prev.vout.size())
- return IsMine(prev.vout[txin.prevout.n]);
+ if (txin.prevout.n < prev.tx->vout.size())
+ return IsMine(prev.tx->vout[txin.prevout.n]);
}
}
return ISMINE_NO;
@@ -1163,9 +1162,9 @@ CAmount CWallet::GetDebit(const CTxIn &txin, const isminefilter& filter) const
if (mi != mapWallet.end())
{
const CWalletTx& prev = (*mi).second;
- if (txin.prevout.n < prev.vout.size())
- if (IsMine(prev.vout[txin.prevout.n]) & filter)
- return prev.vout[txin.prevout.n].nValue;
+ if (txin.prevout.n < prev.tx->vout.size())
+ if (IsMine(prev.tx->vout[txin.prevout.n]) & filter)
+ return prev.tx->vout[txin.prevout.n].nValue;
}
}
return 0;
@@ -1380,14 +1379,14 @@ void CWalletTx::GetAmounts(list<COutputEntry>& listReceived,
CAmount nDebit = GetDebit(filter);
if (nDebit > 0) // debit>0 means we signed/sent this transaction
{
- CAmount nValueOut = GetValueOut();
+ CAmount nValueOut = tx->GetValueOut();
nFee = nDebit - nValueOut;
}
// Sent/received.
- for (unsigned int i = 0; i < vout.size(); ++i)
+ for (unsigned int i = 0; i < tx->vout.size(); ++i)
{
- const CTxOut& txout = vout[i];
+ const CTxOut& txout = tx->vout[i];
isminetype fIsMine = pwallet->IsMine(txout);
// Only need to handle txouts if AT LEAST one of these is true:
// 1) they debit from us (sent)
@@ -1492,7 +1491,7 @@ int CWallet::ScanForWalletTransactions(CBlockIndex* pindexStart, bool fUpdate)
int posInBlock;
for (posInBlock = 0; posInBlock < (int)block.vtx.size(); posInBlock++)
{
- if (AddToWalletIfInvolvingMe(block.vtx[posInBlock], pindex, posInBlock, fUpdate))
+ if (AddToWalletIfInvolvingMe(*block.vtx[posInBlock], pindex, posInBlock, fUpdate))
ret++;
}
pindex = chainActive.Next(pindex);
@@ -1542,9 +1541,11 @@ void CWallet::ReacceptWalletTransactions()
bool CWalletTx::RelayWalletTransaction(CConnman* connman)
{
assert(pwallet->GetBroadcastTransactions());
- if (!IsCoinBase())
+ if (!IsCoinBase() && !isAbandoned() && GetDepthInMainChain() == 0)
{
- if (GetDepthInMainChain() == 0 && !isAbandoned() && InMempool()) {
+ CValidationState state;
+ /* GetDepthInMainChain already catches known conflicts. */
+ if (InMempool() || AcceptToMemoryPool(maxTxFee, state)) {
LogPrintf("Relaying wtx %s\n", GetHash().ToString());
if (connman) {
CInv inv(MSG_TX, GetHash());
@@ -1573,7 +1574,7 @@ set<uint256> CWalletTx::GetConflicts() const
CAmount CWalletTx::GetDebit(const isminefilter& filter) const
{
- if (vin.empty())
+ if (tx->vin.empty())
return 0;
CAmount debit = 0;
@@ -1608,7 +1609,7 @@ CAmount CWalletTx::GetCredit(const isminefilter& filter) const
if (IsCoinBase() && GetBlocksToMaturity() > 0)
return 0;
- int64_t credit = 0;
+ CAmount credit = 0;
if (filter & ISMINE_SPENDABLE)
{
// GetBalance can assume transactions in mapWallet won't change
@@ -1663,11 +1664,11 @@ CAmount CWalletTx::GetAvailableCredit(bool fUseCache) const
CAmount nCredit = 0;
uint256 hashTx = GetHash();
- for (unsigned int i = 0; i < vout.size(); i++)
+ for (unsigned int i = 0; i < tx->vout.size(); i++)
{
if (!pwallet->IsSpent(hashTx, i))
{
- const CTxOut &txout = vout[i];
+ const CTxOut &txout = tx->vout[i];
nCredit += pwallet->GetCredit(txout, ISMINE_SPENDABLE);
if (!MoneyRange(nCredit))
throw std::runtime_error("CWalletTx::GetAvailableCredit() : value out of range");
@@ -1706,11 +1707,11 @@ CAmount CWalletTx::GetAvailableWatchOnlyCredit(const bool& fUseCache) const
return nAvailableWatchCreditCached;
CAmount nCredit = 0;
- for (unsigned int i = 0; i < vout.size(); i++)
+ for (unsigned int i = 0; i < tx->vout.size(); i++)
{
if (!pwallet->IsSpent(GetHash(), i))
{
- const CTxOut &txout = vout[i];
+ const CTxOut &txout = tx->vout[i];
nCredit += pwallet->GetCredit(txout, ISMINE_WATCH_ONLY);
if (!MoneyRange(nCredit))
throw std::runtime_error("CWalletTx::GetAvailableCredit() : value out of range");
@@ -1758,23 +1759,23 @@ bool CWalletTx::IsTrusted() const
return false;
// Trusted if all inputs are from us and are in the mempool:
- BOOST_FOREACH(const CTxIn& txin, vin)
+ BOOST_FOREACH(const CTxIn& txin, tx->vin)
{
// Transactions not sent by us: not trusted
const CWalletTx* parent = pwallet->GetWalletTx(txin.prevout.hash);
if (parent == NULL)
return false;
- const CTxOut& parentOut = parent->vout[txin.prevout.n];
+ const CTxOut& parentOut = parent->tx->vout[txin.prevout.n];
if (pwallet->IsMine(parentOut) != ISMINE_SPENDABLE)
return false;
}
return true;
}
-bool CWalletTx::IsEquivalentTo(const CWalletTx& tx) const
+bool CWalletTx::IsEquivalentTo(const CWalletTx& _tx) const
{
- CMutableTransaction tx1 = *this;
- CMutableTransaction tx2 = tx;
+ CMutableTransaction tx1 = *this->tx;
+ CMutableTransaction tx2 = *_tx.tx;
for (unsigned int i = 0; i < tx1.vin.size(); i++) tx1.vin[i].scriptSig = CScript();
for (unsigned int i = 0; i < tx2.vin.size(); i++) tx2.vin[i].scriptSig = CScript();
return CTransaction(tx1) == CTransaction(tx2);
@@ -1957,10 +1958,10 @@ void CWallet::AvailableCoins(vector<COutput>& vCoins, bool fOnlyConfirmed, const
if (nDepth == 0 && !pcoin->InMempool())
continue;
- for (unsigned int i = 0; i < pcoin->vout.size(); i++) {
- isminetype mine = IsMine(pcoin->vout[i]);
+ for (unsigned int i = 0; i < pcoin->tx->vout.size(); i++) {
+ isminetype mine = IsMine(pcoin->tx->vout[i]);
if (!(IsSpent(wtxid, i)) && mine != ISMINE_NO &&
- !IsLockedCoin((*it).first, i) && (pcoin->vout[i].nValue > 0 || fIncludeZeroValue) &&
+ !IsLockedCoin((*it).first, i) && (pcoin->tx->vout[i].nValue > 0 || fIncludeZeroValue) &&
(!coinControl || !coinControl->HasSelected() || coinControl->fAllowOtherInputs || coinControl->IsSelected(COutPoint((*it).first, i))))
vCoins.push_back(COutput(pcoin, i, nDepth,
((mine & ISMINE_SPENDABLE) != ISMINE_NO) ||
@@ -2017,7 +2018,7 @@ static void ApproximateBestSubset(vector<pair<CAmount, pair<const CWalletTx*,uns
}
}
-bool CWallet::SelectCoinsMinConf(const CAmount& nTargetValue, int nConfMine, int nConfTheirs, vector<COutput> vCoins,
+bool CWallet::SelectCoinsMinConf(const CAmount& nTargetValue, const int nConfMine, const int nConfTheirs, const uint64_t nMaxAncestors, vector<COutput> vCoins,
set<pair<const CWalletTx*,unsigned int> >& setCoinsRet, CAmount& nValueRet) const
{
setCoinsRet.clear();
@@ -2042,8 +2043,11 @@ bool CWallet::SelectCoinsMinConf(const CAmount& nTargetValue, int nConfMine, int
if (output.nDepth < (pcoin->IsFromMe(ISMINE_ALL) ? nConfMine : nConfTheirs))
continue;
+ if (!mempool.TransactionWithinChainLimit(pcoin->GetHash(), nMaxAncestors))
+ continue;
+
int i = output.i;
- CAmount n = pcoin->vout[i].nValue;
+ CAmount n = pcoin->tx->vout[i].nValue;
pair<CAmount,pair<const CWalletTx*,unsigned int> > coin = make_pair(n,make_pair(pcoin, i));
@@ -2130,7 +2134,7 @@ bool CWallet::SelectCoins(const vector<COutput>& vAvailableCoins, const CAmount&
{
if (!out.fSpendable)
continue;
- nValueRet += out.tx->vout[out.i].nValue;
+ nValueRet += out.tx->tx->vout[out.i].nValue;
setCoinsRet.insert(make_pair(out.tx, out.i));
}
return (nValueRet >= nTargetValue);
@@ -2150,9 +2154,9 @@ bool CWallet::SelectCoins(const vector<COutput>& vAvailableCoins, const CAmount&
{
const CWalletTx* pcoin = &it->second;
// Clearly invalid input, fail
- if (pcoin->vout.size() <= outpoint.n)
+ if (pcoin->tx->vout.size() <= outpoint.n)
return false;
- nValueFromPresetInputs += pcoin->vout[outpoint.n].nValue;
+ nValueFromPresetInputs += pcoin->tx->vout[outpoint.n].nValue;
setPresetCoins.insert(make_pair(pcoin, outpoint.n));
} else
return false; // TODO: Allow non-wallet inputs
@@ -2167,10 +2171,17 @@ bool CWallet::SelectCoins(const vector<COutput>& vAvailableCoins, const CAmount&
++it;
}
+ size_t nMaxChainLength = std::min(GetArg("-limitancestorcount", DEFAULT_ANCESTOR_LIMIT), GetArg("-limitdescendantcount", DEFAULT_DESCENDANT_LIMIT));
+ bool fRejectLongChains = GetBoolArg("-walletrejectlongchains", DEFAULT_WALLET_REJECT_LONG_CHAINS);
+
bool res = nTargetValue <= nValueFromPresetInputs ||
- SelectCoinsMinConf(nTargetValue - nValueFromPresetInputs, 1, 6, vCoins, setCoinsRet, nValueRet) ||
- SelectCoinsMinConf(nTargetValue - nValueFromPresetInputs, 1, 1, vCoins, setCoinsRet, nValueRet) ||
- (bSpendZeroConfChange && SelectCoinsMinConf(nTargetValue - nValueFromPresetInputs, 0, 1, vCoins, setCoinsRet, nValueRet));
+ SelectCoinsMinConf(nTargetValue - nValueFromPresetInputs, 1, 6, 0, vCoins, setCoinsRet, nValueRet) ||
+ SelectCoinsMinConf(nTargetValue - nValueFromPresetInputs, 1, 1, 0, vCoins, setCoinsRet, nValueRet) ||
+ (bSpendZeroConfChange && SelectCoinsMinConf(nTargetValue - nValueFromPresetInputs, 0, 1, 2, vCoins, setCoinsRet, nValueRet)) ||
+ (bSpendZeroConfChange && SelectCoinsMinConf(nTargetValue - nValueFromPresetInputs, 0, 1, std::min((size_t)4, nMaxChainLength/3), vCoins, setCoinsRet, nValueRet)) ||
+ (bSpendZeroConfChange && SelectCoinsMinConf(nTargetValue - nValueFromPresetInputs, 0, 1, nMaxChainLength/2, vCoins, setCoinsRet, nValueRet)) ||
+ (bSpendZeroConfChange && SelectCoinsMinConf(nTargetValue - nValueFromPresetInputs, 0, 1, nMaxChainLength, vCoins, setCoinsRet, nValueRet)) ||
+ (bSpendZeroConfChange && !fRejectLongChains && SelectCoinsMinConf(nTargetValue - nValueFromPresetInputs, 0, 1, std::numeric_limits<uint64_t>::max(), vCoins, setCoinsRet, nValueRet));
// because SelectCoinsMinConf clears the setCoinsRet, we now add the possible inputs to the coinset
setCoinsRet.insert(setPresetCoins.begin(), setPresetCoins.end());
@@ -2208,10 +2219,10 @@ bool CWallet::FundTransaction(CMutableTransaction& tx, CAmount& nFeeRet, bool ov
return false;
if (nChangePosInOut != -1)
- tx.vout.insert(tx.vout.begin() + nChangePosInOut, wtx.vout[nChangePosInOut]);
+ tx.vout.insert(tx.vout.begin() + nChangePosInOut, wtx.tx->vout[nChangePosInOut]);
// Add new txins (keeping original txin scriptSig/order)
- BOOST_FOREACH(const CTxIn& txin, wtx.vin)
+ BOOST_FOREACH(const CTxIn& txin, wtx.tx->vin)
{
if (!coinControl.IsSelected(txin.prevout))
{
@@ -2238,7 +2249,7 @@ bool CWallet::CreateTransaction(const vector<CRecipient>& vecSend, CWalletTx& wt
{
if (nValue < 0 || recipient.nAmount < 0)
{
- strFailReason = _("Transaction amounts must be positive");
+ strFailReason = _("Transaction amounts must not be negative");
return false;
}
nValue += recipient.nAmount;
@@ -2246,9 +2257,9 @@ bool CWallet::CreateTransaction(const vector<CRecipient>& vecSend, CWalletTx& wt
if (recipient.fSubtractFeeFromAmount)
nSubtractFeeFromAmount++;
}
- if (vecSend.empty() || nValue < 0)
+ if (vecSend.empty())
{
- strFailReason = _("Transaction amounts must be positive");
+ strFailReason = _("Transaction must have at least one recipient");
return false;
}
@@ -2301,7 +2312,6 @@ bool CWallet::CreateTransaction(const vector<CRecipient>& vecSend, CWalletTx& wt
nChangePosInOut = nChangePosRequest;
txNew.vin.clear();
txNew.vout.clear();
- txNew.wit.SetNull();
wtxNew.fFromMe = true;
bool fFirst = true;
@@ -2351,7 +2361,7 @@ bool CWallet::CreateTransaction(const vector<CRecipient>& vecSend, CWalletTx& wt
}
BOOST_FOREACH(PAIRTYPE(const CWalletTx*, unsigned int) pcoin, setCoins)
{
- CAmount nCredit = pcoin.first->vout[pcoin.second].nValue;
+ CAmount nCredit = pcoin.first->tx->vout[pcoin.second].nValue;
//The coin age after the next block (depth+1) is used instead of the current,
//reflecting an assumption the user would accept a bit more delay for
//a chance at a free transaction.
@@ -2389,7 +2399,11 @@ bool CWallet::CreateTransaction(const vector<CRecipient>& vecSend, CWalletTx& wt
CPubKey vchPubKey;
bool ret;
ret = reservekey.GetReservedKey(vchPubKey);
- assert(ret); // should never fail, as we just unlocked
+ if (!ret)
+ {
+ strFailReason = _("Keypool ran out, please call keypoolrefill first");
+ return false;
+ }
scriptChange = GetScriptForDestination(vchPubKey.GetID());
}
@@ -2466,10 +2480,10 @@ bool CWallet::CreateTransaction(const vector<CRecipient>& vecSend, CWalletTx& wt
BOOST_FOREACH(const PAIRTYPE(const CWalletTx*,unsigned int)& coin, setCoins)
{
bool signSuccess;
- const CScript& scriptPubKey = coin.first->vout[coin.second].scriptPubKey;
+ const CScript& scriptPubKey = coin.first->tx->vout[coin.second].scriptPubKey;
SignatureData sigdata;
if (sign)
- signSuccess = ProduceSignature(TransactionSignatureCreator(this, &txNewConst, nIn, coin.first->vout[coin.second].nValue, SIGHASH_ALL), scriptPubKey, sigdata);
+ signSuccess = ProduceSignature(TransactionSignatureCreator(this, &txNewConst, nIn, coin.first->tx->vout[coin.second].nValue, SIGHASH_ALL), scriptPubKey, sigdata);
else
signSuccess = ProduceSignature(DummySignatureCreator(this), scriptPubKey, sigdata);
@@ -2488,22 +2502,23 @@ bool CWallet::CreateTransaction(const vector<CRecipient>& vecSend, CWalletTx& wt
// Remove scriptSigs if we used dummy signatures for fee calculation
if (!sign) {
- BOOST_FOREACH (CTxIn& vin, txNew.vin)
+ BOOST_FOREACH (CTxIn& vin, txNew.vin) {
vin.scriptSig = CScript();
- txNew.wit.SetNull();
+ vin.scriptWitness.SetNull();
+ }
}
// Embed the constructed transaction data in wtxNew.
- *static_cast<CTransaction*>(&wtxNew) = CTransaction(txNew);
+ wtxNew.SetTx(MakeTransactionRef(std::move(txNew)));
// Limit size
- if (GetTransactionWeight(txNew) >= MAX_STANDARD_TX_WEIGHT)
+ if (GetTransactionWeight(wtxNew) >= MAX_STANDARD_TX_WEIGHT)
{
strFailReason = _("Transaction too large");
return false;
}
- dPriority = wtxNew.ComputePriority(dPriority, nBytes);
+ dPriority = wtxNew.tx->ComputePriority(dPriority, nBytes);
// Allow to override the default confirmation target over the CoinControl instance
int currentConfirmationTarget = nTxConfirmTarget;
@@ -2545,6 +2560,21 @@ bool CWallet::CreateTransaction(const vector<CRecipient>& vecSend, CWalletTx& wt
}
}
+ if (GetBoolArg("-walletrejectlongchains", DEFAULT_WALLET_REJECT_LONG_CHAINS)) {
+ // Lastly, ensure this tx will pass the mempool's chain limits
+ LockPoints lp;
+ CTxMemPoolEntry entry(txNew, 0, 0, 0, 0, false, 0, false, 0, lp);
+ CTxMemPool::setEntries setAncestors;
+ size_t nLimitAncestors = GetArg("-limitancestorcount", DEFAULT_ANCESTOR_LIMIT);
+ size_t nLimitAncestorSize = GetArg("-limitancestorsize", DEFAULT_ANCESTOR_SIZE_LIMIT)*1000;
+ size_t nLimitDescendants = GetArg("-limitdescendantcount", DEFAULT_DESCENDANT_LIMIT);
+ size_t nLimitDescendantSize = GetArg("-limitdescendantsize", DEFAULT_DESCENDANT_SIZE_LIMIT)*1000;
+ std::string errString;
+ if (!mempool.CalculateMemPoolAncestors(entry, setAncestors, nLimitAncestors, nLimitAncestorSize, nLimitDescendants, nLimitDescendantSize, errString)) {
+ strFailReason = _("Transaction has too long of a mempool chain");
+ return false;
+ }
+ }
return true;
}
@@ -2555,7 +2585,7 @@ bool CWallet::CommitTransaction(CWalletTx& wtxNew, CReserveKey& reservekey, CCon
{
{
LOCK2(cs_main, cs_wallet);
- LogPrintf("CommitTransaction:\n%s", wtxNew.ToString());
+ LogPrintf("CommitTransaction:\n%s", wtxNew.tx->ToString());
{
// Take key pair from key pool so it won't be used again
reservekey.KeepKey();
@@ -2565,7 +2595,7 @@ bool CWallet::CommitTransaction(CWalletTx& wtxNew, CReserveKey& reservekey, CCon
AddToWallet(wtxNew);
// Notify that old coins are spent
- BOOST_FOREACH(const CTxIn& txin, wtxNew.vin)
+ BOOST_FOREACH(const CTxIn& txin, wtxNew.tx->vin)
{
CWalletTx &coin = mapWallet[txin.prevout.hash];
coin.BindWallet(this);
@@ -2580,11 +2610,11 @@ bool CWallet::CommitTransaction(CWalletTx& wtxNew, CReserveKey& reservekey, CCon
{
// Broadcast
if (!wtxNew.AcceptToMemoryPool(maxTxFee, state)) {
- // This must not fail. The transaction has already been signed and recorded.
- LogPrintf("CommitTransaction(): Error: Transaction not valid, %s\n", state.GetRejectReason());
- return false;
+ LogPrintf("CommitTransaction(): Transaction cannot be broadcast immediately, %s\n", state.GetRejectReason());
+ // TODO: if we expect the failure to be long term or permanent, instead delete wtx from the wallet and return failure.
+ } else {
+ wtxNew.RelayWalletTransaction(connman);
}
- wtxNew.RelayWalletTransaction(connman);
}
}
return true;
@@ -2929,7 +2959,7 @@ std::map<CTxDestination, CAmount> CWallet::GetAddressBalances()
{
CWalletTx *pcoin = &walletEntry.second;
- if (!CheckFinalTx(*pcoin) || !pcoin->IsTrusted())
+ if (!pcoin->IsTrusted())
continue;
if (pcoin->IsCoinBase() && pcoin->GetBlocksToMaturity() > 0)
@@ -2939,15 +2969,15 @@ std::map<CTxDestination, CAmount> CWallet::GetAddressBalances()
if (nDepth < (pcoin->IsFromMe(ISMINE_ALL) ? 0 : 1))
continue;
- for (unsigned int i = 0; i < pcoin->vout.size(); i++)
+ for (unsigned int i = 0; i < pcoin->tx->vout.size(); i++)
{
CTxDestination addr;
- if (!IsMine(pcoin->vout[i]))
+ if (!IsMine(pcoin->tx->vout[i]))
continue;
- if(!ExtractDestination(pcoin->vout[i].scriptPubKey, addr))
+ if(!ExtractDestination(pcoin->tx->vout[i].scriptPubKey, addr))
continue;
- CAmount n = IsSpent(walletEntry.first, i) ? 0 : pcoin->vout[i].nValue;
+ CAmount n = IsSpent(walletEntry.first, i) ? 0 : pcoin->tx->vout[i].nValue;
if (!balances.count(addr))
balances[addr] = 0;
@@ -2969,16 +2999,16 @@ set< set<CTxDestination> > CWallet::GetAddressGroupings()
{
CWalletTx *pcoin = &walletEntry.second;
- if (pcoin->vin.size() > 0)
+ if (pcoin->tx->vin.size() > 0)
{
bool any_mine = false;
// group all input addresses with each other
- BOOST_FOREACH(CTxIn txin, pcoin->vin)
+ BOOST_FOREACH(CTxIn txin, pcoin->tx->vin)
{
CTxDestination address;
if(!IsMine(txin)) /* If this input isn't mine, ignore it */
continue;
- if(!ExtractDestination(mapWallet[txin.prevout.hash].vout[txin.prevout.n].scriptPubKey, address))
+ if(!ExtractDestination(mapWallet[txin.prevout.hash].tx->vout[txin.prevout.n].scriptPubKey, address))
continue;
grouping.insert(address);
any_mine = true;
@@ -2987,7 +3017,7 @@ set< set<CTxDestination> > CWallet::GetAddressGroupings()
// group change with input addresses
if (any_mine)
{
- BOOST_FOREACH(CTxOut txout, pcoin->vout)
+ BOOST_FOREACH(CTxOut txout, pcoin->tx->vout)
if (IsChange(txout))
{
CTxDestination txoutAddr;
@@ -3004,11 +3034,11 @@ set< set<CTxDestination> > CWallet::GetAddressGroupings()
}
// group lone addrs by themselves
- for (unsigned int i = 0; i < pcoin->vout.size(); i++)
- if (IsMine(pcoin->vout[i]))
+ for (unsigned int i = 0; i < pcoin->tx->vout.size(); i++)
+ if (IsMine(pcoin->tx->vout[i]))
{
CTxDestination address;
- if(!ExtractDestination(pcoin->vout[i].scriptPubKey, address))
+ if(!ExtractDestination(pcoin->tx->vout[i].scriptPubKey, address))
continue;
grouping.insert(address);
groupings.insert(grouping);
@@ -3275,7 +3305,7 @@ void CWallet::GetKeyBirthTimes(std::map<CKeyID, int64_t> &mapKeyBirth) const {
if (blit != mapBlockIndex.end() && chainActive.Contains(blit->second)) {
// ... which are already in a block
int nHeight = blit->second->nHeight;
- BOOST_FOREACH(const CTxOut &txout, wtx.vout) {
+ BOOST_FOREACH(const CTxOut &txout, wtx.tx->vout) {
// iterate over all their outputs
CAffectedKeysVisitor(*this, vAffected).Process(txout.scriptPubKey);
BOOST_FOREACH(const CKeyID &keyid, vAffected) {
@@ -3369,6 +3399,7 @@ std::string CWallet::GetWalletHelpString(bool showDebug)
strUsage += HelpMessageOpt("-dblogsize=<n>", strprintf("Flush wallet database activity from memory to disk log every <n> megabytes (default: %u)", DEFAULT_WALLET_DBLOGSIZE));
strUsage += HelpMessageOpt("-flushwallet", strprintf("Run a thread to flush wallet periodically (default: %u)", DEFAULT_FLUSHWALLET));
strUsage += HelpMessageOpt("-privdb", strprintf("Sets the DB_PRIVATE flag in the wallet db environment (default: %u)", DEFAULT_WALLET_PRIVDB));
+ strUsage += HelpMessageOpt("-walletrejectlongchains", strprintf(_("Wallet will not create transactions that violate mempool chain limits (default: %u)"), DEFAULT_WALLET_REJECT_LONG_CHAINS));
}
return strUsage;
@@ -3465,7 +3496,7 @@ CWallet* CWallet::CreateWalletFromFile(const std::string walletFile)
walletInstance->SetBestChain(chainActive.GetLocator());
}
- else if (mapArgs.count("-usehd")) {
+ else if (IsArgSet("-usehd")) {
bool useHD = GetBoolArg("-usehd", DEFAULT_USE_HD_WALLET);
if (walletInstance->IsHDEnabled() && !useHD) {
InitError(strprintf(_("Error loading %s: You can't disable HD on a already existing HD wallet"), walletFile));
@@ -3597,6 +3628,16 @@ bool CWallet::ParameterInteraction()
LogPrintf("%s: parameter interaction: -blocksonly=1 -> setting -walletbroadcast=0\n", __func__);
}
+ if (GetBoolArg("-salvagewallet", false) && SoftSetBoolArg("-rescan", true)) {
+ // Rewrite just private keys: rescan to find transactions
+ LogPrintf("%s: parameter interaction: -salvagewallet=1 -> setting -rescan=1\n", __func__);
+ }
+
+ // -zapwallettx implies a rescan
+ if (GetBoolArg("-zapwallettxes", false) && SoftSetBoolArg("-rescan", true)) {
+ LogPrintf("%s: parameter interaction: -zapwallettxes=<mode> -> setting -rescan=1\n", __func__);
+ }
+
if (GetBoolArg("-sysperms", false))
return InitError("-sysperms is not allowed in combination with enabled wallet functionality");
if (GetArg("-prune", 0) && GetBoolArg("-rescan", false))
@@ -3606,31 +3647,31 @@ bool CWallet::ParameterInteraction()
InitWarning(AmountHighWarn("-minrelaytxfee") + " " +
_("The wallet will avoid paying less than the minimum relay fee."));
- if (mapArgs.count("-mintxfee"))
+ if (IsArgSet("-mintxfee"))
{
CAmount n = 0;
- if (!ParseMoney(mapArgs["-mintxfee"], n) || 0 == n)
- return InitError(AmountErrMsg("mintxfee", mapArgs["-mintxfee"]));
+ if (!ParseMoney(GetArg("-mintxfee", ""), n) || 0 == n)
+ return InitError(AmountErrMsg("mintxfee", GetArg("-mintxfee", "")));
if (n > HIGH_TX_FEE_PER_KB)
InitWarning(AmountHighWarn("-mintxfee") + " " +
_("This is the minimum transaction fee you pay on every transaction."));
CWallet::minTxFee = CFeeRate(n);
}
- if (mapArgs.count("-fallbackfee"))
+ if (IsArgSet("-fallbackfee"))
{
CAmount nFeePerK = 0;
- if (!ParseMoney(mapArgs["-fallbackfee"], nFeePerK))
- return InitError(strprintf(_("Invalid amount for -fallbackfee=<amount>: '%s'"), mapArgs["-fallbackfee"]));
+ if (!ParseMoney(GetArg("-fallbackfee", ""), nFeePerK))
+ return InitError(strprintf(_("Invalid amount for -fallbackfee=<amount>: '%s'"), GetArg("-fallbackfee", "")));
if (nFeePerK > HIGH_TX_FEE_PER_KB)
InitWarning(AmountHighWarn("-fallbackfee") + " " +
_("This is the transaction fee you may pay when fee estimates are not available."));
CWallet::fallbackFee = CFeeRate(nFeePerK);
}
- if (mapArgs.count("-paytxfee"))
+ if (IsArgSet("-paytxfee"))
{
CAmount nFeePerK = 0;
- if (!ParseMoney(mapArgs["-paytxfee"], nFeePerK))
- return InitError(AmountErrMsg("paytxfee", mapArgs["-paytxfee"]));
+ if (!ParseMoney(GetArg("-paytxfee", ""), nFeePerK))
+ return InitError(AmountErrMsg("paytxfee", GetArg("-paytxfee", "")));
if (nFeePerK > HIGH_TX_FEE_PER_KB)
InitWarning(AmountHighWarn("-paytxfee") + " " +
_("This is the transaction fee you will pay if you send a transaction."));
@@ -3639,21 +3680,21 @@ bool CWallet::ParameterInteraction()
if (payTxFee < ::minRelayTxFee)
{
return InitError(strprintf(_("Invalid amount for -paytxfee=<amount>: '%s' (must be at least %s)"),
- mapArgs["-paytxfee"], ::minRelayTxFee.ToString()));
+ GetArg("-paytxfee", ""), ::minRelayTxFee.ToString()));
}
}
- if (mapArgs.count("-maxtxfee"))
+ if (IsArgSet("-maxtxfee"))
{
CAmount nMaxFee = 0;
- if (!ParseMoney(mapArgs["-maxtxfee"], nMaxFee))
- return InitError(AmountErrMsg("maxtxfee", mapArgs["-maxtxfee"]));
+ if (!ParseMoney(GetArg("-maxtxfee", ""), nMaxFee))
+ return InitError(AmountErrMsg("maxtxfee", GetArg("-maxtxfee", "")));
if (nMaxFee > HIGH_MAX_TX_FEE)
InitWarning(_("-maxtxfee is set very high! Fees this large could be paid on a single transaction."));
maxTxFee = nMaxFee;
if (CFeeRate(maxTxFee, 1000) < ::minRelayTxFee)
{
return InitError(strprintf(_("Invalid amount for -maxtxfee=<amount>: '%s' (must be at least the minrelay fee of %s to prevent stuck transactions)"),
- mapArgs["-maxtxfee"], ::minRelayTxFee.ToString()));
+ GetArg("-maxtxfee", ""), ::minRelayTxFee.ToString()));
}
}
nTxConfirmTarget = GetArg("-txconfirmtarget", DEFAULT_TX_CONFIRM_TARGET);
@@ -3661,6 +3702,9 @@ bool CWallet::ParameterInteraction()
fSendFreeTransactions = GetBoolArg("-sendfreetransactions", DEFAULT_SEND_FREE_TRANSACTIONS);
fWalletRbf = GetBoolArg("-walletrbf", DEFAULT_WALLET_RBF);
+ if (fSendFreeTransactions && GetArg("-limitfreerelay", DEFAULT_LIMITFREERELAY) <= 0)
+ return InitError("Creation of free transactions with their relay disabled is not supported.");
+
return true;
}
@@ -3721,21 +3765,13 @@ CWalletKey::CWalletKey(int64_t nExpires)
nTimeExpires = nExpires;
}
-int CMerkleTx::SetMerkleBranch(const CBlockIndex* pindex, int posInBlock)
+void CMerkleTx::SetMerkleBranch(const CBlockIndex* pindex, int posInBlock)
{
- AssertLockHeld(cs_main);
-
// Update the tx's hashBlock
hashBlock = pindex->GetBlockHash();
// set the position of the transaction in the block
nIndex = posInBlock;
-
- // Is the tx in a block that's in the main chain
- if (!chainActive.Contains(pindex))
- return 0;
-
- return chainActive.Height() - pindex->nHeight + 1;
}
int CMerkleTx::GetDepthInMainChain(const CBlockIndex* &pindexRet) const
diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h
index f536dbe5c8..79ef96c911 100644
--- a/src/wallet/wallet.h
+++ b/src/wallet/wallet.h
@@ -54,6 +54,8 @@ static const CAmount MIN_CHANGE = CENT;
static const bool DEFAULT_SPEND_ZEROCONF_CHANGE = true;
//! Default for -sendfreetransactions
static const bool DEFAULT_SEND_FREE_TRANSACTIONS = false;
+//! Default for -walletrejectlongchains
+static const bool DEFAULT_WALLET_REJECT_LONG_CHAINS = false;
//! -txconfirmtarget default
static const unsigned int DEFAULT_TX_CONFIRM_TARGET = 6;
//! -walletrbf default
@@ -162,13 +164,14 @@ struct COutputEntry
};
/** A transaction with a merkle branch linking it to the block chain. */
-class CMerkleTx : public CTransaction
+class CMerkleTx
{
private:
/** Constant used in hashBlock to indicate tx has been abandoned */
static const uint256 ABANDON_HASH;
public:
+ CTransactionRef tx;
uint256 hashBlock;
/* An nIndex == -1 means that hashBlock (in nonzero) refers to the earliest
@@ -180,32 +183,43 @@ public:
CMerkleTx()
{
+ SetTx(MakeTransactionRef());
Init();
}
- CMerkleTx(const CTransaction& txIn) : CTransaction(txIn)
+ CMerkleTx(CTransactionRef arg)
{
+ SetTx(std::move(arg));
Init();
}
+ /** Helper conversion operator to allow passing CMerkleTx where CTransaction is expected.
+ * TODO: adapt callers and remove this operator. */
+ operator const CTransaction&() const { return *tx; }
+
void Init()
{
hashBlock = uint256();
nIndex = -1;
}
+ void SetTx(CTransactionRef arg)
+ {
+ tx = std::move(arg);
+ }
+
ADD_SERIALIZE_METHODS;
template <typename Stream, typename Operation>
inline void SerializationOp(Stream& s, Operation ser_action) {
std::vector<uint256> vMerkleBranch; // For compatibility with older versions.
- READWRITE(*(CTransaction*)this);
+ READWRITE(tx);
READWRITE(hashBlock);
READWRITE(vMerkleBranch);
READWRITE(nIndex);
}
- int SetMerkleBranch(const CBlockIndex* pIndex, int posInBlock);
+ void SetMerkleBranch(const CBlockIndex* pIndex, int posInBlock);
/**
* Return depth of transaction in blockchain:
@@ -222,6 +236,9 @@ public:
bool hashUnset() const { return (hashBlock.IsNull() || hashBlock == ABANDON_HASH); }
bool isAbandoned() const { return (hashBlock == ABANDON_HASH); }
void setAbandoned() { hashBlock = ABANDON_HASH; }
+
+ const uint256& GetHash() const { return tx->GetHash(); }
+ bool IsCoinBase() const { return tx->IsCoinBase(); }
};
/**
@@ -268,17 +285,7 @@ public:
Init(NULL);
}
- CWalletTx(const CWallet* pwalletIn)
- {
- Init(pwalletIn);
- }
-
- CWalletTx(const CWallet* pwalletIn, const CMerkleTx& txIn) : CMerkleTx(txIn)
- {
- Init(pwalletIn);
- }
-
- CWalletTx(const CWallet* pwalletIn, const CTransaction& txIn) : CMerkleTx(txIn)
+ CWalletTx(const CWallet* pwalletIn, CTransactionRef arg) : CMerkleTx(std::move(arg))
{
Init(pwalletIn);
}
@@ -363,6 +370,7 @@ public:
{
fCreditCached = false;
fAvailableCreditCached = false;
+ fImmatureCreditCached = false;
fWatchDebitCached = false;
fWatchCreditCached = false;
fAvailableWatchCreditCached = false;
@@ -603,7 +611,7 @@ public:
*/
mutable CCriticalSection cs_wallet;
- std::string strWalletFile;
+ const std::string strWalletFile;
void LoadKeyPool(int nIndex, const CKeyPool &keypool)
{
@@ -628,11 +636,9 @@ public:
SetNull();
}
- CWallet(const std::string& strWalletFileIn)
+ CWallet(const std::string& strWalletFileIn) : strWalletFile(strWalletFileIn)
{
SetNull();
-
- strWalletFile = strWalletFileIn;
fFileBacked = true;
}
@@ -690,7 +696,7 @@ public:
* completion the coin set and corresponding actual target value is
* assembled
*/
- bool SelectCoinsMinConf(const CAmount& nTargetValue, int nConfMine, int nConfTheirs, std::vector<COutput> vCoins, std::set<std::pair<const CWalletTx*,unsigned int> >& setCoinsRet, CAmount& nValueRet) const;
+ bool SelectCoinsMinConf(const CAmount& nTargetValue, int nConfMine, int nConfTheirs, uint64_t nMaxAncestors, std::vector<COutput> vCoins, std::set<std::pair<const CWalletTx*,unsigned int> >& setCoinsRet, CAmount& nValueRet) const;
bool IsSpent(const uint256& hash, unsigned int n) const;
diff --git a/src/wallet/walletdb.cpp b/src/wallet/walletdb.cpp
index 9496c4404d..855fe7f74f 100644
--- a/src/wallet/walletdb.cpp
+++ b/src/wallet/walletdb.cpp
@@ -7,7 +7,7 @@
#include "base58.h"
#include "consensus/validation.h"
-#include "main.h" // For CheckTransaction
+#include "validation.h" // For CheckTransaction
#include "protocol.h"
#include "serialize.h"
#include "sync.h"