Merge #9680: Unify CWalletTx construction

b4bc32a451 [wallet] Get rid of CWalletTx default constructor (Russell Yanofsky)
a128bdc9e1 [wallet] Construct CWalletTx objects in CommitTransaction (Russell Yanofsky)

Pull request description:

  Two commits:

  - `Construct CWalletTx objects in CommitTransaction` moves a bunch of CWalletTx initialization into CWallet::CommitTransaction to dedup some code and avoid future inconsistencies in how wallet transactions are created.
  - `Get rid of CWalletTx default constructor` does what is described and eliminates the possibility of empty transaction entries being inadvertently created by mapWallet[hash] accesses.

  Both of these changes were originally part of #9381

Tree-SHA512: af3841c4f0539e0662d81b33c5369fc70aa06ddde1c59cb00fb21c9e4c7d9ff47f1edc5040cb463af1333838802c56b3ef875b939e2b804ee45b8e0294a4371c
This commit is contained in:
Pieter Wuille 2018-03-13 19:07:49 -07:00
commit 6acd8700bc
No known key found for this signature in database
GPG key ID: A636E97631F767E0
10 changed files with 80 additions and 91 deletions

View file

@ -275,9 +275,9 @@ WalletModel::SendCoinsReturn WalletModel::prepareTransaction(WalletModelTransact
int nChangePosRet = -1; int nChangePosRet = -1;
std::string strFailReason; std::string strFailReason;
CWalletTx *newTx = transaction.getTransaction(); CTransactionRef& newTx = transaction.getTransaction();
CReserveKey *keyChange = transaction.getPossibleKeyChange(); CReserveKey *keyChange = transaction.getPossibleKeyChange();
bool fCreated = wallet->CreateTransaction(vecSend, *newTx, *keyChange, nFeeRequired, nChangePosRet, strFailReason, coinControl); bool fCreated = wallet->CreateTransaction(vecSend, newTx, *keyChange, nFeeRequired, nChangePosRet, strFailReason, coinControl);
transaction.setTransactionFee(nFeeRequired); transaction.setTransactionFee(nFeeRequired);
if (fSubtractFeeFromAmount && fCreated) if (fSubtractFeeFromAmount && fCreated)
transaction.reassignAmounts(nChangePosRet); transaction.reassignAmounts(nChangePosRet);
@ -309,8 +309,8 @@ WalletModel::SendCoinsReturn WalletModel::sendCoins(WalletModelTransaction &tran
{ {
LOCK2(cs_main, wallet->cs_wallet); LOCK2(cs_main, wallet->cs_wallet);
CWalletTx *newTx = transaction.getTransaction();
std::vector<std::pair<std::string, std::string>> vOrderForm;
for (const SendCoinsRecipient &rcp : transaction.getRecipients()) for (const SendCoinsRecipient &rcp : transaction.getRecipients())
{ {
if (rcp.paymentRequest.IsInitialized()) if (rcp.paymentRequest.IsInitialized())
@ -321,22 +321,22 @@ WalletModel::SendCoinsReturn WalletModel::sendCoins(WalletModelTransaction &tran
} }
// Store PaymentRequests in wtx.vOrderForm in wallet. // Store PaymentRequests in wtx.vOrderForm in wallet.
std::string key("PaymentRequest");
std::string value; std::string value;
rcp.paymentRequest.SerializeToString(&value); rcp.paymentRequest.SerializeToString(&value);
newTx->vOrderForm.push_back(make_pair(key, value)); vOrderForm.emplace_back("PaymentRequest", std::move(value));
} }
else if (!rcp.message.isEmpty()) // Message from normal bitcoin:URI (bitcoin:123...?message=example) else if (!rcp.message.isEmpty()) // Message from normal bitcoin:URI (bitcoin:123...?message=example)
newTx->vOrderForm.push_back(make_pair("Message", rcp.message.toStdString())); vOrderForm.emplace_back("Message", rcp.message.toStdString());
} }
CTransactionRef& newTx = transaction.getTransaction();
CReserveKey *keyChange = transaction.getPossibleKeyChange(); CReserveKey *keyChange = transaction.getPossibleKeyChange();
CValidationState state; CValidationState state;
if(!wallet->CommitTransaction(*newTx, *keyChange, g_connman.get(), state)) if (!wallet->CommitTransaction(newTx, {} /* mapValue */, std::move(vOrderForm), {} /* fromAccount */, *keyChange, g_connman.get(), state))
return SendCoinsReturn(TransactionCommitFailed, QString::fromStdString(state.GetRejectReason())); return SendCoinsReturn(TransactionCommitFailed, QString::fromStdString(state.GetRejectReason()));
CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION); CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION);
ssTx << *newTx->tx; ssTx << newTx;
transaction_array.append(&(ssTx[0]), ssTx.size()); transaction_array.append(&(ssTx[0]), ssTx.size());
} }

View file

@ -12,12 +12,6 @@ WalletModelTransaction::WalletModelTransaction(const QList<SendCoinsRecipient> &
walletTransaction(0), walletTransaction(0),
fee(0) fee(0)
{ {
walletTransaction = new CWalletTx();
}
WalletModelTransaction::~WalletModelTransaction()
{
delete walletTransaction;
} }
QList<SendCoinsRecipient> WalletModelTransaction::getRecipients() const QList<SendCoinsRecipient> WalletModelTransaction::getRecipients() const
@ -25,14 +19,14 @@ QList<SendCoinsRecipient> WalletModelTransaction::getRecipients() const
return recipients; return recipients;
} }
CWalletTx *WalletModelTransaction::getTransaction() const CTransactionRef& WalletModelTransaction::getTransaction()
{ {
return walletTransaction; return walletTransaction;
} }
unsigned int WalletModelTransaction::getTransactionSize() unsigned int WalletModelTransaction::getTransactionSize()
{ {
return (!walletTransaction ? 0 : ::GetVirtualTransactionSize(*walletTransaction->tx)); return (!walletTransaction ? 0 : ::GetVirtualTransactionSize(*walletTransaction));
} }
CAmount WalletModelTransaction::getTransactionFee() const CAmount WalletModelTransaction::getTransactionFee() const
@ -62,7 +56,7 @@ void WalletModelTransaction::reassignAmounts(int nChangePosRet)
if (out.amount() <= 0) continue; if (out.amount() <= 0) continue;
if (i == nChangePosRet) if (i == nChangePosRet)
i++; i++;
subtotal += walletTransaction->tx->vout[i].nValue; subtotal += walletTransaction->vout[i].nValue;
i++; i++;
} }
rcp.amount = subtotal; rcp.amount = subtotal;
@ -71,7 +65,7 @@ void WalletModelTransaction::reassignAmounts(int nChangePosRet)
{ {
if (i == nChangePosRet) if (i == nChangePosRet)
i++; i++;
rcp.amount = walletTransaction->tx->vout[i].nValue; rcp.amount = walletTransaction->vout[i].nValue;
i++; i++;
} }
} }

View file

@ -20,11 +20,10 @@ class WalletModelTransaction
{ {
public: public:
explicit WalletModelTransaction(const QList<SendCoinsRecipient> &recipients); explicit WalletModelTransaction(const QList<SendCoinsRecipient> &recipients);
~WalletModelTransaction();
QList<SendCoinsRecipient> getRecipients() const; QList<SendCoinsRecipient> getRecipients() const;
CWalletTx *getTransaction() const; CTransactionRef& getTransaction();
unsigned int getTransactionSize(); unsigned int getTransactionSize();
void setTransactionFee(const CAmount& newFee); void setTransactionFee(const CAmount& newFee);
@ -39,7 +38,7 @@ public:
private: private:
QList<SendCoinsRecipient> recipients; QList<SendCoinsRecipient> recipients;
CWalletTx *walletTransaction; CTransactionRef walletTransaction;
std::unique_ptr<CReserveKey> keyChange; std::unique_ptr<CReserveKey> keyChange;
CAmount fee; CAmount fee;
}; };

View file

@ -262,23 +262,20 @@ Result CommitTransaction(CWallet* wallet, const uint256& txid, CMutableTransacti
return result; return result;
} }
CWalletTx wtxBumped(wallet, MakeTransactionRef(std::move(mtx)));
// commit/broadcast the tx // commit/broadcast the tx
CTransactionRef tx = MakeTransactionRef(std::move(mtx));
mapValue_t mapValue = oldWtx.mapValue;
mapValue["replaces_txid"] = oldWtx.GetHash().ToString();
CReserveKey reservekey(wallet); CReserveKey reservekey(wallet);
wtxBumped.mapValue = oldWtx.mapValue;
wtxBumped.mapValue["replaces_txid"] = oldWtx.GetHash().ToString();
wtxBumped.vOrderForm = oldWtx.vOrderForm;
wtxBumped.strFromAccount = oldWtx.strFromAccount;
wtxBumped.fTimeReceivedIsTxTime = true;
wtxBumped.fFromMe = true;
CValidationState state; CValidationState state;
if (!wallet->CommitTransaction(wtxBumped, reservekey, g_connman.get(), state)) { if (!wallet->CommitTransaction(tx, std::move(mapValue), oldWtx.vOrderForm, oldWtx.strFromAccount, reservekey, g_connman.get(), state)) {
// NOTE: CommitTransaction never returns false, so this should never happen. // NOTE: CommitTransaction never returns false, so this should never happen.
errors.push_back(strprintf("The transaction was rejected: %s", FormatStateMessage(state))); errors.push_back(strprintf("The transaction was rejected: %s", FormatStateMessage(state)));
return Result::WALLET_ERROR; return Result::WALLET_ERROR;
} }
bumped_txid = wtxBumped.GetHash(); bumped_txid = tx->GetHash();
if (state.IsInvalid()) { if (state.IsInvalid()) {
// This can happen if the mempool rejected the transaction. Report // This can happen if the mempool rejected the transaction. Report
// what happened in the "errors" response. // what happened in the "errors" response.
@ -286,7 +283,7 @@ Result CommitTransaction(CWallet* wallet, const uint256& txid, CMutableTransacti
} }
// mark the original tx as bumped // mark the original tx as bumped
if (!wallet->MarkReplaced(oldWtx.GetHash(), wtxBumped.GetHash())) { if (!wallet->MarkReplaced(oldWtx.GetHash(), bumped_txid)) {
// TODO: see if JSON-RPC has a standard way of returning a response // TODO: see if JSON-RPC has a standard way of returning a response
// along with an exception. It would be good to return information about // along with an exception. It would be good to return information about
// wtxBumped to the caller even if marking the original transaction // wtxBumped to the caller even if marking the original transaction

View file

@ -404,7 +404,7 @@ UniValue getaddressesbyaccount(const JSONRPCRequest& request)
return ret; return ret;
} }
static void SendMoney(CWallet * const pwallet, const CTxDestination &address, CAmount nValue, bool fSubtractFeeFromAmount, CWalletTx& wtxNew, const CCoinControl& coin_control) static CTransactionRef SendMoney(CWallet * const pwallet, const CTxDestination &address, CAmount nValue, bool fSubtractFeeFromAmount, const CCoinControl& coin_control, mapValue_t mapValue, std::string fromAccount)
{ {
CAmount curBalance = pwallet->GetBalance(); CAmount curBalance = pwallet->GetBalance();
@ -430,16 +430,18 @@ static void SendMoney(CWallet * const pwallet, const CTxDestination &address, CA
int nChangePosRet = -1; int nChangePosRet = -1;
CRecipient recipient = {scriptPubKey, nValue, fSubtractFeeFromAmount}; CRecipient recipient = {scriptPubKey, nValue, fSubtractFeeFromAmount};
vecSend.push_back(recipient); vecSend.push_back(recipient);
if (!pwallet->CreateTransaction(vecSend, wtxNew, reservekey, nFeeRequired, nChangePosRet, strError, coin_control)) { CTransactionRef tx;
if (!pwallet->CreateTransaction(vecSend, tx, reservekey, nFeeRequired, nChangePosRet, strError, coin_control)) {
if (!fSubtractFeeFromAmount && nValue + nFeeRequired > curBalance) if (!fSubtractFeeFromAmount && nValue + nFeeRequired > curBalance)
strError = strprintf("Error: This transaction requires a transaction fee of at least %s", FormatMoney(nFeeRequired)); strError = strprintf("Error: This transaction requires a transaction fee of at least %s", FormatMoney(nFeeRequired));
throw JSONRPCError(RPC_WALLET_ERROR, strError); throw JSONRPCError(RPC_WALLET_ERROR, strError);
} }
CValidationState state; CValidationState state;
if (!pwallet->CommitTransaction(wtxNew, reservekey, g_connman.get(), state)) { if (!pwallet->CommitTransaction(tx, std::move(mapValue), {} /* orderForm */, std::move(fromAccount), reservekey, g_connman.get(), state)) {
strError = strprintf("Error: The transaction was rejected! Reason given: %s", FormatStateMessage(state)); strError = strprintf("Error: The transaction was rejected! Reason given: %s", FormatStateMessage(state));
throw JSONRPCError(RPC_WALLET_ERROR, strError); throw JSONRPCError(RPC_WALLET_ERROR, strError);
} }
return tx;
} }
UniValue sendtoaddress(const JSONRPCRequest& request) UniValue sendtoaddress(const JSONRPCRequest& request)
@ -498,11 +500,11 @@ UniValue sendtoaddress(const JSONRPCRequest& request)
throw JSONRPCError(RPC_TYPE_ERROR, "Invalid amount for send"); throw JSONRPCError(RPC_TYPE_ERROR, "Invalid amount for send");
// Wallet comments // Wallet comments
CWalletTx wtx; mapValue_t mapValue;
if (!request.params[2].isNull() && !request.params[2].get_str().empty()) if (!request.params[2].isNull() && !request.params[2].get_str().empty())
wtx.mapValue["comment"] = request.params[2].get_str(); mapValue["comment"] = request.params[2].get_str();
if (!request.params[3].isNull() && !request.params[3].get_str().empty()) if (!request.params[3].isNull() && !request.params[3].get_str().empty())
wtx.mapValue["to"] = request.params[3].get_str(); mapValue["to"] = request.params[3].get_str();
bool fSubtractFeeFromAmount = false; bool fSubtractFeeFromAmount = false;
if (!request.params[4].isNull()) { if (!request.params[4].isNull()) {
@ -527,9 +529,8 @@ UniValue sendtoaddress(const JSONRPCRequest& request)
EnsureWalletIsUnlocked(pwallet); EnsureWalletIsUnlocked(pwallet);
SendMoney(pwallet, dest, nAmount, fSubtractFeeFromAmount, wtx, coin_control); CTransactionRef tx = SendMoney(pwallet, dest, nAmount, fSubtractFeeFromAmount, coin_control, std::move(mapValue), {} /* fromAccount */);
return tx->GetHash().GetHex();
return wtx.GetHash().GetHex();
} }
UniValue listaddressgroupings(const JSONRPCRequest& request) UniValue listaddressgroupings(const JSONRPCRequest& request)
@ -995,12 +996,11 @@ UniValue sendfrom(const JSONRPCRequest& request)
if (!request.params[3].isNull()) if (!request.params[3].isNull())
nMinDepth = request.params[3].get_int(); nMinDepth = request.params[3].get_int();
CWalletTx wtx; mapValue_t mapValue;
wtx.strFromAccount = strAccount;
if (!request.params[4].isNull() && !request.params[4].get_str().empty()) if (!request.params[4].isNull() && !request.params[4].get_str().empty())
wtx.mapValue["comment"] = request.params[4].get_str(); mapValue["comment"] = request.params[4].get_str();
if (!request.params[5].isNull() && !request.params[5].get_str().empty()) if (!request.params[5].isNull() && !request.params[5].get_str().empty())
wtx.mapValue["to"] = request.params[5].get_str(); mapValue["to"] = request.params[5].get_str();
EnsureWalletIsUnlocked(pwallet); EnsureWalletIsUnlocked(pwallet);
@ -1010,9 +1010,8 @@ UniValue sendfrom(const JSONRPCRequest& request)
throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Account has insufficient funds"); throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Account has insufficient funds");
CCoinControl no_coin_control; // This is a deprecated API CCoinControl no_coin_control; // This is a deprecated API
SendMoney(pwallet, dest, nAmount, false, wtx, no_coin_control); CTransactionRef tx = SendMoney(pwallet, dest, nAmount, false, no_coin_control, std::move(mapValue), std::move(strAccount));
return tx->GetHash().GetHex();
return wtx.GetHash().GetHex();
} }
@ -1083,10 +1082,9 @@ UniValue sendmany(const JSONRPCRequest& request)
if (!request.params[2].isNull()) if (!request.params[2].isNull())
nMinDepth = request.params[2].get_int(); nMinDepth = request.params[2].get_int();
CWalletTx wtx; mapValue_t mapValue;
wtx.strFromAccount = strAccount;
if (!request.params[3].isNull() && !request.params[3].get_str().empty()) if (!request.params[3].isNull() && !request.params[3].get_str().empty())
wtx.mapValue["comment"] = request.params[3].get_str(); mapValue["comment"] = request.params[3].get_str();
UniValue subtractFeeFromAmount(UniValue::VARR); UniValue subtractFeeFromAmount(UniValue::VARR);
if (!request.params[4].isNull()) if (!request.params[4].isNull())
@ -1152,16 +1150,17 @@ UniValue sendmany(const JSONRPCRequest& request)
CAmount nFeeRequired = 0; CAmount nFeeRequired = 0;
int nChangePosRet = -1; int nChangePosRet = -1;
std::string strFailReason; std::string strFailReason;
bool fCreated = pwallet->CreateTransaction(vecSend, wtx, keyChange, nFeeRequired, nChangePosRet, strFailReason, coin_control); CTransactionRef tx;
bool fCreated = pwallet->CreateTransaction(vecSend, tx, keyChange, nFeeRequired, nChangePosRet, strFailReason, coin_control);
if (!fCreated) if (!fCreated)
throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, strFailReason); throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, strFailReason);
CValidationState state; CValidationState state;
if (!pwallet->CommitTransaction(wtx, keyChange, g_connman.get(), state)) { if (!pwallet->CommitTransaction(tx, std::move(mapValue), {} /* orderForm */, std::move(strAccount), keyChange, g_connman.get(), state)) {
strFailReason = strprintf("Transaction commit failed:: %s", FormatStateMessage(state)); strFailReason = strprintf("Transaction commit failed:: %s", FormatStateMessage(state));
throw JSONRPCError(RPC_WALLET_ERROR, strFailReason); throw JSONRPCError(RPC_WALLET_ERROR, strFailReason);
} }
return wtx.GetHash().GetHex(); return tx->GetHash().GetHex();
} }
UniValue addmultisigaddress(const JSONRPCRequest& request) UniValue addmultisigaddress(const JSONRPCRequest& request)

View file

@ -29,7 +29,7 @@ GetResults(CWallet& wallet, std::map<CAmount, CAccountingEntry>& results)
BOOST_AUTO_TEST_CASE(acc_orderupgrade) BOOST_AUTO_TEST_CASE(acc_orderupgrade)
{ {
std::vector<CWalletTx*> vpwtx; std::vector<CWalletTx*> vpwtx;
CWalletTx wtx; CWalletTx wtx(nullptr /* pwallet */, MakeTransactionRef());
CAccountingEntry ae; CAccountingEntry ae;
std::map<CAmount, CAccountingEntry> results; std::map<CAmount, CAccountingEntry> results;
@ -44,7 +44,7 @@ BOOST_AUTO_TEST_CASE(acc_orderupgrade)
wtx.mapValue["comment"] = "z"; wtx.mapValue["comment"] = "z";
m_wallet.AddToWallet(wtx); m_wallet.AddToWallet(wtx);
vpwtx.push_back(&m_wallet.mapWallet[wtx.GetHash()]); vpwtx.push_back(&m_wallet.mapWallet.at(wtx.GetHash()));
vpwtx[0]->nTimeReceived = (unsigned int)1333333335; vpwtx[0]->nTimeReceived = (unsigned int)1333333335;
vpwtx[0]->nOrderPos = -1; vpwtx[0]->nOrderPos = -1;
@ -86,7 +86,7 @@ BOOST_AUTO_TEST_CASE(acc_orderupgrade)
wtx.SetTx(MakeTransactionRef(std::move(tx))); wtx.SetTx(MakeTransactionRef(std::move(tx)));
} }
m_wallet.AddToWallet(wtx); m_wallet.AddToWallet(wtx);
vpwtx.push_back(&m_wallet.mapWallet[wtx.GetHash()]); vpwtx.push_back(&m_wallet.mapWallet.at(wtx.GetHash()));
vpwtx[1]->nTimeReceived = (unsigned int)1333333336; vpwtx[1]->nTimeReceived = (unsigned int)1333333336;
wtx.mapValue["comment"] = "x"; wtx.mapValue["comment"] = "x";
@ -96,7 +96,7 @@ BOOST_AUTO_TEST_CASE(acc_orderupgrade)
wtx.SetTx(MakeTransactionRef(std::move(tx))); wtx.SetTx(MakeTransactionRef(std::move(tx)));
} }
m_wallet.AddToWallet(wtx); m_wallet.AddToWallet(wtx);
vpwtx.push_back(&m_wallet.mapWallet[wtx.GetHash()]); vpwtx.push_back(&m_wallet.mapWallet.at(wtx.GetHash()));
vpwtx[2]->nTimeReceived = (unsigned int)1333333329; vpwtx[2]->nTimeReceived = (unsigned int)1333333329;
vpwtx[2]->nOrderPos = -1; vpwtx[2]->nOrderPos = -1;

View file

@ -627,23 +627,23 @@ public:
CWalletTx& AddTx(CRecipient recipient) CWalletTx& AddTx(CRecipient recipient)
{ {
CWalletTx wtx; CTransactionRef tx;
CReserveKey reservekey(wallet.get()); CReserveKey reservekey(wallet.get());
CAmount fee; CAmount fee;
int changePos = -1; int changePos = -1;
std::string error; std::string error;
CCoinControl dummy; CCoinControl dummy;
BOOST_CHECK(wallet->CreateTransaction({recipient}, wtx, reservekey, fee, changePos, error, dummy)); BOOST_CHECK(wallet->CreateTransaction({recipient}, tx, reservekey, fee, changePos, error, dummy));
CValidationState state; CValidationState state;
BOOST_CHECK(wallet->CommitTransaction(wtx, reservekey, nullptr, state)); BOOST_CHECK(wallet->CommitTransaction(tx, {}, {}, {}, reservekey, nullptr, state));
CMutableTransaction blocktx; CMutableTransaction blocktx;
{ {
LOCK(wallet->cs_wallet); LOCK(wallet->cs_wallet);
blocktx = CMutableTransaction(*wallet->mapWallet.at(wtx.GetHash()).tx); blocktx = CMutableTransaction(*wallet->mapWallet.at(tx->GetHash()).tx);
} }
CreateAndProcessBlock({CMutableTransaction(blocktx)}, GetScriptForRawPubKey(coinbaseKey.GetPubKey())); CreateAndProcessBlock({CMutableTransaction(blocktx)}, GetScriptForRawPubKey(coinbaseKey.GetPubKey()));
LOCK(wallet->cs_wallet); LOCK(wallet->cs_wallet);
auto it = wallet->mapWallet.find(wtx.GetHash()); auto it = wallet->mapWallet.find(tx->GetHash());
BOOST_CHECK(it != wallet->mapWallet.end()); BOOST_CHECK(it != wallet->mapWallet.end());
it->second.SetMerkleBranch(chainActive.Tip(), 1); it->second.SetMerkleBranch(chainActive.Tip(), 1);
return it->second; return it->second;

View file

@ -531,7 +531,7 @@ void CWallet::SyncMetaData(std::pair<TxSpends::iterator, TxSpends::iterator> ran
int nMinOrderPos = std::numeric_limits<int>::max(); int nMinOrderPos = std::numeric_limits<int>::max();
const CWalletTx* copyFrom = nullptr; const CWalletTx* copyFrom = nullptr;
for (TxSpends::iterator it = range.first; it != range.second; ++it) { for (TxSpends::iterator it = range.first; it != range.second; ++it) {
const CWalletTx* wtx = &mapWallet[it->second]; const CWalletTx* wtx = &mapWallet.at(it->second);
if (wtx->nOrderPos < nMinOrderPos) { if (wtx->nOrderPos < nMinOrderPos) {
nMinOrderPos = wtx->nOrderPos;; nMinOrderPos = wtx->nOrderPos;;
copyFrom = wtx; copyFrom = wtx;
@ -544,7 +544,7 @@ void CWallet::SyncMetaData(std::pair<TxSpends::iterator, TxSpends::iterator> ran
for (TxSpends::iterator it = range.first; it != range.second; ++it) for (TxSpends::iterator it = range.first; it != range.second; ++it)
{ {
const uint256& hash = it->second; const uint256& hash = it->second;
CWalletTx* copyTo = &mapWallet[hash]; CWalletTx* copyTo = &mapWallet.at(hash);
if (copyFrom == copyTo) continue; if (copyFrom == copyTo) continue;
assert(copyFrom && "Oldest wallet transaction in range assumed to have been found."); assert(copyFrom && "Oldest wallet transaction in range assumed to have been found.");
if (!copyFrom->IsEquivalentTo(*copyTo)) continue; if (!copyFrom->IsEquivalentTo(*copyTo)) continue;
@ -2629,13 +2629,13 @@ bool CWallet::FundTransaction(CMutableTransaction& tx, CAmount& nFeeRet, int& nC
LOCK2(cs_main, cs_wallet); LOCK2(cs_main, cs_wallet);
CReserveKey reservekey(this); CReserveKey reservekey(this);
CWalletTx wtx; CTransactionRef tx_new;
if (!CreateTransaction(vecSend, wtx, reservekey, nFeeRet, nChangePosInOut, strFailReason, coinControl, false)) { if (!CreateTransaction(vecSend, tx_new, reservekey, nFeeRet, nChangePosInOut, strFailReason, coinControl, false)) {
return false; return false;
} }
if (nChangePosInOut != -1) { if (nChangePosInOut != -1) {
tx.vout.insert(tx.vout.begin() + nChangePosInOut, wtx.tx->vout[nChangePosInOut]); tx.vout.insert(tx.vout.begin() + nChangePosInOut, tx_new->vout[nChangePosInOut]);
// We don't have the normal Create/Commit cycle, and don't want to risk // We don't have the normal Create/Commit cycle, and don't want to risk
// reusing change, so just remove the key from the keypool here. // reusing change, so just remove the key from the keypool here.
reservekey.KeepKey(); reservekey.KeepKey();
@ -2644,11 +2644,11 @@ bool CWallet::FundTransaction(CMutableTransaction& tx, CAmount& nFeeRet, int& nC
// Copy output sizes from new transaction; they may have had the fee // Copy output sizes from new transaction; they may have had the fee
// subtracted from them. // subtracted from them.
for (unsigned int idx = 0; idx < tx.vout.size(); idx++) { for (unsigned int idx = 0; idx < tx.vout.size(); idx++) {
tx.vout[idx].nValue = wtx.tx->vout[idx].nValue; tx.vout[idx].nValue = tx_new->vout[idx].nValue;
} }
// Add new txins while keeping original txin scriptSig/order. // Add new txins while keeping original txin scriptSig/order.
for (const CTxIn& txin : wtx.tx->vin) { for (const CTxIn& txin : tx_new->vin) {
if (!coinControl.IsSelected(txin.prevout)) { if (!coinControl.IsSelected(txin.prevout)) {
tx.vin.push_back(txin); tx.vin.push_back(txin);
@ -2689,7 +2689,7 @@ OutputType CWallet::TransactionChangeType(OutputType change_type, const std::vec
return g_address_type; return g_address_type;
} }
bool CWallet::CreateTransaction(const std::vector<CRecipient>& vecSend, CWalletTx& wtxNew, CReserveKey& reservekey, CAmount& nFeeRet, bool CWallet::CreateTransaction(const std::vector<CRecipient>& vecSend, CTransactionRef& tx, CReserveKey& reservekey, CAmount& nFeeRet,
int& nChangePosInOut, std::string& strFailReason, const CCoinControl& coin_control, bool sign) int& nChangePosInOut, std::string& strFailReason, const CCoinControl& coin_control, bool sign)
{ {
CAmount nValue = 0; CAmount nValue = 0;
@ -2713,8 +2713,6 @@ bool CWallet::CreateTransaction(const std::vector<CRecipient>& vecSend, CWalletT
return false; return false;
} }
wtxNew.fTimeReceivedIsTxTime = true;
wtxNew.BindWallet(this);
CMutableTransaction txNew; CMutableTransaction txNew;
// Discourage fee sniping. // Discourage fee sniping.
@ -2802,7 +2800,6 @@ bool CWallet::CreateTransaction(const std::vector<CRecipient>& vecSend, CWalletT
nChangePosInOut = nChangePosRequest; nChangePosInOut = nChangePosRequest;
txNew.vin.clear(); txNew.vin.clear();
txNew.vout.clear(); txNew.vout.clear();
wtxNew.fFromMe = true;
bool fFirst = true; bool fFirst = true;
CAmount nValueToSelect = nValue; CAmount nValueToSelect = nValue;
@ -3017,11 +3014,11 @@ bool CWallet::CreateTransaction(const std::vector<CRecipient>& vecSend, CWalletT
} }
} }
// Embed the constructed transaction data in wtxNew. // Return the constructed transaction data.
wtxNew.SetTx(MakeTransactionRef(std::move(txNew))); tx = MakeTransactionRef(std::move(txNew));
// Limit size // Limit size
if (GetTransactionWeight(*wtxNew.tx) >= MAX_STANDARD_TX_WEIGHT) if (GetTransactionWeight(*tx) >= MAX_STANDARD_TX_WEIGHT)
{ {
strFailReason = _("Transaction too large"); strFailReason = _("Transaction too large");
return false; return false;
@ -3031,7 +3028,7 @@ bool CWallet::CreateTransaction(const std::vector<CRecipient>& vecSend, CWalletT
if (gArgs.GetBoolArg("-walletrejectlongchains", DEFAULT_WALLET_REJECT_LONG_CHAINS)) { if (gArgs.GetBoolArg("-walletrejectlongchains", DEFAULT_WALLET_REJECT_LONG_CHAINS)) {
// Lastly, ensure this tx will pass the mempool's chain limits // Lastly, ensure this tx will pass the mempool's chain limits
LockPoints lp; LockPoints lp;
CTxMemPoolEntry entry(wtxNew.tx, 0, 0, 0, false, 0, lp); CTxMemPoolEntry entry(tx, 0, 0, 0, false, 0, lp);
CTxMemPool::setEntries setAncestors; CTxMemPool::setEntries setAncestors;
size_t nLimitAncestors = gArgs.GetArg("-limitancestorcount", DEFAULT_ANCESTOR_LIMIT); size_t nLimitAncestors = gArgs.GetArg("-limitancestorcount", DEFAULT_ANCESTOR_LIMIT);
size_t nLimitAncestorSize = gArgs.GetArg("-limitancestorsize", DEFAULT_ANCESTOR_SIZE_LIMIT)*1000; size_t nLimitAncestorSize = gArgs.GetArg("-limitancestorsize", DEFAULT_ANCESTOR_SIZE_LIMIT)*1000;
@ -3058,10 +3055,18 @@ bool CWallet::CreateTransaction(const std::vector<CRecipient>& vecSend, CWalletT
/** /**
* Call after CreateTransaction unless you want to abort * Call after CreateTransaction unless you want to abort
*/ */
bool CWallet::CommitTransaction(CWalletTx& wtxNew, CReserveKey& reservekey, CConnman* connman, CValidationState& state) bool CWallet::CommitTransaction(CTransactionRef tx, mapValue_t mapValue, std::vector<std::pair<std::string, std::string>> orderForm, std::string fromAccount, CReserveKey& reservekey, CConnman* connman, CValidationState& state)
{ {
{ {
LOCK2(cs_main, cs_wallet); LOCK2(cs_main, cs_wallet);
CWalletTx wtxNew(this, std::move(tx));
wtxNew.mapValue = std::move(mapValue);
wtxNew.vOrderForm = std::move(orderForm);
wtxNew.strFromAccount = std::move(fromAccount);
wtxNew.fTimeReceivedIsTxTime = true;
wtxNew.fFromMe = true;
LogPrintf("CommitTransaction:\n%s", wtxNew.tx->ToString()); LogPrintf("CommitTransaction:\n%s", wtxNew.tx->ToString());
{ {
// Take key pair from key pool so it won't be used again // Take key pair from key pool so it won't be used again
@ -3074,7 +3079,7 @@ bool CWallet::CommitTransaction(CWalletTx& wtxNew, CReserveKey& reservekey, CCon
// Notify that old coins are spent // Notify that old coins are spent
for (const CTxIn& txin : wtxNew.tx->vin) for (const CTxIn& txin : wtxNew.tx->vin)
{ {
CWalletTx &coin = mapWallet[txin.prevout.hash]; CWalletTx &coin = mapWallet.at(txin.prevout.hash);
coin.BindWallet(this); coin.BindWallet(this);
NotifyTransactionChanged(this, coin.GetHash(), CT_UPDATED); NotifyTransactionChanged(this, coin.GetHash(), CT_UPDATED);
} }
@ -3085,7 +3090,7 @@ bool CWallet::CommitTransaction(CWalletTx& wtxNew, CReserveKey& reservekey, CCon
// Get the inserted-CWalletTx from mapWallet so that the // Get the inserted-CWalletTx from mapWallet so that the
// fInMempool flag is cached properly // fInMempool flag is cached properly
CWalletTx& wtx = mapWallet[wtxNew.GetHash()]; CWalletTx& wtx = mapWallet.at(wtxNew.GetHash());
if (fBroadcastTransactions) if (fBroadcastTransactions)
{ {
@ -3541,7 +3546,7 @@ std::set< std::set<CTxDestination> > CWallet::GetAddressGroupings()
CTxDestination address; CTxDestination address;
if(!IsMine(txin)) /* If this input isn't mine, ignore it */ if(!IsMine(txin)) /* If this input isn't mine, ignore it */
continue; continue;
if(!ExtractDestination(mapWallet[txin.prevout.hash].tx->vout[txin.prevout.n].scriptPubKey, address)) if(!ExtractDestination(mapWallet.at(txin.prevout.hash).tx->vout[txin.prevout.n].scriptPubKey, address))
continue; continue;
grouping.insert(address); grouping.insert(address);
any_mine = true; any_mine = true;

View file

@ -348,11 +348,6 @@ public:
mutable CAmount nAvailableWatchCreditCached; mutable CAmount nAvailableWatchCreditCached;
mutable CAmount nChangeCached; mutable CAmount nChangeCached;
CWalletTx()
{
Init(nullptr);
}
CWalletTx(const CWallet* pwalletIn, CTransactionRef arg) : CMerkleTx(std::move(arg)) CWalletTx(const CWallet* pwalletIn, CTransactionRef arg) : CMerkleTx(std::move(arg))
{ {
Init(pwalletIn); Init(pwalletIn);
@ -969,9 +964,9 @@ public:
* selected by SelectCoins(); Also create the change output, when needed * selected by SelectCoins(); Also create the change output, when needed
* @note passing nChangePosInOut as -1 will result in setting a random position * @note passing nChangePosInOut as -1 will result in setting a random position
*/ */
bool CreateTransaction(const std::vector<CRecipient>& vecSend, CWalletTx& wtxNew, CReserveKey& reservekey, CAmount& nFeeRet, int& nChangePosInOut, bool CreateTransaction(const std::vector<CRecipient>& vecSend, CTransactionRef& tx, CReserveKey& reservekey, CAmount& nFeeRet, int& nChangePosInOut,
std::string& strFailReason, const CCoinControl& coin_control, bool sign = true); std::string& strFailReason, const CCoinControl& coin_control, bool sign = true);
bool CommitTransaction(CWalletTx& wtxNew, CReserveKey& reservekey, CConnman* connman, CValidationState& state); bool CommitTransaction(CTransactionRef tx, mapValue_t mapValue, std::vector<std::pair<std::string, std::string>> orderForm, std::string fromAccount, CReserveKey& reservekey, CConnman* connman, CValidationState& state);
void ListAccountCreditDebit(const std::string& strAccount, std::list<CAccountingEntry>& entries); void ListAccountCreditDebit(const std::string& strAccount, std::list<CAccountingEntry>& entries);
bool AddAccountingEntry(const CAccountingEntry&); bool AddAccountingEntry(const CAccountingEntry&);

View file

@ -265,7 +265,7 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue,
{ {
uint256 hash; uint256 hash;
ssKey >> hash; ssKey >> hash;
CWalletTx wtx; CWalletTx wtx(nullptr /* pwallet */, MakeTransactionRef());
ssValue >> wtx; ssValue >> wtx;
CValidationState state; CValidationState state;
if (!(CheckTransaction(*wtx.tx, state) && (wtx.GetHash() == hash) && state.IsValid())) if (!(CheckTransaction(*wtx.tx, state) && (wtx.GetHash() == hash) && state.IsValid()))
@ -603,7 +603,7 @@ DBErrors CWalletDB::LoadWallet(CWallet* pwallet)
pwallet->UpdateTimeFirstKey(1); pwallet->UpdateTimeFirstKey(1);
for (uint256 hash : wss.vWalletUpgrade) for (uint256 hash : wss.vWalletUpgrade)
WriteTx(pwallet->mapWallet[hash]); WriteTx(pwallet->mapWallet.at(hash));
// Rewrite encrypted wallets of versions 0.4.0 and 0.5.0rc: // Rewrite encrypted wallets of versions 0.4.0 and 0.5.0rc:
if (wss.fIsEncrypted && (wss.nFileVersion == 40000 || wss.nFileVersion == 50000)) if (wss.fIsEncrypted && (wss.nFileVersion == 40000 || wss.nFileVersion == 50000))
@ -664,7 +664,7 @@ DBErrors CWalletDB::FindWalletTx(std::vector<uint256>& vTxHash, std::vector<CWal
uint256 hash; uint256 hash;
ssKey >> hash; ssKey >> hash;
CWalletTx wtx; CWalletTx wtx(nullptr /* pwallet */, MakeTransactionRef());
ssValue >> wtx; ssValue >> wtx;
vTxHash.push_back(hash); vTxHash.push_back(hash);