@@ -34,14 +34,60 @@ using interfaces::FoundBlock;
34
34
namespace wallet {
35
35
static constexpr size_t OUTPUT_GROUP_MAX_ENTRIES{100 };
36
36
37
+ /* * Whether the descriptor represents, directly or not, a witness program. */
38
+ static bool IsSegwit (const Descriptor& desc) {
39
+ if (const auto typ = desc.GetOutputType ()) return *typ != OutputType::LEGACY;
40
+ return false ;
41
+ }
42
+
43
+ /* * Whether to assume ECDSA signatures' will be high-r. */
44
+ static bool UseMaxSig (const std::optional<CTxIn>& txin, const CCoinControl* coin_control) {
45
+ // Use max sig if watch only inputs were used or if this particular input is an external input
46
+ // to ensure a sufficient fee is attained for the requested feerate.
47
+ return coin_control && (coin_control->fAllowWatchOnly || (txin && coin_control->IsExternalSelected (txin->prevout )));
48
+ }
49
+
50
+ /* * Get the size of an input (in witness units) once it's signed.
51
+ *
52
+ * @param desc The output script descriptor of the coin spent by this input.
53
+ * @param txin Optionally the txin to estimate the size of. Used to determine the size of ECDSA signatures.
54
+ * @param coin_control Information about the context to determine the size of ECDSA signatures.
55
+ * @param tx_is_segwit Whether the transaction has at least a single input spending a segwit coin.
56
+ * @param can_grind_r Whether the signer will be able to grind the R of the signature.
57
+ */
58
+ static std::optional<int64_t > MaxInputWeight (const Descriptor& desc, const std::optional<CTxIn>& txin,
59
+ const CCoinControl* coin_control, const bool tx_is_segwit,
60
+ const bool can_grind_r) {
61
+ if (const auto sat_weight = desc.MaxSatisfactionWeight (!can_grind_r || UseMaxSig (txin, coin_control))) {
62
+ const bool is_segwit = IsSegwit (desc);
63
+ // Account for the size of the scriptsig and the number of elements on the witness stack. Note
64
+ // that if any input in the transaction is spending a witness program, we need to specify the
65
+ // witness stack size for every input regardless of whether it is segwit itself.
66
+ // NOTE: this also works in case of mixed scriptsig-and-witness such as in p2sh-wrapped segwit v0
67
+ // outputs. In this case the size of the scriptsig length will always be one (since the redeemScript
68
+ // is always a push of the witness program in this case, which is smaller than 253 bytes).
69
+ const int64_t scriptsig_len = is_segwit ? 1 : GetSizeOfCompactSize (*sat_weight / WITNESS_SCALE_FACTOR);
70
+ // FIXME: use the real number of stack elements instead of the "1" placeholder.
71
+ const int64_t witstack_len = is_segwit ? GetSizeOfCompactSize (1 ) : (tx_is_segwit ? 1 : 0 );
72
+ // previous txid + previous vout + sequence + scriptsig len + witstack size + scriptsig or witness
73
+ // NOTE: sat_weight already accounts for the witness discount accordingly.
74
+ return (32 + 4 + 4 + scriptsig_len) * WITNESS_SCALE_FACTOR + witstack_len + *sat_weight;
75
+ }
76
+
77
+ return {};
78
+ }
79
+
37
80
int CalculateMaximumSignedInputSize (const CTxOut& txout, const COutPoint outpoint, const SigningProvider* provider, bool can_grind_r, const CCoinControl* coin_control)
38
81
{
39
- CMutableTransaction txn;
40
- txn.vin .push_back (CTxIn (outpoint));
41
- if (!provider || !DummySignInput (*provider, txn.vin [0 ], txout, can_grind_r, coin_control)) {
42
- return -1 ;
82
+ if (!provider) return -1 ;
83
+
84
+ if (const auto desc = InferDescriptor (txout.scriptPubKey , *provider)) {
85
+ if (const auto weight = MaxInputWeight (*desc, {}, coin_control, true , can_grind_r)) {
86
+ return static_cast <int >(GetVirtualTransactionSize (*weight, 0 , 0 ));
87
+ }
43
88
}
44
- return GetVirtualTransactionInputSize (txn.vin [0 ]);
89
+
90
+ return -1 ;
45
91
}
46
92
47
93
int CalculateMaximumSignedInputSize (const CTxOut& txout, const CWallet* wallet, const CCoinControl* coin_control)
@@ -50,15 +96,65 @@ int CalculateMaximumSignedInputSize(const CTxOut& txout, const CWallet* wallet,
50
96
return CalculateMaximumSignedInputSize (txout, COutPoint (), provider.get (), wallet->CanGrindR (), coin_control);
51
97
}
52
98
99
+ /* * Infer a descriptor for the given output script. */
100
+ static std::unique_ptr<Descriptor> GetDescriptor (const CWallet* wallet, const CCoinControl* coin_control,
101
+ const CScript script_pubkey)
102
+ {
103
+ MultiSigningProvider providers;
104
+ for (const auto spkman: wallet->GetScriptPubKeyMans (script_pubkey)) {
105
+ providers.AddProvider (spkman->GetSolvingProvider (script_pubkey));
106
+ }
107
+ if (coin_control) {
108
+ providers.AddProvider (std::make_unique<FlatSigningProvider>(coin_control->m_external_provider ));
109
+ }
110
+ return InferDescriptor (script_pubkey, providers);
111
+ }
112
+
113
+ /* * Infer the maximum size of this input after it will be signed. */
114
+ static std::optional<int64_t > GetSignedTxinWeight (const CWallet* wallet, const CCoinControl* coin_control,
115
+ const CTxIn& txin, const CTxOut& txo, const bool tx_is_segwit,
116
+ const bool can_grind_r)
117
+ {
118
+ // If weight was provided, use that.
119
+ if (coin_control && coin_control->HasInputWeight (txin.prevout )) {
120
+ return coin_control->GetInputWeight (txin.prevout );
121
+ }
122
+
123
+ // Otherwise, use the maximum satisfaction size provided by the descriptor.
124
+ std::unique_ptr<Descriptor> desc{GetDescriptor (wallet, coin_control, txo.scriptPubKey )};
125
+ if (desc) return MaxInputWeight (*desc, {txin}, coin_control, tx_is_segwit, can_grind_r);
126
+
127
+ return {};
128
+ }
129
+
53
130
// txouts needs to be in the order of tx.vin
54
131
TxSize CalculateMaximumSignedTxSize (const CTransaction &tx, const CWallet *wallet, const std::vector<CTxOut>& txouts, const CCoinControl* coin_control)
55
132
{
56
- CMutableTransaction txNew (tx);
57
- if (!wallet->DummySignTx (txNew, txouts, coin_control)) return TxSize{-1 , -1 };
58
- CTransaction ctx (txNew);
59
- int64_t vsize = GetVirtualTransactionSize (ctx);
60
- int64_t weight = GetTransactionWeight (ctx);
61
- return TxSize{vsize, weight};
133
+ // nVersion + nLockTime + input count + output count
134
+ int64_t weight = (4 + 4 + GetSizeOfCompactSize (tx.vin .size ()) + GetSizeOfCompactSize (tx.vout .size ())) * WITNESS_SCALE_FACTOR;
135
+ // Whether any input spends a witness program. Necessary to run before the next loop over the
136
+ // inputs in order to accurately compute the compactSize length for the witness data per input.
137
+ bool is_segwit = std::any_of (txouts.begin (), txouts.end (), [&](const CTxOut& txo) {
138
+ std::unique_ptr<Descriptor> desc{GetDescriptor (wallet, coin_control, txo.scriptPubKey )};
139
+ if (desc) return IsSegwit (*desc);
140
+ return false ;
141
+ });
142
+ // Segwit marker and flag
143
+ if (is_segwit) weight += 2 ;
144
+
145
+ // Add the size of the transaction outputs.
146
+ for (const auto & txo : tx.vout ) weight += GetTransactionOutputWeight (txo);
147
+
148
+ // Add the size of the transaction inputs as if they were signed.
149
+ for (uint32_t i = 0 ; i < txouts.size (); i++) {
150
+ const auto txin_weight = GetSignedTxinWeight (wallet, coin_control, tx.vin [i], txouts[i], is_segwit, wallet->CanGrindR ());
151
+ if (!txin_weight) return TxSize{-1 , -1 };
152
+ assert (*txin_weight > -1 );
153
+ weight += *txin_weight;
154
+ }
155
+
156
+ // It's ok to use 0 as the number of sigops since we never create any pathological transaction.
157
+ return TxSize{GetVirtualTransactionSize (weight, 0 , 0 ), weight};
62
158
}
63
159
64
160
TxSize CalculateMaximumSignedTxSize (const CTransaction &tx, const CWallet *wallet, const CCoinControl* coin_control)
@@ -309,7 +405,9 @@ CoinsResult AvailableCoins(const CWallet& wallet,
309
405
std::unique_ptr<SigningProvider> provider = wallet.GetSolvingProvider (output.scriptPubKey );
310
406
311
407
int input_bytes = CalculateMaximumSignedInputSize (output, COutPoint (), provider.get (), can_grind_r, coinControl);
312
- bool solvable = provider ? InferDescriptor (output.scriptPubKey , *provider)->IsSolvable () : false ;
408
+ // Because CalculateMaximumSignedInputSize infers a solvable descriptor to get the satisfaction size,
409
+ // it is safe to assume that this input is solvable if input_bytes is greater than -1.
410
+ bool solvable = input_bytes > -1 ;
313
411
bool spendable = ((mine & ISMINE_SPENDABLE) != ISMINE_NO) || (((mine & ISMINE_WATCH_ONLY) != ISMINE_NO) && (coinControl && coinControl->fAllowWatchOnly && solvable));
314
412
315
413
// Filter by spendable outputs only
0 commit comments