@@ -670,11 +670,11 @@ class MemPoolAccept
670
670
AssertLockHeld (m_pool.cs );
671
671
CAmount mempoolRejectFee = m_pool.GetMinFee ().GetFee (package_size);
672
672
if (mempoolRejectFee > 0 && package_fee < mempoolRejectFee) {
673
- return state.Invalid (TxValidationResult::TX_MEMPOOL_POLICY , " mempool min fee not met" , strprintf (" %d < %d" , package_fee, mempoolRejectFee));
673
+ return state.Invalid (TxValidationResult::TX_RECONSIDERABLE , " mempool min fee not met" , strprintf (" %d < %d" , package_fee, mempoolRejectFee));
674
674
}
675
675
676
676
if (package_fee < m_pool.m_min_relay_feerate .GetFee (package_size)) {
677
- return state.Invalid (TxValidationResult::TX_MEMPOOL_POLICY , " min relay fee not met" ,
677
+ return state.Invalid (TxValidationResult::TX_RECONSIDERABLE , " min relay fee not met" ,
678
678
strprintf (" %d < %d" , package_fee, m_pool.m_min_relay_feerate .GetFee (package_size)));
679
679
}
680
680
return true ;
@@ -867,6 +867,8 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws)
867
867
// method of ensuring the tx remains bumped. For example, the fee-bumping child could disappear
868
868
// due to a replacement.
869
869
if (!bypass_limits && ws.m_modified_fees < m_pool.m_min_relay_feerate .GetFee (ws.m_vsize )) {
870
+ // Even though this is a fee-related failure, this result is TX_MEMPOOL_POLICY, not
871
+ // TX_RECONSIDERABLE, because it cannot be bypassed using package validation.
870
872
return state.Invalid (TxValidationResult::TX_MEMPOOL_POLICY, " min relay fee not met" ,
871
873
strprintf (" %d < %d" , ws.m_modified_fees , m_pool.m_min_relay_feerate .GetFee (ws.m_vsize )));
872
874
}
@@ -981,6 +983,9 @@ bool MemPoolAccept::ReplacementChecks(Workspace& ws)
981
983
// descendant transaction of a direct conflict to pay a higher feerate than the transaction that
982
984
// might replace them, under these rules.
983
985
if (const auto err_string{PaysMoreThanConflicts (ws.m_iters_conflicting , newFeeRate, hash)}) {
986
+ // Even though this is a fee-related failure, this result is TX_MEMPOOL_POLICY, not
987
+ // TX_RECONSIDERABLE, because it cannot be bypassed using package validation.
988
+ // This must be changed if package RBF is enabled.
984
989
return state.Invalid (TxValidationResult::TX_MEMPOOL_POLICY, " insufficient fee" , *err_string);
985
990
}
986
991
@@ -1002,6 +1007,9 @@ bool MemPoolAccept::ReplacementChecks(Workspace& ws)
1002
1007
}
1003
1008
if (const auto err_string{PaysForRBF (ws.m_conflicting_fees , ws.m_modified_fees , ws.m_vsize ,
1004
1009
m_pool.m_incremental_relay_feerate , hash)}) {
1010
+ // Even though this is a fee-related failure, this result is TX_MEMPOOL_POLICY, not
1011
+ // TX_RECONSIDERABLE, because it cannot be bypassed using package validation.
1012
+ // This must be changed if package RBF is enabled.
1005
1013
return state.Invalid (TxValidationResult::TX_MEMPOOL_POLICY, " insufficient fee" , *err_string);
1006
1014
}
1007
1015
return true ;
@@ -1139,7 +1147,8 @@ bool MemPoolAccept::Finalize(const ATMPArgs& args, Workspace& ws)
1139
1147
if (!args.m_package_submission && !bypass_limits) {
1140
1148
LimitMempoolSize (m_pool, m_active_chainstate.CoinsTip ());
1141
1149
if (!m_pool.exists (GenTxid::Txid (hash)))
1142
- return state.Invalid (TxValidationResult::TX_MEMPOOL_POLICY, " mempool full" );
1150
+ // The tx no longer meets our (new) mempool minimum feerate but could be reconsidered in a package.
1151
+ return state.Invalid (TxValidationResult::TX_RECONSIDERABLE, " mempool full" );
1143
1152
}
1144
1153
return true ;
1145
1154
}
@@ -1201,7 +1210,7 @@ bool MemPoolAccept::SubmitPackage(const ATMPArgs& args, std::vector<Workspace>&
1201
1210
}
1202
1211
}
1203
1212
1204
- std::vector<uint256 > all_package_wtxids;
1213
+ std::vector<Wtxid > all_package_wtxids;
1205
1214
all_package_wtxids.reserve (workspaces.size ());
1206
1215
std::transform (workspaces.cbegin (), workspaces.cend (), std::back_inserter (all_package_wtxids),
1207
1216
[](const auto & ws) { return ws.m_ptx ->GetWitnessHash (); });
@@ -1211,7 +1220,7 @@ bool MemPoolAccept::SubmitPackage(const ATMPArgs& args, std::vector<Workspace>&
1211
1220
const auto effective_feerate = args.m_package_feerates ? ws.m_package_feerate :
1212
1221
CFeeRate{ws.m_modified_fees , static_cast <uint32_t >(ws.m_vsize )};
1213
1222
const auto effective_feerate_wtxids = args.m_package_feerates ? all_package_wtxids :
1214
- std::vector<uint256>( {ws.m_ptx ->GetWitnessHash ()}) ;
1223
+ std::vector<Wtxid> {ws.m_ptx ->GetWitnessHash ()};
1215
1224
results.emplace (ws.m_ptx ->GetWitnessHash (),
1216
1225
MempoolAcceptResult::Success (std::move (ws.m_replaced_transactions ), ws.m_vsize ,
1217
1226
ws.m_base_fees , effective_feerate, effective_feerate_wtxids));
@@ -1226,8 +1235,15 @@ MempoolAcceptResult MemPoolAccept::AcceptSingleTransaction(const CTransactionRef
1226
1235
LOCK (m_pool.cs ); // mempool "read lock" (held through GetMainSignals().TransactionAddedToMempool())
1227
1236
1228
1237
Workspace ws (ptx);
1238
+ const std::vector<Wtxid> single_wtxid{ws.m_ptx ->GetWitnessHash ()};
1229
1239
1230
- if (!PreChecks (args, ws)) return MempoolAcceptResult::Failure (ws.m_state );
1240
+ if (!PreChecks (args, ws)) {
1241
+ if (ws.m_state .GetResult () == TxValidationResult::TX_RECONSIDERABLE) {
1242
+ // Failed for fee reasons. Provide the effective feerate and which tx was included.
1243
+ return MempoolAcceptResult::FeeFailure (ws.m_state , CFeeRate (ws.m_modified_fees , ws.m_vsize ), single_wtxid);
1244
+ }
1245
+ return MempoolAcceptResult::Failure (ws.m_state );
1246
+ }
1231
1247
1232
1248
if (m_rbf && !ReplacementChecks (ws)) return MempoolAcceptResult::Failure (ws.m_state );
1233
1249
@@ -1238,14 +1254,18 @@ MempoolAcceptResult MemPoolAccept::AcceptSingleTransaction(const CTransactionRef
1238
1254
if (!ConsensusScriptChecks (args, ws)) return MempoolAcceptResult::Failure (ws.m_state );
1239
1255
1240
1256
const CFeeRate effective_feerate{ws.m_modified_fees , static_cast <uint32_t >(ws.m_vsize )};
1241
- const std::vector<uint256> single_wtxid{ws.m_ptx ->GetWitnessHash ()};
1242
1257
// Tx was accepted, but not added
1243
1258
if (args.m_test_accept ) {
1244
1259
return MempoolAcceptResult::Success (std::move (ws.m_replaced_transactions ), ws.m_vsize ,
1245
1260
ws.m_base_fees , effective_feerate, single_wtxid);
1246
1261
}
1247
1262
1248
- if (!Finalize (args, ws)) return MempoolAcceptResult::Failure (ws.m_state );
1263
+ if (!Finalize (args, ws)) {
1264
+ // The only possible failure reason is fee-related (mempool full).
1265
+ // Failed for fee reasons. Provide the effective feerate and which txns were included.
1266
+ Assume (ws.m_state .GetResult () == TxValidationResult::TX_RECONSIDERABLE);
1267
+ return MempoolAcceptResult::FeeFailure (ws.m_state , CFeeRate (ws.m_modified_fees , ws.m_vsize ), {ws.m_ptx ->GetWitnessHash ()});
1268
+ }
1249
1269
1250
1270
GetMainSignals ().TransactionAddedToMempool (ptx, m_pool.GetAndIncrementSequence ());
1251
1271
@@ -1299,11 +1319,16 @@ PackageMempoolAcceptResult MemPoolAccept::AcceptMultipleTransactions(const std::
1299
1319
const auto m_total_modified_fees = std::accumulate (workspaces.cbegin (), workspaces.cend (), CAmount{0 },
1300
1320
[](CAmount sum, auto & ws) { return sum + ws.m_modified_fees ; });
1301
1321
const CFeeRate package_feerate (m_total_modified_fees, m_total_vsize);
1322
+ std::vector<Wtxid> all_package_wtxids;
1323
+ all_package_wtxids.reserve (workspaces.size ());
1324
+ std::transform (workspaces.cbegin (), workspaces.cend (), std::back_inserter (all_package_wtxids),
1325
+ [](const auto & ws) { return ws.m_ptx ->GetWitnessHash (); });
1302
1326
TxValidationState placeholder_state;
1303
1327
if (args.m_package_feerates &&
1304
1328
!CheckFeeRate (m_total_vsize, m_total_modified_fees, placeholder_state)) {
1305
- package_state.Invalid (PackageValidationResult::PCKG_POLICY, " package-fee-too-low" );
1306
- return PackageMempoolAcceptResult (package_state, {});
1329
+ package_state.Invalid (PackageValidationResult::PCKG_TX, " transaction failed" );
1330
+ return PackageMempoolAcceptResult (package_state, {{workspaces.back ().m_ptx ->GetWitnessHash (),
1331
+ MempoolAcceptResult::FeeFailure (placeholder_state, CFeeRate (m_total_modified_fees, m_total_vsize), all_package_wtxids)}});
1307
1332
}
1308
1333
1309
1334
// Apply package mempool ancestor/descendant limits. Skip if there is only one transaction,
@@ -1314,10 +1339,6 @@ PackageMempoolAcceptResult MemPoolAccept::AcceptMultipleTransactions(const std::
1314
1339
return PackageMempoolAcceptResult (package_state, std::move (results));
1315
1340
}
1316
1341
1317
- std::vector<uint256> all_package_wtxids;
1318
- all_package_wtxids.reserve (workspaces.size ());
1319
- std::transform (workspaces.cbegin (), workspaces.cend (), std::back_inserter (all_package_wtxids),
1320
- [](const auto & ws) { return ws.m_ptx ->GetWitnessHash (); });
1321
1342
for (Workspace& ws : workspaces) {
1322
1343
ws.m_package_feerate = package_feerate;
1323
1344
if (!PolicyScriptChecks (args, ws)) {
@@ -1330,7 +1351,7 @@ PackageMempoolAcceptResult MemPoolAccept::AcceptMultipleTransactions(const std::
1330
1351
const auto effective_feerate = args.m_package_feerates ? ws.m_package_feerate :
1331
1352
CFeeRate{ws.m_modified_fees , static_cast <uint32_t >(ws.m_vsize )};
1332
1353
const auto effective_feerate_wtxids = args.m_package_feerates ? all_package_wtxids :
1333
- std::vector<uint256 >{ws.m_ptx ->GetWitnessHash ()};
1354
+ std::vector<Wtxid >{ws.m_ptx ->GetWitnessHash ()};
1334
1355
results.emplace (ws.m_ptx ->GetWitnessHash (),
1335
1356
MempoolAcceptResult::Success (std::move (ws.m_replaced_transactions ),
1336
1357
ws.m_vsize , ws.m_base_fees , effective_feerate,
@@ -1510,7 +1531,7 @@ PackageMempoolAcceptResult MemPoolAccept::AcceptPackage(const Package& package,
1510
1531
// in package validation, because its fees should only be "used" once.
1511
1532
assert (m_pool.exists (GenTxid::Wtxid (wtxid)));
1512
1533
results_final.emplace (wtxid, single_res);
1513
- } else if (single_res.m_state .GetResult () != TxValidationResult::TX_MEMPOOL_POLICY &&
1534
+ } else if (single_res.m_state .GetResult () != TxValidationResult::TX_RECONSIDERABLE &&
1514
1535
single_res.m_state .GetResult () != TxValidationResult::TX_MISSING_INPUTS) {
1515
1536
// Package validation policy only differs from individual policy in its evaluation
1516
1537
// of feerate. For example, if a transaction fails here due to violation of a
0 commit comments