Skip to content
Bitcoin Roots

v31.1-roots.1 · Commit 2: [PATCH 02/17] feat(policy): preserve Roots parsing and local transaction checks

src/validation.cpp

Before: src/validation.cpp · After: src/validation.cpp

File metadata
index d3cabe4464790ef84348df10aef05f268e02488c..5a07852971bb4688ccdd1c4b26f42dbda946ba4b 100644

Download original patch · Release notes

Diff rows 1–99 of 99. 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/validation.cpp CHANGED
@@ -268,6 +268,35 @@ bool CheckSequenceLocksAtTip(CBlockIndex* tip,
268
268
  return EvaluateSequenceLocks(index, {lock_points.height, lock_points.time});
269
269
  }
270
270
 
271
+ static int64_t GetAccurateTransactionSigOpCost(const CTransaction& tx, const CCoinsViewCache& inputs, script_verify_flags flags)
272
+ {
273
+ if (tx.IsCoinBase()) {
274
+ return 0;
275
+ }
276
+
277
+ unsigned int nSigOps = 0;
278
+ for (const auto& txin : tx.vin) {
279
+ nSigOps += txin.scriptSig.GetSigOpCount(false);
280
+ }
281
+
282
+ if (flags & SCRIPT_VERIFY_P2SH) {
283
+ nSigOps += GetP2SHSigOpCount(tx, inputs);
284
+ }
285
+
286
+ nSigOps *= WITNESS_SCALE_FACTOR;
287
+
288
+ if (flags & SCRIPT_VERIFY_WITNESS) {
289
+ for (const auto& txin : tx.vin) {
290
+ const Coin& coin = inputs.AccessCoin(txin.prevout);
291
+ assert(!coin.IsSpent());
292
+ const CTxOut &prevout = coin.out;
293
+ nSigOps += CountWitnessSigOps(txin.scriptSig, prevout.scriptPubKey, txin.scriptWitness, flags);
294
+ }
295
+ }
296
+
297
+ return nSigOps;
298
+ }
299
+
271
300
  static void LimitMempoolSize(CTxMemPool& pool, CCoinsViewCache& coins_cache)
272
301
  EXCLUSIVE_LOCKS_REQUIRED(::cs_main, pool.cs)
273
302
  {
@@ -812,7 +841,7 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws)
812
841
 
813
842
  // Rather not work on nonstandard transactions (unless -testnet/-regtest)
814
843
  std::string reason;
815
- if (m_pool.m_opts.require_standard && !IsStandardTx(tx, m_pool.m_opts.max_datacarrier_bytes, m_pool.m_opts.permit_bare_multisig, m_pool.m_opts.dust_relay_feerate, reason)) {
844
+ if (m_pool.m_opts.require_standard && !IsStandardTx(tx, m_pool.m_opts, reason)) {
816
845
  return state.Invalid(TxValidationResult::TX_NOT_STANDARD, reason);
817
846
  }
818
847
 
@@ -900,13 +929,42 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws)
900
929
  return false; // state filled in by CheckTxInputs
901
930
  }
902
931
 
903
- if (m_pool.m_opts.require_standard && !AreInputsStandard(tx, m_view)) {
904
- return state.Invalid(TxValidationResult::TX_INPUTS_NOT_STANDARD, "bad-txns-nonstandard-inputs");
932
+ // Local policy only. Consensus input maturity remains in CheckTxInputs.
933
+ const int64_t next_height{int64_t{m_active_chainstate.m_chain.Height()} + 1};
934
+ uint64_t coinblocks{0};
935
+ for (const auto& input : tx.vin) {
936
+ const auto& coin = m_view.AccessCoin(input.prevout);
937
+ const int64_t depth{std::max<int64_t>(0, next_height - coin.nHeight)};
938
+ if (depth < m_pool.m_opts.minrelaymaturity) {
939
+ return state.Invalid(TxValidationResult::TX_PREMATURE_SPEND, "bad-txns-input-immature-depth");
940
+ }
941
+ // Only compare against the configured bound: cap before multiplying.
942
+ const uint64_t remaining{m_pool.m_opts.minrelaycoinblocks - coinblocks};
943
+ if (depth > 0 && coin.out.nValue > 0) {
944
+ const uint64_t value{static_cast<uint64_t>(coin.out.nValue)};
945
+ coinblocks += value > remaining / depth ? remaining : value * depth;
946
+ }
947
+ }
948
+ if (coinblocks < m_pool.m_opts.minrelaycoinblocks) {
949
+ return state.Invalid(TxValidationResult::TX_PREMATURE_SPEND, "bad-txns-input-immature-coinblocks");
950
+ }
951
+ if (m_pool.m_opts.datacarrier_fullcount || !m_pool.m_opts.accept_non_std_datacarrier) {
952
+ const auto [standard_bytes, nonstandard_bytes] = DatacarrierBytes(tx, m_view);
953
+ if (nonstandard_bytes && !m_pool.m_opts.accept_non_std_datacarrier) {
954
+ return state.Invalid(TxValidationResult::TX_INPUTS_NOT_STANDARD, "txn-datacarrier-nonstandard");
955
+ }
956
+ if (m_pool.m_opts.datacarrier_fullcount && standard_bytes + nonstandard_bytes > m_pool.m_opts.max_datacarrier_bytes.value_or(0)) {
957
+ return state.Invalid(TxValidationResult::TX_INPUTS_NOT_STANDARD, "txn-datacarrier-exceeded");
958
+ }
959
+ }
960
+
961
+ if (m_pool.m_opts.require_standard && !AreInputsStandard(tx, m_view, m_pool.m_opts, "bad-txns-input-", reason)) {
962
+ return state.Invalid(TxValidationResult::TX_INPUTS_NOT_STANDARD, reason);
905
963
  }
906
964
 
907
965
  // Check for non-standard witnesses.
908
- if (tx.HasWitness() && m_pool.m_opts.require_standard && !IsWitnessStandard(tx, m_view)) {
909
- return state.Invalid(TxValidationResult::TX_WITNESS_MUTATED, "bad-witness-nonstandard");
966
+ if (tx.HasWitness() && m_pool.m_opts.require_standard && !IsWitnessStandard(tx, m_view, "bad-witness-", reason)) {
967
+ return state.Invalid(TxValidationResult::TX_WITNESS_MUTATED, reason);
910
968
  }
911
969
 
912
970
  int64_t nSigOpsCost = GetTransactionSigOpCost(tx, m_view, STANDARD_SCRIPT_VERIFY_FLAGS);
@@ -942,7 +1000,9 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws)
942
1000
  }
943
1001
  }
944
1002
 
945
- if (nSigOpsCost > MAX_STANDARD_TX_SIGOPS_COST)
1003
+ if (nSigOpsCost > MAX_STANDARD_TX_SIGOPS_COST ||
1004
+ (nBytesPerSigOpStrict && GetAccurateTransactionSigOpCost(tx, m_view, STANDARD_SCRIPT_VERIFY_FLAGS) >
1005
+ ws.m_vsize * WITNESS_SCALE_FACTOR / nBytesPerSigOpStrict))
946
1006
  return state.Invalid(TxValidationResult::TX_NOT_STANDARD, "bad-txns-too-many-sigops",
947
1007
  strprintf("%d", nSigOpsCost));
948
1008