Skip to content

Commit 607d5a4

Browse files
committed
Merge bitcoin#23202: wallet: allow psbtbumpfee to work with txs with external inputs
c3b099a wallet, tests: Test bumpfee's max input weight calculation (Andrew Chow) 116a620 Make DUMMY_CHECKER availble outside of script/sign.cpp (Andrew Chow) ff63832 test, bumpfee: Check that psbtbumpfee can bump txs with external inputs (Andrew Chow) 1bc8106 bumpfee: be able to bump fee of a tx with external inputs (Andrew Chow) 31dd3dc bumpfee: Clear scriptSigs and scriptWitnesses before calculated max size (Andrew Chow) a0c3afb bumpfee: extract weights of external inputs when bumping fee (Andrew Chow) 612f1e4 bumpfee: Calculate fee by looking up UTXOs (Andrew Chow) Pull request description: This PR allows `psbtbumpfee` to return a PSBT for transactions that contain external inputs. This does not work for bumping in the GUI nor `bumpfee` because these need private keys available to sign and send the transaction. But `psbtbumpfee` returns a psbt, so it is fine to not be able to sign. In order to correctly estimate the size of the inputs for coin selection, the fee bumper will use the size of the inputs of the transaction being bumped. Because the sizes of signatures are not guaranteed, for external inputs, the fee bumper will verify the scripts with a special SignatureChecker which will compute the weight of all of the signatures in that input, and compute their weights if those signatures were maximally sized. This allows the fee bumper to obtain a max size estimate for each external input. Builds on bitcoin#23201 as it relies on the ability to pass weights in to coin selection. Closes bitcoin#23189 ACKs for top commit: ishaanam: reACK c3b099a t-bast: Re-ran my tests agains bitcoin@c3b099a, ACK Tree-SHA512: 40016ec52d351430977579cfa2694c7e6764f42c9ce09d3a6f1753b767f86053f296d9de988248df033be6d725d67badbf2a5ef82c8ace23c61487729b7691e5
2 parents e5a8314 + c3b099a commit 607d5a4

File tree

10 files changed

+225
-28
lines changed

10 files changed

+225
-28
lines changed

src/Makefile.test.include

+1
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,7 @@ BITCOIN_TESTS =\
162162

163163
if ENABLE_WALLET
164164
BITCOIN_TESTS += \
165+
wallet/test/feebumper_tests.cpp \
165166
wallet/test/psbt_wallet_tests.cpp \
166167
wallet/test/spend_tests.cpp \
167168
wallet/test/wallet_tests.cpp \

src/script/interpreter.h

+2-2
Original file line numberDiff line numberDiff line change
@@ -307,10 +307,10 @@ using MutableTransactionSignatureChecker = GenericTransactionSignatureChecker<CM
307307
class DeferringSignatureChecker : public BaseSignatureChecker
308308
{
309309
protected:
310-
BaseSignatureChecker& m_checker;
310+
const BaseSignatureChecker& m_checker;
311311

312312
public:
313-
DeferringSignatureChecker(BaseSignatureChecker& checker) : m_checker(checker) {}
313+
DeferringSignatureChecker(const BaseSignatureChecker& checker) : m_checker(checker) {}
314314

315315
bool CheckECDSASignature(const std::vector<unsigned char>& scriptSig, const std::vector<unsigned char>& vchPubKey, const CScript& scriptCode, SigVersion sigversion) const override
316316
{

src/script/sign.cpp

+4-1
Original file line numberDiff line numberDiff line change
@@ -596,8 +596,11 @@ class DummySignatureChecker final : public BaseSignatureChecker
596596
bool CheckECDSASignature(const std::vector<unsigned char>& scriptSig, const std::vector<unsigned char>& vchPubKey, const CScript& scriptCode, SigVersion sigversion) const override { return true; }
597597
bool CheckSchnorrSignature(Span<const unsigned char> sig, Span<const unsigned char> pubkey, SigVersion sigversion, ScriptExecutionData& execdata, ScriptError* serror) const override { return true; }
598598
};
599-
const DummySignatureChecker DUMMY_CHECKER;
599+
}
600+
601+
const BaseSignatureChecker& DUMMY_CHECKER = DummySignatureChecker();
600602

603+
namespace {
601604
class DummySignatureCreator final : public BaseSignatureCreator {
602605
private:
603606
char m_r_len = 32;

src/script/sign.h

+2
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,8 @@ class MutableTransactionSignatureCreator : public BaseSignatureCreator
5252
bool CreateSchnorrSig(const SigningProvider& provider, std::vector<unsigned char>& sig, const XOnlyPubKey& pubkey, const uint256* leaf_hash, const uint256* merkle_root, SigVersion sigversion) const override;
5353
};
5454

55+
/** A signature checker that accepts all signatures */
56+
extern const BaseSignatureChecker& DUMMY_CHECKER;
5557
/** A signature creator that just produces 71-byte empty signatures. */
5658
extern const BaseSignatureCreator& DUMMY_SIGNATURE_CREATOR;
5759
/** A signature creator that just produces 72-byte empty signatures. */

src/wallet/feebumper.cpp

+75-19
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
// Distributed under the MIT software license, see the accompanying
33
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
44

5+
#include <consensus/validation.h>
56
#include <interfaces/chain.h>
67
#include <policy/fees.h>
78
#include <policy/policy.h>
@@ -19,7 +20,7 @@
1920
namespace wallet {
2021
//! Check whether transaction has descendant in wallet or mempool, or has been
2122
//! mined, or conflicts with a mined transaction. Return a feebumper::Result.
22-
static feebumper::Result PreconditionChecks(const CWallet& wallet, const CWalletTx& wtx, std::vector<bilingual_str>& errors) EXCLUSIVE_LOCKS_REQUIRED(wallet.cs_wallet)
23+
static feebumper::Result PreconditionChecks(const CWallet& wallet, const CWalletTx& wtx, bool require_mine, std::vector<bilingual_str>& errors) EXCLUSIVE_LOCKS_REQUIRED(wallet.cs_wallet)
2324
{
2425
if (wallet.HasWalletSpend(wtx.tx)) {
2526
errors.push_back(Untranslated("Transaction has descendants in the wallet"));
@@ -48,20 +49,21 @@ static feebumper::Result PreconditionChecks(const CWallet& wallet, const CWallet
4849
return feebumper::Result::WALLET_ERROR;
4950
}
5051

51-
// check that original tx consists entirely of our inputs
52-
// if not, we can't bump the fee, because the wallet has no way of knowing the value of the other inputs (thus the fee)
53-
isminefilter filter = wallet.GetLegacyScriptPubKeyMan() && wallet.IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS) ? ISMINE_WATCH_ONLY : ISMINE_SPENDABLE;
54-
if (!AllInputsMine(wallet, *wtx.tx, filter)) {
55-
errors.push_back(Untranslated("Transaction contains inputs that don't belong to this wallet"));
56-
return feebumper::Result::WALLET_ERROR;
52+
if (require_mine) {
53+
// check that original tx consists entirely of our inputs
54+
// if not, we can't bump the fee, because the wallet has no way of knowing the value of the other inputs (thus the fee)
55+
isminefilter filter = wallet.GetLegacyScriptPubKeyMan() && wallet.IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS) ? ISMINE_WATCH_ONLY : ISMINE_SPENDABLE;
56+
if (!AllInputsMine(wallet, *wtx.tx, filter)) {
57+
errors.push_back(Untranslated("Transaction contains inputs that don't belong to this wallet"));
58+
return feebumper::Result::WALLET_ERROR;
59+
}
5760
}
5861

59-
6062
return feebumper::Result::OK;
6163
}
6264

6365
//! Check if the user provided a valid feeRate
64-
static feebumper::Result CheckFeeRate(const CWallet& wallet, const CWalletTx& wtx, const CFeeRate& newFeerate, const int64_t maxTxSize, std::vector<bilingual_str>& errors)
66+
static feebumper::Result CheckFeeRate(const CWallet& wallet, const CWalletTx& wtx, const CFeeRate& newFeerate, const int64_t maxTxSize, CAmount old_fee, std::vector<bilingual_str>& errors)
6567
{
6668
// check that fee rate is higher than mempool's minimum fee
6769
// (no point in bumping fee if we know that the new tx won't be accepted to the mempool)
@@ -83,8 +85,6 @@ static feebumper::Result CheckFeeRate(const CWallet& wallet, const CWalletTx& wt
8385
CFeeRate incrementalRelayFee = std::max(wallet.chain().relayIncrementalFee(), CFeeRate(WALLET_INCREMENTAL_RELAY_FEE));
8486

8587
// Given old total fee and transaction size, calculate the old feeRate
86-
isminefilter filter = wallet.GetLegacyScriptPubKeyMan() && wallet.IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS) ? ISMINE_WATCH_ONLY : ISMINE_SPENDABLE;
87-
CAmount old_fee = CachedTxGetDebit(wallet, wtx, filter) - wtx.tx->GetValueOut();
8888
const int64_t txSize = GetVirtualTransactionSize(*(wtx.tx));
8989
CFeeRate nOldFeeRate(old_fee, txSize);
9090
// Min total fee is old fee + relay fee
@@ -150,12 +150,12 @@ bool TransactionCanBeBumped(const CWallet& wallet, const uint256& txid)
150150
if (wtx == nullptr) return false;
151151

152152
std::vector<bilingual_str> errors_dummy;
153-
feebumper::Result res = PreconditionChecks(wallet, *wtx, errors_dummy);
153+
feebumper::Result res = PreconditionChecks(wallet, *wtx, /* require_mine=*/ true, errors_dummy);
154154
return res == feebumper::Result::OK;
155155
}
156156

157157
Result CreateRateBumpTransaction(CWallet& wallet, const uint256& txid, const CCoinControl& coin_control, std::vector<bilingual_str>& errors,
158-
CAmount& old_fee, CAmount& new_fee, CMutableTransaction& mtx)
158+
CAmount& old_fee, CAmount& new_fee, CMutableTransaction& mtx, bool require_mine)
159159
{
160160
// We are going to modify coin control later, copy to re-use
161161
CCoinControl new_coin_control(coin_control);
@@ -169,13 +169,63 @@ Result CreateRateBumpTransaction(CWallet& wallet, const uint256& txid, const CCo
169169
}
170170
const CWalletTx& wtx = it->second;
171171

172-
Result result = PreconditionChecks(wallet, wtx, errors);
172+
// Retrieve all of the UTXOs and add them to coin control
173+
// While we're here, calculate the input amount
174+
std::map<COutPoint, Coin> coins;
175+
CAmount input_value = 0;
176+
std::vector<CTxOut> spent_outputs;
177+
for (const CTxIn& txin : wtx.tx->vin) {
178+
coins[txin.prevout]; // Create empty map entry keyed by prevout.
179+
}
180+
wallet.chain().findCoins(coins);
181+
for (const CTxIn& txin : wtx.tx->vin) {
182+
const Coin& coin = coins.at(txin.prevout);
183+
if (coin.out.IsNull()) {
184+
errors.push_back(Untranslated(strprintf("%s:%u is already spent", txin.prevout.hash.GetHex(), txin.prevout.n)));
185+
return Result::MISC_ERROR;
186+
}
187+
if (wallet.IsMine(txin.prevout)) {
188+
new_coin_control.Select(txin.prevout);
189+
} else {
190+
new_coin_control.SelectExternal(txin.prevout, coin.out);
191+
}
192+
input_value += coin.out.nValue;
193+
spent_outputs.push_back(coin.out);
194+
}
195+
196+
// Figure out if we need to compute the input weight, and do so if necessary
197+
PrecomputedTransactionData txdata;
198+
txdata.Init(*wtx.tx, std::move(spent_outputs), /* force=*/ true);
199+
for (unsigned int i = 0; i < wtx.tx->vin.size(); ++i) {
200+
const CTxIn& txin = wtx.tx->vin.at(i);
201+
const Coin& coin = coins.at(txin.prevout);
202+
203+
if (new_coin_control.IsExternalSelected(txin.prevout)) {
204+
// For external inputs, we estimate the size using the size of this input
205+
int64_t input_weight = GetTransactionInputWeight(txin);
206+
// Because signatures can have different sizes, we need to figure out all of the
207+
// signature sizes and replace them with the max sized signature.
208+
// In order to do this, we verify the script with a special SignatureChecker which
209+
// will observe the signatures verified and record their sizes.
210+
SignatureWeights weights;
211+
TransactionSignatureChecker tx_checker(wtx.tx.get(), i, coin.out.nValue, txdata, MissingDataBehavior::FAIL);
212+
SignatureWeightChecker size_checker(weights, tx_checker);
213+
VerifyScript(txin.scriptSig, coin.out.scriptPubKey, &txin.scriptWitness, STANDARD_SCRIPT_VERIFY_FLAGS, size_checker);
214+
// Add the difference between max and current to input_weight so that it represents the largest the input could be
215+
input_weight += weights.GetWeightDiffToMax();
216+
new_coin_control.SetInputWeight(txin.prevout, input_weight);
217+
}
218+
}
219+
220+
Result result = PreconditionChecks(wallet, wtx, require_mine, errors);
173221
if (result != Result::OK) {
174222
return result;
175223
}
176224

177225
// Fill in recipients(and preserve a single change key if there is one)
226+
// While we're here, calculate the output amount
178227
std::vector<CRecipient> recipients;
228+
CAmount output_value = 0;
179229
for (const auto& output : wtx.tx->vout) {
180230
if (!OutputIsChange(wallet, output)) {
181231
CRecipient recipient = {output.scriptPubKey, output.nValue, false};
@@ -185,16 +235,22 @@ Result CreateRateBumpTransaction(CWallet& wallet, const uint256& txid, const CCo
185235
ExtractDestination(output.scriptPubKey, change_dest);
186236
new_coin_control.destChange = change_dest;
187237
}
238+
output_value += output.nValue;
188239
}
189240

190-
isminefilter filter = wallet.GetLegacyScriptPubKeyMan() && wallet.IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS) ? ISMINE_WATCH_ONLY : ISMINE_SPENDABLE;
191-
old_fee = CachedTxGetDebit(wallet, wtx, filter) - wtx.tx->GetValueOut();
241+
old_fee = input_value - output_value;
192242

193243
if (coin_control.m_feerate) {
194244
// The user provided a feeRate argument.
195245
// We calculate this here to avoid compiler warning on the cs_wallet lock
196-
const int64_t maxTxSize{CalculateMaximumSignedTxSize(*wtx.tx, &wallet).vsize};
197-
Result res = CheckFeeRate(wallet, wtx, *new_coin_control.m_feerate, maxTxSize, errors);
246+
// We need to make a temporary transaction with no input witnesses as the dummy signer expects them to be empty for external inputs
247+
CMutableTransaction mtx{*wtx.tx};
248+
for (auto& txin : mtx.vin) {
249+
txin.scriptSig.clear();
250+
txin.scriptWitness.SetNull();
251+
}
252+
const int64_t maxTxSize{CalculateMaximumSignedTxSize(CTransaction(mtx), &wallet, &new_coin_control).vsize};
253+
Result res = CheckFeeRate(wallet, wtx, *new_coin_control.m_feerate, maxTxSize, old_fee, errors);
198254
if (res != Result::OK) {
199255
return res;
200256
}
@@ -254,7 +310,7 @@ Result CommitTransaction(CWallet& wallet, const uint256& txid, CMutableTransacti
254310
const CWalletTx& oldWtx = it->second;
255311

256312
// make sure the transaction still has no descendants and hasn't been mined in the meantime
257-
Result result = PreconditionChecks(wallet, oldWtx, errors);
313+
Result result = PreconditionChecks(wallet, oldWtx, /* require_mine=*/ false, errors);
258314
if (result != Result::OK) {
259315
return result;
260316
}

src/wallet/feebumper.h

+64-2
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
#ifndef BITCOIN_WALLET_FEEBUMPER_H
66
#define BITCOIN_WALLET_FEEBUMPER_H
77

8+
#include <consensus/consensus.h>
9+
#include <script/interpreter.h>
810
#include <primitives/transaction.h>
911

1012
class uint256;
@@ -31,14 +33,25 @@ enum class Result
3133
//! Return whether transaction can be bumped.
3234
bool TransactionCanBeBumped(const CWallet& wallet, const uint256& txid);
3335

34-
//! Create bumpfee transaction based on feerate estimates.
36+
/** Create bumpfee transaction based on feerate estimates.
37+
*
38+
* @param[in] wallet The wallet to use for this bumping
39+
* @param[in] txid The txid of the transaction to bump
40+
* @param[in] coin_control A CCoinControl object which provides feerates and other information used for coin selection
41+
* @param[out] errors Errors
42+
* @param[out] old_fee The fee the original transaction pays
43+
* @param[out] new_fee the fee that the bump transaction pays
44+
* @param[out] mtx The bump transaction itself
45+
* @param[in] require_mine Whether the original transaction must consist of inputs that can be spent by the wallet
46+
*/
3547
Result CreateRateBumpTransaction(CWallet& wallet,
3648
const uint256& txid,
3749
const CCoinControl& coin_control,
3850
std::vector<bilingual_str>& errors,
3951
CAmount& old_fee,
4052
CAmount& new_fee,
41-
CMutableTransaction& mtx);
53+
CMutableTransaction& mtx,
54+
bool require_mine);
4255

4356
//! Sign the new transaction,
4457
//! @return false if the tx couldn't be found or if it was
@@ -55,6 +68,55 @@ Result CommitTransaction(CWallet& wallet,
5568
std::vector<bilingual_str>& errors,
5669
uint256& bumped_txid);
5770

71+
struct SignatureWeights
72+
{
73+
private:
74+
int m_sigs_count{0};
75+
int64_t m_sigs_weight{0};
76+
77+
public:
78+
void AddSigWeight(const size_t weight, const SigVersion sigversion)
79+
{
80+
switch (sigversion) {
81+
case SigVersion::BASE:
82+
m_sigs_weight += weight * WITNESS_SCALE_FACTOR;
83+
m_sigs_count += 1 * WITNESS_SCALE_FACTOR;
84+
break;
85+
case SigVersion::WITNESS_V0:
86+
m_sigs_weight += weight;
87+
m_sigs_count++;
88+
break;
89+
case SigVersion::TAPROOT:
90+
case SigVersion::TAPSCRIPT:
91+
assert(false);
92+
}
93+
}
94+
95+
int64_t GetWeightDiffToMax() const
96+
{
97+
// Note: the witness scaling factor is already accounted for because the count is multiplied by it.
98+
return (/* max signature size=*/ 72 * m_sigs_count) - m_sigs_weight;
99+
}
100+
};
101+
102+
class SignatureWeightChecker : public DeferringSignatureChecker
103+
{
104+
private:
105+
SignatureWeights& m_weights;
106+
107+
public:
108+
SignatureWeightChecker(SignatureWeights& weights, const BaseSignatureChecker& checker) : DeferringSignatureChecker(checker), m_weights(weights) {}
109+
110+
bool CheckECDSASignature(const std::vector<unsigned char>& sig, const std::vector<unsigned char>& pubkey, const CScript& script, SigVersion sigversion) const override
111+
{
112+
if (m_checker.CheckECDSASignature(sig, pubkey, script, sigversion)) {
113+
m_weights.AddSigWeight(sig.size(), sigversion);
114+
return true;
115+
}
116+
return false;
117+
}
118+
};
119+
58120
} // namespace feebumper
59121
} // namespace wallet
60122

src/wallet/interfaces.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -291,7 +291,7 @@ class WalletImpl : public Wallet
291291
CAmount& new_fee,
292292
CMutableTransaction& mtx) override
293293
{
294-
return feebumper::CreateRateBumpTransaction(*m_wallet.get(), txid, coin_control, errors, old_fee, new_fee, mtx) == feebumper::Result::OK;
294+
return feebumper::CreateRateBumpTransaction(*m_wallet.get(), txid, coin_control, errors, old_fee, new_fee, mtx, /* require_mine= */ true) == feebumper::Result::OK;
295295
}
296296
bool signBumpTransaction(CMutableTransaction& mtx) override { return feebumper::SignTransaction(*m_wallet.get(), mtx); }
297297
bool commitBumpTransaction(const uint256& txid,

src/wallet/rpc/spend.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -1045,7 +1045,7 @@ static RPCHelpMan bumpfee_helper(std::string method_name)
10451045
CMutableTransaction mtx;
10461046
feebumper::Result res;
10471047
// Targeting feerate bump.
1048-
res = feebumper::CreateRateBumpTransaction(*pwallet, hash, coin_control, errors, old_fee, new_fee, mtx);
1048+
res = feebumper::CreateRateBumpTransaction(*pwallet, hash, coin_control, errors, old_fee, new_fee, mtx, /*require_mine=*/ !want_psbt);
10491049
if (res != feebumper::Result::OK) {
10501050
switch(res) {
10511051
case feebumper::Result::INVALID_ADDRESS_OR_KEY:

src/wallet/test/feebumper_tests.cpp

+54
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
// Copyright (c) 2022 The Bitcoin Core developers
2+
// Distributed under the MIT software license, see the accompanying
3+
// file COPYING or https://www.opensource.org/licenses/mit-license.php.
4+
5+
#include <primitives/transaction.h>
6+
#include <script/script.h>
7+
#include <util/strencodings.h>
8+
#include <wallet/feebumper.h>
9+
#include <wallet/test/util.h>
10+
#include <wallet/test/wallet_test_fixture.h>
11+
12+
#include <boost/test/unit_test.hpp>
13+
14+
namespace wallet {
15+
namespace feebumper {
16+
BOOST_FIXTURE_TEST_SUITE(feebumper_tests, WalletTestingSetup)
17+
18+
static void CheckMaxWeightComputation(const std::string& script_str, const std::vector<std::string>& witness_str_stack, const std::string& prevout_script_str, int64_t expected_max_weight)
19+
{
20+
std::vector script_data(ParseHex(script_str));
21+
CScript script(script_data.begin(), script_data.end());
22+
CTxIn input(uint256(), 0, script);
23+
24+
for (const auto& s : witness_str_stack) {
25+
input.scriptWitness.stack.push_back(ParseHex(s));
26+
}
27+
28+
std::vector prevout_script_data(ParseHex(prevout_script_str));
29+
CScript prevout_script(prevout_script_data.begin(), prevout_script_data.end());
30+
31+
int64_t weight = GetTransactionInputWeight(input);
32+
SignatureWeights weights;
33+
SignatureWeightChecker size_checker(weights, DUMMY_CHECKER);
34+
bool script_ok = VerifyScript(input.scriptSig, prevout_script, &input.scriptWitness, STANDARD_SCRIPT_VERIFY_FLAGS, size_checker);
35+
BOOST_CHECK(script_ok);
36+
weight += weights.GetWeightDiffToMax();
37+
BOOST_CHECK_EQUAL(weight, expected_max_weight);
38+
}
39+
40+
BOOST_AUTO_TEST_CASE(external_max_weight_test)
41+
{
42+
// P2PKH
43+
CheckMaxWeightComputation("453042021f03c8957c5ce12940ee6e3333ecc3f633d9a1ac53a55b3ce0351c617fa96abe021f0dccdcce3ef45a63998be9ec748b561baf077b8e862941d0cd5ec08f5afe68012102fccfeb395f0ecd3a77e7bc31c3bc61dc987418b18e395d441057b42ca043f22c", {}, "76a914f60dcfd3392b28adc7662669603641f578eed72d88ac", 593);
44+
// P2SH-P2WPKH
45+
CheckMaxWeightComputation("160014001dca1b22c599b5a56a87c78417ad2ff39552f1", {"3042021f5443c58eaf45f3e5ef46f8516f966b334a7d497cedda4edb2b9fad57c90c3b021f63a77cb56cde848e2e2dd20b487eec2f53101f634193786083f60b4d23a82301", "026cfe86116f161057deb240201d6b82ebd4f161e0200d63dc9aca65a1d6b38bb7"}, "a9147c8ab5ad7708b97ccb6b483d57aba48ee85214df87", 364);
46+
// P2WPKH
47+
CheckMaxWeightComputation("", {"3042021f0f8906f0394979d5b737134773e5b88bf036c7d63542301d600ab677ba5a59021f0e9fe07e62c113045fa1c1532e2914720e8854d189c4f5b8c88f57956b704401", "0359edba11ed1a0568094a6296a16c4d5ee4c8cfe2f5e2e6826871b5ecf8188f79"}, "00149961a78658030cc824af4c54fbf5294bec0cabdd", 272);
48+
// P2WSH HTLC
49+
CheckMaxWeightComputation("", {"3042021f5c4c29e6b686aae5b6d0751e90208592ea96d26bc81d78b0d3871a94a21fa8021f74dc2f971e438ccece8699c8fd15704c41df219ab37b63264f2147d15c34d801", "01", "6321024cf55e52ec8af7866617dc4e7ff8433758e98799906d80e066c6f32033f685f967029000b275210214827893e2dcbe4ad6c20bd743288edad21100404eb7f52ccd6062fd0e7808f268ac"}, "002089e84892873c679b1129edea246e484fd914c2601f776d4f2f4a001eb8059703", 318);
50+
}
51+
52+
BOOST_AUTO_TEST_SUITE_END()
53+
} // namespace feebumper
54+
} // namespace wallet

0 commit comments

Comments
 (0)