Skip to content

Commit 21656e9

Browse files
committed
Merge bitcoin/bitcoin#29862: test: Validate oversized transactions or without inputs
969e047 Replace hard-coded constant in test (Lőrinc) 327a31d Validate oversized transaction (Lőrinc) 1984187 Validate transaction without inputs (Lőrinc) c3a8843 Use SCRIPT_VERIFY_NONE instead of hard-coded 0 in transaction_tests (Lőrinc) Pull request description: Based on https://maflcko.github.io/b-c-cov/test_bitcoin.coverage/src/consensus/tx_check.cpp.gcov.html empty inputs and oversized transactions weren't covered by Boost unit tests (though they're covered by [python](https://github.com/bitcoin/bitcoin/blob/master/test/functional/mempool_accept.py#L231) [tests](https://github.com/bitcoin/bitcoin/blob/master/test/functional/data/invalid_txs.py#L102)). <img alt="image" src="https://github.com/bitcoin/bitcoin/assets/1841944/57a74ff5-5466-401f-a4fe-d79e36964adf"> I have tried including the empty transaction into [tx_invalid.json](https://github.com/bitcoin/bitcoin/blob/master/src/test/data/tx_invalid.json#L34-L36), but it failed for another reason, so I added a separate test case for it in the end. The oversized tx data is on the failure threshold now (lower threshold fails for a different reason, but I guess that's fine, we're testing the boundary here). ACKs for top commit: achow101: ACK 969e047 tdb3: ACK 969e047 pending `MSan, depends` CI failure. glozow: utACK 969e047 Tree-SHA512: 2a472690eabfdacc276b7e0414d3a4ebc75c227405b202c9fe3c8befad875f6e4d9b40c056fb05971ad3ae479c8f53edebb2eeeb700088856caf5cf58bfca0c1
2 parents a52837b + 969e047 commit 21656e9

File tree

2 files changed

+59
-24
lines changed

2 files changed

+59
-24
lines changed

src/test/transaction_tests.cpp

Lines changed: 57 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -72,17 +72,16 @@ static std::map<std::string, unsigned int> mapFlagNames = {
7272

7373
unsigned int ParseScriptFlags(std::string strFlags)
7474
{
75-
if (strFlags.empty() || strFlags == "NONE") return 0;
76-
unsigned int flags = 0;
77-
std::vector<std::string> words = SplitString(strFlags, ',');
75+
unsigned int flags = SCRIPT_VERIFY_NONE;
76+
if (strFlags.empty() || strFlags == "NONE") return flags;
7877

78+
std::vector<std::string> words = SplitString(strFlags, ',');
7979
for (const std::string& word : words)
8080
{
8181
if (!mapFlagNames.count(word))
8282
BOOST_ERROR("Bad test: unknown verification flag '" << word << "'");
8383
flags |= mapFlagNames[word];
8484
}
85-
8685
return flags;
8786
}
8887

@@ -98,7 +97,7 @@ bool CheckMapFlagNames()
9897

9998
std::string FormatScriptFlags(unsigned int flags)
10099
{
101-
if (flags == 0) {
100+
if (flags == SCRIPT_VERIFY_NONE) {
102101
return "";
103102
}
104103
std::string ret;
@@ -370,6 +369,41 @@ BOOST_AUTO_TEST_CASE(tx_invalid)
370369
}
371370
}
372371

372+
BOOST_AUTO_TEST_CASE(tx_no_inputs)
373+
{
374+
CMutableTransaction empty;
375+
376+
TxValidationState state;
377+
BOOST_CHECK_MESSAGE(!CheckTransaction(CTransaction(empty), state), "Transaction with no inputs should be invalid.");
378+
BOOST_CHECK(state.GetRejectReason() == "bad-txns-vin-empty");
379+
}
380+
381+
BOOST_AUTO_TEST_CASE(tx_oversized)
382+
{
383+
auto createTransaction =[](size_t payloadSize) {
384+
CMutableTransaction tx;
385+
tx.vin.resize(1);
386+
tx.vout.emplace_back(1, CScript() << OP_RETURN << std::vector<unsigned char>(payloadSize));
387+
return CTransaction(tx);
388+
};
389+
const auto maxTransactionSize = MAX_BLOCK_WEIGHT / WITNESS_SCALE_FACTOR;
390+
const auto oversizedTransactionBaseSize = ::GetSerializeSize(TX_NO_WITNESS(createTransaction(maxTransactionSize))) - maxTransactionSize;
391+
392+
auto maxPayloadSize = maxTransactionSize - oversizedTransactionBaseSize;
393+
{
394+
TxValidationState state;
395+
CheckTransaction(createTransaction(maxPayloadSize), state);
396+
BOOST_CHECK(state.GetRejectReason() != "bad-txns-oversize");
397+
}
398+
399+
maxPayloadSize += 1;
400+
{
401+
TxValidationState state;
402+
BOOST_CHECK_MESSAGE(!CheckTransaction(createTransaction(maxPayloadSize), state), "Oversized transaction should be invalid");
403+
BOOST_CHECK(state.GetRejectReason() == "bad-txns-oversize");
404+
}
405+
}
406+
373407
BOOST_AUTO_TEST_CASE(basic_transaction_tests)
374408
{
375409
// Random real transaction (e2769b09e784f32f62ef849763d4f45b98e07ba658647343b915ff832b110436)
@@ -615,11 +649,11 @@ BOOST_AUTO_TEST_CASE(test_witness)
615649
// Normal pay-to-compressed-pubkey.
616650
CreateCreditAndSpend(keystore, scriptPubkey1, output1, input1);
617651
CreateCreditAndSpend(keystore, scriptPubkey2, output2, input2);
618-
CheckWithFlag(output1, input1, 0, true);
652+
CheckWithFlag(output1, input1, SCRIPT_VERIFY_NONE, true);
619653
CheckWithFlag(output1, input1, SCRIPT_VERIFY_P2SH, true);
620654
CheckWithFlag(output1, input1, SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH, true);
621655
CheckWithFlag(output1, input1, STANDARD_SCRIPT_VERIFY_FLAGS, true);
622-
CheckWithFlag(output1, input2, 0, false);
656+
CheckWithFlag(output1, input2, SCRIPT_VERIFY_NONE, false);
623657
CheckWithFlag(output1, input2, SCRIPT_VERIFY_P2SH, false);
624658
CheckWithFlag(output1, input2, SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH, false);
625659
CheckWithFlag(output1, input2, STANDARD_SCRIPT_VERIFY_FLAGS, false);
@@ -628,23 +662,23 @@ BOOST_AUTO_TEST_CASE(test_witness)
628662
CreateCreditAndSpend(keystore, GetScriptForDestination(ScriptHash(scriptPubkey1)), output1, input1);
629663
CreateCreditAndSpend(keystore, GetScriptForDestination(ScriptHash(scriptPubkey2)), output2, input2);
630664
ReplaceRedeemScript(input2.vin[0].scriptSig, scriptPubkey1);
631-
CheckWithFlag(output1, input1, 0, true);
665+
CheckWithFlag(output1, input1, SCRIPT_VERIFY_NONE, true);
632666
CheckWithFlag(output1, input1, SCRIPT_VERIFY_P2SH, true);
633667
CheckWithFlag(output1, input1, SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH, true);
634668
CheckWithFlag(output1, input1, STANDARD_SCRIPT_VERIFY_FLAGS, true);
635-
CheckWithFlag(output1, input2, 0, true);
669+
CheckWithFlag(output1, input2, SCRIPT_VERIFY_NONE, true);
636670
CheckWithFlag(output1, input2, SCRIPT_VERIFY_P2SH, false);
637671
CheckWithFlag(output1, input2, SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH, false);
638672
CheckWithFlag(output1, input2, STANDARD_SCRIPT_VERIFY_FLAGS, false);
639673

640674
// Witness pay-to-compressed-pubkey (v0).
641675
CreateCreditAndSpend(keystore, destination_script_1, output1, input1);
642676
CreateCreditAndSpend(keystore, destination_script_2, output2, input2);
643-
CheckWithFlag(output1, input1, 0, true);
677+
CheckWithFlag(output1, input1, SCRIPT_VERIFY_NONE, true);
644678
CheckWithFlag(output1, input1, SCRIPT_VERIFY_P2SH, true);
645679
CheckWithFlag(output1, input1, SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH, true);
646680
CheckWithFlag(output1, input1, STANDARD_SCRIPT_VERIFY_FLAGS, true);
647-
CheckWithFlag(output1, input2, 0, true);
681+
CheckWithFlag(output1, input2, SCRIPT_VERIFY_NONE, true);
648682
CheckWithFlag(output1, input2, SCRIPT_VERIFY_P2SH, true);
649683
CheckWithFlag(output1, input2, SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH, false);
650684
CheckWithFlag(output1, input2, STANDARD_SCRIPT_VERIFY_FLAGS, false);
@@ -653,23 +687,23 @@ BOOST_AUTO_TEST_CASE(test_witness)
653687
CreateCreditAndSpend(keystore, GetScriptForDestination(ScriptHash(destination_script_1)), output1, input1);
654688
CreateCreditAndSpend(keystore, GetScriptForDestination(ScriptHash(destination_script_2)), output2, input2);
655689
ReplaceRedeemScript(input2.vin[0].scriptSig, destination_script_1);
656-
CheckWithFlag(output1, input1, 0, true);
690+
CheckWithFlag(output1, input1, SCRIPT_VERIFY_NONE, true);
657691
CheckWithFlag(output1, input1, SCRIPT_VERIFY_P2SH, true);
658692
CheckWithFlag(output1, input1, SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH, true);
659693
CheckWithFlag(output1, input1, STANDARD_SCRIPT_VERIFY_FLAGS, true);
660-
CheckWithFlag(output1, input2, 0, true);
694+
CheckWithFlag(output1, input2, SCRIPT_VERIFY_NONE, true);
661695
CheckWithFlag(output1, input2, SCRIPT_VERIFY_P2SH, true);
662696
CheckWithFlag(output1, input2, SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH, false);
663697
CheckWithFlag(output1, input2, STANDARD_SCRIPT_VERIFY_FLAGS, false);
664698

665699
// Normal pay-to-uncompressed-pubkey.
666700
CreateCreditAndSpend(keystore, scriptPubkey1L, output1, input1);
667701
CreateCreditAndSpend(keystore, scriptPubkey2L, output2, input2);
668-
CheckWithFlag(output1, input1, 0, true);
702+
CheckWithFlag(output1, input1, SCRIPT_VERIFY_NONE, true);
669703
CheckWithFlag(output1, input1, SCRIPT_VERIFY_P2SH, true);
670704
CheckWithFlag(output1, input1, SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH, true);
671705
CheckWithFlag(output1, input1, STANDARD_SCRIPT_VERIFY_FLAGS, true);
672-
CheckWithFlag(output1, input2, 0, false);
706+
CheckWithFlag(output1, input2, SCRIPT_VERIFY_NONE, false);
673707
CheckWithFlag(output1, input2, SCRIPT_VERIFY_P2SH, false);
674708
CheckWithFlag(output1, input2, SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH, false);
675709
CheckWithFlag(output1, input2, STANDARD_SCRIPT_VERIFY_FLAGS, false);
@@ -678,11 +712,11 @@ BOOST_AUTO_TEST_CASE(test_witness)
678712
CreateCreditAndSpend(keystore, GetScriptForDestination(ScriptHash(scriptPubkey1L)), output1, input1);
679713
CreateCreditAndSpend(keystore, GetScriptForDestination(ScriptHash(scriptPubkey2L)), output2, input2);
680714
ReplaceRedeemScript(input2.vin[0].scriptSig, scriptPubkey1L);
681-
CheckWithFlag(output1, input1, 0, true);
715+
CheckWithFlag(output1, input1, SCRIPT_VERIFY_NONE, true);
682716
CheckWithFlag(output1, input1, SCRIPT_VERIFY_P2SH, true);
683717
CheckWithFlag(output1, input1, SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH, true);
684718
CheckWithFlag(output1, input1, STANDARD_SCRIPT_VERIFY_FLAGS, true);
685-
CheckWithFlag(output1, input2, 0, true);
719+
CheckWithFlag(output1, input2, SCRIPT_VERIFY_NONE, true);
686720
CheckWithFlag(output1, input2, SCRIPT_VERIFY_P2SH, false);
687721
CheckWithFlag(output1, input2, SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH, false);
688722
CheckWithFlag(output1, input2, STANDARD_SCRIPT_VERIFY_FLAGS, false);
@@ -697,19 +731,19 @@ BOOST_AUTO_TEST_CASE(test_witness)
697731

698732
// Normal 2-of-2 multisig
699733
CreateCreditAndSpend(keystore, scriptMulti, output1, input1, false);
700-
CheckWithFlag(output1, input1, 0, false);
734+
CheckWithFlag(output1, input1, SCRIPT_VERIFY_NONE, false);
701735
CreateCreditAndSpend(keystore2, scriptMulti, output2, input2, false);
702-
CheckWithFlag(output2, input2, 0, false);
736+
CheckWithFlag(output2, input2, SCRIPT_VERIFY_NONE, false);
703737
BOOST_CHECK(*output1 == *output2);
704738
UpdateInput(input1.vin[0], CombineSignatures(input1, input2, output1));
705739
CheckWithFlag(output1, input1, STANDARD_SCRIPT_VERIFY_FLAGS, true);
706740

707741
// P2SH 2-of-2 multisig
708742
CreateCreditAndSpend(keystore, GetScriptForDestination(ScriptHash(scriptMulti)), output1, input1, false);
709-
CheckWithFlag(output1, input1, 0, true);
743+
CheckWithFlag(output1, input1, SCRIPT_VERIFY_NONE, true);
710744
CheckWithFlag(output1, input1, SCRIPT_VERIFY_P2SH, false);
711745
CreateCreditAndSpend(keystore2, GetScriptForDestination(ScriptHash(scriptMulti)), output2, input2, false);
712-
CheckWithFlag(output2, input2, 0, true);
746+
CheckWithFlag(output2, input2, SCRIPT_VERIFY_NONE, true);
713747
CheckWithFlag(output2, input2, SCRIPT_VERIFY_P2SH, false);
714748
BOOST_CHECK(*output1 == *output2);
715749
UpdateInput(input1.vin[0], CombineSignatures(input1, input2, output1));
@@ -718,10 +752,10 @@ BOOST_AUTO_TEST_CASE(test_witness)
718752

719753
// Witness 2-of-2 multisig
720754
CreateCreditAndSpend(keystore, destination_script_multi, output1, input1, false);
721-
CheckWithFlag(output1, input1, 0, true);
755+
CheckWithFlag(output1, input1, SCRIPT_VERIFY_NONE, true);
722756
CheckWithFlag(output1, input1, SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_WITNESS, false);
723757
CreateCreditAndSpend(keystore2, destination_script_multi, output2, input2, false);
724-
CheckWithFlag(output2, input2, 0, true);
758+
CheckWithFlag(output2, input2, SCRIPT_VERIFY_NONE, true);
725759
CheckWithFlag(output2, input2, SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_WITNESS, false);
726760
BOOST_CHECK(*output1 == *output2);
727761
UpdateInput(input1.vin[0], CombineSignatures(input1, input2, output1));

test/functional/mempool_accept.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
CTxInWitness,
1919
CTxOut,
2020
MAX_BLOCK_WEIGHT,
21+
WITNESS_SCALE_FACTOR,
2122
MAX_MONEY,
2223
SEQUENCE_FINAL,
2324
tx_from_hex,
@@ -228,7 +229,7 @@ def run_test(self):
228229

229230
self.log.info('A really large transaction')
230231
tx = tx_from_hex(raw_tx_reference)
231-
tx.vin = [tx.vin[0]] * math.ceil(MAX_BLOCK_WEIGHT // 4 / len(tx.vin[0].serialize()))
232+
tx.vin = [tx.vin[0]] * math.ceil((MAX_BLOCK_WEIGHT // WITNESS_SCALE_FACTOR) / len(tx.vin[0].serialize()))
232233
self.check_mempool_result(
233234
result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': 'bad-txns-oversize'}],
234235
rawtxs=[tx.serialize().hex()],

0 commit comments

Comments
 (0)