From 8a64acebf3d996de676f935cb11d551d60a42552 Mon Sep 17 00:00:00 2001 From: furszy Date: Wed, 9 Dec 2020 03:08:25 -0300 Subject: [PATCH] Make CWalletTx store a CTransactionRef --- src/qt/pivx/coldstakingmodel.cpp | 2 +- src/qt/pivx/masternodewizarddialog.cpp | 4 +- src/qt/pivx/sendconfirmdialog.cpp | 28 +-- src/qt/transactionrecord.cpp | 94 ++++----- src/qt/walletmodel.cpp | 8 +- src/sapling/sapling_operation.cpp | 8 +- src/sapling/saplingscriptpubkeyman.cpp | 32 +-- src/test/librust/sapling_rpc_wallet_tests.cpp | 2 +- src/test/librust/sapling_wallet_tests.cpp | 36 ++-- src/test/librust/utiltest.cpp | 2 +- src/wallet/rpcwallet.cpp | 40 ++-- .../test/wallet_shielded_balances_tests.cpp | 12 +- src/wallet/test/wallet_tests.cpp | 4 +- src/wallet/wallet.cpp | 193 +++++++++--------- src/wallet/wallet.h | 30 ++- 15 files changed, 250 insertions(+), 245 deletions(-) diff --git a/src/qt/pivx/coldstakingmodel.cpp b/src/qt/pivx/coldstakingmodel.cpp index d67c4a3f0ca216..9b86108fbe4cfc 100644 --- a/src/qt/pivx/coldstakingmodel.cpp +++ b/src/qt/pivx/coldstakingmodel.cpp @@ -40,7 +40,7 @@ void ColdStakingModel::refresh() const auto *wtx = utxo.tx; const QString txId = QString::fromStdString(wtx->GetHash().GetHex()); - const CTxOut& out = wtx->vout[utxo.i]; + const CTxOut& out = wtx->tx->vout[utxo.i]; // First parse the cs delegation CSDelegation delegation; diff --git a/src/qt/pivx/masternodewizarddialog.cpp b/src/qt/pivx/masternodewizarddialog.cpp index 763693e8c583bb..81b70dab7ec57b 100644 --- a/src/qt/pivx/masternodewizarddialog.cpp +++ b/src/qt/pivx/masternodewizarddialog.cpp @@ -260,8 +260,8 @@ bool MasterNodeWizardDialog::createMN() CWalletTx* walletTx = currentTransaction.getTransaction(); std::string txID = walletTx->GetHash().GetHex(); int indexOut = -1; - for (int i=0; i < (int)walletTx->vout.size(); i++) { - CTxOut& out = walletTx->vout[i]; + for (int i=0; i < (int)walletTx->tx->vout.size(); i++) { + const CTxOut& out = walletTx->tx->vout[i]; if (out.nValue == 10000 * COIN) { indexOut = i; break; diff --git a/src/qt/pivx/sendconfirmdialog.cpp b/src/qt/pivx/sendconfirmdialog.cpp index a8b11b0a83864d..35065c6920e307 100644 --- a/src/qt/pivx/sendconfirmdialog.cpp +++ b/src/qt/pivx/sendconfirmdialog.cpp @@ -83,7 +83,7 @@ TxDetailDialog::TxDetailDialog(QWidget *parent, bool _isConfirmDialog, const QSt void TxDetailDialog::setInputsType(const CWalletTx* _tx) { - if (_tx->sapData && _tx->sapData->vShieldedSpend.empty()) { + if (_tx->tx->sapData && _tx->tx->sapData->vShieldedSpend.empty()) { ui->labelTitlePrevTx->setText(tr("Previous Transaction")); ui->labelOutputIndex->setText(tr("Output Index")); } else { @@ -110,11 +110,11 @@ void TxDetailDialog::setData(WalletModel *_model, const QModelIndex &index) ui->textId->setTextInteractionFlags(Qt::TextSelectableByMouse); // future: subdivide shielded and transparent by type and // do not show send xxx recipients for txes with a single output + change (show the address directly). - if (_tx->vout.size() == 1 || (_tx->sapData && _tx->sapData->vShieldedOutput.size() == 1)) { + if (_tx->tx->vout.size() == 1 || (_tx->tx->sapData && _tx->tx->sapData->vShieldedOutput.size() == 1)) { ui->textSendLabel->setText((address.size() < 40) ? address : address.left(20) + "..." + address.right(20)); } else { - ui->textSendLabel->setText(QString::number(_tx->vout.size() + - (_tx->sapData ? _tx->sapData->vShieldedOutput.size() : 0)) + " recipients"); + ui->textSendLabel->setText(QString::number(_tx->tx->vout.size() + + (_tx->tx->sapData ? _tx->tx->sapData->vShieldedOutput.size() : 0)) + " recipients"); } ui->textSend->setVisible(false); isShieldedToShieldedRecv = rec->type == TransactionRecord::Type::RecvWithShieldedAddress; @@ -127,7 +127,7 @@ void TxDetailDialog::setData(WalletModel *_model, const QModelIndex &index) } setInputsType(_tx); - int inputsSize = (_tx->sapData && !_tx->sapData->vShieldedSpend.empty()) ? _tx->sapData->vShieldedSpend.size() : _tx->vin.size(); + int inputsSize = (_tx->tx->sapData && !_tx->tx->sapData->vShieldedSpend.empty()) ? _tx->tx->sapData->vShieldedSpend.size() : _tx->tx->vin.size(); ui->textInputs->setText(QString::number(inputsSize) + shieldedInputsExtraMsg); ui->textConfirmations->setText(QString::number(rec->status.depth)); ui->textDate->setText(GUIUtil::dateTimeStrWithSeconds(date)); @@ -222,7 +222,7 @@ void TxDetailDialog::setData(WalletModel *_model, WalletModelTransaction* _tx) ui->labelDividerMemo->setVisible(false); } - int inputsSize = (walletTx->sapData && !walletTx->sapData->vShieldedSpend.empty()) ? walletTx->sapData->vShieldedSpend.size() : walletTx->vin.size(); + int inputsSize = (walletTx->tx->sapData && !walletTx->tx->sapData->vShieldedSpend.empty()) ? walletTx->tx->sapData->vShieldedSpend.size() : walletTx->tx->vin.size(); ui->textInputs->setText(QString::number(inputsSize)); ui->textFee->setText(BitcoinUnits::formatWithUnit(nDisplayUnit, txFee, false, BitcoinUnits::separatorAlways)); } @@ -258,11 +258,11 @@ void TxDetailDialog::onInputsClicked() if (showGrid) { const CWalletTx* walletTx = (this->tx) ? this->tx->getTransaction() : model->getTx(this->txHash); if (walletTx) { - if (walletTx->sapData && walletTx->sapData->vShieldedSpend.empty()) { + if (walletTx->tx->sapData && walletTx->tx->sapData->vShieldedSpend.empty()) { // transparent inputs - ui->gridInputs->setMinimumHeight(50 + (50 * walletTx->vin.size())); + ui->gridInputs->setMinimumHeight(50 + (50 * walletTx->tx->vin.size())); int i = 1; - for (const CTxIn& in : walletTx->vin) { + for (const CTxIn& in : walletTx->tx->vin) { QString hash = QString::fromStdString(in.prevout.hash.GetHex()); loadInputs(hash.left(18) + "..." + hash.right(18), QString::number(in.prevout.n), @@ -270,9 +270,9 @@ void TxDetailDialog::onInputsClicked() i++; } } else { - ui->gridInputs->setMinimumHeight(50 + (50 * walletTx->sapData->vShieldedSpend.size())); + ui->gridInputs->setMinimumHeight(50 + (50 * walletTx->tx->sapData->vShieldedSpend.size())); bool fInfoAvailable = false; - for (int i = 0; i < (int) walletTx->sapData->vShieldedSpend.size(); ++i) { + for (int i = 0; i < (int) walletTx->tx->sapData->vShieldedSpend.size(); ++i) { Optional opAddr = model->getShieldedAddressFromSpendDesc(walletTx, i); if (opAddr) { QString addr = *opAddr; @@ -334,7 +334,7 @@ void TxDetailDialog::onOutputsClicked() // transparent recipients int i = 0; - for (const CTxOut& out : walletTx->vout) { + for (const CTxOut& out : walletTx->tx->vout) { QString labelRes; CTxDestination dest; bool isCsAddress = out.scriptPubKey.IsPayToColdStaking(); @@ -350,8 +350,8 @@ void TxDetailDialog::onOutputsClicked() } // shielded recipients - if (walletTx->sapData) { - for (int j = 0; j < (int) walletTx->sapData->vShieldedOutput.size(); ++j) { + if (walletTx->tx->sapData) { + for (int j = 0; j < (int) walletTx->tx->sapData->vShieldedOutput.size(); ++j) { const SaplingOutPoint op(walletTx->GetHash(), j); // TODO: This only works for txs that are stored, not for when this is a confirmation dialog.. if (walletTx->mapSaplingNoteData.find(op) == walletTx->mapSaplingNoteData.end()) { diff --git a/src/qt/transactionrecord.cpp b/src/qt/transactionrecord.cpp index acc6ec0774c08e..60f48b017383e6 100644 --- a/src/qt/transactionrecord.cpp +++ b/src/qt/transactionrecord.cpp @@ -30,18 +30,18 @@ bool TransactionRecord::decomposeCoinStake(const CWallet* wallet, const CWalletT } const uint256& hash = wtx.GetHash(); - TransactionRecord sub(hash, wtx.GetTxTime(), wtx.GetTotalSize()); + TransactionRecord sub(hash, wtx.GetTxTime(), wtx.tx->GetTotalSize()); - if (isminetype mine = wallet->IsMine(wtx.vout[1])) { + if (isminetype mine = wallet->IsMine(wtx.tx->vout[1])) { // Check for cold stakes. - if (wtx.HasP2CSOutputs()) { + if (wtx.tx->HasP2CSOutputs()) { sub.credit = nCredit; sub.debit = -nDebit; loadHotOrColdStakeOrContract(wallet, wtx, sub); } else { // PIV stake reward CTxDestination address; - if (!ExtractDestination(wtx.vout[1].scriptPubKey, address)) + if (!ExtractDestination(wtx.tx->vout[1].scriptPubKey, address)) return true; sub.involvesWatchAddress = mine & ISMINE_WATCH_ONLY; @@ -52,12 +52,12 @@ bool TransactionRecord::decomposeCoinStake(const CWallet* wallet, const CWalletT } else { //Masternode reward CTxDestination destMN; - int nIndexMN = (int) wtx.vout.size() - 1; - if (ExtractDestination(wtx.vout[nIndexMN].scriptPubKey, destMN) && (mine = IsMine(*wallet, destMN)) ) { + int nIndexMN = (int) wtx.tx->vout.size() - 1; + if (ExtractDestination(wtx.tx->vout[nIndexMN].scriptPubKey, destMN) && (mine = IsMine(*wallet, destMN)) ) { sub.involvesWatchAddress = mine & ISMINE_WATCH_ONLY; sub.type = TransactionRecord::MNReward; sub.address = EncodeDestination(destMN); - sub.credit = wtx.vout[nIndexMN].nValue; + sub.credit = wtx.tx->vout[nIndexMN].nValue; } } @@ -71,7 +71,7 @@ bool TransactionRecord::decomposeZcSpendTx(const CWallet* wallet, const CWalletT { // Return if it's not a zc spend - if (!wtx.HasZerocoinSpendInputs()) { + if (!wtx.tx->HasZerocoinSpendInputs()) { return false; } @@ -80,8 +80,8 @@ bool TransactionRecord::decomposeZcSpendTx(const CWallet* wallet, const CWalletT int64_t nTime = wtx.GetTxTime(); //zerocoin spend outputs - for (unsigned int nOut = 0; nOut < wtx.vout.size(); nOut++) { - const CTxOut& txout = wtx.vout[nOut]; + for (unsigned int nOut = 0; nOut < wtx.tx->vout.size(); nOut++) { + const CTxOut& txout = wtx.tx->vout[nOut]; // change that was reminted as zerocoins if (txout.IsZerocoinMint()) { continue; @@ -95,7 +95,7 @@ bool TransactionRecord::decomposeZcSpendTx(const CWallet* wallet, const CWalletT // a zerocoinspend that was sent to an address held by this wallet isminetype mine = wallet->IsMine(txout); if (mine) { - TransactionRecord sub(hash, nTime, wtx.GetTotalSize()); + TransactionRecord sub(hash, nTime, wtx.tx->GetTotalSize()); sub.involvesWatchAddress = mine & ISMINE_WATCH_ONLY; sub.type = TransactionRecord::RecvFromZerocoinSpend; sub.credit = txout.nValue; @@ -112,9 +112,9 @@ bool TransactionRecord::decomposeP2CS(const CWallet* wallet, const CWalletTx& wt const CAmount& nCredit, const CAmount& nDebit, QList& parts) { - if (wtx.HasP2CSOutputs()) { + if (wtx.tx->HasP2CSOutputs()) { // Delegate tx. - TransactionRecord sub(wtx.GetHash(), wtx.GetTxTime(), wtx.GetTotalSize()); + TransactionRecord sub(wtx.GetHash(), wtx.GetTxTime(), wtx.tx->GetTotalSize()); sub.credit = nCredit; sub.debit = -nDebit; loadHotOrColdStakeOrContract(wallet, wtx, sub, true); @@ -122,7 +122,7 @@ bool TransactionRecord::decomposeP2CS(const CWallet* wallet, const CWalletTx& wt return true; } else if (wtx.HasP2CSInputs()) { // Delegation unlocked - TransactionRecord sub(wtx.GetHash(), wtx.GetTxTime(), wtx.GetTotalSize()); + TransactionRecord sub(wtx.GetHash(), wtx.GetTxTime(), wtx.tx->GetTotalSize()); loadUnlockColdStake(wallet, wtx, sub); parts.append(sub); return true; @@ -135,9 +135,9 @@ bool TransactionRecord::decomposeP2CS(const CWallet* wallet, const CWalletTx& wt */ bool TransactionRecord::decomposeCreditTransaction(const CWallet* wallet, const CWalletTx& wtx, QList& parts) { - TransactionRecord sub(wtx.GetHash(), wtx.GetTxTime(), wtx.GetTotalSize()); - for (unsigned int nOut = 0; nOut < wtx.vout.size(); nOut++) { - const CTxOut& txout = wtx.vout[nOut]; + TransactionRecord sub(wtx.GetHash(), wtx.GetTxTime(), wtx.tx->GetTotalSize()); + for (unsigned int nOut = 0; nOut < wtx.tx->vout.size(); nOut++) { + const CTxOut& txout = wtx.tx->vout[nOut]; isminetype mine = wallet->IsMine(txout); if (mine) { CTxDestination address; @@ -162,9 +162,9 @@ bool TransactionRecord::decomposeCreditTransaction(const CWallet* wallet, const } } - if (wtx.hasSaplingData()) { + if (wtx.tx->hasSaplingData()) { auto sspkm = wallet->GetSaplingScriptPubKeyMan(); - for (int i = 0; i < (int) wtx.sapData->vShieldedOutput.size(); ++i) { + for (int i = 0; i < (int) wtx.tx->sapData->vShieldedOutput.size(); ++i) { SaplingOutPoint out(sub.hash, i); auto opAddr = sspkm->GetOutPointAddress(wtx, out); if (opAddr) { @@ -191,21 +191,21 @@ bool TransactionRecord::decomposeSendToSelfTransaction(const CWalletTx& wtx, con QList& parts, const CWallet* wallet) { // Payment to self tx is presented as a single record. - TransactionRecord sub(wtx.GetHash(), wtx.GetTxTime(), wtx.GetTotalSize()); + TransactionRecord sub(wtx.GetHash(), wtx.GetTxTime(), wtx.tx->GetTotalSize()); sub.address = ""; CAmount nChange = wtx.GetChange(); - if (!wtx.hasSaplingData()) { + if (!wtx.tx->hasSaplingData()) { sub.type = TransactionRecord::SendToSelf; // Label for payment to self CTxDestination address; - if (ExtractDestination(wtx.vout[0].scriptPubKey, address)) { + if (ExtractDestination(wtx.tx->vout[0].scriptPubKey, address)) { sub.address = EncodeDestination(address); } } else { // we know that all of the inputs and outputs are mine and that have shielded data. // Let's see if only have transparent inputs, so we know that this is a // transparent -> shield transaction - if (wtx.sapData->vShieldedSpend.empty()) { + if (wtx.tx->sapData->vShieldedSpend.empty()) { sub.type = TransactionRecord::SendToSelfShieldedAddress; sub.shieldedCredit = wtx.GetCredit(ISMINE_SPENDABLE_SHIELDED); nChange += wtx.GetShieldedChange(); @@ -221,11 +221,11 @@ bool TransactionRecord::decomposeSendToSelfTransaction(const CWalletTx& wtx, con // we know that the inputs are shielded now, let's see if // if we have transparent outputs. if we have then we are converting back coins, // from shield to transparent - if (!wtx.vout.empty()) { + if (!wtx.tx->vout.empty()) { sub.type = TransactionRecord::SendToSelfShieldToTransparent; // Label for payment to self CTxDestination address; - if (ExtractDestination(wtx.vout[0].scriptPubKey, address)) { + if (ExtractDestination(wtx.tx->vout[0].scriptPubKey, address)) { sub.address = EncodeDestination(address); } // little hack to show the correct amount @@ -249,13 +249,13 @@ bool TransactionRecord::decomposeShieldedDebitTransaction(const CWallet* wallet, bool involvesWatchAddress, QList& parts) { // Return early if there are no outputs. - if (wtx.sapData->vShieldedOutput.empty()) { + if (wtx.tx->sapData->vShieldedOutput.empty()) { return false; } - TransactionRecord sub(wtx.GetHash(), wtx.GetTxTime(), wtx.GetTotalSize()); + TransactionRecord sub(wtx.GetHash(), wtx.GetTxTime(), wtx.tx->GetTotalSize()); auto sspkm = wallet->GetSaplingScriptPubKeyMan(); - for (int i = 0; i < (int) wtx.sapData->vShieldedOutput.size(); ++i) { + for (int i = 0; i < (int) wtx.tx->sapData->vShieldedOutput.size(); ++i) { SaplingOutPoint out(sub.hash, i); auto opAddr = sspkm->GetOutPointAddress(wtx, out); // skip change @@ -287,19 +287,19 @@ bool TransactionRecord::decomposeDebitTransaction(const CWallet* wallet, const C QList& parts) { // Return early if there are no outputs. - if (wtx.vout.empty() && wtx.sapData->vShieldedOutput.empty()) { + if (wtx.tx->vout.empty() && wtx.tx->sapData->vShieldedOutput.empty()) { return false; } // GetValueOut is the sum of transparent outs and negative sapValueBalance (shielded outs minus shielded spends). // Therefore to get the sum of the whole outputs of the tx, must re-add the shielded inputs spent to it - CAmount nTxFee = nDebit - (wtx.GetValueOut() + wtx.GetDebit(ISMINE_SPENDABLE_SHIELDED | ISMINE_WATCH_ONLY_SHIELDED)); - unsigned int txSize = wtx.GetTotalSize(); + CAmount nTxFee = nDebit - (wtx.tx->GetValueOut() + wtx.GetDebit(ISMINE_SPENDABLE_SHIELDED | ISMINE_WATCH_ONLY_SHIELDED)); + unsigned int txSize = wtx.tx->GetTotalSize(); const uint256& txHash = wtx.GetHash(); const int64_t txTime = wtx.GetTxTime(); - for (unsigned int nOut = 0; nOut < wtx.vout.size(); nOut++) { - const CTxOut& txout = wtx.vout[nOut]; + for (unsigned int nOut = 0; nOut < wtx.tx->vout.size(); nOut++) { + const CTxOut& txout = wtx.tx->vout[nOut]; if (wallet->IsMine(txout)) { // Ignore parts sent to self, as this is usually the change @@ -316,7 +316,7 @@ bool TransactionRecord::decomposeDebitTransaction(const CWallet* wallet, const C if (ExtractDestination(txout.scriptPubKey, address)) { //This is most likely only going to happen when resyncing deterministic wallet without the knowledge of the //private keys that the change was sent to. Do not display a "sent to" here. - if (wtx.HasZerocoinMintOutputs()) + if (wtx.tx->HasZerocoinMintOutputs()) continue; // Sent to PIVX Address sub.type = TransactionRecord::SendToAddress; @@ -351,7 +351,7 @@ std::pair areInputsAndOutputsFromAndToMe(const CWalletTx& wtx, Sapli { // Check if all the shielded spends are from me bool allShieldedSpendsFromMe = true; - for (const auto& spend : wtx.sapData->vShieldedSpend) { + for (const auto& spend : wtx.tx->sapData->vShieldedSpend) { if (!sspkm->IsSaplingNullifierFromMe(spend.nullifier)) { allShieldedSpendsFromMe = false; break; @@ -360,7 +360,7 @@ std::pair areInputsAndOutputsFromAndToMe(const CWalletTx& wtx, Sapli // Check if all the shielded outputs are to me bool allShieldedOutToMe = true; - for (int i = 0; i < (int) wtx.sapData->vShieldedOutput.size(); ++i) { + for (int i = 0; i < (int) wtx.tx->sapData->vShieldedOutput.size(); ++i) { SaplingOutPoint op(wtx.GetHash(), i); isminetype mine = sspkm->IsMine(wtx, op); if (mine & ISMINE_WATCH_ONLY_SHIELDED) involvesWatchAddress = true; @@ -412,14 +412,14 @@ QList TransactionRecord::decomposeTransaction(const CWallet* bool involvesWatchAddress = false; isminetype fAllFromMe = ISMINE_SPENDABLE; - for (const CTxIn& txin : wtx.vin) { + for (const CTxIn& txin : wtx.tx->vin) { isminetype mine = wallet->IsMine(txin); if (mine & ISMINE_WATCH_ONLY) involvesWatchAddress = true; if (fAllFromMe > mine) fAllFromMe = mine; } isminetype fAllToMe = ISMINE_SPENDABLE; - for (const CTxOut& txout : wtx.vout) { + for (const CTxOut& txout : wtx.tx->vout) { isminetype mine = wallet->IsMine(txout); if (mine & ISMINE_WATCH_ONLY) involvesWatchAddress = true; if (fAllToMe > mine) fAllToMe = mine; @@ -439,14 +439,14 @@ QList TransactionRecord::decomposeTransaction(const CWallet* } // Check if the tx is debit and decompose it. - if (fAllFromMe || wtx.HasZerocoinMintOutputs()) { + if (fAllFromMe || wtx.tx->HasZerocoinMintOutputs()) { if (decomposeDebitTransaction(wallet, wtx, nDebit, involvesWatchAddress, parts)) { return parts; } } // if we get to this point, we have a mixed debit transaction, can't break down payees. - TransactionRecord record(wtx.GetHash(), wtx.GetTxTime(), wtx.GetTotalSize(), TransactionRecord::Other, "", nNet, 0); + TransactionRecord record(wtx.GetHash(), wtx.GetTxTime(), wtx.tx->GetTotalSize(), TransactionRecord::Other, "", nNet, 0); record.involvesWatchAddress = involvesWatchAddress; parts.append(record); return parts; @@ -475,10 +475,10 @@ void TransactionRecord::loadUnlockColdStake(const CWallet* wallet, const CWallet const CScript* p2csScript = nullptr; bool isSpendable = false; - for (const auto &input : wtx.vin) { + for (const auto &input : wtx.tx->vin) { const CWalletTx* tx = wallet->GetWalletTx(input.prevout.hash); - if (tx && tx->vout[input.prevout.n].scriptPubKey.IsPayToColdStaking()) { - p2csScript = &tx->vout[input.prevout.n].scriptPubKey; + if (tx && tx->tx->vout[input.prevout.n].scriptPubKey.IsPayToColdStaking()) { + p2csScript = &tx->tx->vout[input.prevout.n].scriptPubKey; isSpendable = wallet->IsMine(input) & ISMINE_SPENDABLE_ALL; break; } @@ -512,7 +512,7 @@ void TransactionRecord::loadHotOrColdStakeOrContract( // Get the p2cs CTxOut p2csUtxo; - for (const auto & txout : wtx.vout) { + for (const auto & txout : wtx.tx->vout) { if (txout.scriptPubKey.IsPayToColdStaking()) { p2csUtxo = txout; break; @@ -599,12 +599,12 @@ void TransactionRecord::updateStatus(const CWalletTx& wtx) status.depth = depth; if (!IsFinalTx(wtx, chainHeight + 1)) { - if (wtx.nLockTime < LOCKTIME_THRESHOLD) { + if (wtx.tx->nLockTime < LOCKTIME_THRESHOLD) { status.status = TransactionStatus::OpenUntilBlock; - status.open_for = wtx.nLockTime - chainHeight; + status.open_for = wtx.tx->nLockTime - chainHeight; } else { status.status = TransactionStatus::OpenUntilDate; - status.open_for = wtx.nLockTime; + status.open_for = wtx.tx->nLockTime; } } // For generated transactions, determine maturity diff --git a/src/qt/walletmodel.cpp b/src/qt/walletmodel.cpp index 70b6f013752f7f..bb0d3f381c3e78 100644 --- a/src/qt/walletmodel.cpp +++ b/src/qt/walletmodel.cpp @@ -122,7 +122,7 @@ CAmount WalletModel::getBalance(const CCoinControl* coinControl, bool fIncludeDe for (const COutput& out : vCoins) { bool fSkip = fUnlockedOnly && isLockedCoin(out.tx->GetHash(), out.i); if (out.fSpendable && !fSkip) - nBalance += out.tx->vout[out.i].nValue; + nBalance += out.tx->tx->vout[out.i].nValue; } return nBalance; @@ -574,7 +574,7 @@ OperationResult WalletModel::PrepareShieldedTransaction(WalletModelTransaction* } // load the transaction and key change (if needed) - modelTransaction->setTransaction(new CWalletTx(wallet, operation.getFinalTx())); + modelTransaction->setTransaction(new CWalletTx(wallet, MakeTransactionRef(operation.getFinalTx()))); modelTransaction->setTransactionFee(operation.getFee()); // in the future, fee will be dynamically calculated. return operationResult; } @@ -981,7 +981,7 @@ void WalletModel::listCoins(std::map>& for (const COutput& out : vCoins) { if (!out.fSpendable) continue; - const CScript& scriptPubKey = out.tx->vout[out.i].scriptPubKey; + const CScript& scriptPubKey = out.tx->tx->vout[out.i].scriptPubKey; const bool isP2CS = scriptPubKey.IsPayToColdStaking(); CTxDestination outputAddress; @@ -1006,7 +1006,7 @@ void WalletModel::listCoins(std::map>& ListCoinsValue value{ out.tx->GetHash(), out.i, - out.tx->vout[out.i].nValue, + out.tx->tx->vout[out.i].nValue, out.tx->GetTxTime(), out.nDepth }; diff --git a/src/sapling/sapling_operation.cpp b/src/sapling/sapling_operation.cpp index 3e397f9d4a736d..2152363ac6c025 100644 --- a/src/sapling/sapling_operation.cpp +++ b/src/sapling/sapling_operation.cpp @@ -218,7 +218,7 @@ OperationResult SaplingOperation::build() OperationResult SaplingOperation::send(std::string& retTxHash) { - CWalletTx wtx(pwalletMain, finalTx); + CWalletTx wtx(pwalletMain, MakeTransactionRef(finalTx)); const CWallet::CommitResult& res = pwalletMain->CommitTransaction(wtx, tkeyChange, g_connman.get()); if (res.status != CWallet::CommitStatus::OK) { return errorOut(res.ToString()); @@ -265,7 +265,7 @@ OperationResult SaplingOperation::loadUtxos(TxValues& txValues) for (const auto& outpoint : vCoins) { const auto* tx = pwalletMain->GetWalletTx(outpoint.outPoint.hash); if (!tx) continue; - nSelectedValue += tx->vout[outpoint.outPoint.n].nValue; + nSelectedValue += tx->tx->vout[outpoint.outPoint.n].nValue; selectedUTXOInputs.emplace_back(tx, outpoint.outPoint.n, 0, true, true); } return loadUtxos(txValues, selectedUTXOInputs, nSelectedValue); @@ -299,7 +299,7 @@ OperationResult SaplingOperation::loadUtxos(TxValues& txValues) CAmount selectedUTXOAmount = 0; std::vector selectedTInputs; for (const COutput& t : transInputs) { - const auto& outPoint = t.tx->vout[t.i]; + const auto& outPoint = t.tx->tx->vout[t.i]; selectedUTXOAmount += outPoint.nValue; selectedTInputs.emplace_back(t); if (selectedUTXOAmount >= txValues.target) { @@ -333,7 +333,7 @@ OperationResult SaplingOperation::loadUtxos(TxValues& txValues, const std::vecto // update the transaction with these inputs for (const auto& t : transInputs) { - const auto& outPoint = t.tx->vout[t.i]; + const auto& outPoint = t.tx->tx->vout[t.i]; txBuilder.AddTransparentInput(COutPoint(t.tx->GetHash(), t.i), outPoint.scriptPubKey, outPoint.nValue); } return OperationResult(true); diff --git a/src/sapling/saplingscriptpubkeyman.cpp b/src/sapling/saplingscriptpubkeyman.cpp index 2e2f8f8bb0b76f..d04bd75f5c794f 100644 --- a/src/sapling/saplingscriptpubkeyman.cpp +++ b/src/sapling/saplingscriptpubkeyman.cpp @@ -71,7 +71,7 @@ void SaplingScriptPubKeyMan::UpdateSaplingNullifierNoteMapWithTx(CWalletTx& wtx) const libzcash::SaplingIncomingViewingKey& ivk = *(nd.ivk); uint64_t position = nd.witnesses.front().position(); auto extfvk = wallet->mapSaplingFullViewingKeys.at(ivk); - OutputDescription output = wtx.sapData->vShieldedOutput[op.n]; + OutputDescription output = wtx.tx->sapData->vShieldedOutput[op.n]; auto optPlaintext = libzcash::SaplingNotePlaintext::decrypt(output.encCiphertext, ivk, output.ephemeralKey, output.cmu); if (!optPlaintext) { // An item in mapSaplingNoteData must have already been successfully decrypted, @@ -413,7 +413,7 @@ void SaplingScriptPubKeyMan::GetNotes(const std::vector& saplin if (!nd.IsMyNote()) continue; const libzcash::SaplingIncomingViewingKey& ivk = *(nd.ivk); - const OutputDescription& outDesc = wtx->sapData->vShieldedOutput[op.n]; + const OutputDescription& outDesc = wtx->tx->sapData->vShieldedOutput[op.n]; auto maybe_pt = libzcash::SaplingNotePlaintext::decrypt( outDesc.encCiphertext, ivk, @@ -492,10 +492,10 @@ void SaplingScriptPubKeyMan::GetFilteredNotes( const libzcash::SaplingIncomingViewingKey& ivk = *(nd.ivk); auto maybe_pt = libzcash::SaplingNotePlaintext::decrypt( - wtx.sapData->vShieldedOutput[op.n].encCiphertext, + wtx.tx->sapData->vShieldedOutput[op.n].encCiphertext, ivk, - wtx.sapData->vShieldedOutput[op.n].ephemeralKey, - wtx.sapData->vShieldedOutput[op.n].cmu); + wtx.tx->sapData->vShieldedOutput[op.n].ephemeralKey, + wtx.tx->sapData->vShieldedOutput[op.n].cmu); assert(static_cast(maybe_pt)); auto notePt = maybe_pt.get(); @@ -531,9 +531,9 @@ void SaplingScriptPubKeyMan::GetFilteredNotes( Optional SaplingScriptPubKeyMan::GetAddressFromInputIfPossible(const CWalletTx* wtx, int index) const { - if (!wtx->sapData || wtx->sapData->vShieldedSpend.empty()) return nullopt; + if (!wtx->tx->sapData || wtx->tx->sapData->vShieldedSpend.empty()) return nullopt; - SpendDescription spendDesc = wtx->sapData->vShieldedSpend.at(index); + SpendDescription spendDesc = wtx->tx->sapData->vShieldedSpend.at(index); if (!IsSaplingNullifierFromMe(spendDesc.nullifier)) return nullopt; // Knowing that the spent note is from us, we can get the address from @@ -629,7 +629,7 @@ Optionalshield // tx for the first time, a failure to decode can happen only if this note was sent (from a t-addr) // using this wallet.dat on another computer (and never sent t->shield txes from this computer). - if (!tx.vin.empty()) { + if (!tx.tx->vin.empty()) { try { ovks.emplace(getCommonOVK()); } catch (...) { @@ -637,7 +637,7 @@ OptionalvShieldedSpend) { + for (const auto& spend : tx.tx->sapData->vShieldedSpend) { const auto& it = mapSaplingNullifiersToNotes.find(spend.nullifier); if (it != mapSaplingNullifiersToNotes.end()) { const SaplingOutPoint& prevOut = it->second; @@ -672,7 +672,7 @@ isminetype SaplingScriptPubKeyMan::IsMine(const CWalletTx& wtx, const SaplingOut CAmount SaplingScriptPubKeyMan::GetCredit(const CWalletTx& tx, const isminefilter& filter, const bool fUnspent) const { CAmount nCredit = 0; - for (int i = 0; i < (int) tx.sapData->vShieldedOutput.size(); ++i) { + for (int i = 0; i < (int) tx.tx->sapData->vShieldedOutput.size(); ++i) { SaplingOutPoint op(tx.GetHash(), i); if (tx.mapSaplingNoteData.find(op) == tx.mapSaplingNoteData.end()) { continue; @@ -720,13 +720,13 @@ CAmount SaplingScriptPubKeyMan::GetDebit(const CTransaction& tx, const isminefil CAmount SaplingScriptPubKeyMan::GetShieldedChange(const CWalletTx& wtx) const { - if (!wtx.isSaplingVersion() || wtx.sapData->vShieldedOutput.empty()) { + if (!wtx.tx->isSaplingVersion() || wtx.tx->sapData->vShieldedOutput.empty()) { return 0; } const uint256& txHash = wtx.GetHash(); CAmount nChange = 0; SaplingOutPoint op{txHash, 0}; - for (uint32_t pos = 0; pos < (uint32_t) wtx.sapData->vShieldedOutput.size(); ++pos) { + for (uint32_t pos = 0; pos < (uint32_t) wtx.tx->sapData->vShieldedOutput.size(); ++pos) { op.n = pos; if (!wtx.mapSaplingNoteData.count(op)) continue; const auto& nd = wtx.mapSaplingNoteData.at(op); @@ -759,8 +759,8 @@ bool SaplingScriptPubKeyMan::IsNoteSaplingChange(const std::setmapWallet[op.hash]; - if (tx.sapData) { - for (const SpendDescription& spend : tx.sapData->vShieldedSpend) { + if (tx.tx->sapData) { + for (const SpendDescription& spend : tx.tx->sapData->vShieldedSpend) { if (nullifierSet.count(std::make_pair(address, spend.nullifier))) { return true; } @@ -915,8 +915,8 @@ void SaplingScriptPubKeyMan::GetConflicts(const CWalletTx& wtx, std::setcs_wallet); std::pair range_o; - if (wtx.IsShieldedTx()) { - for (const SpendDescription& spend : wtx.sapData->vShieldedSpend) { + if (wtx.tx->IsShieldedTx()) { + for (const SpendDescription& spend : wtx.tx->sapData->vShieldedSpend) { const uint256& nullifier = spend.nullifier; if (mapTxSaplingNullifiers.count(nullifier) <= 1) { continue; // No conflict if zero or one spends diff --git a/src/test/librust/sapling_rpc_wallet_tests.cpp b/src/test/librust/sapling_rpc_wallet_tests.cpp index 630ace9499c537..0fe25474668572 100644 --- a/src/test/librust/sapling_rpc_wallet_tests.cpp +++ b/src/test/librust/sapling_rpc_wallet_tests.cpp @@ -408,7 +408,7 @@ BOOST_AUTO_TEST_CASE(rpc_shieldedsendmany_taddr_to_sapling) // Add a fake transaction to the wallet CMutableTransaction mtx; mtx.vout.emplace_back(5 * COIN, GetScriptForDestination(taddr)); - CWalletTx wtx(pwalletMain, mtx); + CWalletTx wtx(pwalletMain, MakeTransactionRef(mtx)); pwalletMain->LoadToWallet(wtx); // Fake-mine the transaction diff --git a/src/test/librust/sapling_wallet_tests.cpp b/src/test/librust/sapling_wallet_tests.cpp index e8ff87637cf1b3..d203c5120613cc 100644 --- a/src/test/librust/sapling_wallet_tests.cpp +++ b/src/test/librust/sapling_wallet_tests.cpp @@ -102,7 +102,7 @@ BOOST_AUTO_TEST_CASE(SetSaplingNoteAddrsInCWalletTx) { builder.SetFee(10000000); auto tx = builder.Build().GetTxOrThrow(); - CWalletTx wtx {&wallet, tx}; + CWalletTx wtx {&wallet, MakeTransactionRef(tx)}; BOOST_CHECK_EQUAL(0, wtx.mapSaplingNoteData.size()); mapSaplingNoteData_t noteData; @@ -165,7 +165,7 @@ BOOST_AUTO_TEST_CASE(FindMySaplingNotes) { auto tx = builder.Build().GetTxOrThrow(); // No Sapling notes can be found in tx which does not belong to the wallet - CWalletTx wtx {&wallet, tx}; + CWalletTx wtx {&wallet, MakeTransactionRef(tx)}; BOOST_CHECK(!wallet.HaveSaplingSpendingKey(extfvk)); auto noteMap = wallet.GetSaplingScriptPubKeyMan()->FindMySaplingNotes(wtx).first; BOOST_CHECK_EQUAL(0, noteMap.size()); @@ -212,7 +212,7 @@ BOOST_AUTO_TEST_CASE(GetConflictedSaplingNotes) { builder.AddSaplingOutput(extfvk.fvk.ovk, pk, 35000000, {}); builder.SetFee(10000000); auto tx = builder.Build().GetTxOrThrow(); - CWalletTx wtx {&wallet, tx}; + CWalletTx wtx {&wallet, MakeTransactionRef(tx)}; // Fake-mine the transaction BOOST_CHECK_EQUAL(0, chainActive.Height()); @@ -245,10 +245,10 @@ BOOST_AUTO_TEST_CASE(GetConflictedSaplingNotes) { // Decrypt output note B auto maybe_pt = libzcash::SaplingNotePlaintext::decrypt( - wtx.sapData->vShieldedOutput[0].encCiphertext, + wtx.tx->sapData->vShieldedOutput[0].encCiphertext, ivk, - wtx.sapData->vShieldedOutput[0].ephemeralKey, - wtx.sapData->vShieldedOutput[0].cmu); + wtx.tx->sapData->vShieldedOutput[0].ephemeralKey, + wtx.tx->sapData->vShieldedOutput[0].cmu); BOOST_CHECK(static_cast(maybe_pt) == true); auto maybe_note = maybe_pt.get().note(ivk); BOOST_CHECK(static_cast(maybe_note) == true); @@ -275,8 +275,8 @@ BOOST_AUTO_TEST_CASE(GetConflictedSaplingNotes) { builder3.AddSaplingOutput(extfvk.fvk.ovk, pk, 19999000, {}); auto tx3 = builder3.Build().GetTxOrThrow(); - CWalletTx wtx2 {&wallet, tx2}; - CWalletTx wtx3 {&wallet, tx3}; + CWalletTx wtx2 {&wallet, MakeTransactionRef(tx2)}; + CWalletTx wtx3 {&wallet, MakeTransactionRef(tx3)}; const auto& hash2 = wtx2.GetHash(); const auto& hash3 = wtx3.GetHash(); @@ -325,7 +325,7 @@ BOOST_AUTO_TEST_CASE(SaplingNullifierIsSpent) { builder.SetFee(10000000); auto tx = builder.Build().GetTxOrThrow(); - CWalletTx wtx {&wallet, tx}; + CWalletTx wtx {&wallet, MakeTransactionRef(tx)}; BOOST_CHECK(wallet.AddSaplingZKey(sk)); BOOST_CHECK(wallet.HaveSaplingSpendingKey(extfvk)); @@ -387,7 +387,7 @@ BOOST_AUTO_TEST_CASE(NavigateFromSaplingNullifierToNote) { builder.SetFee(10000000); auto tx = builder.Build().GetTxOrThrow(); - CWalletTx wtx {&wallet, tx}; + CWalletTx wtx {&wallet, MakeTransactionRef(tx)}; BOOST_CHECK(wallet.AddSaplingZKey(sk)); BOOST_CHECK(wallet.HaveSaplingSpendingKey(extfvk)); @@ -491,7 +491,7 @@ BOOST_AUTO_TEST_CASE(SpentSaplingNoteIsFromMe) { builder.SetFee(10000000); auto tx = builder.Build().GetTxOrThrow(); - CWalletTx wtx {&wallet, tx}; + CWalletTx wtx {&wallet, MakeTransactionRef(tx)}; BOOST_CHECK(wallet.AddSaplingZKey(sk)); BOOST_CHECK(wallet.HaveSaplingSpendingKey(extfvk)); @@ -536,10 +536,10 @@ BOOST_AUTO_TEST_CASE(SpentSaplingNoteIsFromMe) { // Decrypt note B auto maybe_pt = libzcash::SaplingNotePlaintext::decrypt( - wtx.sapData->vShieldedOutput[0].encCiphertext, + wtx.tx->sapData->vShieldedOutput[0].encCiphertext, ivk, - wtx.sapData->vShieldedOutput[0].ephemeralKey, - wtx.sapData->vShieldedOutput[0].cmu); + wtx.tx->sapData->vShieldedOutput[0].ephemeralKey, + wtx.tx->sapData->vShieldedOutput[0].cmu); BOOST_CHECK_EQUAL(static_cast(maybe_pt), true); auto maybe_note = maybe_pt.get().note(ivk); BOOST_CHECK_EQUAL(static_cast(maybe_note), true); @@ -568,7 +568,7 @@ BOOST_AUTO_TEST_CASE(SpentSaplingNoteIsFromMe) { BOOST_CHECK_EQUAL(tx2.sapData->vShieldedOutput.size(), 1); // 0.025 dust change added to the fee BOOST_CHECK_EQUAL(tx2.sapData->valueBalance, 12500000); // 0.025 dust change added to the fee - CWalletTx wtx2 {&wallet, tx2}; + CWalletTx wtx2 {&wallet, MakeTransactionRef(tx2)}; // Fake-mine this tx into the next block BOOST_CHECK_EQUAL(0, chainActive.Height()); @@ -945,7 +945,7 @@ BOOST_AUTO_TEST_CASE(UpdatedSaplingNoteData) { auto tx = builder.Build().GetTxOrThrow(); // Wallet contains extfvk1 but not extfvk2 - CWalletTx wtx {&wallet, tx}; + CWalletTx wtx {&wallet, MakeTransactionRef(tx)}; BOOST_CHECK(wallet.AddSaplingZKey(sk)); BOOST_CHECK(wallet.HaveSaplingSpendingKey(extfvk)); BOOST_CHECK(!wallet.HaveSaplingSpendingKey(extfvk2)); @@ -1063,7 +1063,7 @@ BOOST_AUTO_TEST_CASE(MarkAffectedSaplingTransactionsDirty) { BOOST_CHECK_EQUAL(tx1.sapData->vShieldedOutput.size(), 1); BOOST_CHECK_EQUAL(tx1.sapData->valueBalance, -40000000); - CWalletTx wtx {&wallet, tx1}; + CWalletTx wtx {&wallet, MakeTransactionRef(tx1)}; // Fake-mine the transaction BOOST_CHECK_EQUAL(0, chainActive.Height()); @@ -1118,7 +1118,7 @@ BOOST_AUTO_TEST_CASE(MarkAffectedSaplingTransactionsDirty) { BOOST_CHECK_EQUAL(tx2.sapData->vShieldedOutput.size(), 1); // 0.05 dust change added to the fee BOOST_CHECK_EQUAL(tx2.sapData->valueBalance, 15000000); // 0.05 dust change added to the fee - CWalletTx wtx2 {&wallet, tx2}; + CWalletTx wtx2 {&wallet, MakeTransactionRef(tx2)}; wallet.MarkAffectedTransactionsDirty(wtx); diff --git a/src/test/librust/utiltest.cpp b/src/test/librust/utiltest.cpp index 541989ca13093a..5d918f1b9c2510 100644 --- a/src/test/librust/utiltest.cpp +++ b/src/test/librust/utiltest.cpp @@ -76,7 +76,7 @@ CWalletTx GetValidSaplingReceive(const Consensus::Params& consensusParams, } CTransaction tx = builder.Build().GetTxOrThrow(); - CWalletTx wtx {pwalletIn, tx}; + CWalletTx wtx {pwalletIn, MakeTransactionRef(tx)}; return wtx; } diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index dc515daafd581e..275e27d5c01068 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -1085,7 +1085,7 @@ UniValue CreateColdStakeDelegation(const UniValue& params, CWalletTx& wtxNew, CR ->setRecipients(recipients) ->build(); if (!res) throw JSONRPCError(RPC_WALLET_ERROR, res.getError()); - wtxNew = CWalletTx(pwalletMain, operation.getFinalTx()); + wtxNew = CWalletTx(pwalletMain, MakeTransactionRef(operation.getFinalTx())); } UniValue result(UniValue::VOBJ); @@ -1339,7 +1339,7 @@ UniValue viewshieldedtransaction(const JSONRPCRequest& request) throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid or non-wallet transaction id"); const CWalletTx& wtx = pwalletMain->mapWallet[hash]; - if (!wtx.IsShieldedTx()) { + if (!wtx.tx->IsShieldedTx()) { throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid transaction, no shielded data available"); } @@ -1378,8 +1378,8 @@ UniValue viewshieldedtransaction(const JSONRPCRequest& request) ovks.insert(sspkm->getCommonOVK()); // Sapling spends - for (size_t i = 0; i < wtx.sapData->vShieldedSpend.size(); ++i) { - const auto& spend = wtx.sapData->vShieldedSpend[i]; + for (size_t i = 0; i < wtx.tx->sapData->vShieldedSpend.size(); ++i) { + const auto& spend = wtx.tx->sapData->vShieldedSpend[i]; // Fetch the note that is being spent auto res = sspkm->mapSaplingNullifiersToNotes.find(spend.nullifier); @@ -1416,7 +1416,7 @@ UniValue viewshieldedtransaction(const JSONRPCRequest& request) } // Sapling outputs - for (uint32_t i = 0; i < wtx.sapData->vShieldedOutput.size(); ++i) { + for (uint32_t i = 0; i < wtx.tx->sapData->vShieldedOutput.size(); ++i) { auto op = SaplingOutPoint(hash, i); if (!wtx.mapSaplingNoteData.count(op)) continue; const auto& nd = wtx.mapSaplingNoteData.at(op); @@ -1444,7 +1444,7 @@ UniValue viewshieldedtransaction(const JSONRPCRequest& request) outputs.push_back(entry_); } - entry.pushKV("fee", FormatMoney(pcoinsTip->GetValueIn(wtx) - wtx.GetValueOut())); + entry.pushKV("fee", FormatMoney(pcoinsTip->GetValueIn(wtx) - wtx.tx->GetValueOut())); entry.pushKV("spends", spends); entry.pushKV("outputs", outputs); @@ -1837,7 +1837,7 @@ UniValue getreceivedbyaddress(const JSONRPCRequest& request) if (wtx.IsCoinBase() || !IsFinalTx(wtx)) continue; - for (const CTxOut& txout : wtx.vout) + for (const CTxOut& txout : wtx.tx->vout) if (txout.scriptPubKey == scriptPubKey) if (wtx.GetDepthInMainChain() >= nMinDepth) nAmount += txout.nValue; @@ -1889,7 +1889,7 @@ UniValue getreceivedbylabel(const JSONRPCRequest& request) if (wtx.IsCoinBase() || !IsFinalTx(wtx)) continue; - for (const CTxOut& txout : wtx.vout) { + for (const CTxOut& txout : wtx.tx->vout) { CTxDestination address; if (ExtractDestination(txout.scriptPubKey, address) && IsMine(*pwalletMain, address) && setAddress.count(address)) if (wtx.GetDepthInMainChain() >= nMinDepth) @@ -2266,7 +2266,7 @@ UniValue ListReceived(const UniValue& params, bool by_label) if (nDepth < nMinDepth) continue; - for (const CTxOut& txout : wtx.vout) { + for (const CTxOut& txout : wtx.tx->vout) { CTxDestination address; if (!ExtractDestination(txout.scriptPubKey, address)) continue; @@ -2571,8 +2571,8 @@ UniValue listcoldutxos(const JSONRPCRequest& request) if(pcoin->GetColdStakingCredit() == 0 && pcoin->GetStakeDelegationCredit() == 0) continue; - for (unsigned int i = 0; i < pcoin->vout.size(); i++) { - const CTxOut& out = pcoin->vout[i]; + for (unsigned int i = 0; i < pcoin->tx->vout.size(); i++) { + const CTxOut& out = pcoin->tx->vout[i]; isminetype mine = pwalletMain->IsMine(out); if (!bool(mine & ISMINE_COLD) && !bool(mine & ISMINE_SPENDABLE_DELEGATED)) continue; @@ -2925,7 +2925,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.pushKV("amount", ValueFromAmount(nNet - nFee)); if (wtx.IsFromMe(filter)) @@ -3340,21 +3340,21 @@ UniValue listunspent(const JSONRPCRequest& request) if (destinations.size()) { CTxDestination address; - if (!ExtractDestination(out.tx->vout[out.i].scriptPubKey, address)) + if (!ExtractDestination(out.tx->tx->vout[out.i].scriptPubKey, address)) continue; if (!destinations.count(address)) continue; } - CAmount nValue = out.tx->vout[out.i].nValue; - const CScript& pk = out.tx->vout[out.i].scriptPubKey; + CAmount nValue = out.tx->tx->vout[out.i].nValue; + const CScript& pk = out.tx->tx->vout[out.i].scriptPubKey; UniValue entry(UniValue::VOBJ); entry.pushKV("txid", out.tx->GetHash().GetHex()); entry.pushKV("vout", out.i); entry.pushKV("generated", out.tx->IsCoinStake() || out.tx->IsCoinBase()); CTxDestination address; - if (ExtractDestination(out.tx->vout[out.i].scriptPubKey, address)) { + if (ExtractDestination(out.tx->tx->vout[out.i].scriptPubKey, address)) { entry.pushKV("address", EncodeDestination(address)); if (pwalletMain->HasAddressBook(address)) { entry.pushKV("label", pwalletMain->GetNameForAddressBookEntry(address)); @@ -3466,7 +3466,7 @@ UniValue lockunspent(const JSONRPCRequest& request) const CWalletTx& wtx = it->second; - if (outpt.n >= wtx.vout.size()) { + if (outpt.n >= wtx.tx->vout.size()) { throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, vout index out of bounds"); } @@ -3826,13 +3826,13 @@ UniValue printAddresses() std::map mapAddresses; for (const COutput& out : vCoins) { CTxDestination utxoAddress; - ExtractDestination(out.tx->vout[out.i].scriptPubKey, utxoAddress); + ExtractDestination(out.tx->tx->vout[out.i].scriptPubKey, utxoAddress); std::string strAdd = EncodeDestination(utxoAddress); if (mapAddresses.find(strAdd) == mapAddresses.end()) //if strAdd is not already part of the map - mapAddresses[strAdd] = (double)out.tx->vout[out.i].nValue / (double)COIN; + mapAddresses[strAdd] = (double)out.tx->tx->vout[out.i].nValue / (double)COIN; else - mapAddresses[strAdd] += (double)out.tx->vout[out.i].nValue / (double)COIN; + mapAddresses[strAdd] += (double)out.tx->tx->vout[out.i].nValue / (double)COIN; } UniValue ret(UniValue::VARR); diff --git a/src/wallet/test/wallet_shielded_balances_tests.cpp b/src/wallet/test/wallet_shielded_balances_tests.cpp index 490e492e5da364..684e7574741dc0 100644 --- a/src/wallet/test/wallet_shielded_balances_tests.cpp +++ b/src/wallet/test/wallet_shielded_balances_tests.cpp @@ -93,10 +93,10 @@ SaplingSpendValues UpdateWalletInternalNotesData(CWalletTx& wtx, SaplingOutPoint assert(nd.IsMyNote()); const auto& ivk = *(nd.ivk); auto maybe_pt = libzcash::SaplingNotePlaintext::decrypt( - wtx.sapData->vShieldedOutput[sapPoint.n].encCiphertext, + wtx.tx->sapData->vShieldedOutput[sapPoint.n].encCiphertext, ivk, - wtx.sapData->vShieldedOutput[sapPoint.n].ephemeralKey, - wtx.sapData->vShieldedOutput[sapPoint.n].cmu); + wtx.tx->sapData->vShieldedOutput[sapPoint.n].ephemeralKey, + wtx.tx->sapData->vShieldedOutput[sapPoint.n].cmu); assert(static_cast(maybe_pt)); boost::optional notePlainText = maybe_pt.get(); libzcash::SaplingNote note = notePlainText->note(ivk).get(); @@ -176,7 +176,7 @@ BOOST_AUTO_TEST_CASE(GetShieldedSimpleCachedCreditAndDebit) CTransaction tx = builder.Build().GetTxOrThrow(); // add tx to wallet and update it. - wallet.AddToWallet({&wallet, tx}); + wallet.AddToWallet({&wallet, MakeTransactionRef(tx)}); CWalletTx& wtxDebit = wallet.mapWallet[tx.GetHash()]; // Update tx notes data (shielded change need it) CWalletTx& wtxDebitUpdated = SetWalletNotesData(&wallet, wtxDebit); @@ -226,7 +226,7 @@ CWalletTx& buildTxAndLoadToWallet(CWallet& wallet, libzcash::SaplingExtendedSpen CTransaction tx = builder.Build().GetTxOrThrow(); // add tx to wallet and update it. - wallet.AddToWallet({&wallet, tx}); + wallet.AddToWallet({&wallet, MakeTransactionRef(tx)}); CWalletTx& wtx = wallet.mapWallet[tx.GetHash()]; // Update tx notes data and return the updated wtx. return SetWalletNotesData(&wallet, wtx); @@ -297,7 +297,7 @@ FakeBlock SimpleFakeMine(CWalletTx& wtx, SaplingMerkleTree& currentTree) fakeBlock.block.nVersion = 8; fakeBlock.block.vtx.emplace_back(MakeTransactionRef(wtx)); fakeBlock.block.hashMerkleRoot = BlockMerkleRoot(fakeBlock.block); - for (const OutputDescription& out : wtx.sapData->vShieldedOutput) { + for (const OutputDescription& out : wtx.tx->sapData->vShieldedOutput) { currentTree.append(out.cmu); } fakeBlock.block.hashFinalSaplingRoot = currentTree.root(); diff --git a/src/wallet/test/wallet_tests.cpp b/src/wallet/test/wallet_tests.cpp index 30380e2faf855a..d98392a5cc5a80 100644 --- a/src/wallet/test/wallet_tests.cpp +++ b/src/wallet/test/wallet_tests.cpp @@ -43,7 +43,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(pwalletMain, tx); + CWalletTx* wtx = new CWalletTx(pwalletMain, MakeTransactionRef(tx)); if (fIsFromMe) { wtx->m_amounts[CWalletTx::DEBIT].Set(ISMINE_SPENDABLE, 1); } @@ -352,7 +352,7 @@ CWalletTx& BuildAndLoadTxToWallet(const std::vector& vin, mTx.vin = vin; mTx.vout = vout; CTransaction tx(mTx); - wallet.LoadToWallet({&wallet, tx}); + wallet.LoadToWallet({&wallet, MakeTransactionRef(tx)}); return wallet.mapWallet[tx.GetHash()]; } diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index 25882c3f8a2974..11055e5bf20fcf 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -66,7 +66,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)); } //////////////////////////////////////////////////////////////////////////////////////////////////// @@ -490,7 +490,7 @@ void CWallet::SetBestChainInternal(CWalletDB& walletdb, const CBlockLocator& loc // transactions in which we only have transparent addresses involved. if (!wtx.mapSaplingNoteData.empty()) { // Sanity check - if (!wtx.isSaplingVersion()) { + if (!wtx.tx->isSaplingVersion()) { LogPrintf("SetBestChain(): ERROR, Invalid tx version found with sapling data\n"); walletdb.TxnAbort(); uiInterface.ThreadSafeMessageBox( @@ -579,8 +579,8 @@ std::set CWallet::GetConflicts(const uint256& txid) const std::pair range; - for (const CTxIn& txin : wtx.vin) { - if (mapTxSpends.count(txin.prevout) <= 1 || wtx.HasZerocoinSpendInputs()) + for (const CTxIn& txin : wtx.tx->vin) { + if (mapTxSpends.count(txin.prevout) <= 1 || wtx.tx->HasZerocoinSpendInputs()) continue; // No conflict if zero or one spends range = mapTxSpends.equal_range(txin.prevout); for (TxSpends::const_iterator it = range.first; it != range.second; ++it) @@ -756,11 +756,11 @@ void CWallet::AddToSpends(const uint256& wtxid) if (thisTx.IsCoinBase()) // Coinbases don't spend anything! return; - for (const CTxIn& txin : thisTx.vin) + for (const CTxIn& txin : thisTx.tx->vin) AddToSpends(txin.prevout, wtxid); - if (CanSupportFeature(FEATURE_SAPLING) && thisTx.sapData) { - for (const SpendDescription &spend : thisTx.sapData->vShieldedSpend) { + if (CanSupportFeature(FEATURE_SAPLING) && thisTx.tx->sapData) { + for (const SpendDescription &spend : thisTx.tx->sapData->vShieldedSpend) { GetSaplingScriptPubKeyMan()->AddToSaplingSpends(spend.nullifier, wtxid); } } @@ -774,7 +774,7 @@ bool CWallet::GetVinAndKeysFromOutput(COutput out, CTxIn& txinRet, CPubKey& pubK CScript pubScript; txinRet = CTxIn(out.tx->GetHash(), out.i); - pubScript = out.tx->vout[out.i].scriptPubKey; // the inputs PubKey + pubScript = out.tx->tx->vout[out.i].scriptPubKey; // the inputs PubKey CTxDestination address1; ExtractDestination(pubScript, address1, fColdStake); @@ -904,7 +904,7 @@ bool CWallet::IsKeyUsed(const CPubKey& vchPubKey) { it != mapWallet.end() && vchPubKey.IsValid(); ++it) { const CWalletTx& wtx = (*it).second; - for (const CTxOut& txout : wtx.vout) + for (const CTxOut& txout : wtx.tx->vout) if (txout.scriptPubKey == scriptPubKey) return true; } @@ -1005,7 +1005,7 @@ bool CWallet::LoadToWallet(const CWalletTx& wtxIn) m_sspk_man->UpdateNullifierNoteMapWithTx(mapWallet[hash]); wtxOrdered.emplace(wtx.nOrderPos, &wtx); AddToSpends(hash); - for (const CTxIn& txin : wtx.vin) { + for (const CTxIn& txin : wtx.tx->vin) { if (mapWallet.count(txin.prevout.hash)) { CWalletTx& prevtx = mapWallet[txin.prevout.hash]; if (prevtx.nIndex == -1 && !prevtx.hashUnset()) { @@ -1032,11 +1032,11 @@ bool CWallet::FindNotesDataAndAddMissingIVKToKeystore(const CTransaction& tx, Op void CWallet::AddExternalNotesDataToTx(CWalletTx& wtx) const { - if (HasSaplingSPKM() && wtx.IsShieldedTx()) { + if (HasSaplingSPKM() && wtx.tx->IsShieldedTx()) { const uint256& txId = wtx.GetHash(); // Add the external outputs. SaplingOutPoint op {txId, 0}; - for (unsigned int i = 0; i < wtx.sapData->vShieldedOutput.size(); i++) { + for (unsigned int i = 0; i < wtx.tx->sapData->vShieldedOutput.size(); i++) { op.n = i; if (wtx.mapSaplingNoteData.count(op)) continue; // internal output auto recovered = GetSaplingScriptPubKeyMan()->TryToRecoverNote(wtx, op); @@ -1102,8 +1102,8 @@ bool CWallet::AddToWalletIfInvolvingMe(const CTransaction& tx, const uint256& bl m_spk_man->MarkUnusedAddresses(txout.scriptPubKey); } - CWalletTx wtx(this, tx); - if (wtx.IsShieldedTx()) { + CWalletTx wtx(this, MakeTransactionRef(tx)); + if (wtx.tx->IsShieldedTx()) { if (saplingNoteData && !saplingNoteData->empty()) { wtx.SetSaplingNoteData(*saplingNoteData); } @@ -1168,7 +1168,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 - for (const CTxIn& txin: wtx.vin) + for (const CTxIn& txin: wtx.tx->vin) { if (mapWallet.count(txin.prevout.hash)) mapWallet[txin.prevout.hash].MarkDirty(); @@ -1230,7 +1230,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 - for (const CTxIn& txin: wtx.vin) + for (const CTxIn& txin: wtx.tx->vin) { if (mapWallet.count(txin.prevout.hash)) mapWallet[txin.prevout.hash].MarkDirty(); @@ -1290,8 +1290,8 @@ isminetype CWallet::IsMine(const CTxIn& txin) const std::map::const_iterator mi = mapWallet.find(txin.prevout.hash); 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; @@ -1310,7 +1310,7 @@ bool CWallet::IsUsed(const CTxDestination address) const if (wtx.IsCoinBase()) { continue; } - for (const CTxOut& txout : wtx.vout) { + for (const CTxOut& txout : wtx.tx->vout) { if (txout.scriptPubKey == scriptPubKey) return true; } @@ -1325,9 +1325,9 @@ CAmount CWallet::GetDebit(const CTxIn& txin, const isminefilter& filter) const std::map::const_iterator mi = mapWallet.find(txin.prevout.hash); 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; @@ -1400,7 +1400,7 @@ bool CWalletTx::IsAmountCached(AmountType type, const isminefilter& filter) cons //! filter decides which addresses will count towards the debit CAmount CWalletTx::GetDebit(const isminefilter& filter) const { - if (vin.empty() && (sapData && sapData->vShieldedSpend.empty())) { + if (tx->vin.empty() && (tx->sapData && tx->sapData->vShieldedSpend.empty())) { return 0; } @@ -1488,9 +1488,9 @@ CAmount CWalletTx::GetAvailableCredit(bool fUseCache, const isminefilter& filter if (filter != ISMINE_SPENDABLE_SHIELDED && filter != ISMINE_WATCH_ONLY_SHIELDED) { const 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, filter); if (!Params().GetConsensus().MoneyRange(nCredit)) throw std::runtime_error(std::string(__func__) + " : value out of range"); @@ -1535,8 +1535,8 @@ CAmount CWalletTx::GetLockedCredit() const CAmount nCredit = 0; uint256 hashTx = GetHash(); - for (unsigned int i = 0; i < vout.size(); i++) { - const CTxOut& txout = vout[i]; + for (unsigned int i = 0; i < tx->vout.size(); i++) { + const CTxOut& txout = tx->vout[i]; // Skip spent coins if (pwallet->IsSpent(hashTx, i)) continue; @@ -1547,7 +1547,7 @@ CAmount CWalletTx::GetLockedCredit() const } // Add masternode collaterals which are handled like locked coins - else if (fMasterNode && vout[i].nValue == 10000 * COIN) { + else if (fMasterNode && tx->vout[i].nValue == 10000 * COIN) { nCredit += pwallet->GetCredit(txout, ISMINE_SPENDABLE); } @@ -1587,27 +1587,27 @@ void CWalletTx::GetAmounts(std::list& listReceived, bool isFromMyTaddr = nDebit > 0; // debit>0 means we signed/sent this transaction if (isFromMyTaddr) {// debit>0 means we signed/sent this transaction - CAmount nValueOut = GetValueOut(); // transasparent outputs plus the negative Sapling valueBalance - CAmount nValueIn = GetShieldedValueIn(); + CAmount nValueOut = tx->GetValueOut(); // transasparent outputs plus the negative Sapling valueBalance + CAmount nValueIn = tx->GetShieldedValueIn(); nFee = nDebit - nValueOut + nValueIn; // If we sent utxos from this transaction, create output for value taken from (negative valueBalance) // or added (positive valueBalance) to the transparent value pool by Sapling shielding and unshielding. - if (sapData) { - if (sapData->valueBalance < 0) { - COutputEntry output = {CNoDestination(), -sapData->valueBalance, (int) vout.size()}; + if (tx->sapData) { + if (tx->sapData->valueBalance < 0) { + COutputEntry output = {CNoDestination(), -tx->sapData->valueBalance, (int) tx->vout.size()}; listSent.push_back(output); - } else if (sapData->valueBalance > 0) { - COutputEntry output = {CNoDestination(), sapData->valueBalance, (int) vout.size()}; + } else if (tx->sapData->valueBalance > 0) { + COutputEntry output = {CNoDestination(), tx->sapData->valueBalance, (int) tx->vout.size()}; listReceived.push_back(output); } } } // Sent/received. - bool hasZerocoinSpends = HasZerocoinSpendInputs(); - for (unsigned int i = 0; i < vout.size(); ++i) { - const CTxOut& txout = vout[i]; + bool hasZerocoinSpends = tx->HasZerocoinSpendInputs(); + for (unsigned int i = 0; i < tx->vout.size(); ++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) @@ -1939,7 +1939,7 @@ CAmount CWallet::GetAvailableBalance(isminefilter& filter, bool useCache, int mi CAmount CWallet::GetColdStakingBalance() const { return loopTxsBalance([](const uint256& id, const CWalletTx& pcoin, CAmount& nTotal) { - if (pcoin.HasP2CSOutputs() && pcoin.IsTrusted()) + if (pcoin.tx->HasP2CSOutputs() && pcoin.IsTrusted()) nTotal += pcoin.GetColdStakingCredit(); }); } @@ -1961,7 +1961,7 @@ CAmount CWallet::GetStakingBalance(const bool fIncludeColdStaking) const CAmount CWallet::GetDelegatedBalance() const { return loopTxsBalance([](const uint256& id, const CWalletTx& pcoin, CAmount& nTotal) { - if (pcoin.HasP2CSOutputs() && pcoin.IsTrusted()) + if (pcoin.tx->HasP2CSOutputs() && pcoin.IsTrusted()) nTotal += pcoin.GetStakeDelegationCredit(); }); } @@ -2051,7 +2051,7 @@ CAmount CWallet::GetLegacyBalance(const isminefilter& filter, int minDepth) cons // treat change outputs specially, as part of the amount debited. CAmount debit = wtx.GetDebit(filter); const bool outgoing = debit > 0; - for (const CTxOut& out : wtx.vout) { + for (const CTxOut& out : wtx.tx->vout) { if (outgoing && IsChange(out)) { debit -= out.nValue; } else if (IsMine(out) & filter && depth >= minDepth) { @@ -2094,9 +2094,9 @@ void CWallet::GetAvailableP2CSCoins(std::vector& vCoins) const { if (fConflicted || nDepth < 0) continue; - if (pcoin->HasP2CSOutputs()) { - for (int i = 0; i < (int) pcoin->vout.size(); i++) { - const auto &utxo = pcoin->vout[i]; + if (pcoin->tx->HasP2CSOutputs()) { + for (int i = 0; i < (int) pcoin->tx->vout.size(); i++) { + const auto &utxo = pcoin->tx->vout[i]; if (IsSpent(wtxid, i)) continue; @@ -2167,12 +2167,12 @@ bool CWallet::GetMasternodeVinAndKeys(CTxIn& txinRet, CPubKey& pubKeyRet, CKey& } // Verify index limits - if (nOutputIndex < 0 || nOutputIndex >= (int) wtx->vout.size()) { + if (nOutputIndex < 0 || nOutputIndex >= (int) wtx->tx->vout.size()) { strError = "Invalid masternode output index"; return error("%s: output index %d not found in %s", __func__, nOutputIndex, strTxHash); } - CTxOut txOut = wtx->vout[nOutputIndex]; + CTxOut txOut = wtx->tx->vout[nOutputIndex]; // Masternode collateral value if (txOut.nValue != 10000 * COIN) { @@ -2300,8 +2300,8 @@ bool CWallet::AvailableCoins(std::vector* pCoins, // --> populates // Check min depth filtering requirements if (nDepth < coinsFilter.minDepth) continue; - for (unsigned int i = 0; i < pcoin->vout.size(); i++) { - const auto& output = pcoin->vout[i]; + for (unsigned int i = 0; i < pcoin->tx->vout.size(); i++) { + const auto& output = pcoin->tx->vout[i]; // Filter by specific destinations if needed if (coinsFilter.onlyFilteredDest && !coinsFilter.onlyFilteredDest->empty()) { @@ -2346,16 +2346,16 @@ std::map > CWallet::AvailableCoinsByAddres std::map > mapCoins; for (COutput& out : vCoins) { - if (maxCoinValue > 0 && out.tx->vout[out.i].nValue > maxCoinValue) + if (maxCoinValue > 0 && out.tx->tx->vout[out.i].nValue > maxCoinValue) continue; CTxDestination address; bool fColdStakeAddr = false; - if (!ExtractDestination(out.tx->vout[out.i].scriptPubKey, address, fColdStakeAddr)) { + if (!ExtractDestination(out.tx->tx->vout[out.i].scriptPubKey, address, fColdStakeAddr)) { // if this is a P2CS we don't have the owner key - check if we have the staking key fColdStakeAddr = true; - if ( !out.tx->vout[out.i].scriptPubKey.IsPayToColdStaking() || - !ExtractDestination(out.tx->vout[out.i].scriptPubKey, address, fColdStakeAddr) ) + if ( !out.tx->tx->vout[out.i].scriptPubKey.IsPayToColdStaking() || + !ExtractDestination(out.tx->tx->vout[out.i].scriptPubKey, address, fColdStakeAddr) ) continue; } @@ -2423,10 +2423,10 @@ bool CWallet::StakeableCoins(std::vector* pCoins) // Check min depth requirement for stake inputs if (nDepth < Params().GetConsensus().nStakeMinDepth) continue; - for (unsigned int index = 0; index < pcoin->vout.size(); index++) { + for (unsigned int index = 0; index < pcoin->tx->vout.size(); index++) { auto res = CheckOutputAvailability( - pcoin->vout[index], + pcoin->tx->vout[index], index, wtxid, STAKEABLE_COINS, @@ -2470,7 +2470,7 @@ bool CWallet::SelectCoinsMinConf(const CAmount& nTargetValue, int nConfMine, int continue; int i = output.i; - CAmount n = pcoin->vout[i].nValue; + CAmount n = pcoin->tx->vout[i].nValue; std::pair > coin = std::make_pair(n, std::make_pair(pcoin, i)); @@ -2543,7 +2543,7 @@ bool CWallet::SelectCoinsToSpend(const std::vector& vAvailableCoins, co if (!out.fSpendable) continue; - nValueRet += out.tx->vout[out.i].nValue; + nValueRet += out.tx->tx->vout[out.i].nValue; setCoinsRet.emplace(out.tx, out.i); } return (nValueRet >= nTargetValue); @@ -2561,9 +2561,9 @@ bool CWallet::SelectCoinsToSpend(const std::vector& vAvailableCoins, co if (it != mapWallet.end()) { const CWalletTx* pcoin = &it->second; // Clearly invalid input, fail - if (pcoin->vout.size() <= outpoint.outPoint.n) + if (pcoin->tx->vout.size() <= outpoint.outPoint.n) return false; - nValueFromPresetInputs += pcoin->vout[outpoint.outPoint.n].nValue; + nValueFromPresetInputs += pcoin->tx->vout[outpoint.outPoint.n].nValue; setPresetCoins.emplace(pcoin, outpoint.outPoint.n); } else return false; // TODO: Allow non-wallet inputs @@ -2638,10 +2638,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) - for (const CTxIn& txin : wtx.vin) { + for (const CTxIn& txin : wtx.tx->vin) { if (!coinControl.IsSelected(txin.prevout)) { tx.vin.push_back(txin); @@ -2798,7 +2798,7 @@ bool CWallet::CreateTransaction(const std::vector& vecSend, // Fill vin for (const std::pair& coin : setCoins) { - if(coin.first->vout[coin.second].scriptPubKey.IsPayToColdStaking()) { + if(coin.first->tx->vout[coin.second].scriptPubKey.IsPayToColdStaking()) { wtxNew->fStakeDelegationVoided = true; } txNew.vin.emplace_back(coin.first->GetHash(), coin.second); @@ -2809,12 +2809,12 @@ bool CWallet::CreateTransaction(const std::vector& vecSend, CTransaction txNewConst(txNew); for (const std::pair & 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; bool haveKey = coin.first->GetStakeDelegationCredit() > 0; if (sign) { signSuccess = ProduceSignature( - TransactionSignatureCreator(this, &txNewConst, nIn, coin.first->vout[coin.second].nValue, SIGHASH_ALL), + TransactionSignatureCreator(this, &txNewConst, nIn, coin.first->tx->vout[coin.second].nValue, SIGHASH_ALL), scriptPubKey, sigdata, !haveKey // fColdStake = false @@ -2842,7 +2842,7 @@ bool CWallet::CreateTransaction(const std::vector& vecSend, } // Embed the constructed transaction data in wtxNew. - *static_cast(wtxNew) = CTransaction(txNew); + wtxNew->SetTx(MakeTransactionRef(std::move(txNew))); // Limit size if (nBytes >= MAX_STANDARD_TX_SIZE) { @@ -2920,7 +2920,7 @@ bool CWallet::CreateCoinStake( int nAttempts = 0; for (auto it = availableCoins->begin(); it != availableCoins->end();) { COutPoint outPoint = COutPoint(it->tx->GetHash(), it->i); - CPivStake stakeInput(it->tx->vout[it->i], + CPivStake stakeInput(it->tx->tx->vout[it->i], outPoint, it->pindex); @@ -3061,7 +3061,7 @@ CWallet::CommitResult CWallet::CommitTransaction(CWalletTx& wtxNew, CReserveKey* CommitResult res; { LOCK2(cs_main, cs_wallet); - LogPrintf("%s:\n%s", __func__, wtxNew.ToString()); + LogPrintf("%s:\n%s", __func__, wtxNew.tx->ToString()); { // Take key pair from key pool so it won't be used again if (opReservekey) opReservekey->KeepKey(); @@ -3071,9 +3071,9 @@ CWallet::CommitResult CWallet::CommitTransaction(CWalletTx& wtxNew, CReserveKey* AddToWallet(wtxNew); // Notify that old coins are spent - if (!wtxNew.HasZerocoinSpendInputs()) { + if (!wtxNew.tx->HasZerocoinSpendInputs()) { std::set updated_hashes; - for (const CTxIn& txin : wtxNew.vin) { + for (const CTxIn& txin : wtxNew.tx->vin) { // notify only once if (updated_hashes.find(txin.prevout.hash) != updated_hashes.end()) continue; @@ -3343,15 +3343,15 @@ std::map 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) && - !ExtractDestination(pcoin->vout[i].scriptPubKey, addr, true) ) + if ( !ExtractDestination(pcoin->tx->vout[i].scriptPubKey, addr) && + !ExtractDestination(pcoin->tx->vout[i].scriptPubKey, addr, true) ) 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; @@ -3372,14 +3372,14 @@ std::set > CWallet::GetAddressGroupings() for (std::pair walletEntry : mapWallet) { 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 - for (CTxIn txin : pcoin->vin) { + for (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; @@ -3387,7 +3387,7 @@ std::set > CWallet::GetAddressGroupings() // group change with input addresses if (any_mine) { - for (CTxOut txout : pcoin->vout) + for (CTxOut txout : pcoin->tx->vout) if (IsChange(txout)) { CTxDestination txoutAddr; if (!ExtractDestination(txout.scriptPubKey, txoutAddr)) @@ -3402,10 +3402,10 @@ std::set > 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); @@ -3637,7 +3637,7 @@ void CWallet::GetKeyBirthTimes(std::map& mapKeyBirth) const if (blit != mapBlockIndex.end() && chainActive.Contains(blit->second)) { // ... which are already in a block int nHeight = blit->second->nHeight; - for (const CTxOut& txout : wtx.vout) { + for (const CTxOut& txout : wtx.tx->vout) { // iterate over all their outputs CAffectedKeysVisitor(*this, vAffected).Process(txout.scriptPubKey); for (const CKeyID& keyid : vAffected) { @@ -3713,7 +3713,7 @@ void CWallet::AutoCombineDust(CConnman* connman) continue; // no p2cs accepted, those coins are "locked" - if (out.tx->vout[out.i].scriptPubKey.IsPayToColdStaking()) + if (out.tx->tx->vout[out.i].scriptPubKey.IsPayToColdStaking()) continue; COutPoint outpt(out.tx->GetHash(), out.i); @@ -4395,13 +4395,13 @@ CAmount CWallet::GetDebit(const CTransaction& tx, const isminefilter& filter) co CAmount CWallet::GetCredit(const CWalletTx& tx, const isminefilter& filter) const { CAmount nCredit = 0; - for (unsigned int i = 0; i < tx.vout.size(); i++) { - nCredit += GetCredit(tx.vout[i], filter); + for (unsigned int i = 0; i < tx.tx->vout.size(); i++) { + nCredit += GetCredit(tx.tx->vout[i], filter); } // Shielded credit if (filter & ISMINE_SPENDABLE_SHIELDED || filter & ISMINE_WATCH_ONLY_SHIELDED) { - if (tx.hasSaplingData()) { + if (tx.tx->hasSaplingData()) { nCredit += m_sspk_man->GetCredit(tx, filter, false); } } @@ -4485,18 +4485,9 @@ CWalletTx::CWalletTx() Init(NULL); } -CWalletTx::CWalletTx(const CWallet* pwalletIn) -{ - Init(pwalletIn); -} - -CWalletTx::CWalletTx(const CWallet* pwalletIn, const CMerkleTx& txIn) : CMerkleTx(txIn) -{ - Init(pwalletIn); -} - -CWalletTx::CWalletTx(const CWallet* pwalletIn, const CTransaction& txIn) : CMerkleTx(txIn) +CWalletTx::CWalletTx(const CWallet* pwalletIn, CTransactionRef arg) { + // todo: set tx ref Init(pwalletIn); } @@ -4543,12 +4534,12 @@ bool CWalletTx::IsTrusted(int& nDepth, bool& fConflicted) const return false; // Trusted if all inputs are from us and are in the mempool: - for (const CTxIn& txin : vin) { + for (const CTxIn& txin : tx->vin) { // Transactions not sent by us: not trusted const CWalletTx* parent = pwallet->GetWalletTx(txin.prevout.hash); if (parent == nullptr) 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; } @@ -4594,7 +4585,7 @@ void CWalletTx::SetSaplingNoteData(mapSaplingNoteData_t ¬eData) { mapSaplingNoteData.clear(); for (const std::pair nd : noteData) { - if (nd.first.n < sapData->vShieldedOutput.size()) { + if (nd.first.n < tx->sapData->vShieldedOutput.size()) { mapSaplingNoteData[nd.first] = nd.second; } else { throw std::logic_error("CWalletTx::SetSaplingNoteData(): Invalid note"); @@ -4612,7 +4603,7 @@ OptionalsapData->vShieldedOutput[op.n]; + auto output = this->tx->sapData->vShieldedOutput[op.n]; auto nd = this->mapSaplingNoteData.at(op); auto maybe_pt = libzcash::SaplingNotePlaintext::decrypt( @@ -4635,7 +4626,7 @@ Optional> CWalletTx::RecoverSaplingNote( SaplingOutPoint op, std::set& ovks) const { - auto output = this->sapData->vShieldedOutput[op.n]; + auto output = this->tx->sapData->vShieldedOutput[op.n]; for (auto ovk : ovks) { auto outPt = libzcash::SaplingOutgoingPlaintext::decrypt( diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h index 8d63b44856639b..6f9e45f4c9e3ce 100644 --- a/src/wallet/wallet.h +++ b/src/wallet/wallet.h @@ -848,13 +848,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 * block in the chain we know this or any in-wallet dependency conflicts @@ -865,27 +866,38 @@ class CMerkleTx : public CTransaction 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_ZERO; nIndex = -1; } + void SetTx(CTransactionRef arg) + { + tx = std::move(arg); + } + ADD_SERIALIZE_METHODS; template inline void SerializationOp(Stream& s, Operation ser_action) { std::vector vMerkleBranch; // For compatibility with older versions. - READWRITE(*(CTransaction*)this); + READWRITE(tx); READWRITE(hashBlock); READWRITE(vMerkleBranch); READWRITE(nIndex); @@ -908,6 +920,10 @@ class CMerkleTx : public CTransaction 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(); } + bool IsCoinStake() const { return tx->IsCoinStake(); } }; /** @@ -946,9 +962,7 @@ class CWalletTx : public CMerkleTx mutable CAmount nShieldedChangeCached; CWalletTx(); - CWalletTx(const CWallet* pwalletIn); - CWalletTx(const CWallet* pwalletIn, const CMerkleTx& txIn); - CWalletTx(const CWallet* pwalletIn, const CTransaction& txIn); + CWalletTx(const CWallet* pwalletIn, CTransactionRef arg); void Init(const CWallet* pwalletIn); ADD_SERIALIZE_METHODS; @@ -979,7 +993,7 @@ class CWalletTx : public CMerkleTx READWRITE(fFromMe); READWRITE(fSpent); - if (this->isSaplingVersion()) { + if (this->tx->isSaplingVersion()) { READWRITE(mapSaplingNoteData); } @@ -1072,7 +1086,7 @@ class COutput COutput(const CWalletTx* txIn, int iIn, int nDepthIn, bool fSpendableIn, bool fSolvableIn) : tx(txIn), i(iIn), nDepth(nDepthIn), fSpendable(fSpendableIn), fSolvable(fSolvableIn) {} - CAmount Value() const { return tx->vout[i].nValue; } + CAmount Value() const { return tx->tx->vout[i].nValue; } std::string ToString() const; };