-
Notifications
You must be signed in to change notification settings - Fork 375
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge #14457: test: add invalid tx templates for use in functional tests
59e3877 test: add invalid tx templates for use in functional tests (James O'Beirne) Pull request description: This change adds a list of `CTransaction`-generating templates which each correspond to a specific type of invalid transaction. We then use this list to test for a wider variety of invalid tx types in `p2p_invalid_tx.py` and `feature_block.py`. Consolidating all invalid tx types will allow us to more easily cover all tx reject cases from a variety of tests without repeating ourselves. Validation logic doesn't differ much between mempool and block acceptance, but there *is* a difference and we should be sure we're testing both comprehensively. Right now, I've only added templates covering the tx reject types listed below but if this approach seems worthwhile I will expand the list to be fully comprehensive. ``` bad-txns-in-belowout bad-txns-inputs-duplicate bad-txns-too-many-sigops bad-txns-vin-empty bad-txns-vout-empty bad-txns-vout-negative ``` Tree-SHA512: 05407f4a953fbd7c44c08bb49bb989cefd39a2b05ea00f5b3c92197a3f05e1b302f789e33832445734220e1c333d133aba385740b77b84139b170c583471ce20
- Loading branch information
Showing
5 changed files
with
254 additions
and
20 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,180 @@ | ||
#!/usr/bin/env python3 | ||
# Copyright (c) 2015-2018 The Bitcoin Core developers | ||
# Distributed under the MIT software license, see the accompanying | ||
# file COPYING or http://www.opensource.org/licenses/mit-license.php. | ||
""" | ||
Templates for constructing various sorts of invalid transactions. | ||
These templates (or an iterator over all of them) can be reused in different | ||
contexts to test using a number of invalid transaction types. | ||
Hopefully this makes it easier to get coverage of a full variety of tx | ||
validation checks through different interfaces (AcceptBlock, AcceptToMemPool, | ||
etc.) without repeating ourselves. | ||
Invalid tx cases not covered here can be found by running: | ||
$ diff \ | ||
<(grep -IREho "bad-txns[a-zA-Z-]+" src | sort -u) \ | ||
<(grep -IEho "bad-txns[a-zA-Z-]+" test/functional/data/invalid_txs.py | sort -u) | ||
""" | ||
import abc | ||
|
||
from test_framework.messages import CTransaction, CTxIn, CTxOut, COutPoint | ||
from test_framework import script as sc | ||
from test_framework.blocktools import create_tx_with_script, MAX_BLOCK_SIGOPS | ||
|
||
basic_p2sh = sc.CScript([sc.OP_HASH160, sc.hash160(sc.CScript([sc.OP_0])), sc.OP_EQUAL]) | ||
|
||
|
||
class BadTxTemplate: | ||
"""Allows simple construction of a certain kind of invalid tx. Base class to be subclassed.""" | ||
__metaclass__ = abc.ABCMeta | ||
|
||
# The expected error code given by bitcoind upon submission of the tx. | ||
reject_reason = "" | ||
|
||
# Only specified if it differs from mempool acceptance error. | ||
block_reject_reason = "" | ||
|
||
# Do we expect to be disconnected after submitting this tx? | ||
expect_disconnect = False | ||
|
||
# Is this tx considered valid when included in a block, but not for acceptance into | ||
# the mempool (i.e. does it violate policy but not consensus)? | ||
valid_in_block = False | ||
|
||
def __init__(self, *, spend_tx=None, spend_block=None): | ||
self.spend_tx = spend_block.vtx[0] if spend_block else spend_tx | ||
self.spend_avail = sum(o.nValue for o in self.spend_tx.vout) | ||
self.valid_txin = CTxIn(COutPoint(self.spend_tx.sha256, 0), b"", 0xffffffff) | ||
|
||
@abc.abstractmethod | ||
def get_tx(self, *args, **kwargs): | ||
"""Return a CTransaction that is invalid per the subclass.""" | ||
pass | ||
|
||
|
||
class OutputMissing(BadTxTemplate): | ||
reject_reason = "bad-txns-vout-empty" | ||
expect_disconnect = False | ||
|
||
def get_tx(self): | ||
tx = CTransaction() | ||
tx.vin.append(self.valid_txin) | ||
tx.calc_sha256() | ||
return tx | ||
|
||
|
||
class InputMissing(BadTxTemplate): | ||
reject_reason = "bad-txns-vin-empty" | ||
expect_disconnect = False | ||
|
||
def get_tx(self): | ||
tx = CTransaction() | ||
tx.vout.append(CTxOut(0, sc.CScript([sc.OP_TRUE] * 100))) | ||
tx.calc_sha256() | ||
return tx | ||
|
||
|
||
class SizeTooSmall(BadTxTemplate): | ||
reject_reason = "tx-size-small" | ||
expect_disconnect = False | ||
valid_in_block = True | ||
|
||
def get_tx(self): | ||
tx = CTransaction() | ||
tx.vin.append(self.valid_txin) | ||
tx.vout.append(CTxOut(0, sc.CScript([sc.OP_TRUE]))) | ||
tx.calc_sha256() | ||
return tx | ||
|
||
|
||
class BadInputOutpointIndex(BadTxTemplate): | ||
# Won't be rejected - nonexistent outpoint index is treated as an orphan since the coins | ||
# database can't distinguish between spent outpoints and outpoints which never existed. | ||
reject_reason = None | ||
expect_disconnect = False | ||
|
||
def get_tx(self): | ||
num_indices = len(self.spend_tx.vin) | ||
bad_idx = num_indices + 100 | ||
|
||
tx = CTransaction() | ||
tx.vin.append(CTxIn(COutPoint(self.spend_tx.sha256, bad_idx), b"", 0xffffffff)) | ||
tx.vout.append(CTxOut(0, basic_p2sh)) | ||
tx.calc_sha256() | ||
return tx | ||
|
||
|
||
class DuplicateInput(BadTxTemplate): | ||
reject_reason = 'bad-txns-inputs-duplicate' | ||
expect_disconnect = True | ||
|
||
def get_tx(self): | ||
tx = CTransaction() | ||
tx.vin.append(self.valid_txin) | ||
tx.vin.append(self.valid_txin) | ||
tx.vout.append(CTxOut(1, basic_p2sh)) | ||
tx.calc_sha256() | ||
return tx | ||
|
||
|
||
class NonexistentInput(BadTxTemplate): | ||
reject_reason = None # Added as an orphan tx. | ||
expect_disconnect = False | ||
|
||
def get_tx(self): | ||
tx = CTransaction() | ||
tx.vin.append(CTxIn(COutPoint(self.spend_tx.sha256 + 1, 0), b"", 0xffffffff)) | ||
tx.vin.append(self.valid_txin) | ||
tx.vout.append(CTxOut(1, basic_p2sh)) | ||
tx.calc_sha256() | ||
return tx | ||
|
||
|
||
class SpendTooMuch(BadTxTemplate): | ||
reject_reason = 'bad-txns-in-belowout' | ||
expect_disconnect = True | ||
|
||
def get_tx(self): | ||
return create_tx_with_script( | ||
self.spend_tx, 0, script_pub_key=basic_p2sh, amount=(self.spend_avail + 1)) | ||
|
||
|
||
class SpendNegative(BadTxTemplate): | ||
reject_reason = 'bad-txns-vout-negative' | ||
expect_disconnect = True | ||
|
||
def get_tx(self): | ||
return create_tx_with_script(self.spend_tx, 0, amount=-1) | ||
|
||
|
||
class InvalidOPIFConstruction(BadTxTemplate): | ||
reject_reason = "mandatory-script-verify-flag-failed (Invalid OP_IF construction)" | ||
expect_disconnect = True | ||
valid_in_block = True | ||
|
||
def get_tx(self): | ||
return create_tx_with_script( | ||
self.spend_tx, 0, script_sig=b'\x64' * 35, | ||
amount=(self.spend_avail // 2)) | ||
|
||
|
||
class TooManySigops(BadTxTemplate): | ||
reject_reason = "bad-txns-too-many-sigops" | ||
block_reject_reason = "bad-blk-sigops, out-of-bounds SigOpCount" | ||
expect_disconnect = False | ||
|
||
def get_tx(self): | ||
lotsa_checksigs = sc.CScript([sc.OP_CHECKSIG] * (MAX_BLOCK_SIGOPS)) | ||
return create_tx_with_script( | ||
self.spend_tx, 0, | ||
script_pub_key=lotsa_checksigs, | ||
amount=1) | ||
|
||
|
||
def iter_all_templates(): | ||
"""Iterate through all bad transaction template types.""" | ||
return BadTxTemplate.__subclasses__() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters