Skip to content
Bitcoin Roots

v30.3-roots.1 · Commit 49: [PATCH 49/68] wallet: snapshot sweep fee settings under lock

src/wallet/test/spend_tests.cpp

Before: src/wallet/test/spend_tests.cpp · After: src/wallet/test/spend_tests.cpp

File metadata
index dd1ac13a193f2c3d88b9992dc9d407d2887a1093..67e535d15990592dcd99ac606d04d9d85d73ca33 100644

Download original patch · Release notes

Diff rows 1–61 of 61. Line numbers refer to the original before/after files.

+ Added− RemovedUnmarked lines are context.

Scroll the code area horizontally to read long lines. The two line-number columns refer to before and after.

src/wallet/test/spend_tests.cpp CHANGED
@@ -105,6 +105,61 @@ BOOST_FIXTURE_TEST_CASE(sweep_transaction_failure_atomicity, TestChain100Setup)
105
105
  BOOST_CHECK(committed_authorization.BroadcastStarted());
106
106
  }
107
107
 
108
+ BOOST_FIXTURE_TEST_CASE(sweep_transaction_uses_one_fee_snapshot, TestChain100Setup)
109
+ {
110
+ CreateAndProcessBlock({}, GetScriptForRawPubKey(coinbaseKey.GetPubKey()));
111
+ auto wallet = CreateSyncedWallet(*m_node.chain, WITH_LOCK(Assert(m_node.chainman)->GetMutex(), return m_node.chainman->ActiveChain()), coinbaseKey);
112
+ const CKey key{GenerateRandomKey()};
113
+ const CScript script{GetScriptForDestination(PKHash{key.GetPubKey()})};
114
+ const std::map<COutPoint, Coin> coins{{COutPoint{Txid{}, 1}, Coin{CTxOut{COIN, script}, 1, false}}};
115
+ const CFeeRate initial_rate{1000};
116
+ const CFeeRate changed_rate{10000};
117
+ WITH_LOCK(wallet->cs_wallet, wallet->m_pay_tx_fee = initial_rate);
118
+
119
+ // Change the wallet setting when signing the fee-adjusted transaction,
120
+ // after the operation has selected its fee rate. This deterministically
121
+ // models a concurrent settxfee without timing-sensitive threads.
122
+ class FeeChangingProvider final : public SigningProvider
123
+ {
124
+ CWallet& m_wallet;
125
+ FlatSigningProvider m_provider;
126
+ CFeeRate m_changed_rate;
127
+
128
+ public:
129
+ mutable int key_requests{0};
130
+ FeeChangingProvider(CWallet& wallet, const CKey& key, CFeeRate changed_rate)
131
+ : m_wallet{wallet}, m_changed_rate{changed_rate}
132
+ {
133
+ m_provider.keys.emplace(key.GetPubKey().GetID(), key);
134
+ m_provider.pubkeys.emplace(key.GetPubKey().GetID(), key.GetPubKey());
135
+ }
136
+ bool GetKey(const CKeyID& id, CKey& key_out) const override
137
+ {
138
+ AssertLockNotHeld(m_wallet.cs_wallet);
139
+ if (++key_requests == 2) {
140
+ WITH_LOCK(m_wallet.cs_wallet, m_wallet.m_pay_tx_fee = m_changed_rate);
141
+ }
142
+ return m_provider.GetKey(id, key_out);
143
+ }
144
+ bool GetPubKey(const CKeyID& id, CPubKey& pubkey) const override
145
+ {
146
+ return m_provider.GetPubKey(id, pubkey);
147
+ }
148
+ } provider{*wallet, key, changed_rate};
149
+
150
+ interfaces::SweepAuthorization authorization;
151
+ auto result{CreateSweepTransaction(*wallet, provider, coins, script, [&](const CTransactionRef&, std::string&) {
152
+ AssertLockNotHeld(wallet->cs_wallet);
153
+ return true;
154
+ }, authorization)};
155
+ BOOST_REQUIRE(result);
156
+ BOOST_CHECK_GE(provider.key_requests, 2);
157
+ BOOST_CHECK(WITH_LOCK(wallet->cs_wallet, return wallet->m_pay_tx_fee == changed_rate));
158
+ const auto vsize{GetVirtualTransactionSize(*result->tx)};
159
+ BOOST_CHECK_GE(result->fee, initial_rate.GetFee(vsize));
160
+ BOOST_CHECK_LT(result->fee, changed_rate.GetFee(vsize));
161
+ }
162
+
108
163
  BOOST_FIXTURE_TEST_CASE(SubtractFee, TestChain100Setup)
109
164
  {
110
165
  CreateAndProcessBlock({}, GetScriptForRawPubKey(coinbaseKey.GetPubKey()));