23
23
// calculation, but we should be able to refactor after priority is removed).
24
24
// NOTE: this requires that all inputs must be in mapWallet (eg the tx should
25
25
// be IsAllFromMe).
26
- int64_t CalculateMaximumSignedTxSize (const CTransaction &tx, const CWallet *pWallet )
26
+ int64_t CalculateMaximumSignedTxSize (const CTransaction &tx, const CWallet *wallet )
27
27
{
28
28
CMutableTransaction txNew (tx);
29
29
std::vector<CInputCoin> vCoins;
30
30
// Look up the inputs. We should have already checked that this transaction
31
31
// IsAllFromMe(ISMINE_SPENDABLE), so every input should already be in our
32
32
// wallet, with a valid index into the vout array.
33
33
for (auto & input : tx.vin ) {
34
- const auto mi = pWallet ->mapWallet .find (input.prevout .hash );
35
- assert (mi != pWallet ->mapWallet .end () && input.prevout .n < mi->second .tx ->vout .size ());
34
+ const auto mi = wallet ->mapWallet .find (input.prevout .hash );
35
+ assert (mi != wallet ->mapWallet .end () && input.prevout .n < mi->second .tx ->vout .size ());
36
36
vCoins.emplace_back (CInputCoin (&(mi->second ), input.prevout .n ));
37
37
}
38
- if (!pWallet ->DummySignTx (txNew, vCoins)) {
38
+ if (!wallet ->DummySignTx (txNew, vCoins)) {
39
39
// This should never happen, because IsAllFromMe(ISMINE_SPENDABLE)
40
40
// implies that we can sign for every input.
41
41
return -1 ;
42
42
}
43
43
return GetVirtualTransactionSize (txNew);
44
44
}
45
45
46
- bool CFeeBumper ::preconditionChecks (const CWallet *pWallet , const CWalletTx& wtx) {
47
- if (pWallet ->HasWalletSpend (wtx.GetHash ())) {
48
- vErrors .push_back (" Transaction has descendants in the wallet" );
49
- currentResult = BumpFeeResult::INVALID_PARAMETER;
46
+ bool FeeBumper ::preconditionChecks (const CWallet *wallet , const CWalletTx& wtx) {
47
+ if (wallet ->HasWalletSpend (wtx.GetHash ())) {
48
+ errors .push_back (" Transaction has descendants in the wallet" );
49
+ current_result = BumpFeeResult::INVALID_PARAMETER;
50
50
return false ;
51
51
}
52
52
53
53
{
54
54
LOCK (mempool.cs );
55
55
auto it_mp = mempool.mapTx .find (wtx.GetHash ());
56
56
if (it_mp != mempool.mapTx .end () && it_mp->GetCountWithDescendants () > 1 ) {
57
- vErrors .push_back (" Transaction has descendants in the mempool" );
58
- currentResult = BumpFeeResult::INVALID_PARAMETER;
57
+ errors .push_back (" Transaction has descendants in the mempool" );
58
+ current_result = BumpFeeResult::INVALID_PARAMETER;
59
59
return false ;
60
60
}
61
61
}
62
62
63
63
if (wtx.GetDepthInMainChain () != 0 ) {
64
- vErrors .push_back (" Transaction has been mined, or is conflicted with a mined transaction" );
65
- currentResult = BumpFeeResult::WALLET_ERROR;
64
+ errors .push_back (" Transaction has been mined, or is conflicted with a mined transaction" );
65
+ current_result = BumpFeeResult::WALLET_ERROR;
66
66
return false ;
67
67
}
68
68
return true ;
69
69
}
70
70
71
- CFeeBumper::CFeeBumper (const CWallet *pWallet , const uint256 txidIn , const CCoinControl& coin_control, CAmount totalFee )
71
+ FeeBumper::FeeBumper (const CWallet *wallet , const uint256 txid_in , const CCoinControl& coin_control, CAmount total_fee )
72
72
:
73
- txid(std::move(txidIn )),
74
- nOldFee (0 ),
75
- nNewFee (0 )
73
+ txid(std::move(txid_in )),
74
+ old_fee (0 ),
75
+ new_fee (0 )
76
76
{
77
- vErrors .clear ();
78
- bumpedTxid .SetNull ();
79
- AssertLockHeld (pWallet ->cs_wallet );
80
- auto it = pWallet ->mapWallet .find (txid);
81
- if (it == pWallet ->mapWallet .end ()) {
82
- vErrors .push_back (" Invalid or non-wallet transaction id" );
83
- currentResult = BumpFeeResult::INVALID_ADDRESS_OR_KEY;
77
+ errors .clear ();
78
+ bumped_txid .SetNull ();
79
+ AssertLockHeld (wallet ->cs_wallet );
80
+ auto it = wallet ->mapWallet .find (txid);
81
+ if (it == wallet ->mapWallet .end ()) {
82
+ errors .push_back (" Invalid or non-wallet transaction id" );
83
+ current_result = BumpFeeResult::INVALID_ADDRESS_OR_KEY;
84
84
return ;
85
85
}
86
86
const CWalletTx& wtx = it->second ;
87
87
88
- if (!preconditionChecks (pWallet , wtx)) {
88
+ if (!preconditionChecks (wallet , wtx)) {
89
89
return ;
90
90
}
91
91
92
92
if (!SignalsOptInRBF (*wtx.tx )) {
93
- vErrors .push_back (" Transaction is not BIP 125 replaceable" );
94
- currentResult = BumpFeeResult::WALLET_ERROR;
93
+ errors .push_back (" Transaction is not BIP 125 replaceable" );
94
+ current_result = BumpFeeResult::WALLET_ERROR;
95
95
return ;
96
96
}
97
97
98
98
if (wtx.mapValue .count (" replaced_by_txid" )) {
99
- vErrors .push_back (strprintf (" Cannot bump transaction %s which was already bumped by transaction %s" , txid.ToString (), wtx.mapValue .at (" replaced_by_txid" )));
100
- currentResult = BumpFeeResult::WALLET_ERROR;
99
+ errors .push_back (strprintf (" Cannot bump transaction %s which was already bumped by transaction %s" , txid.ToString (), wtx.mapValue .at (" replaced_by_txid" )));
100
+ current_result = BumpFeeResult::WALLET_ERROR;
101
101
return ;
102
102
}
103
103
104
104
// check that original tx consists entirely of our inputs
105
105
// 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)
106
- if (!pWallet ->IsAllFromMe (*wtx.tx , ISMINE_SPENDABLE)) {
107
- vErrors .push_back (" Transaction contains inputs that don't belong to this wallet" );
108
- currentResult = BumpFeeResult::WALLET_ERROR;
106
+ if (!wallet ->IsAllFromMe (*wtx.tx , ISMINE_SPENDABLE)) {
107
+ errors .push_back (" Transaction contains inputs that don't belong to this wallet" );
108
+ current_result = BumpFeeResult::WALLET_ERROR;
109
109
return ;
110
110
}
111
111
112
112
// figure out which output was change
113
113
// if there was no change output or multiple change outputs, fail
114
114
int nOutput = -1 ;
115
115
for (size_t i = 0 ; i < wtx.tx ->vout .size (); ++i) {
116
- if (pWallet ->IsChange (wtx.tx ->vout [i])) {
116
+ if (wallet ->IsChange (wtx.tx ->vout [i])) {
117
117
if (nOutput != -1 ) {
118
- vErrors .push_back (" Transaction has multiple change outputs" );
119
- currentResult = BumpFeeResult::WALLET_ERROR;
118
+ errors .push_back (" Transaction has multiple change outputs" );
119
+ current_result = BumpFeeResult::WALLET_ERROR;
120
120
return ;
121
121
}
122
122
nOutput = i;
123
123
}
124
124
}
125
125
if (nOutput == -1 ) {
126
- vErrors .push_back (" Transaction does not have a change output" );
127
- currentResult = BumpFeeResult::WALLET_ERROR;
126
+ errors .push_back (" Transaction does not have a change output" );
127
+ current_result = BumpFeeResult::WALLET_ERROR;
128
128
return ;
129
129
}
130
130
131
131
// Calculate the expected size of the new transaction.
132
132
int64_t txSize = GetVirtualTransactionSize (*(wtx.tx ));
133
- const int64_t maxNewTxSize = CalculateMaximumSignedTxSize (*wtx.tx , pWallet );
133
+ const int64_t maxNewTxSize = CalculateMaximumSignedTxSize (*wtx.tx , wallet );
134
134
if (maxNewTxSize < 0 ) {
135
- vErrors .push_back (" Transaction contains inputs that cannot be signed" );
136
- currentResult = BumpFeeResult::INVALID_ADDRESS_OR_KEY;
135
+ errors .push_back (" Transaction contains inputs that cannot be signed" );
136
+ current_result = BumpFeeResult::INVALID_ADDRESS_OR_KEY;
137
137
return ;
138
138
}
139
139
140
140
// calculate the old fee and fee-rate
141
- nOldFee = wtx.GetDebit (ISMINE_SPENDABLE) - wtx.tx ->GetValueOut ();
142
- CFeeRate nOldFeeRate (nOldFee , txSize);
141
+ old_fee = wtx.GetDebit (ISMINE_SPENDABLE) - wtx.tx ->GetValueOut ();
142
+ CFeeRate nOldFeeRate (old_fee , txSize);
143
143
CFeeRate nNewFeeRate;
144
144
// The wallet uses a conservative WALLET_INCREMENTAL_RELAY_FEE value to
145
145
// future proof against changes to network wide policy for incremental relay
@@ -149,26 +149,26 @@ CFeeBumper::CFeeBumper(const CWallet *pWallet, const uint256 txidIn, const CCoin
149
149
walletIncrementalRelayFee = ::incrementalRelayFee;
150
150
}
151
151
152
- if (totalFee > 0 ) {
152
+ if (total_fee > 0 ) {
153
153
CAmount minTotalFee = nOldFeeRate.GetFee (maxNewTxSize) + ::incrementalRelayFee.GetFee (maxNewTxSize);
154
- if (totalFee < minTotalFee) {
155
- vErrors .push_back (strprintf (" Insufficient totalFee, must be at least %s (oldFee %s + incrementalFee %s)" ,
154
+ if (total_fee < minTotalFee) {
155
+ errors .push_back (strprintf (" Insufficient totalFee, must be at least %s (oldFee %s + incrementalFee %s)" ,
156
156
FormatMoney (minTotalFee), FormatMoney (nOldFeeRate.GetFee (maxNewTxSize)), FormatMoney (::incrementalRelayFee.GetFee (maxNewTxSize))));
157
- currentResult = BumpFeeResult::INVALID_PARAMETER;
157
+ current_result = BumpFeeResult::INVALID_PARAMETER;
158
158
return ;
159
159
}
160
160
CAmount requiredFee = GetRequiredFee (maxNewTxSize);
161
- if (totalFee < requiredFee) {
162
- vErrors .push_back (strprintf (" Insufficient totalFee (cannot be less than required fee %s)" ,
161
+ if (total_fee < requiredFee) {
162
+ errors .push_back (strprintf (" Insufficient totalFee (cannot be less than required fee %s)" ,
163
163
FormatMoney (requiredFee)));
164
- currentResult = BumpFeeResult::INVALID_PARAMETER;
164
+ current_result = BumpFeeResult::INVALID_PARAMETER;
165
165
return ;
166
166
}
167
- nNewFee = totalFee ;
168
- nNewFeeRate = CFeeRate (totalFee , maxNewTxSize);
167
+ new_fee = total_fee ;
168
+ nNewFeeRate = CFeeRate (total_fee , maxNewTxSize);
169
169
} else {
170
- nNewFee = GetMinimumFee (maxNewTxSize, coin_control, mempool, ::feeEstimator, nullptr /* FeeCalculation */ );
171
- nNewFeeRate = CFeeRate (nNewFee , maxNewTxSize);
170
+ new_fee = GetMinimumFee (maxNewTxSize, coin_control, mempool, ::feeEstimator, nullptr /* FeeCalculation */ );
171
+ nNewFeeRate = CFeeRate (new_fee , maxNewTxSize);
172
172
173
173
// New fee rate must be at least old rate + minimum incremental relay rate
174
174
// walletIncrementalRelayFee.GetFeePerK() should be exact, because it's initialized
@@ -177,53 +177,53 @@ CFeeBumper::CFeeBumper(const CWallet *pWallet, const uint256 txidIn, const CCoin
177
177
// add 1 satoshi to the result, because it may have been rounded down.
178
178
if (nNewFeeRate.GetFeePerK () < nOldFeeRate.GetFeePerK () + 1 + walletIncrementalRelayFee.GetFeePerK ()) {
179
179
nNewFeeRate = CFeeRate (nOldFeeRate.GetFeePerK () + 1 + walletIncrementalRelayFee.GetFeePerK ());
180
- nNewFee = nNewFeeRate.GetFee (maxNewTxSize);
180
+ new_fee = nNewFeeRate.GetFee (maxNewTxSize);
181
181
}
182
182
}
183
183
184
184
// Check that in all cases the new fee doesn't violate maxTxFee
185
- if (nNewFee > maxTxFee) {
186
- vErrors .push_back (strprintf (" Specified or calculated fee %s is too high (cannot be higher than maxTxFee %s)" ,
187
- FormatMoney (nNewFee ), FormatMoney (maxTxFee)));
188
- currentResult = BumpFeeResult::WALLET_ERROR;
185
+ if (new_fee > maxTxFee) {
186
+ errors .push_back (strprintf (" Specified or calculated fee %s is too high (cannot be higher than maxTxFee %s)" ,
187
+ FormatMoney (new_fee ), FormatMoney (maxTxFee)));
188
+ current_result = BumpFeeResult::WALLET_ERROR;
189
189
return ;
190
190
}
191
191
192
192
// check that fee rate is higher than mempool's minimum fee
193
193
// (no point in bumping fee if we know that the new tx won't be accepted to the mempool)
194
194
// This may occur if the user set TotalFee or paytxfee too low, if fallbackfee is too low, or, perhaps,
195
195
// in a rare situation where the mempool minimum fee increased significantly since the fee estimation just a
196
- // moment earlier. In this case, we report an error to the user, who may use totalFee to make an adjustment.
196
+ // moment earlier. In this case, we report an error to the user, who may use total_fee to make an adjustment.
197
197
CFeeRate minMempoolFeeRate = mempool.GetMinFee (gArgs .GetArg (" -maxmempool" , DEFAULT_MAX_MEMPOOL_SIZE) * 1000000 );
198
198
if (nNewFeeRate.GetFeePerK () < minMempoolFeeRate.GetFeePerK ()) {
199
- vErrors .push_back (strprintf (
199
+ errors .push_back (strprintf (
200
200
" New fee rate (%s) is lower than the minimum fee rate (%s) to get into the mempool -- "
201
201
" the totalFee value should be at least %s or the settxfee value should be at least %s to add transaction" ,
202
202
FormatMoney (nNewFeeRate.GetFeePerK ()),
203
203
FormatMoney (minMempoolFeeRate.GetFeePerK ()),
204
204
FormatMoney (minMempoolFeeRate.GetFee (maxNewTxSize)),
205
205
FormatMoney (minMempoolFeeRate.GetFeePerK ())));
206
- currentResult = BumpFeeResult::WALLET_ERROR;
206
+ current_result = BumpFeeResult::WALLET_ERROR;
207
207
return ;
208
208
}
209
209
210
210
// Now modify the output to increase the fee.
211
211
// If the output is not large enough to pay the fee, fail.
212
- CAmount nDelta = nNewFee - nOldFee ;
212
+ CAmount nDelta = new_fee - old_fee ;
213
213
assert (nDelta > 0 );
214
214
mtx = *wtx.tx ;
215
215
CTxOut* poutput = &(mtx.vout [nOutput]);
216
216
if (poutput->nValue < nDelta) {
217
- vErrors .push_back (" Change output is too small to bump the fee" );
218
- currentResult = BumpFeeResult::WALLET_ERROR;
217
+ errors .push_back (" Change output is too small to bump the fee" );
218
+ current_result = BumpFeeResult::WALLET_ERROR;
219
219
return ;
220
220
}
221
221
222
222
// If the output would become dust, discard it (converting the dust to fee)
223
223
poutput->nValue -= nDelta;
224
224
if (poutput->nValue <= GetDustThreshold (*poutput, ::dustRelayFee)) {
225
225
LogPrint (BCLog::RPC, " Bumping fee and discarding dust output\n " );
226
- nNewFee += poutput->nValue ;
226
+ new_fee += poutput->nValue ;
227
227
mtx.vout .erase (mtx.vout .begin () + nOutput);
228
228
}
229
229
@@ -234,63 +234,63 @@ CFeeBumper::CFeeBumper(const CWallet *pWallet, const uint256 txidIn, const CCoin
234
234
}
235
235
}
236
236
237
- currentResult = BumpFeeResult::OK;
237
+ current_result = BumpFeeResult::OK;
238
238
}
239
239
240
- bool CFeeBumper ::signTransaction (CWallet *pWallet )
240
+ bool FeeBumper ::signTransaction (CWallet *wallet )
241
241
{
242
- return pWallet ->SignTransaction (mtx);
242
+ return wallet ->SignTransaction (mtx);
243
243
}
244
244
245
- bool CFeeBumper ::commit (CWallet *pWallet )
245
+ bool FeeBumper ::commit (CWallet *wallet )
246
246
{
247
- AssertLockHeld (pWallet ->cs_wallet );
248
- if (!vErrors .empty () || currentResult != BumpFeeResult::OK) {
247
+ AssertLockHeld (wallet ->cs_wallet );
248
+ if (!errors .empty () || current_result != BumpFeeResult::OK) {
249
249
return false ;
250
250
}
251
- auto it = txid.IsNull () ? pWallet ->mapWallet .end () : pWallet ->mapWallet .find (txid);
252
- if (it == pWallet ->mapWallet .end ()) {
253
- vErrors .push_back (" Invalid or non-wallet transaction id" );
254
- currentResult = BumpFeeResult::MISC_ERROR;
251
+ auto it = txid.IsNull () ? wallet ->mapWallet .end () : wallet ->mapWallet .find (txid);
252
+ if (it == wallet ->mapWallet .end ()) {
253
+ errors .push_back (" Invalid or non-wallet transaction id" );
254
+ current_result = BumpFeeResult::MISC_ERROR;
255
255
return false ;
256
256
}
257
257
CWalletTx& oldWtx = it->second ;
258
258
259
259
// make sure the transaction still has no descendants and hasn't been mined in the meantime
260
- if (!preconditionChecks (pWallet , oldWtx)) {
260
+ if (!preconditionChecks (wallet , oldWtx)) {
261
261
return false ;
262
262
}
263
263
264
- CWalletTx wtxBumped (pWallet , MakeTransactionRef (std::move (mtx)));
264
+ CWalletTx wtxBumped (wallet , MakeTransactionRef (std::move (mtx)));
265
265
// commit/broadcast the tx
266
- CReserveKey reservekey (pWallet );
266
+ CReserveKey reservekey (wallet );
267
267
wtxBumped.mapValue = oldWtx.mapValue ;
268
268
wtxBumped.mapValue [" replaces_txid" ] = oldWtx.GetHash ().ToString ();
269
269
wtxBumped.vOrderForm = oldWtx.vOrderForm ;
270
270
wtxBumped.strFromAccount = oldWtx.strFromAccount ;
271
271
wtxBumped.fTimeReceivedIsTxTime = true ;
272
272
wtxBumped.fFromMe = true ;
273
273
CValidationState state;
274
- if (!pWallet ->CommitTransaction (wtxBumped, reservekey, g_connman.get (), state)) {
274
+ if (!wallet ->CommitTransaction (wtxBumped, reservekey, g_connman.get (), state)) {
275
275
// NOTE: CommitTransaction never returns false, so this should never happen.
276
- vErrors .push_back (strprintf (" The transaction was rejected: %s" , state.GetRejectReason ()));
276
+ errors .push_back (strprintf (" The transaction was rejected: %s" , state.GetRejectReason ()));
277
277
return false ;
278
278
}
279
279
280
- bumpedTxid = wtxBumped.GetHash ();
280
+ bumped_txid = wtxBumped.GetHash ();
281
281
if (state.IsInvalid ()) {
282
282
// This can happen if the mempool rejected the transaction. Report
283
283
// what happened in the "errors" response.
284
- vErrors .push_back (strprintf (" The transaction was rejected: %s" , FormatStateMessage (state)));
284
+ errors .push_back (strprintf (" The transaction was rejected: %s" , FormatStateMessage (state)));
285
285
}
286
286
287
287
// mark the original tx as bumped
288
- if (!pWallet ->MarkReplaced (oldWtx.GetHash (), wtxBumped.GetHash ())) {
288
+ if (!wallet ->MarkReplaced (oldWtx.GetHash (), wtxBumped.GetHash ())) {
289
289
// TODO: see if JSON-RPC has a standard way of returning a response
290
290
// along with an exception. It would be good to return information about
291
291
// wtxBumped to the caller even if marking the original transaction
292
292
// replaced does not succeed for some reason.
293
- vErrors .push_back (" Created new bumpfee transaction but could not mark the original transaction as replaced" );
293
+ errors .push_back (" Created new bumpfee transaction but could not mark the original transaction as replaced" );
294
294
}
295
295
return true ;
296
296
}
0 commit comments