Skip to content
Bitcoin Roots

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

src/test/transaction_tests.cpp

Before: src/test/transaction_tests.cpp · After: src/test/transaction_tests.cpp

File metadata
index 916f565c04df41b909ad35e50b917cdb04caaa4f..4db01b19c3d6bfe187f78cac51c09f832b335c93 100644

Download original patch · Release notes

Diff rows 1–291 of 291. 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/test/transaction_tests.cpp CHANGED
@@ -14,6 +14,7 @@
14
14
  #include <consensus/tx_verify.h>
15
15
  #include <consensus/validation.h>
16
16
  #include <core_io.h>
17
+ #include <kernel/mempool_options.h>
17
18
  #include <key.h>
18
19
  #include <policy/policy.h>
19
20
  #include <policy/settings.h>
@@ -49,8 +50,8 @@ using util::ToString;
49
50
 
50
51
  typedef std::vector<unsigned char> valtype;
51
52
 
52
- static CFeeRate g_dust{DUST_RELAY_TX_FEE};
53
- static bool g_bare_multi{DEFAULT_PERMIT_BAREMULTISIG};
53
+
54
+ static kernel::MemPoolOptions g_mempool_opts;
54
55
 
55
56
  static const std::map<std::string, script_verify_flag_name>& mapFlagNames = ScriptFlagNamesToEnum();
56
57
 
@@ -764,21 +765,30 @@ BOOST_AUTO_TEST_CASE(test_IsStandard)
764
765
  CKey key = GenerateRandomKey();
765
766
  t.vout[0].scriptPubKey = GetScriptForDestination(PKHash(key.GetPubKey()));
766
767
 
767
- constexpr auto CheckIsStandard = [](const auto& t, const unsigned int max_op_return_relay = MAX_OP_RETURN_RELAY) {
768
+ constexpr auto CheckIsStandard = [](const auto& t, const unsigned int max_op_return_relay = MAX_OP_RETURN_RELAY, const ignore_rejects_type& ignore_rejects = empty_ignore_rejects) {
768
769
  std::string reason;
769
- BOOST_CHECK(IsStandardTx(CTransaction{t}, max_op_return_relay, g_bare_multi, g_dust, reason));
770
+ auto opts = g_mempool_opts;
771
+ opts.max_datacarrier_bytes = max_op_return_relay;
772
+ BOOST_CHECK(IsStandardTx(CTransaction{t}, opts, reason, ignore_rejects));
770
773
  BOOST_CHECK(reason.empty());
771
774
  };
772
- constexpr auto CheckIsNotStandard = [](const auto& t, const std::string& reason_in, const unsigned int max_op_return_relay = MAX_OP_RETURN_RELAY) {
775
+ constexpr auto CheckIsNotStandard = [](const auto& t, const std::string& reason_in, const unsigned int max_op_return_relay = MAX_OP_RETURN_RELAY, const ignore_rejects_type& ignore_rejects = empty_ignore_rejects) {
773
776
  std::string reason;
774
- BOOST_CHECK(!IsStandardTx(CTransaction{t}, max_op_return_relay, g_bare_multi, g_dust, reason));
777
+ auto opts = g_mempool_opts;
778
+ opts.max_datacarrier_bytes = max_op_return_relay;
779
+ BOOST_CHECK(!IsStandardTx(CTransaction{t}, opts, reason, ignore_rejects));
775
780
  BOOST_CHECK_EQUAL(reason_in, reason);
776
781
  };
777
782
 
783
+ g_mempool_opts.permit_bare_pubkey = true;
778
784
  CheckIsStandard(t);
779
785
 
786
+ g_mempool_opts.permitephemeral_anchor = true;
787
+ g_mempool_opts.permitephemeral_dust = true;
788
+ g_mempool_opts.permitephemeral_send = true;
789
+
780
790
  // Check dust with default relay fee:
781
- CAmount nDustThreshold = 182 * g_dust.GetFeePerK() / 1000;
791
+ CAmount nDustThreshold = 182 * g_mempool_opts.dust_relay_feerate.GetFeePerK() / 1000;
782
792
  BOOST_CHECK_EQUAL(nDustThreshold, 546);
783
793
 
784
794
  // Add dust outputs up to allowed maximum, still standard!
@@ -813,25 +823,66 @@ BOOST_AUTO_TEST_CASE(test_IsStandard)
813
823
 
814
824
  // Check dust with odd relay fee to verify rounding:
815
825
  // nDustThreshold = 182 * 3702 / 1000
816
- g_dust = CFeeRate(3702);
826
+ g_mempool_opts.dust_relay_feerate = CFeeRate(3702);
817
827
  // dust:
818
828
  t.vout[0].nValue = 674 - 1;
819
829
  CheckIsNotStandard(t, "dust");
820
830
  // not dust:
821
831
  t.vout[0].nValue = 674;
822
832
  CheckIsStandard(t);
823
- g_dust = CFeeRate{DUST_RELAY_TX_FEE};
833
+ g_mempool_opts.dust_relay_feerate = CFeeRate{DUST_RELAY_TX_FEE};
824
834
 
825
835
  t.vout[0].scriptPubKey = CScript() << OP_1;
826
836
  CheckIsNotStandard(t, "scriptpubkey");
827
837
 
828
- // Custom 83-byte TxoutType::NULL_DATA (standard with max_op_return_relay of 83)
829
- t.vout[0].scriptPubKey = CScript() << OP_RETURN << "04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef3804678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38"_hex;
830
- BOOST_CHECK_EQUAL(83, t.vout[0].scriptPubKey.size());
831
- CheckIsStandard(t, /*max_op_return_relay=*/83);
838
+ // Test rejectparasites
839
+ t.vout[0].scriptPubKey = CScript() << OP_RETURN;
840
+ t.vout.emplace_back(674, GetScriptForDestination(PKHash(key.GetPubKey())));
841
+ t.nLockTime = PARASITE_CAT21_LOCKTIME;
842
+ g_mempool_opts.reject_parasites = false;
843
+ CheckIsStandard(t);
844
+ g_mempool_opts.reject_parasites = true;
845
+ CheckIsNotStandard(t, "parasite-cat21");
846
+ t.nLockTime = 0;
847
+ CheckIsStandard(t);
848
+ g_mempool_opts.reject_parasites = false;
832
849
 
833
- // Non-standard if max_op_return_relay datacarrier arg is one less
834
- CheckIsNotStandard(t, "datacarrier", /*max_op_return_relay=*/82);
850
+ // Test rejecttokens
851
+ t.vout[0].scriptPubKey = CScript() << OP_RETURN << OP_13 << OP_FALSE;
852
+ g_mempool_opts.reject_tokens = false;
853
+ CheckIsStandard(t);
854
+ g_mempool_opts.reject_tokens = true;
855
+ CheckIsNotStandard(t, "tokens-runes");
856
+ // At least one data push is needed after OP_13 to match
857
+ t.vout[0].scriptPubKey = CScript() << OP_RETURN << OP_13;
858
+ CheckIsStandard(t);
859
+ // Test rejecttokens applying to OLGA
860
+ const auto olga_header = CScript() << OP_0 << "003e7374616d703a000000000000000000000000000000000000000000000000"_hex;
861
+ t.vout[0].scriptPubKey = olga_header;
862
+ t.vout.resize(1);
863
+ // Missing a second output, so not OLGA
864
+ CheckIsStandard(t);
865
+ t.vout.emplace_back(1000, olga_header);
866
+ CheckIsNotStandard(t, "tokens-olga");
867
+ t.vout.emplace_back(1000, olga_header);
868
+ CheckIsNotStandard(t, "tokens-olga");
869
+ g_mempool_opts.reject_tokens = false;
870
+ CheckIsStandard(t);
871
+ t.vout.resize(1);
872
+
873
+ // MAX_OP_RETURN_RELAY-byte TxoutType::NULL_DATA (standard)
874
+ g_mempool_opts.permitbaredatacarrier = true;
875
+ t.vout[0].scriptPubKey = CScript() << OP_RETURN;
876
+ while (t.vout[0].scriptPubKey.size() < MAX_OP_RETURN_RELAY) {
877
+ t.vout[0].scriptPubKey << OP_0;
878
+ }
879
+ BOOST_CHECK_EQUAL(MAX_OP_RETURN_RELAY, t.vout[0].scriptPubKey.size());
880
+ CheckIsStandard(t);
881
+
882
+ // MAX_OP_RETURN_RELAY+1-byte TxoutType::NULL_DATA (non-standard)
883
+ t.vout[0].scriptPubKey << OP_0;
884
+ BOOST_CHECK_EQUAL(MAX_OP_RETURN_RELAY + 1, t.vout[0].scriptPubKey.size());
885
+ CheckIsNotStandard(t, "datacarrier");
835
886
 
836
887
  // Data payload can be encoded in any way...
837
888
  t.vout[0].scriptPubKey = CScript() << OP_RETURN << ""_hex;
@@ -853,28 +904,40 @@ BOOST_AUTO_TEST_CASE(test_IsStandard)
853
904
  t.vout[0].scriptPubKey = CScript() << OP_RETURN;
854
905
  CheckIsStandard(t);
855
906
 
856
- // Multiple TxoutType::NULL_DATA are permitted
907
+ // Multiple carriers require an explicit local policy relaxation
857
908
  t.vout.resize(2);
858
909
  t.vout[0].scriptPubKey = CScript() << OP_RETURN << "04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38"_hex;
859
910
  t.vout[0].nValue = 0;
860
911
  t.vout[1].scriptPubKey = CScript() << OP_RETURN << "04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38"_hex;
861
912
  t.vout[1].nValue = 0;
862
- CheckIsStandard(t);
913
+ CheckIsNotStandard(t, "multi-op-return", MAX_STANDARD_TX_WEIGHT / WITNESS_SCALE_FACTOR);
914
+ CheckIsStandard(t, MAX_STANDARD_TX_WEIGHT / WITNESS_SCALE_FACTOR, {"multi-op-return"});
863
915
 
864
916
  t.vout[0].scriptPubKey = CScript() << OP_RETURN << "04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38"_hex;
865
917
  t.vout[1].scriptPubKey = CScript() << OP_RETURN;
866
- CheckIsStandard(t);
918
+ CheckIsNotStandard(t, "multi-op-return", MAX_STANDARD_TX_WEIGHT / WITNESS_SCALE_FACTOR);
919
+ CheckIsStandard(t, MAX_STANDARD_TX_WEIGHT / WITNESS_SCALE_FACTOR, {"multi-op-return"});
867
920
 
868
921
  t.vout[0].scriptPubKey = CScript() << OP_RETURN;
869
922
  t.vout[1].scriptPubKey = CScript() << OP_RETURN;
870
- CheckIsStandard(t);
923
+ CheckIsNotStandard(t, "multi-op-return", MAX_STANDARD_TX_WEIGHT / WITNESS_SCALE_FACTOR);
924
+ CheckIsStandard(t, MAX_STANDARD_TX_WEIGHT / WITNESS_SCALE_FACTOR, {"multi-op-return"});
871
925
 
872
926
  t.vout[0].scriptPubKey = CScript() << OP_RETURN << "04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef3804678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38"_hex;
873
927
  t.vout[1].scriptPubKey = CScript() << OP_RETURN << "04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef3804678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38"_hex;
874
928
  const auto datacarrier_size = t.vout[0].scriptPubKey.size() + t.vout[1].scriptPubKey.size();
875
- CheckIsStandard(t); // Default max relay should never trigger
876
- CheckIsStandard(t, /*max_op_return_relay=*/datacarrier_size);
877
- CheckIsNotStandard(t, "datacarrier", /*max_op_return_relay=*/datacarrier_size-1);
929
+ CheckIsNotStandard(t, "datacarrier");
930
+ CheckIsStandard(t, MAX_STANDARD_TX_WEIGHT / WITNESS_SCALE_FACTOR, {"multi-op-return"}); // Explicit generous aggregate limit
931
+ CheckIsStandard(t, /*max_op_return_relay=*/datacarrier_size, {"multi-op-return"});
932
+ CheckIsNotStandard(t, "datacarrier", /*max_op_return_relay=*/datacarrier_size-1, {"multi-op-return"});
933
+
934
+ // Bare carrier transactions still require explicit permission.
935
+ t.vout.resize(1);
936
+ t.vout[0].scriptPubKey = CScript() << OP_RETURN;
937
+ g_mempool_opts.permitbaredatacarrier = false;
938
+ CheckIsNotStandard(t, "bare-datacarrier");
939
+ g_mempool_opts.permitbaredatacarrier = true;
940
+ CheckIsStandard(t);
878
941
 
879
942
  // Check large scriptSig (non-standard if size is >1650 bytes)
880
943
  t.vout.resize(1);
@@ -937,16 +1000,16 @@ BOOST_AUTO_TEST_CASE(test_IsStandard)
937
1000
  BOOST_CHECK_EQUAL(GetTransactionWeight(CTransaction(t)), 400004);
938
1001
  CheckIsNotStandard(t, "tx-size");
939
1002
 
940
- // Check bare multisig (standard if policy flag g_bare_multi is set)
941
- g_bare_multi = true;
1003
+ // Check bare multisig (standard if the policy flag is set)
1004
+ g_mempool_opts.permit_bare_multisig = true;
942
1005
  t.vout[0].scriptPubKey = GetScriptForMultisig(1, {key.GetPubKey()}); // simple 1-of-1
943
1006
  t.vin.resize(1);
944
1007
  t.vin[0].scriptSig = CScript() << std::vector<unsigned char>(65, 0);
945
1008
  CheckIsStandard(t);
946
1009
 
947
- g_bare_multi = false;
1010
+ g_mempool_opts.permit_bare_multisig = false;
948
1011
  CheckIsNotStandard(t, "bare-multisig");
949
- g_bare_multi = DEFAULT_PERMIT_BAREMULTISIG;
1012
+ g_mempool_opts.permit_bare_multisig = true;
950
1013
 
951
1014
  // Add dust outputs up to allowed maximum
952
1015
  assert(t.vout.size() == 1);
@@ -1005,6 +1068,9 @@ BOOST_AUTO_TEST_CASE(test_IsStandard)
1005
1068
  for (int op = OP_1; op <= OP_16; op += 1) {
1006
1069
  t.vout[0].scriptPubKey = CScript() << (opcodetype)op << std::vector<unsigned char>(2, 0);
1007
1070
  t.vout[0].nValue = 240;
1071
+ g_mempool_opts.acceptunknownwitness = false;
1072
+ CheckIsNotStandard(t, "scriptpubkey-unknown-witnessversion");
1073
+ g_mempool_opts.acceptunknownwitness = true;
1008
1074
  CheckIsStandard(t);
1009
1075
 
1010
1076
  t.vout[0].nValue = 239;
@@ -1018,6 +1084,34 @@ BOOST_AUTO_TEST_CASE(test_IsStandard)
1018
1084
  CheckIsStandard(t);
1019
1085
  t.vout[0].nValue = 239;
1020
1086
  CheckIsNotStandard(t, "dust");
1087
+
1088
+ // Test permitbareanchor
1089
+ g_mempool_opts.permitbareanchor = false;
1090
+ t.vout[1].scriptPubKey = GetScriptForDestination(PKHash(key.GetPubKey()));
1091
+ t.vout[1].nValue = COIN;
1092
+ CheckIsStandard(t);
1093
+ t.vout.resize(1);
1094
+ CheckIsNotStandard(t, "bare-anchor");
1095
+ g_mempool_opts.permitbareanchor = true;
1096
+ CheckIsStandard(t);
1097
+
1098
+ // Test permitephemeral
1099
+ g_mempool_opts.permitephemeral_anchor = false;
1100
+ CheckIsNotStandard(t, "anchor");
1101
+ t.vout[0].nValue = 0;
1102
+ CheckIsNotStandard(t, "anchor");
1103
+ g_mempool_opts.permitephemeral_anchor = true;
1104
+ g_mempool_opts.permitephemeral_dust = false;
1105
+ CheckIsStandard(t);
1106
+ t.vout[0].nValue = 1;
1107
+ CheckIsNotStandard(t, "dust-nonzero");
1108
+ g_mempool_opts.permitephemeral_dust = true;
1109
+ g_mempool_opts.permitephemeral_send = false;
1110
+ CheckIsStandard(t);
1111
+ t.vout[0].scriptPubKey = GetScriptForDestination(PKHash(key.GetPubKey()));
1112
+ CheckIsNotStandard(t, "dust-nonanchor");
1113
+ g_mempool_opts.permitephemeral_send = true;
1114
+ CheckIsStandard(t);
1021
1115
  }
1022
1116
 
1023
1117
  BOOST_AUTO_TEST_CASE(max_standard_legacy_sigops)
@@ -1115,55 +1209,6 @@ BOOST_AUTO_TEST_CASE(max_standard_legacy_sigops)
1115
1209
  BOOST_CHECK(!::AreInputsStandard(CTransaction(tx_max_sigops), coins));
1116
1210
  }
1117
1211
 
1118
- BOOST_AUTO_TEST_CASE(checktxinputs_invalid_transactions_test)
1119
- {
1120
- auto check_invalid{[](CAmount input_value, CAmount output_value, bool coinbase, int spend_height, TxValidationResult expected_result, std::string_view expected_reason) {
1121
- CCoinsView coins_dummy;
1122
- CCoinsViewCache inputs(&coins_dummy);
1123
-
1124
- const COutPoint prevout{Txid::FromUint256(uint256::ONE), 0};
1125
- inputs.AddCoin(prevout, Coin{{input_value, CScript() << OP_TRUE}, /*nHeightIn=*/1, coinbase}, /*possible_overwrite=*/false);
1126
-
1127
- CMutableTransaction mtx;
1128
- mtx.vin.emplace_back(prevout);
1129
- mtx.vout.emplace_back(output_value, CScript() << OP_TRUE);
1130
-
1131
- TxValidationState state;
1132
- CAmount txfee{0};
1133
- BOOST_CHECK(!Consensus::CheckTxInputs(CTransaction{mtx}, state, inputs, spend_height, txfee));
1134
- BOOST_CHECK(state.IsInvalid());
1135
- BOOST_CHECK_EQUAL(state.GetResult(), expected_result);
1136
- BOOST_CHECK_EQUAL(state.GetRejectReason(), expected_reason);
1137
- }};
1138
-
1139
- check_invalid(/*input_value=*/MAX_MONEY + 1,
1140
- /*output_value=*/0,
1141
- /*coinbase=*/false,
1142
- /*spend_height=*/2,
1143
- TxValidationResult::TX_CONSENSUS, /*expected_reason=*/"bad-txns-inputvalues-outofrange");
1144
-
1145
- check_invalid(/*input_value=*/1 * COIN,
1146
- /*output_value=*/2 * COIN,
1147
- /*coinbase=*/false,
1148
- /*spend_height=*/2,
1149
- TxValidationResult::TX_CONSENSUS, /*expected_reason=*/"bad-txns-in-belowout");
1150
-
1151
- check_invalid(/*input_value=*/1 * COIN,
1152
- /*output_value=*/0,
1153
- /*coinbase=*/true,
1154
- /*spend_height=*/COINBASE_MATURITY,
1155
- TxValidationResult::TX_PREMATURE_SPEND, /*expected_reason=*/"bad-txns-premature-spend-of-coinbase");
1156
- }
1157
-
1158
- BOOST_AUTO_TEST_CASE(getvalueout_out_of_range_throws)
1159
- {
1160
- CMutableTransaction mtx;
1161
- mtx.vout.emplace_back(MAX_MONEY + 1, CScript() << OP_TRUE);
1162
-
1163
- const CTransaction tx{mtx};
1164
- BOOST_CHECK_EXCEPTION(tx.GetValueOut(), std::runtime_error, HasReason("GetValueOut: value out of range"));
1165
- }
1166
-
1167
1212
  /** Sanity check the return value of SpendsNonAnchorWitnessProg for various output types. */
1168
1213
  BOOST_AUTO_TEST_CASE(spends_witness_prog)
1169
1214
  {