mirror of
https://github.com/bitcoin/bitcoin.git
synced 2025-02-02 09:46:52 -05:00
Merge bitcoin/bitcoin#30050: refactor, wallet: get serialized size of CRecipient
s directly
a9c7300135
move-only: refactor CreateTransactionInternal (josibake)adc6ab25bb
wallet: use CRecipient instead of CTxOut (josibake) Pull request description: Broken out from #28201 --- In order to estimate fees properly, we need to know what the final serialized transaction size will be. This PR refactors `CreateTransactionInternal` to: * Get the serialized size directly from the `CRecipient`: this sets us up in a future PR to calculate the serialized size of silent payment `CTxDestinations` (see797e21c8c1
) * Use the new `GetSerializeSizeForRecipient` to move the serialize size calculation to *before* coin selection and the output creation to *after* coin selection: this also sets us up for silent payments sending in a future PR in that silent payments outputs cannot be created until after the inputs to the transaction have been selected Aside from the silent payments use case, I think this structure logically makes more sense. As a reminder, move-only commits are best reviewed with something like `git diff -w --color-moved=dimmed-zebra` ACKs for top commit: S3RK: reACKa9c7300135
achow101: ACKa9c7300135
rkrux: tACK [a9c7300
](a9c7300135
) Tree-SHA512: 412e1764b98f7428c8530c3a68f55e32063d6b66ab2ff613e1c7e12d49b049807cb60055cfe7f7e8ffe7ac7f0f9931427cbfd3efe7d4f97a5a0f6d1bf1aaac58
This commit is contained in:
commit
f0745d028e
1 changed files with 23 additions and 17 deletions
|
@ -983,6 +983,16 @@ static void DiscourageFeeSniping(CMutableTransaction& tx, FastRandomContext& rng
|
|||
}
|
||||
}
|
||||
|
||||
size_t GetSerializeSizeForRecipient(const CRecipient& recipient)
|
||||
{
|
||||
return ::GetSerializeSize(CTxOut(recipient.nAmount, GetScriptForDestination(recipient.dest)));
|
||||
}
|
||||
|
||||
bool IsDust(const CRecipient& recipient, const CFeeRate& dustRelayFee)
|
||||
{
|
||||
return ::IsDust(CTxOut(recipient.nAmount, GetScriptForDestination(recipient.dest)), dustRelayFee);
|
||||
}
|
||||
|
||||
static util::Result<CreatedTransactionResult> CreateTransactionInternal(
|
||||
CWallet& wallet,
|
||||
const std::vector<CRecipient>& vecSend,
|
||||
|
@ -1005,12 +1015,20 @@ static util::Result<CreatedTransactionResult> CreateTransactionInternal(
|
|||
|
||||
// Set the long term feerate estimate to the wallet's consolidate feerate
|
||||
coin_selection_params.m_long_term_feerate = wallet.m_consolidate_feerate;
|
||||
// Static vsize overhead + outputs vsize. 4 nVersion, 4 nLocktime, 1 input count, 1 witness overhead (dummy, flag, stack size)
|
||||
coin_selection_params.tx_noinputs_size = 10 + GetSizeOfCompactSize(vecSend.size()); // bytes for output count
|
||||
|
||||
CAmount recipients_sum = 0;
|
||||
const OutputType change_type = wallet.TransactionChangeType(coin_control.m_change_type ? *coin_control.m_change_type : wallet.m_default_change_type, vecSend);
|
||||
ReserveDestination reservedest(&wallet, change_type);
|
||||
unsigned int outputs_to_subtract_fee_from = 0; // The number of outputs which we are subtracting the fee from
|
||||
for (const auto& recipient : vecSend) {
|
||||
if (IsDust(recipient, wallet.chain().relayDustFee())) {
|
||||
return util::Error{_("Transaction amount too small")};
|
||||
}
|
||||
|
||||
// Include the fee cost for outputs.
|
||||
coin_selection_params.tx_noinputs_size += GetSerializeSizeForRecipient(recipient);
|
||||
recipients_sum += recipient.nAmount;
|
||||
|
||||
if (recipient.fSubtractFeeFromAmount) {
|
||||
|
@ -1095,23 +1113,6 @@ static util::Result<CreatedTransactionResult> CreateTransactionInternal(
|
|||
const auto change_spend_fee = coin_selection_params.m_discard_feerate.GetFee(coin_selection_params.change_spend_size);
|
||||
coin_selection_params.min_viable_change = std::max(change_spend_fee + 1, dust);
|
||||
|
||||
// Static vsize overhead + outputs vsize. 4 version, 4 nLocktime, 1 input count, 1 witness overhead (dummy, flag, stack size)
|
||||
coin_selection_params.tx_noinputs_size = 10 + GetSizeOfCompactSize(vecSend.size()); // bytes for output count
|
||||
|
||||
// vouts to the payees
|
||||
for (const auto& recipient : vecSend)
|
||||
{
|
||||
CTxOut txout(recipient.nAmount, GetScriptForDestination(recipient.dest));
|
||||
|
||||
// Include the fee cost for outputs.
|
||||
coin_selection_params.tx_noinputs_size += ::GetSerializeSize(txout);
|
||||
|
||||
if (IsDust(txout, wallet.chain().relayDustFee())) {
|
||||
return util::Error{_("Transaction amount too small")};
|
||||
}
|
||||
txNew.vout.push_back(txout);
|
||||
}
|
||||
|
||||
// Include the fees for things that aren't inputs, excluding the change output
|
||||
const CAmount not_input_fees = coin_selection_params.m_effective_feerate.GetFee(coin_selection_params.m_subtract_fee_outputs ? 0 : coin_selection_params.tx_noinputs_size);
|
||||
CAmount selection_target = recipients_sum + not_input_fees;
|
||||
|
@ -1152,6 +1153,11 @@ static util::Result<CreatedTransactionResult> CreateTransactionInternal(
|
|||
result.GetWaste(),
|
||||
result.GetSelectedValue());
|
||||
|
||||
// vouts to the payees
|
||||
for (const auto& recipient : vecSend)
|
||||
{
|
||||
txNew.vout.emplace_back(recipient.nAmount, GetScriptForDestination(recipient.dest));
|
||||
}
|
||||
const CAmount change_amount = result.GetChange(coin_selection_params.min_viable_change, coin_selection_params.m_change_fee);
|
||||
if (change_amount > 0) {
|
||||
CTxOut newTxOut(change_amount, scriptChange);
|
||||
|
|
Loading…
Add table
Reference in a new issue