@@ -34,14 +34,60 @@ using interfaces::FoundBlock;
3434namespace wallet {
3535static constexpr size_t OUTPUT_GROUP_MAX_ENTRIES{100 };
3636
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+
3780int CalculateMaximumSignedInputSize (const CTxOut& txout, const COutPoint outpoint, const SigningProvider* provider, bool can_grind_r, const CCoinControl* coin_control)
3881{
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+ }
4388 }
44- return GetVirtualTransactionInputSize (txn.vin [0 ]);
89+
90+ return -1 ;
4591}
4692
4793int CalculateMaximumSignedInputSize (const CTxOut& txout, const CWallet* wallet, const CCoinControl* coin_control)
@@ -50,15 +96,65 @@ int CalculateMaximumSignedInputSize(const CTxOut& txout, const CWallet* wallet,
5096 return CalculateMaximumSignedInputSize (txout, COutPoint (), provider.get (), wallet->CanGrindR (), coin_control);
5197}
5298
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+
53130// txouts needs to be in the order of tx.vin
54131TxSize CalculateMaximumSignedTxSize (const CTransaction &tx, const CWallet *wallet, const std::vector<CTxOut>& txouts, const CCoinControl* coin_control)
55132{
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};
62158}
63159
64160TxSize CalculateMaximumSignedTxSize (const CTransaction &tx, const CWallet *wallet, const CCoinControl* coin_control)
@@ -309,7 +405,9 @@ CoinsResult AvailableCoins(const CWallet& wallet,
309405 std::unique_ptr<SigningProvider> provider = wallet.GetSolvingProvider (output.scriptPubKey );
310406
311407 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 ;
313411 bool spendable = ((mine & ISMINE_SPENDABLE) != ISMINE_NO) || (((mine & ISMINE_WATCH_ONLY) != ISMINE_NO) && (coinControl && coinControl->fAllowWatchOnly && solvable));
314412
315413 // Filter by spendable outputs only
0 commit comments