-
Notifications
You must be signed in to change notification settings - Fork 338
refactor: interfaces, make 'createTransaction' less error-prone #807
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -23,6 +23,7 @@ | |
| #include <psbt.h> | ||
| #include <util/translation.h> | ||
| #include <wallet/coincontrol.h> | ||
| #include <wallet/types.h> | ||
| #include <wallet/wallet.h> | ||
|
|
||
| #include <cstdint> | ||
|
|
@@ -149,6 +150,8 @@ bool WalletModel::validateAddress(const QString& address) const | |
|
|
||
| WalletModel::SendCoinsReturn WalletModel::prepareTransaction(WalletModelTransaction &transaction, const CCoinControl& coinControl) | ||
| { | ||
| transaction.getWtx() = nullptr; // reset tx output | ||
|
|
||
| CAmount total = 0; | ||
| bool fSubtractFeeFromAmount = false; | ||
| QList<SendCoinsRecipient> recipients = transaction.getRecipients(); | ||
|
|
@@ -199,27 +202,21 @@ WalletModel::SendCoinsReturn WalletModel::prepareTransaction(WalletModelTransact | |
| } | ||
|
|
||
| try { | ||
| CAmount nFeeRequired = 0; | ||
| int nChangePosRet = -1; | ||
|
|
||
| auto& newTx = transaction.getWtx(); | ||
| const auto& res = m_wallet->createTransaction(vecSend, coinControl, /*sign=*/!wallet().privateKeysDisabled(), nChangePosRet, nFeeRequired); | ||
| newTx = res ? *res : nullptr; | ||
| transaction.setTransactionFee(nFeeRequired); | ||
| if (fSubtractFeeFromAmount && newTx) | ||
| transaction.reassignAmounts(nChangePosRet); | ||
|
|
||
| if(!newTx) | ||
| { | ||
| if(!fSubtractFeeFromAmount && (total + nFeeRequired) > nBalance) | ||
| { | ||
| return SendCoinsReturn(AmountWithFeeExceedsBalance); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In commit "gui: remove unreachable AmountWithFeeExceedsBalance error" (355199c) This is a nice catch noticing that this code doesn't work. But I think the fact that it doesn't work is a pretty unfortunate problem, and the current PR will make fixing it harder. It seems like bitcoin/bitcoin#20640 unintentionally introduced a bug where the more accurate error message "The total exceeds your balance when the %1 transaction fee is included" can never trigger, and instead only less informative "Insufficient funds" or "The amount exceeds your balance" errors will be shown. It looks like there are few ways this could be fixed:
Against that background, I think this PR (as of edc3f9a) makes some nice cleanups, but I don't like the current changes because I think they make all of the fixes above except maybe the last one harder to implement. So I don't think I would ACK this PR currently, I'd happily ACK it if it either (1) fixed the problem, maybe using one of the easier fixes suggested above, or (2) did not fix the problem, but at least did not make it harder to fix in the future. This could be implemented by keeping most of the changes in the PR, but not deleting this GUI code in this commit and not deleting the |
||
| } | ||
| const auto& res = m_wallet->createTransaction(vecSend, coinControl, /*sign=*/!wallet().privateKeysDisabled(), /*change_pos=*/std::nullopt); | ||
| if (!res) { | ||
| Q_EMIT message(tr("Send Coins"), QString::fromStdString(util::ErrorString(res).translated), | ||
| CClientUIInterface::MSG_ERROR); | ||
| CClientUIInterface::MSG_ERROR); | ||
| return TransactionCreationFailed; | ||
| } | ||
|
|
||
| newTx = res->tx; | ||
| CAmount nFeeRequired = res->fee; | ||
| transaction.setTransactionFee(nFeeRequired); | ||
| if (fSubtractFeeFromAmount && newTx) { | ||
| transaction.reassignAmounts(static_cast<int>(res->change_pos.value_or(-1))); | ||
| } | ||
|
|
||
| // Reject absurdly high fee. (This can never happen because the | ||
| // wallet never creates transactions with fee greater than | ||
| // m_default_max_tx_fee. This merely a belt-and-suspenders check). | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am not sure why this is needed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is just a safety belt that resets the state in case the caller invokes the function with an existing
WalletModelTransaction. This shouldn’t happen nowadays since we create a new pointer per call, but if it ever does, for example with a duplicate recipient, the function would returnStatusCode::OKwith a tx even though nothing was sent.Overall, this function needs lot more love but this reset is quite simple and effective to prevent other issues for now.