test: add invalid tx templates for use in functional tests #14457

pull jamesob wants to merge 1 commits into bitcoin:master from jamesob:2018-10-invalid-tx-tests changing 5 files +254 −20
  1. jamesob commented at 9:30 AM on October 10, 2018: member

    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
    
  2. jamesob force-pushed on Oct 10, 2018
  3. practicalswift commented at 9:34 AM on October 10, 2018: contributor

    Excellent! Thanks for doing this

    Concept ACK

  4. fanquake added the label Tests on Oct 10, 2018
  5. promag commented at 6:42 AM on October 11, 2018: member

    Concept ACK! And looking the code LGTM. IMO there is no need to be comprehensive.

  6. in test/functional/feature_block.py:11 in 1483640cf1 outdated
       6 | @@ -7,7 +7,9 @@
       7 |  import struct
       8 |  import time
       9 |  
      10 | -from test_framework.blocktools import create_block, create_coinbase, create_tx_with_script, get_legacy_sigopcount_block
      11 | +from test_framework.blocktools import (
      12 | +    create_block, create_coinbase, create_tx_with_script, get_legacy_sigopcount_block,
    


    jimmysong commented at 11:09 PM on October 12, 2018:

    nit: put these one per line so diffs are easier to see later.

  7. in test/functional/feature_block.py:140 in 1483640cf1 outdated
     131 | +        # Submit blocks for rejection, each of which contains a single transaction
     132 | +        # (aside from coinbase) which should be considered invalid.
     133 | +        for TxTemplate in invalid_txs.iter_all_templates():
     134 | +            template = TxTemplate(spend_tx=spend_tx)
     135 | +
     136 | +            # Something about the serialization code for missing inputs creates
    


    jimmysong commented at 11:12 PM on October 12, 2018:

    Maybe put the test names here so someone can look for it in the future?


    jamesob commented at 4:40 PM on October 16, 2018:

    Not sure what you mean by this - which test names?

  8. jimmysong commented at 11:13 PM on October 12, 2018: contributor

    A couple of nits, but overall, very solid PR. Thanks!

  9. in test/functional/data/invalid_txs.py:83 in 1483640cf1 outdated
      78 | +        tx.vout.append(CTxOut(0, sc.CScript([sc.OP_TRUE] * 100)))
      79 | +        tx.calc_sha256()
      80 | +        return tx
      81 | +
      82 | +
      83 | +
    


    practicalswift commented at 1:46 PM on October 13, 2018:

    Since this is a new file you might want to run it file through black to get PEP-8 formatting. Including fixing this case of too many blank lines :-)

  10. in test/functional/feature_block.py:12 in 1483640cf1 outdated
       6 | @@ -7,7 +7,9 @@
       7 |  import struct
       8 |  import time
       9 |  
      10 | -from test_framework.blocktools import create_block, create_coinbase, create_tx_with_script, get_legacy_sigopcount_block
      11 | +from test_framework.blocktools import (
      12 | +    create_block, create_coinbase, create_tx_with_script, get_legacy_sigopcount_block,
      13 | +    MAX_BLOCK_SIGOPS)
    


    practicalswift commented at 1:52 PM on October 13, 2018:

    Not used in this file?


  11. in test/functional/data/invalid_txs.py:59 in 1483640cf1 outdated
      56 | +    def get_ctx(self, *args, **kwargs):
      57 | +        """Return a CTransaction that is invalid per the subclass."""
      58 | +        pass
      59 | +
      60 | +
      61 | +class OutputMissing(BadTxTemplate):
    


    practicalswift commented at 1:53 PM on October 13, 2018:

    Should be referenced from a test at least? :-)

    Applies also to other unused classes added in this PR


    jamesob commented at 4:38 PM on October 16, 2018:

    These are all accessed via iter_all_templates().


    practicalswift commented at 8:14 PM on October 16, 2018:

    @jamesob Ah, got it! Thanks for the clarification!

  12. in test/functional/data/invalid_txs.py:34 in 1483640cf1 outdated
      29 | +
      30 | +MAX_P2SH_SIGOPS = 15  # See policy/policy.h.
      31 | +
      32 | +
      33 | +class BadTxTemplate:
      34 | +    """Allows simple consruction of a certain kind of invalid tx. Base class to be subclassed."""
    


    practicalswift commented at 1:06 PM on October 16, 2018:

    Should be "construction" :-)

  13. jamesob force-pushed on Oct 16, 2018
  14. jamesob force-pushed on Oct 16, 2018
  15. jamesob commented at 6:47 PM on October 16, 2018: member

    Addressed @practicalswift @jimmysong feedback. Thanks for the looks.

  16. sipa commented at 7:19 AM on October 17, 2018: member

    Concept ACK

  17. jonasschnelli commented at 7:41 AM on October 17, 2018: contributor

    Neat!

    utACK 74306a55a5fd15ed194d8addb50cb55a849f293c

  18. in test/functional/data/invalid_txs.py:50 in 74306a55a5 outdated
      45 | +
      46 | +    # Is this tx considered valid when included in a block, but not for acceptance into
      47 | +    # the mempool (i.e. does it violate policy but not consensus)?
      48 | +    valid_in_block = False
      49 | +
      50 | +    def __init__(self, spend_tx=None, spend_block=None):
    


    MarcoFalke commented at 10:00 PM on October 23, 2018:

    nit: Could use self , *, spend_tx=... to enforce named args.

  19. in test/functional/data/invalid_txs.py:56 in 74306a55a5 outdated
      51 | +        self.spend_tx = spend_block.vtx[0] if spend_block else spend_tx
      52 | +        self.spend_avail = sum(i.nValue for i in self.spend_tx.vout)
      53 | +        self.valid_txin = CTxIn(COutPoint(self.spend_tx.sha256, 0), b"", 0xffffffff)
      54 | +
      55 | +    @abc.abstractmethod
      56 | +    def get_ctx(self, *args, **kwargs):
    


    MarcoFalke commented at 10:00 PM on October 23, 2018:

    nit: The developer notes discourage the leading C, so might want to call this get_tx?

  20. MarcoFalke commented at 10:01 PM on October 23, 2018: member

    Concept ACK

  21. jamesob force-pushed on Oct 24, 2018
  22. jamesob commented at 7:45 PM on October 24, 2018: member

    Addressed @MarcoFalke's feedback.

  23. conscott commented at 5:26 AM on October 25, 2018: contributor

    Tested ACK 428c144fc3acc02d36cb0e01dd631d39f0e9a00c

    Nice! I guess the follow up is to also use these in the mempool_accept.py test, possibly adding bad-txns-vout-toolarge, bad-txns-txouttotal-toolarge

  24. in test/functional/feature_block.py:105 in 428c144fc3 outdated
      99 | @@ -95,16 +100,21 @@ def run_test(self):
     100 |          self.save_spendable_output()
     101 |          self.sync_blocks([b0])
     102 |  
     103 | +        # These constants chosen specifically to trigger an immature coinbase spend
     104 | +        # at a certain time below.
     105 | +        NUM_BUFFER_BLOCKS_TO_GENERATE = 100
    


    ryanofsky commented at 4:45 PM on November 7, 2018:

    Why are both of these increasing by one?


    jamesob commented at 6:11 PM on November 7, 2018:

    Just because I added an additional coinbase to (try to) spend for the new tests included below.


    MarcoFalke commented at 9:24 PM on November 27, 2018:

    Why not borrow a coinbase output that is later used and keep those numbers as they were before? Since all blocks/tx are invalid that spend this coinbase output, there should be no downside in recycling it.


    jamesob commented at 10:23 PM on November 27, 2018:

    Yep, good point. Fixed.

  25. ryanofsky approved
  26. ryanofsky commented at 4:49 PM on November 7, 2018: member

    utACK 428c144fc3acc02d36cb0e01dd631d39f0e9a00c, with caveat that I didn't really take time to understand changes to feature_block.py, though they seem reasonable. The new module and changes to p2p_invalid_tx.py look good.

  27. DrahtBot commented at 9:08 AM on November 21, 2018: member

    <!--e57a25ab6845829454e8d69fc972939a-->

    The following sections might be updated with supplementary metadata relevant to reviewers and maintainers.

    <!--174a7506f384e20aa4161008e828411d-->

    Conflicts

    Reviewers, this pull request conflicts with the following ones:

    • #14696 (qa: Add explicit references to related CVE's in p2p_invalid_block test. by lucash-dev)

    If you consider this pull request important, please also help to review the conflicting pull requests. Ideally, start with the one that should be merged first.

  28. in test/functional/data/invalid_txs.py:52 in 428c144fc3 outdated
      47 | +    # the mempool (i.e. does it violate policy but not consensus)?
      48 | +    valid_in_block = False
      49 | +
      50 | +    def __init__(self, *, spend_tx=None, spend_block=None):
      51 | +        self.spend_tx = spend_block.vtx[0] if spend_block else spend_tx
      52 | +        self.spend_avail = sum(i.nValue for i in self.spend_tx.vout)
    


    MarcoFalke commented at 9:07 PM on November 27, 2018:

    nit:

            self.spend_avail = sum(o.nValue for o in self.spend_tx.vout)
    
  29. MarcoFalke commented at 9:26 PM on November 27, 2018: member

    Concept ACK 428c144fc3acc02d36cb0e01dd631d39f0e9a00c

  30. jamesob force-pushed on Nov 27, 2018
  31. MarcoFalke commented at 10:32 PM on November 27, 2018: member

    travis fails :(

    cc @practicalswift

  32. practicalswift commented at 10:44 PM on November 27, 2018: contributor

    @MarcoFalke Thanks for the ping! @jamesob vulture identifies MAX_P2SH_SIGOPS as unused. Regarding the other warnings: it seems like vulture doesn't understand that the classes are referenced using BadTxTemplate.__subclasses__(). Could the class usage be made more explicit so that vulture (and humans) can infer it? If not, add the class names to --ignore-names in test/lint/lint-python-dead-code.sh :-)

  33. test: add invalid tx templates for use in functional tests
    Add templates for easily constructing different kinds of invalid
    transactions and use them in feature_block and p2p_invalid_tx.
    59e387705c
  34. jamesob force-pushed on Nov 27, 2018
  35. jamesob commented at 10:55 PM on November 27, 2018: member

    @practicalswift thanks for the advice. I've excluded the whole invalid_txs.py file from analysis by vulture because there are more than a few class names spuriously detected, and any time someone adds a new invalid txn class they'd have to update that file otherwise.

  36. in test/functional/feature_block.py:143 in 59e387705c
     139 | +            template = TxTemplate(spend_tx=attempt_spend_tx)
     140 | +
     141 | +            # Something about the serialization code for missing inputs creates
     142 | +            # a different hash in the test client than on bitcoind, resulting
     143 | +            # in a mismatching merkle root during block validation.
     144 | +            # Skip until we figure out what's going on.
    


    MarcoFalke commented at 8:47 PM on November 30, 2018:

    missing inputs means the vin is empty and is thus interpreted as the witness dummy vin?


    MarcoFalke commented at 8:26 PM on December 22, 2018:

    See:

    tx as sent:     CTransaction(nVersion=1 vin=[] vout=[CTxOut(nValue=0.00000000 scriptPubKey=51515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151)] wit=CTxWitness() nLockTime=0)
    tx as received: CTransaction(nVersion=1 vin=[] vout=[] wit=CTxWitness() nLockTime=0)
    

    MarcoFalke commented at 8:33 PM on December 22, 2018:

    One solution would be:

    diff --git a/test/functional/feature_block.py b/test/functional/feature_block.py
    index 697a0b19ac..edbdcf2d55 100755
    --- a/test/functional/feature_block.py
    +++ b/test/functional/feature_block.py
    @@ -137,12 +137,6 @@ class FullBlockTest(BitcoinTestFramework):
             for TxTemplate in invalid_txs.iter_all_templates():
                 template = TxTemplate(spend_tx=attempt_spend_tx)
     
    -            # Something about the serialization code for missing inputs creates
    -            # a different hash in the test client than on bitcoind, resulting
    -            # in a mismatching merkle root during block validation.
    -            # Skip until we figure out what's going on.
    -            if TxTemplate == invalid_txs.InputMissing:
    -                continue
                 if template.valid_in_block:
                     continue
     
    @@ -150,7 +144,10 @@ class FullBlockTest(BitcoinTestFramework):
                 blockname = "for_invalid.%s" % TxTemplate.__name__
                 badblock = self.next_block(blockname)
                 badtx = template.get_tx()
    -            self.sign_tx(badtx, attempt_spend_tx)
    +            if TxTemplate != invalid_txs.InputMissing:
    +                self.sign_tx(badtx, attempt_spend_tx)
    +            else:
    +                badtx.vout = []  # Also set outputs empty, so we can calculate the correct hash
                 badtx.rehash()
                 badblock = self.update_block(blockname, [badtx])
                 self.sync_blocks(
    
  37. ryanofsky approved
  38. ryanofsky commented at 9:24 PM on December 4, 2018: member

    utACK 59e387705c7e55ec40400301346354fa2d0c613f. Changes since last review: rebase, minor tweaks, variable, renames, dead code linter update.

  39. laanwj commented at 1:43 PM on January 2, 2019: member

    utACK 59e387705c7e55ec40400301346354fa2d0c613f

  40. laanwj merged this on Jan 2, 2019
  41. laanwj closed this on Jan 2, 2019

  42. laanwj referenced this in commit df894fa69a on Jan 2, 2019
  43. Munkybooty referenced this in commit b4992b8f16 on Aug 24, 2021
  44. Munkybooty referenced this in commit 9714c0a652 on Aug 24, 2021
  45. Munkybooty referenced this in commit 2c87da151b on Sep 5, 2021
  46. vijaydasmp referenced this in commit 7f035d5d73 on Oct 23, 2021
  47. vijaydasmp referenced this in commit 551ef4b23b on Oct 23, 2021
  48. vijaydasmp referenced this in commit 8e32f6740c on Oct 23, 2021
  49. vijaydasmp referenced this in commit b6e22304ef on Oct 26, 2021
  50. vijaydasmp referenced this in commit 363d251b90 on Oct 26, 2021
  51. DrahtBot locked this on Dec 16, 2021

github-metadata-mirror

This is a metadata mirror of the GitHub repository bitcoin/bitcoin. This site is not affiliated with GitHub. Content is generated from a GitHub metadata backup.
generated: 2026-04-27 21:14 UTC

This site is hosted by @0xB10C
More mirrored repositories can be found on mirror.b10c.me