Changeset View
Changeset View
Standalone View
Standalone View
test/functional/data/invalid_txs.py
| Show First 20 Lines • Show All 53 Lines • ▼ Show 20 Lines | class BadTxTemplate: | ||||
| __metaclass__ = abc.ABCMeta | __metaclass__ = abc.ABCMeta | ||||
| # The expected error code given by bitcoind upon submission of the tx. | # The expected error code given by bitcoind upon submission of the tx. | ||||
| reject_reason: Optional[str] = "" | reject_reason: Optional[str] = "" | ||||
| # Only specified if it differs from mempool acceptance error. | # Only specified if it differs from mempool acceptance error. | ||||
| block_reject_reason = "" | 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 | # 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)? | # the mempool (i.e. does it violate policy but not consensus)? | ||||
| valid_in_block = False | valid_in_block = False | ||||
| def __init__(self, *, spend_tx=None, spend_block=None): | def __init__(self, *, spend_tx=None, spend_block=None): | ||||
| self.spend_tx = spend_block.vtx[0] if spend_block else spend_tx | 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.spend_avail = sum(o.nValue for o in self.spend_tx.vout) | ||||
| self.valid_txin = CTxIn(COutPoint(self.spend_tx.txid_int, 0), b"", 0xFFFFFFFF) | self.valid_txin = CTxIn(COutPoint(self.spend_tx.txid_int, 0), b"", 0xFFFFFFFF) | ||||
| @abc.abstractmethod | @abc.abstractmethod | ||||
| def get_tx(self, *args, **kwargs): | def get_tx(self, *args, **kwargs): | ||||
| """Return a CTransaction that is invalid per the subclass.""" | """Return a CTransaction that is invalid per the subclass.""" | ||||
| pass | pass | ||||
| class OutputMissing(BadTxTemplate): | class OutputMissing(BadTxTemplate): | ||||
| reject_reason = "bad-txns-vout-empty" | reject_reason = "bad-txns-vout-empty" | ||||
| expect_disconnect = True | |||||
| def get_tx(self): | def get_tx(self): | ||||
| tx = CTransaction() | tx = CTransaction() | ||||
| tx.vin.append(self.valid_txin) | tx.vin.append(self.valid_txin) | ||||
| return tx | return tx | ||||
| class InputMissing(BadTxTemplate): | class InputMissing(BadTxTemplate): | ||||
| reject_reason = "bad-txns-vin-empty" | reject_reason = "bad-txns-vin-empty" | ||||
| expect_disconnect = True | |||||
| def get_tx(self): | def get_tx(self): | ||||
| tx = CTransaction() | tx = CTransaction() | ||||
| tx.vout.append(CTxOut(0, sc.CScript([sc.OP_TRUE] * 100))) | tx.vout.append(CTxOut(0, sc.CScript([sc.OP_TRUE] * 100))) | ||||
| return tx | return tx | ||||
| class SizeTooSmall(BadTxTemplate): | class SizeTooSmall(BadTxTemplate): | ||||
| Show All 10 Lines | |||||
| class BadInputOutpointIndex(BadTxTemplate): | class BadInputOutpointIndex(BadTxTemplate): | ||||
| # Won't be rejected - nonexistent outpoint index is treated as an orphan since the coins | # 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 | # database can't distinguish between spent outpoints and outpoints which | ||||
| # never existed. | # never existed. | ||||
| reject_reason = None | reject_reason = None | ||||
| # But fails in block | # But fails in block | ||||
| block_reject_reason = "bad-txns-inputs-missingorspent" | block_reject_reason = "bad-txns-inputs-missingorspent" | ||||
| expect_disconnect = False | |||||
| def get_tx(self): | def get_tx(self): | ||||
| num_indices = len(self.spend_tx.vin) | num_indices = len(self.spend_tx.vin) | ||||
| bad_idx = num_indices + 100 | bad_idx = num_indices + 100 | ||||
| tx = CTransaction() | tx = CTransaction() | ||||
| tx.vin.append( | tx.vin.append( | ||||
| CTxIn(COutPoint(self.spend_tx.txid_int, bad_idx), b"", 0xFFFFFFFF) | CTxIn(COutPoint(self.spend_tx.txid_int, bad_idx), b"", 0xFFFFFFFF) | ||||
| ) | ) | ||||
| tx.vout.append(CTxOut(0, basic_p2sh)) | tx.vout.append(CTxOut(0, basic_p2sh)) | ||||
| return tx | return tx | ||||
| class DuplicateInput(BadTxTemplate): | class DuplicateInput(BadTxTemplate): | ||||
| reject_reason = "bad-txns-inputs-duplicate" | reject_reason = "bad-txns-inputs-duplicate" | ||||
| expect_disconnect = True | expect_disconnect = False | ||||
| def get_tx(self): | def get_tx(self): | ||||
| tx = CTransaction() | tx = CTransaction() | ||||
| tx.vin.append(self.valid_txin) | tx.vin.append(self.valid_txin) | ||||
| tx.vin.append(self.valid_txin) | tx.vin.append(self.valid_txin) | ||||
| tx.vout.append(CTxOut(1, basic_p2sh)) | tx.vout.append(CTxOut(1, basic_p2sh)) | ||||
| return tx | return tx | ||||
| class PrevoutNullInput(BadTxTemplate): | class PrevoutNullInput(BadTxTemplate): | ||||
| reject_reason = "bad-txns-prevout-null" | reject_reason = "bad-txns-prevout-null" | ||||
| expect_disconnect = True | |||||
| def get_tx(self): | def get_tx(self): | ||||
| tx = CTransaction() | tx = CTransaction() | ||||
| tx.vin.append(self.valid_txin) | tx.vin.append(self.valid_txin) | ||||
| tx.vin.append(CTxIn(COutPoint(txid=0, n=0xFFFFFFFF))) | tx.vin.append(CTxIn(COutPoint(txid=0, n=0xFFFFFFFF))) | ||||
| tx.vout.append(CTxOut(1, basic_p2sh)) | tx.vout.append(CTxOut(1, basic_p2sh)) | ||||
| return tx | return tx | ||||
| class NonexistentInput(BadTxTemplate): | class NonexistentInput(BadTxTemplate): | ||||
| # Added as an orphan tx. | # Added as an orphan tx. | ||||
| reject_reason = None | reject_reason = None | ||||
| expect_disconnect = False | |||||
| # But fails in block | # But fails in block | ||||
| block_reject_reason = "bad-txns-inputs-missingorspent" | block_reject_reason = "bad-txns-inputs-missingorspent" | ||||
| def get_tx(self): | def get_tx(self): | ||||
| tx = CTransaction() | tx = CTransaction() | ||||
| tx.vin.append(CTxIn(COutPoint(self.spend_tx.txid_int + 1, 0), b"", 0xFFFFFFFF)) | tx.vin.append(CTxIn(COutPoint(self.spend_tx.txid_int + 1, 0), b"", 0xFFFFFFFF)) | ||||
| tx.vin.append(self.valid_txin) | tx.vin.append(self.valid_txin) | ||||
| tx.vout.append(CTxOut(1, basic_p2sh)) | tx.vout.append(CTxOut(1, basic_p2sh)) | ||||
| return tx | return tx | ||||
| class SpendTooMuch(BadTxTemplate): | class SpendTooMuch(BadTxTemplate): | ||||
| reject_reason = "bad-txns-in-belowout" | reject_reason = "bad-txns-in-belowout" | ||||
| expect_disconnect = True | |||||
| def get_tx(self): | def get_tx(self): | ||||
| return create_tx_with_script( | return create_tx_with_script( | ||||
| self.spend_tx, 0, script_pub_key=basic_p2sh, amount=(self.spend_avail + 1) | self.spend_tx, 0, script_pub_key=basic_p2sh, amount=(self.spend_avail + 1) | ||||
| ) | ) | ||||
| class CreateNegative(BadTxTemplate): | class CreateNegative(BadTxTemplate): | ||||
| reject_reason = "bad-txns-vout-negative" | reject_reason = "bad-txns-vout-negative" | ||||
| expect_disconnect = True | |||||
| def get_tx(self): | def get_tx(self): | ||||
| return create_tx_with_script(self.spend_tx, 0, amount=-1) | return create_tx_with_script(self.spend_tx, 0, amount=-1) | ||||
| class CreateTooLarge(BadTxTemplate): | class CreateTooLarge(BadTxTemplate): | ||||
| reject_reason = "bad-txns-vout-toolarge" | reject_reason = "bad-txns-vout-toolarge" | ||||
| expect_disconnect = True | |||||
| def get_tx(self): | def get_tx(self): | ||||
| return create_tx_with_script(self.spend_tx, 0, amount=MAX_MONEY + 1) | return create_tx_with_script(self.spend_tx, 0, amount=MAX_MONEY + 1) | ||||
| class CreateSumTooLarge(BadTxTemplate): | class CreateSumTooLarge(BadTxTemplate): | ||||
| reject_reason = "bad-txns-txouttotal-toolarge" | reject_reason = "bad-txns-txouttotal-toolarge" | ||||
| expect_disconnect = True | |||||
| def get_tx(self): | def get_tx(self): | ||||
| tx = create_tx_with_script(self.spend_tx, 0, amount=MAX_MONEY) | tx = create_tx_with_script(self.spend_tx, 0, amount=MAX_MONEY) | ||||
| tx.vout = [tx.vout[0]] * 2 | tx.vout = [tx.vout[0]] * 2 | ||||
| return tx | return tx | ||||
| class InvalidOPIFConstruction(BadTxTemplate): | class InvalidOPIFConstruction(BadTxTemplate): | ||||
| reject_reason = "mandatory-script-verify-flag-failed (Invalid OP_IF construction)" | reject_reason = "mandatory-script-verify-flag-failed (Invalid OP_IF construction)" | ||||
| block_reject_reason = BLOCK_NONPUSH_REJECT_REASON | block_reject_reason = BLOCK_NONPUSH_REJECT_REASON | ||||
| expect_disconnect = True | |||||
| def get_tx(self): | def get_tx(self): | ||||
| return create_tx_with_script( | return create_tx_with_script( | ||||
| self.spend_tx, 0, script_sig=b"\x64" * 35, amount=(self.spend_avail // 2) | self.spend_tx, 0, script_sig=b"\x64" * 35, amount=(self.spend_avail // 2) | ||||
| ) | ) | ||||
| class NonPushScriptSig(BadTxTemplate): | class NonPushScriptSig(BadTxTemplate): | ||||
| reject_reason = MEMPOOL_NONPUSH_REJECT_REASON | reject_reason = MEMPOOL_NONPUSH_REJECT_REASON | ||||
| block_reject_reason = BLOCK_NONPUSH_REJECT_REASON | block_reject_reason = BLOCK_NONPUSH_REJECT_REASON | ||||
| expect_disconnect = False | |||||
| def get_tx(self): | def get_tx(self): | ||||
| return create_tx_with_script( | return create_tx_with_script( | ||||
| self.spend_tx, 0, script_sig=b"\x61", amount=(self.spend_avail // 2) | self.spend_tx, 0, script_sig=b"\x61", amount=(self.spend_avail // 2) | ||||
| ) | ) | ||||
| def getDisabledOpcodeTemplate(opcode): | def getDisabledOpcodeTemplate(opcode): | ||||
| Show All 9 Lines | def get_tx(self): | ||||
| return tx | return tx | ||||
| return type( | return type( | ||||
| f"DisabledOpcode_{str(opcode)}", | f"DisabledOpcode_{str(opcode)}", | ||||
| (BadTxTemplate,), | (BadTxTemplate,), | ||||
| { | { | ||||
| "reject_reason": "disabled opcode", | "reject_reason": "disabled opcode", | ||||
| "block_reject_reason": BLOCK_NONPUSH_REJECT_REASON, | "block_reject_reason": BLOCK_NONPUSH_REJECT_REASON, | ||||
| "expect_disconnect": True, | |||||
| "get_tx": get_tx, | "get_tx": get_tx, | ||||
| }, | }, | ||||
| ) | ) | ||||
| class NonStandardAndInvalid(BadTxTemplate): | class NonStandardAndInvalid(BadTxTemplate): | ||||
| """A non-standard transaction which is also consensus-invalid should return the consensus error.""" | """A non-standard transaction which is also consensus-invalid should return the consensus error.""" | ||||
| reject_reason = "mandatory-script-verify-flag-failed (OP_RETURN was encountered)" | reject_reason = "mandatory-script-verify-flag-failed (OP_RETURN was encountered)" | ||||
| block_reject_reason = BLOCK_NONPUSH_REJECT_REASON | block_reject_reason = BLOCK_NONPUSH_REJECT_REASON | ||||
| expect_disconnect = True | |||||
| def get_tx(self): | def get_tx(self): | ||||
| return create_tx_with_script( | return create_tx_with_script( | ||||
| self.spend_tx, | self.spend_tx, | ||||
| 0, | 0, | ||||
| script_sig=b"\x00" * 3 + b"\xab\x6a", | script_sig=b"\x00" * 3 + b"\xab\x6a", | ||||
| amount=(self.spend_avail // 2), | amount=(self.spend_avail // 2), | ||||
| ) | ) | ||||
| Show All 12 Lines | |||||