示例#1
0
def make_separator_tx(tx_to_spend, key_for_tx_to_spend, n_sgnings):
    """create Transaction with scriptPubKey in form of:
    <pk1> OP_CHECKSIGVERIFY OP_CODESEPARATOR <pk2> OP_CHECKSIGVERIFY OP_CODESEPARATOR ... <pk N_signings> OP_CHECKSIG
    """
    tx = CTransaction()
    tx.vin.append(CTxIn(COutPoint(tx_to_spend.sha256, 0), b"", 0xffffffff))

    keys = []
    script_list = []
    for i in range(n_sgnings - 1):
        k = CECKey()
        k.set_secretbytes(b"x" * (i + 1))
        keys.append(k)
        script_list.extend(
            [k.get_pubkey(), OP_CHECKSIGVERIFY, OP_CODESEPARATOR])

    k = CECKey()
    k.set_secretbytes(b"x" * n_sgnings)
    keys.append(k)
    script_list.extend([k.get_pubkey(), OP_CHECKSIG])

    amount = tx_to_spend.vout[0].nValue - 2000
    tx.vout.append(CTxOut(amount, CScript(script_list)))

    sighash = SignatureHashForkId(tx_to_spend.vout[0].scriptPubKey, tx, 0,
                                  SIGHASH_ALL | SIGHASH_FORKID,
                                  tx_to_spend.vout[0].nValue)
    tx.vin[0].scriptSig = CScript([
        key_for_tx_to_spend.sign(sighash) +
        bytes(bytearray([SIGHASH_ALL | SIGHASH_FORKID]))
    ])

    tx.rehash()
    return tx, keys
def create_tx(utxos, n_outputs, fee_delta=0):
    total_input = 0
    tx = CTransaction()
    for utxo in utxos:
        tx.vin.append(
            CTxIn(COutPoint(utxo.tx.sha256, utxo.ndx), b"", 0xffffffff))
        total_input += utxo.tx.vout[utxo.ndx].nValue

    amount_per_output = total_input // n_outputs - len(
        utxos) * 300 - n_outputs * 200 - 100 - fee_delta

    new_utxos = []

    for i in range(n_outputs):
        k = new_key()
        new_utxos.append(UTXO(tx, i, k))
        tx.vout.append(
            CTxOut(amount_per_output, CScript([k.get_pubkey(), OP_CHECKSIG])))

    for input_ndx, (utxo, input) in enumerate(zip(utxos, tx.vin)):
        sighash = SignatureHashForkId(utxo.tx.vout[utxo.ndx].scriptPubKey, tx,
                                      input_ndx, SIGHASH_ALL | SIGHASH_FORKID,
                                      utxo.tx.vout[utxo.ndx].nValue)
        input.scriptSig = CScript([
            utxo.key.sign(sighash) +
            bytes(bytearray([SIGHASH_ALL | SIGHASH_FORKID]))
        ])

    tx.rehash()

    return tx, new_utxos
示例#3
0
def make_unlock_script(tx, tx_to_spend):
    sighash = SignatureHashForkId(tx_to_spend.vout[0].scriptPubKey, tx, 0,
                                  SIGHASH_ALL | SIGHASH_FORKID,
                                  tx_to_spend.vout[0].nValue)
    sig = MaxMultiSigTest.THE_KEY.sign(sighash) + bytes(
        bytearray([SIGHASH_ALL | SIGHASH_FORKID]))
    return CScript([OP_0, sig])
示例#4
0
def create_parent_tx(tx_to_spend,
                     key_for_tx_to_spend,
                     n_outputs,
                     invalidity=None):
    tx = CTransaction()
    tx.vin.append(CTxIn(COutPoint(tx_to_spend.sha256, 0), b"", 0xffffffff))

    keys = []
    if invalidity == "low_fee":
        amount_per_output = tx_to_spend.vout[0].nValue // n_outputs - 10
    else:
        amount_per_output = tx_to_spend.vout[0].nValue // n_outputs - 2000

    for i in range(n_outputs):
        k = CECKey()
        keys.append(k)
        k.set_secretbytes(b"x" * (i + 1))
        tx.vout.append(
            CTxOut(amount_per_output, CScript([k.get_pubkey(), OP_CHECKSIG])))

    if invalidity == "bad_signature":
        sighash = b"\xff" * 32
    else:
        sighash = SignatureHashForkId(tx_to_spend.vout[0].scriptPubKey, tx, 0,
                                      SIGHASH_ALL | SIGHASH_FORKID,
                                      tx_to_spend.vout[0].nValue)

    tx.vin[0].scriptSig = CScript([
        key_for_tx_to_spend.sign(sighash) +
        bytes(bytearray([SIGHASH_ALL | SIGHASH_FORKID]))
    ])

    tx.rehash()
    return tx, keys
示例#5
0
        def create_fund_and_spend_tx(spend, multi=False, sig='schnorr'):
            if multi:
                script = CScript([OP_1, public_key, OP_1, OP_CHECKMULTISIG])
            else:
                script = CScript([public_key, OP_CHECKSIG])

            # Fund transaction
            txfund = create_transaction(spend.tx, spend.n, b'', 50 * COIN,
                                        script)
            txfund.rehash()

            # Spend transaction
            txspend = CTransaction()
            txspend.vout.append(CTxOut(50 * COIN - 1000, CScript([OP_TRUE])))
            txspend.vin.append(CTxIn(COutPoint(txfund.sha256, 0), b''))

            # Sign the transaction
            sighashtype = SIGHASH_ALL | SIGHASH_FORKID
            hashbyte = bytes([sighashtype & 0xff])
            sighash = SignatureHashForkId(script, txspend, 0, sighashtype,
                                          50 * COIN)
            if sig == 'schnorr':
                txsig = schnorr.sign(privkeybytes, sighash) + hashbyte
            elif sig == 'ecdsa':
                txsig = private_key.sign(sighash) + hashbyte
            elif isinstance(sig, bytes):
                txsig = sig + hashbyte
            if multi:
                txspend.vin[0].scriptSig = CScript([b'', txsig])
            else:
                txspend.vin[0].scriptSig = CScript([txsig])
            txspend.rehash()

            return txfund, txspend
示例#6
0
def new_transaction(utxokey, utxo, target_tx_size):
    ndx, tx_to_spend = utxo
    padding_size = target_tx_size
    while True:
        tx = CTransaction()
        tx.vin.append(CTxIn(COutPoint(tx_to_spend.sha256, ndx), b''))
        tx.vin[0].scriptSig = b''
        tx.vout.append(
            CTxOut(tx_to_spend.vout[0].nValue - 2 * target_tx_size,
                   SIMPLE_OUTPUT_SCRIPT))
        tx.vout.append(
            CTxOut(1,
                   CScript([OP_FALSE, OP_RETURN] + [bytes(1) * padding_size])))
        sighash = SignatureHashForkId(tx_to_spend.vout[0].scriptPubKey, tx, 0,
                                      SIGHASH_ALL | SIGHASH_FORKID,
                                      tx_to_spend.vout[0].nValue)
        sig = utxokey.sign(sighash) + bytes(
            bytearray([SIGHASH_ALL | SIGHASH_FORKID]))
        tx.vin[0].scriptSig = CScript([sig])
        tx.rehash()

        diff = target_tx_size - len(tx.serialize())
        if diff == 0:
            return tx
        padding_size += diff
 def make_spend_txn(txtype, fund_txn_hash, fund_txn_num_vouts,
                    out_value):
     # Create txn
     spend_tx = CTransaction()
     for idx in range(fund_txn_num_vouts):
         spend_tx.vin.append(CTxIn(COutPoint(fund_txn_hash, idx), b''))
         sighash = SignatureHashForkId(
             redeem_script, spend_tx, idx,
             SIGHASH_ANYONECANPAY | SIGHASH_FORKID | SIGHASH_NONE,
             out_value)
         sig = key.sign(sighash) + bytes(
             bytearray([
                 SIGHASH_ANYONECANPAY | SIGHASH_FORKID | SIGHASH_NONE
             ]))
         spend_tx.vin[idx].scriptSig = CScript(
             [OP_0, sig, redeem_script])
         # Standard transaction
         if TxType.standard == txtype:
             spend_tx.vout.append(
                 CTxOut(out_value - 1000, CScript([OP_RETURN])))
         # Non-standard transaction
         elif TxType.nonstandard == txtype:
             spend_tx.vout.append(
                 CTxOut(out_value - 1000, CScript([OP_TRUE])))
         spend_tx.rehash()
     return spend_tx
        def create_fund_and_spend_tx(dummy=OP_0, sigtype='ecdsa'):
            spendfrom = spendable_outputs.pop()

            script = CScript([OP_1, public_key, OP_1, OP_CHECKMULTISIG])

            value = spendfrom.vout[0].nValue

            # Fund transaction
            txfund = create_tx_with_script(spendfrom, 0, b'', value, script)
            txfund.rehash()
            fundings.append(txfund)

            # Spend transaction
            txspend = CTransaction()
            txspend.vout.append(CTxOut(value - 1000, CScript([OP_TRUE])))
            txspend.vin.append(CTxIn(COutPoint(txfund.sha256, 0), b''))

            # Sign the transaction
            sighashtype = SIGHASH_ALL | SIGHASH_FORKID
            hashbyte = bytes([sighashtype & 0xff])
            sighash = SignatureHashForkId(script, txspend, 0, sighashtype,
                                          value)
            if sigtype == 'schnorr':
                txsig = schnorr.sign(privkeybytes, sighash) + hashbyte
            elif sigtype == 'ecdsa':
                txsig = private_key.sign_ecdsa(sighash) + hashbyte
            txspend.vin[0].scriptSig = CScript([dummy, txsig])
            txspend.rehash()

            return txspend
    def prepare_for_test(self, height, label, coinbases, connections):
        transactions = []
        n_generated_utxos = 0
        while n_generated_utxos < self._NUMBER_OF_UTXOS_PER_HEIGHT:
            tx_to_spend = coinbases()

            tx = CTransaction()
            transactions.append(tx)
            tx.vin.append(CTxIn(COutPoint(tx_to_spend.sha256, 0), b''))

            locking_key = self._UTXO_KEY
            cscript = CScript([locking_key.get_pubkey(), OP_CHECKSIG]) if locking_key else CScript([OP_TRUE])
            for x in range(24):
                coinbaseoutput = CTxOut(2 * COIN, cscript)
                tx.vout.append(coinbaseoutput)
                n_generated_utxos += 1

            if self.COINBASE_KEY:
                tx.rehash()
                sighash = SignatureHashForkId(tx_to_spend.vout[0].scriptPubKey, tx, 0, SIGHASH_ALL | SIGHASH_FORKID,
                                              tx_to_spend.vout[0].nValue)
                sig = self._coinbase_key.sign(sighash) + bytes(bytearray([SIGHASH_ALL | SIGHASH_FORKID]))
                tx.vin[0].scriptSig = CScript([sig])
            else:
                tx.vin[0].scriptSig = CScript([OP_TRUE])

            tx.rehash()
            self.log.info(f"Created UTXO Tx {loghash(tx.hash)} with {n_generated_utxos} outputs")

        return transactions, None
示例#10
0
        def create_fund_and_spend_tx(spend, forkvalue=0):
            # Fund transaction
            script = CScript([public_key, OP_CHECKSIG])
            txfund = create_tx_with_script(spend.tx,
                                           spend.n,
                                           b'',
                                           amount=50 * COIN - 1000,
                                           script_pub_key=script)
            txfund.rehash()

            # Spend transaction
            txspend = CTransaction()
            txspend.vout.append(CTxOut(50 * COIN - 2000, CScript([OP_TRUE])))
            txspend.vin.append(CTxIn(COutPoint(txfund.sha256, 0), b''))

            # Sign the transaction
            sighashtype = (forkvalue << 8) | SIGHASH_ALL | SIGHASH_FORKID
            sighash = SignatureHashForkId(script, txspend, 0, sighashtype,
                                          50 * COIN - 1000)
            sig = private_key.sign_ecdsa(sighash) + \
                bytes(bytearray([SIGHASH_ALL | SIGHASH_FORKID]))
            txspend.vin[0].scriptSig = CScript([sig])
            txspend.rehash()

            return [txfund, txspend]
示例#11
0
 def sign_tx(self, tx, spend_tx, n):
     sighash = SignatureHashForkId(spend_tx.vout[n].scriptPubKey, tx, 0,
                                   SIGHASH_ALL | SIGHASH_FORKID,
                                   spend_tx.vout[n].nValue)
     tx.vin[0].scriptSig = CScript([
         self.prvkey.sign(sighash) +
         bytes(bytearray([SIGHASH_ALL | SIGHASH_FORKID])), self.pubkey
     ])
示例#12
0
 def next_block(self,
                number,
                spend=None,
                additional_coinbase_value=0,
                script=None):
     if self.tip == None:
         base_block_hash = self.genesis_hash
     else:
         base_block_hash = self.tip.sha256
     # First create the coinbase
     height = self.block_heights[base_block_hash] + 1
     coinbase = create_coinbase(absoluteHeight=height,
                                pubkey=self.coinbase_pubkey)
     coinbase.vout[0].nValue += additional_coinbase_value
     if (spend != None):
         coinbase.vout[0].nValue += spend.tx.vout[
             spend.n].nValue - 1  # all but one satoshi to fees
     coinbase.rehash()
     block = create_block(base_block_hash, coinbase, self.block_time)
     if (spend != None):
         tx = CTransaction()
         tx.vin.append(
             CTxIn(COutPoint(spend.tx.sha256, spend.n), "",
                   0xffffffff))  # no signature yet
         # This copies the java comparison tool testing behavior: the first
         # txout has a garbage scriptPubKey, "to make sure we're not
         # pre-verifying too much" (?)
         tx.vout.append(
             CTxOut(0, CScript([random.randint(0, 255), height & 255])))
         if script == None:
             tx.vout.append(CTxOut(1, CScript([OP_TRUE])))
         else:
             tx.vout.append(CTxOut(1, script))
         # Now sign it if necessary
         scriptSig = ""
         scriptPubKey = bytearray(spend.tx.vout[spend.n].scriptPubKey)
         if (scriptPubKey[0] == OP_TRUE):  # looks like an anyone-can-spend
             scriptSig = CScript([OP_TRUE])
         else:
             # We have to actually sign it
             sighash = SignatureHashForkId(
                 spend.tx.vout[spend.n].scriptPubKey, tx, 0,
                 SIGHASH_ALL | SIGHASH_FORKID,
                 spend.tx.vout[spend.n].nValue)
             scriptSig = CScript([
                 self.coinbase_key.sign(sighash) +
                 bytes(bytearray([SIGHASH_ALL | SIGHASH_FORKID]))
             ])
         tx.vin[0].scriptSig = scriptSig
         # Now add the transaction to the block
         block = self.add_transactions_to_block(block, [tx])
     block.solve()
     self.tip = block
     self.block_heights[block.sha256] = height
     self.block_time += 1
     assert number not in self.blocks
     self.blocks[number] = block
     return block
 def sign_tx(self, tx, spend_tx):
     scriptPubKey = bytearray(spend_tx.vout[0].scriptPubKey)
     if (scriptPubKey[0] == OP_TRUE):  # an anyone-can-spend
         tx.vin[0].scriptSig = CScript()
         return
     sighash = SignatureHashForkId(
         spend_tx.vout[0].scriptPubKey, tx, 0, SIGHASH_ALL | SIGHASH_FORKID, spend_tx.vout[0].nValue)
     tx.vin[0].scriptSig = CScript(
         [self.coinbase_key.sign_ecdsa(sighash) + bytes(bytearray([SIGHASH_ALL | SIGHASH_FORKID]))])
 def sign_tx(self, tx, spend_tx, n, *, key):
     scriptPubKey = bytearray(spend_tx.vout[n].scriptPubKey)
     sighash = SignatureHashForkId(spend_tx.vout[n].scriptPubKey, tx, 0,
                                   SIGHASH_ALL | SIGHASH_FORKID,
                                   spend_tx.vout[n].nValue)
     tx.vin[0].scriptSig = CScript([
         key.sign(sighash) +
         bytes(bytearray([SIGHASH_ALL | SIGHASH_FORKID]))
     ])
示例#15
0
def create_children_txs(parent_tx1, keys1, parent_tx2, keys2, invalidity=None):
    ret = []
    for n, (txout1, key1, txout2, key2) in enumerate(
            zip(parent_tx1.vout, keys1, parent_tx2.vout, keys2)):
        amount1 = txout1.nValue if invalidity == "low_fee" else int(
            0.99 * txout1.nValue)
        amount2 = txout2.nValue if invalidity == "low_fee" else int(
            0.99 * txout2.nValue)

        amount = amount1 + amount2

        tx = CTransaction()
        tx.vin.append(CTxIn(COutPoint(parent_tx1.sha256, n), b"", 0xffffffff))
        tx.vin.append(CTxIn(COutPoint(parent_tx2.sha256, n), b"", 0xffffffff))

        k = CECKey()
        k.set_secretbytes(b"x" * (n + 1))
        tx.vout.append(CTxOut(amount, CScript([k.get_pubkey(), OP_CHECKSIG])))
        tx.calc_sha256()

        sighash1 = SignatureHashForkId(parent_tx1.vout[n].scriptPubKey, tx, 0,
                                       SIGHASH_ALL | SIGHASH_FORKID,
                                       parent_tx1.vout[n].nValue)
        tx.vin[0].scriptSig = CScript([
            key1.sign(sighash1) +
            bytes(bytearray([SIGHASH_ALL | SIGHASH_FORKID]))
        ])

        if invalidity == "bad_signature":
            sighash2 = b"\xff" * 32
        else:
            sighash2 = SignatureHashForkId(parent_tx2.vout[n].scriptPubKey, tx,
                                           1, SIGHASH_ALL | SIGHASH_FORKID,
                                           parent_tx2.vout[n].nValue)

        tx.vin[1].scriptSig = CScript([
            key2.sign(sighash2) +
            bytes(bytearray([SIGHASH_ALL | SIGHASH_FORKID]))
        ])

        tx.rehash()
        ret.append(tx)

    return ret
 def spend_p2sh_tx(output_script=CScript([OP_TRUE])):
     # Create the transaction
     spent_p2sh_tx = CTransaction()
     spent_p2sh_tx.vin.append(CTxIn(COutPoint(p2sh_tx.sha256, 0), b''))
     spent_p2sh_tx.vout.append(CTxOut(1, output_script))
     # Sign the transaction using the redeem script
     sighash = SignatureHashForkId(
         redeem_script, spent_p2sh_tx, 0, SIGHASH_ALL | SIGHASH_FORKID, p2sh_tx.vout[0].nValue)
     sig = private_key.sign(sighash) + \
         bytes(bytearray([SIGHASH_ALL | SIGHASH_FORKID]))
     spent_p2sh_tx.vin[0].scriptSig = CScript([sig, redeem_script])
     spent_p2sh_tx.rehash()
     return spent_p2sh_tx
示例#17
0
def make_unlock_modified00(tx, tx_to_spend):
    sighash = SignatureHashForkId(tx_to_spend.vout[0].scriptPubKey, tx, 0, SIGHASH_ALL | SIGHASH_FORKID,
                                  tx_to_spend.vout[0].nValue)
    sig = HandleTxsModified00Node.THE_KEY.sign(sighash) + bytes(bytearray([SIGHASH_ALL | SIGHASH_FORKID]))
    return CScript([sig])

    class HandleTxsDefaultNode(GenesisHeightBasedSimpleTestsCase):
        ARGS = GenesisHeightBasedSimpleTestsCase.ARGS + ['-banscore=1000000', '-whitelist=127.0.0.1', '-acceptnonstdtxn=0', '-acceptnonstdoutputs=1']
        NAME = "Reject nonstandard transactions and accept p2sh transactions before Genesis. Accept nonstandard and reject p2sh transactions after Genesis"
    
        THE_KEY = make_key()
        P2PK_LOCKING_SCRIPT = CScript([THE_KEY.get_pubkey(), OP_CHECKSIG])
    
        TEST_PRE_GENESIS_STANDARD_TX = [
            SimpleTestDefinition("PRE-GENESIS", P2PK_LOCKING_SCRIPT,
                                 "PRE-GENESIS", make_unlock_default)
        ]
    
        TEST_PRE_GENESIS_NONSTANDARD_TX = [
            SimpleTestDefinition("PRE-GENESIS", P2PK_LOCKING_SCRIPT,
                                 "PRE-GENESIS", make_unlock_default, test_tx_locking_script=CScript([OP_TRUE]),
                                                p2p_reject_reason = b'scriptpubkey')
        ]
    
        TEST_PRE_GENESIS_P2SH_TX = [
            SimpleTestDefinition("PRE-GENESIS", P2PK_LOCKING_SCRIPT,
                                 "PRE-GENESIS", make_unlock_default, test_tx_locking_script=CScript([OP_HASH160, hash160(CScript([OP_TRUE])), OP_EQUAL]))
        ]
    
        TEST_GENESIS_STANDARD_TX = [
            SimpleTestDefinition("GENESIS", P2PK_LOCKING_SCRIPT,
                                 "GENESIS", make_unlock_default)
        ]
    
        TEST_GENESIS_NONSTANDARD_TX = [
            SimpleTestDefinition("GENESIS", P2PK_LOCKING_SCRIPT,
                                 "GENESIS", make_unlock_default, test_tx_locking_script=CScript([OP_TRUE]))
        ]
    
        # P2SH transaction will be rejected from p2p, but not rejected as part of the block
        TEST_GENESIS_P2SH_TX = [
            SimpleTestDefinition("GENESIS", P2PK_LOCKING_SCRIPT,
                                 "GENESIS", make_unlock_default, test_tx_locking_script=CScript([OP_HASH160, hash160(CScript([OP_TRUE])), OP_EQUAL]),
                                            p2p_reject_reason=b'bad-txns-vout-p2sh')
        ]
    
        TESTS = TEST_PRE_GENESIS_STANDARD_TX + TEST_PRE_GENESIS_NONSTANDARD_TX + TEST_PRE_GENESIS_P2SH_TX + TEST_GENESIS_STANDARD_TX + TEST_GENESIS_NONSTANDARD_TX + TEST_GENESIS_P2SH_TX
示例#18
0
 def spend_p2sh_tx(p2sh_tx_to_spend, output_script=CScript([OP_TRUE])):
     # Create the transaction
     spent_p2sh_tx = CTransaction()
     spent_p2sh_tx.vin.append(
         CTxIn(COutPoint(p2sh_tx_to_spend.sha256, 0), b''))
     spent_p2sh_tx.vout.append(CTxOut(1000, output_script))
     # Sign the transaction using the redeem script
     sighash = SignatureHashForkId(redeem_script, spent_p2sh_tx, 0,
                                   SIGHASH_ALL | SIGHASH_FORKID,
                                   p2sh_tx_to_spend.vout[0].nValue)
     sig = self.coinbase_key.sign(sighash) + bytes(
         bytearray([SIGHASH_ALL | SIGHASH_FORKID]))
     spent_p2sh_tx.vin[0].scriptSig = CScript([sig, redeem_script])
     assert len(spent_p2sh_tx.vin[0].scriptSig
                ) >= 198, "needs to pass input sigchecks limit"
     spent_p2sh_tx.rehash()
     return spent_p2sh_tx
def spend_tx_to_data(tx_to_spend, key_for_tx_to_spend):
    "Create and send block with coinbase, returns conbase (tx, key) tuple"
    tx = CTransaction()
    tx.vin.append(CTxIn(COutPoint(tx_to_spend.sha256, 0), b"", 0xffffffff))

    amount = tx_to_spend.vout[0].nValue - 2000
    tx.vout.append(CTxOut(amount, OP_TRUE_OP_RETURN_SCRIPT))

    sighash = SignatureHashForkId(tx_to_spend.vout[0].scriptPubKey, tx, 0,
                                  SIGHASH_ALL | SIGHASH_FORKID,
                                  tx_to_spend.vout[0].nValue)
    tx.vin[0].scriptSig = CScript([
        key_for_tx_to_spend.sign(sighash) +
        bytes(bytearray([SIGHASH_ALL | SIGHASH_FORKID]))
    ])

    tx.rehash()
    return tx
示例#20
0
        def create_fund_and_spend_tx(multi=False, sig='schnorr'):
            spendfrom = spendable_outputs.pop()
            vout = 1

            if multi:
                script = CScript([OP_1, public_key, OP_1, OP_CHECKMULTISIG])
            else:
                script = CScript([public_key, OP_CHECKSIG])

            value = spendfrom.vout[vout].nValue

            # Fund transaction
            txfund = create_tx_with_script(spendfrom,
                                           vout,
                                           b'',
                                           amount=value,
                                           script_pub_key=script)
            txfund.rehash()
            fundings.append(txfund)

            # Spend transaction
            txspend = CTransaction()
            txspend.vout.append(CTxOut(value - 1000, CScript([OP_TRUE])))
            txspend.vin.append(CTxIn(COutPoint(txfund.txid, 0), b''))

            # Sign the transaction
            sighashtype = SIGHASH_ALL | SIGHASH_FORKID
            hashbyte = bytes([sighashtype & 0xff])
            sighash = SignatureHashForkId(script, txspend, 0, sighashtype,
                                          value)
            if sig == 'schnorr':
                txsig = private_key.sign_schnorr(sighash) + hashbyte
            elif sig == 'ecdsa':
                txsig = private_key.sign_ecdsa(sighash) + hashbyte
            elif isinstance(sig, bytes):
                txsig = sig + hashbyte
            if multi:
                txspend.vin[0].scriptSig = CScript([b'', txsig])
            else:
                txspend.vin[0].scriptSig = CScript([txsig])
            txspend.rehash()

            return txspend
def create_fund_and_activation_specific_spending_tx(spend, pre_fork_only):
    # Creates 2 transactions:
    # 1) txfund: create outputs to be used by txspend. Must be valid pre-fork.
    # 2) txspend: spending transaction that is specific to the activation
    #    being used and can be pre-fork-only or post-fork-only, depending on the
    #    function parameter.

    # This specific implementation uses the replay protection mechanism to
    # create transactions that are only valid before or after the fork.

    # Generate a key pair to test
    private_key = ECKey()
    private_key.generate()
    public_key = private_key.get_pubkey().get_bytes()

    # Fund transaction
    script = CScript([public_key, OP_CHECKSIG])
    txfund = create_tx_with_script(spend.tx,
                                   spend.n,
                                   b'',
                                   amount=int(SUBSIDY * COIN),
                                   script_pub_key=script)
    txfund.rehash()

    # Activation specific spending tx
    txspend = CTransaction()
    txspend.vout.append(CTxOut(int(SUBSIDY * COIN) - 1000, CScript([OP_TRUE])))
    txspend.vin.append(CTxIn(COutPoint(txfund.txid, 0), b''))

    # Sign the transaction
    # Use forkvalues that create pre-fork-only or post-fork-only
    # transactions.
    forkvalue = 0 if pre_fork_only else 0xffdead
    sighashtype = (forkvalue << 8) | SIGHASH_ALL | SIGHASH_FORKID
    sighash = SignatureHashForkId(script, txspend, 0, sighashtype,
                                  int(SUBSIDY * COIN))
    sig = private_key.sign_ecdsa(sighash) + \
        bytes(bytearray([SIGHASH_ALL | SIGHASH_FORKID]))
    txspend.vin[0].scriptSig = CScript([sig])
    txspend.rehash()

    return txfund, txspend
    def create_tx(self,
                  outpoints,
                  noutput,
                  feerate,
                  make_long_eval_script=False):
        """creates p2pk transaction always using the same key (created in constructor), if make_long_eval_script is set
        we are prepending long evaluating script to the locking script
        """
        pre_script = MemepoolAcceptingTransactionsDuringReorg.long_eval_script if make_long_eval_script else []

        tx = CTransaction()
        total_input = 0
        for parent_tx, n in outpoints:
            tx.vin.append(
                CTxIn(COutPoint(parent_tx.sha256, n), CScript([b"0" * 72]),
                      0xffffffff))
            total_input += parent_tx.vout[n].nValue

        for _ in range(noutput):
            tx.vout.append(
                CTxOut(total_input // noutput,
                       CScript(pre_script + [self.public_key, OP_CHECKSIG])))

        tx.rehash()

        tx_size = len(tx.serialize())
        fee_per_output = int(tx_size * feerate // noutput)

        for output in tx.vout:
            output.nValue -= fee_per_output

        for input, (parent_tx, n) in zip(tx.vin, outpoints):
            sighash = SignatureHashForkId(parent_tx.vout[n].scriptPubKey, tx,
                                          0, SIGHASH_ALL | SIGHASH_FORKID,
                                          parent_tx.vout[n].nValue)
            input.scriptSig = CScript([
                self.private_key.sign(sighash) +
                bytes(bytearray([SIGHASH_ALL | SIGHASH_FORKID]))
            ])

        tx.rehash()
        return tx
示例#23
0
def create_fund_and_spend_tx(node, spend, multi=False):

    privkeybytes = b"Schnorr!" * 4
    private_key = CECKey()
    private_key.set_secretbytes(privkeybytes)
    # get uncompressed public key serialization
    public_key = private_key.get_pubkey()

    if multi:
        script = CScript([OP_1, public_key, OP_1, OP_CHECKMULTISIG])
    else:
        script = CScript([public_key, OP_CHECKSIG])

    # Fund transaction
    prevtx = FromHex(CTransaction(), node.getrawtransaction(spend['txid']))
    prevtx.rehash()
    fee = 500
    fund_amount = 50 * COIN - fee
    txfund = create_transaction(prevtx, spend['vout'], b'', fund_amount,
                                script)
    txfund = FromHex(CTransaction(),
                     node.signrawtransactionwithwallet(ToHex(txfund))["hex"])
    txfund.rehash()

    # Spend transaction
    txspend = CTransaction()
    txspend.vout.append(CTxOut(fund_amount - 1000, CScript([OP_TRUE])))
    txspend.vin.append(CTxIn(COutPoint(txfund.sha256, 0), b''))

    # Sign the transaction
    sighashtype = SIGHASH_ALL | SIGHASH_FORKID
    hashbyte = bytes([sighashtype & 0xff])
    sighash = SignatureHashForkId(script, txspend, 0, sighashtype, fund_amount)
    txsig = schnorr.sign(privkeybytes, sighash) + hashbyte
    if multi:
        txspend.vin[0].scriptSig = CScript([b'', txsig])
    else:
        txspend.vin[0].scriptSig = CScript([txsig])
    txspend.rehash()

    return txfund, txspend
示例#24
0
        def create_fund_and_spend_tx(scriptsigextra, redeemextra) -> Tuple[CTransaction, CTransaction]:
            spendfrom = spendable_txns.pop()

            redeem_script = CScript(redeemextra + [OP_1, public_key, OP_1, OP_CHECKMULTISIG])
            script_pubkey = CScript([OP_HASH160, hash160(redeem_script), OP_EQUAL])

            value = spendfrom.vout[0].nValue
            value1 = value - 500

            # Fund transaction
            txfund = create_tx_with_script(spendfrom, 0, b'', value1, script_pubkey)
            txfund.rehash()

            p2sh = script_to_p2sh(redeem_script)
            self.log.info(f"scriptPubKey {script_pubkey!r}")
            self.log.info(f"redeemScript {redeem_script!r} -> p2sh address {p2sh}")

            # Spend transaction
            value2 = value1 - 500
            txspend = CTransaction()
            txspend.vout.append(
                CTxOut(value2, CScript([OP_TRUE])))
            txspend.vin.append(
                CTxIn(COutPoint(txfund.sha256, 0), b''))

            # Sign the transaction
            sighashtype = SIGHASH_ALL | SIGHASH_FORKID
            hashbyte = bytes([sighashtype & 0xff])
            sighash = SignatureHashForkId(
                redeem_script, txspend, 0, sighashtype, value1)
            txsig = schnorr.sign(privkeybytes, sighash) + hashbyte
            dummy = OP_1  # Required for 1-of-1 schnorr sig
            txspend.vin[0].scriptSig = ss = CScript([dummy, txsig] + scriptsigextra + [redeem_script])
            self.log.info(f"scriptSig: {ss!r}")
            txspend.rehash()

            return txfund, txspend
def create_fund_and_spend_tx(node, spendfrom, dummy):

    privkeybytes = b"Schnorr!" * 4
    private_key = CECKey()
    private_key.set_secretbytes(privkeybytes)
    # get uncompressed public key serialization
    public_key = private_key.get_pubkey()

    script = CScript([OP_1, public_key, OP_1, OP_CHECKMULTISIG])

    value = spendfrom.vout[0].nValue
    value -= 1000

    # Fund transaction
    txfund = create_transaction(spendfrom, 0, b'', value, script)
    txfund = FromHex(CTransaction(), node.signrawtransactionwithwallet(ToHex(txfund))["hex"])
    txfund.rehash()
    #fundings.append(txfund)

    # Spend transaction
    txspend = CTransaction()
    txspend.vout.append(
        CTxOut(value-1000, CScript([OP_TRUE])))
    txspend.vin.append(
        CTxIn(COutPoint(txfund.sha256, 0), b''))

    # Sign the transaction
    sighashtype = SIGHASH_ALL | SIGHASH_FORKID
    hashbyte = bytes([sighashtype & 0xff])
    sighash = SignatureHashForkId(
        script, txspend, 0, sighashtype, value)
    txsig = schnorr.sign(privkeybytes, sighash) + hashbyte
    txspend.vin[0].scriptSig = CScript([dummy, txsig])
    txspend.rehash()

    return txfund, txspend
示例#26
0
def spend_separator_tx(tx_sep_tx, keys_for_sep_tx):
    """spends Transaction with scriptPubKey in form of:
    <pk1> OP_CHECKSIGVERIFY OP_CODESEPARATOR <pk2> OP_CHECKSIGVERIFY OP_CODESEPARATOR ... <pk N_signings> OP_CHECKSIG
    """

    tx = CTransaction()

    tx.vin.append(CTxIn(COutPoint(tx_sep_tx.sha256, 0), b"", 0xffffffff))

    k = CECKey()
    k.set_secretbytes(b"horsebattery")

    amount = tx_sep_tx.vout[0].nValue - 2000

    script_lists = [[]]

    for item in list(tx_sep_tx.vout[0].scriptPubKey):
        for l in script_lists:
            l.append(item)
        if item == OP_CODESEPARATOR:
            script_lists.append([])

    tx.vout.append(CTxOut(amount, CScript([k.get_pubkey(), OP_CHECKSIG])))

    flags = bytes(bytearray([SIGHASH_ALL | SIGHASH_FORKID]))

    sign_list = []
    for sc, key in zip(script_lists, keys_for_sep_tx):
        sighash = SignatureHashForkId(CScript(sc), tx, 0,
                                      SIGHASH_ALL | SIGHASH_FORKID,
                                      tx_sep_tx.vout[0].nValue)
        sign_list.append(key.sign(sighash) + flags)

    tx.vin[0].scriptSig = CScript(reversed(sign_list))
    tx.rehash()
    return tx, k
示例#27
0
    def run_test(self):
        node = self.nodes[0]
        node.add_p2p_connection(P2PDataStore())
        # Allocate as many UTXOs as are needed
        num_utxos = sum(
            len(tx_case['inputs']) for tx_case in TX_CASES
            if isinstance(tx_case, dict))

        value = int(SUBSIDY * 1_000_000)
        fee = 10_000

        pubkey_bytes = bytes.fromhex(
            '020000000000000000000000000000000000000000000000000000000000000001'
        )
        pubkey = ECPubKey()
        pubkey.set(pubkey_bytes)

        max_utxo_value = (value - fee) // num_utxos
        spendable_outputs = []
        utxo_idx = 0
        # Prepare UTXOs for the tests below
        for tx_case in TX_CASES:
            if tx_case == 'ENABLE_REPLAY_PROTECTION':
                continue
            for tree, leaf_idx, _ in tx_case['inputs']:
                utxo_value = max_utxo_value - utxo_idx * 100  # deduct 100*i coins for unique amounts

                tree_result = taproot_tree_helper(tree)
                merkle_root = tree_result['hash']
                tweak_hash = TaggedHash("TapTweak", pubkey_bytes + merkle_root)
                commitment = pubkey.add(tweak_hash)
                ops = [OP_SCRIPTTYPE, OP_1, commitment.get_bytes()]
                script_case = tree_result['items'][leaf_idx]['leaf'][
                    'script_case']
                if script_case.get('state', False):
                    ops.append(script_case['state'])
                utxo_script = CScript(ops)
                spendable_outputs.append(CTxOut(utxo_value, utxo_script))
                utxo_idx += 1

        anyonecanspend_address = node.decodescript('51')['p2sh']
        burn_address = node.decodescript('00')['p2sh']
        p2sh_script = CScript([OP_HASH160, bytes(20), OP_EQUAL])
        node.generatetoaddress(1, anyonecanspend_address)
        node.generatetoaddress(100, burn_address)

        # Build and send fan-out transaction creating all the UTXOs
        block_hash = node.getblockhash(1)
        coin = int(node.getblock(block_hash)['tx'][0], 16)
        tx_fan_out = CTransaction()
        tx_fan_out.vin.append(CTxIn(COutPoint(coin, 1), CScript([b'\x51'])))
        tx_fan_out.vout = spendable_outputs
        tx_fan_out.rehash()

        node.p2p.send_txs_and_test([tx_fan_out], node)

        utxo_idx = 0
        for tx_case in TX_CASES:
            if tx_case == 'ENABLE_REPLAY_PROTECTION':
                node.setmocktime(ACTIVATION_TIME)
                node.generatetoaddress(11, burn_address)
                continue
            num_inputs = len(tx_case['inputs'])
            num_outputs = tx_case['outputs']
            # Build tx for this test, will broadcast later
            tx = CTransaction()
            spent_outputs = spendable_outputs[:num_inputs]
            del spendable_outputs[:num_inputs]
            assert len(spent_outputs) == num_inputs
            total_input_amount = sum(output.nValue for output in spent_outputs)
            max_output_amount = (total_input_amount - fee) // num_outputs
            for i in range(num_outputs):
                output_amount = max_output_amount - i * 77
                output_script = CScript(
                    [OP_HASH160, i.to_bytes(20, 'big'), OP_EQUAL])
                tx.vout.append(CTxOut(output_amount, output_script))
            for _ in range(num_inputs):
                tx.vin.append(
                    CTxIn(COutPoint(tx_fan_out.txid, utxo_idx), CScript()))
                utxo_idx += 1
            for input_idx, input_case in enumerate(tx_case['inputs']):
                tree, leaf_idx, sig_hash_types = input_case
                tree_result = taproot_tree_helper(tree)
                result_item = tree_result['items'][leaf_idx]
                leaf = result_item['leaf']
                script_case = leaf['script_case']
                exec_script = CScript(script_case['script'])
                keys = script_case.get('keys', [])
                assert len(sig_hash_types) == len(keys)
                sigs = []
                for sig_hash_type, key in zip(sig_hash_types, keys):
                    if sig_hash_type & SIGHASH_LOTUS == SIGHASH_LOTUS:
                        sighash = SignatureHashLotus(
                            tx_to=tx,
                            spent_utxos=spent_outputs,
                            sig_hash_type=sig_hash_type,
                            input_index=input_idx,
                            executed_script_hash=leaf['tapleaf_hash'],
                            codeseparator_pos=script_case.get(
                                'codesep', 0xffff_ffff),
                        )
                    elif sig_hash_type & SIGHASH_FORKID:
                        sighash = SignatureHashForkId(
                            exec_script,
                            tx,
                            input_idx,
                            sig_hash_type,
                            spent_outputs[input_idx].nValue,
                        )
                    else:
                        raise NotImplemented
                    private_key = ECKey()
                    private_key.set(key, True)
                    if script_case.get('schnorr', False):
                        signature = private_key.sign_schnorr(sighash)
                    else:
                        signature = private_key.sign_ecdsa(sighash)
                    signature += bytes(
                        [tx_case.get('suffix', sig_hash_type & 0xff)])
                    sigs.append(signature)
                control_block = bytearray(pubkey_bytes)
                control_block[0] = 0xc0
                control_block[0] |= int(pubkey_bytes[0] == 0x03)
                control_block += result_item['path']
                tx.vin[input_idx].scriptSig = CScript(
                    script_case['script_inputs'] + sigs +
                    [exec_script, control_block])
            # Broadcast transaction and check success/failure
            tx.rehash()
            if 'error' not in tx_case:
                node.p2p.send_txs_and_test([tx], node)
            else:
                node.p2p.send_txs_and_test([tx],
                                           node,
                                           success=False,
                                           reject_reason=tx_case['error'])
    def make_transactions(self,
                          txtype,
                          num_txns,
                          stxn_vin_size,
                          create_double_spends=False):
        key = CECKey()
        key.set_secretbytes(b"horsebattery")
        key.set_compressed(True)
        # Each coin being spent will always result in at least 14 expensive ECDSA checks.
        # 0x7f03 33 OP_NUM2BIN creates a valid non-zero compressed pubkey.
        redeem_script = CScript([
            OP_1,
            key.get_pubkey(), 0x7f03, 33, OP_NUM2BIN, OP_DUP, OP_2DUP, OP_2DUP,
            OP_2DUP, OP_3DUP, OP_3DUP, OP_15, OP_CHECKMULTISIG
        ])

        # Calculate how many found txns are needed to create a required spend money txns (num_txns)
        # - a fund txns are of type 1 - N (N=vouts_size_per_fund_txn)
        # - a spend money txns are of type M-1 (M inputs & 1 output)
        def estimate_fund_txns_number(num_txns, vouts_size_per_fund_txn):
            fund_txns_num = 1
            if num_txns >= vouts_size_per_fund_txn:
                if num_txns % vouts_size_per_fund_txn == 0:
                    fund_txns_num = num_txns // vouts_size_per_fund_txn
                else:
                    fund_txns_num = num_txns // vouts_size_per_fund_txn + 1
            return fund_txns_num * vouts_size_per_fund_txn

        # Create funding transactions that will provide funds for other transcations
        def make_fund_txn(node, out_value, num_vout_txns):
            # Create fund txn
            ftx = CTransaction()
            for i in range(num_vout_txns):
                ftx.vout.append(
                    CTxOut(
                        out_value,
                        CScript([OP_HASH160,
                                 hash160(redeem_script), OP_EQUAL])))
            # fund the transcation:
            ftxHex = node.fundrawtransaction(
                ToHex(ftx), {'changePosition': len(ftx.vout)})['hex']
            ftxHex = node.signrawtransaction(ftxHex)['hex']
            ftx = FromHex(CTransaction(), ftxHex)
            ftx.rehash()
            return ftx, ftxHex

        # Create a spend txn
        def make_spend_txn(txtype, fund_txn_hash, fund_txn_num_vouts,
                           out_value):
            # Create txn
            spend_tx = CTransaction()
            for idx in range(fund_txn_num_vouts):
                spend_tx.vin.append(CTxIn(COutPoint(fund_txn_hash, idx), b''))
                sighash = SignatureHashForkId(
                    redeem_script, spend_tx, idx,
                    SIGHASH_ANYONECANPAY | SIGHASH_FORKID | SIGHASH_NONE,
                    out_value)
                sig = key.sign(sighash) + bytes(
                    bytearray([
                        SIGHASH_ANYONECANPAY | SIGHASH_FORKID | SIGHASH_NONE
                    ]))
                spend_tx.vin[idx].scriptSig = CScript(
                    [OP_0, sig, redeem_script])
                # Standard transaction
                if TxType.standard == txtype:
                    spend_tx.vout.append(
                        CTxOut(out_value - 1000, CScript([OP_RETURN])))
                # Non-standard transaction
                elif TxType.nonstandard == txtype:
                    spend_tx.vout.append(
                        CTxOut(out_value - 1000, CScript([OP_TRUE])))
                spend_tx.rehash()
            return spend_tx

        #
        # Generate some blocks to have enough spendable coins
        #
        node = self.nodes[0]
        node.generate(101)

        #
        # Estimate a number of required fund txns
        #
        out_value = 2000
        # Number of outputs in each fund txn
        fund_txn_num_vouts = stxn_vin_size
        fund_txns_num = estimate_fund_txns_number(num_txns, fund_txn_num_vouts)

        #
        # Create and send fund txns to the mempool
        #
        fund_txns = []
        for i in range(fund_txns_num):
            ftx, ftxHex = make_fund_txn(node, out_value, fund_txn_num_vouts)
            node.sendrawtransaction(ftxHex)
            fund_txns.append(ftx)
        # Ensure that mempool is empty to avoid 'too-long-mempool-chain' errors in next test
        node.generate(1)

        #
        # Create spend transactions.
        #
        txtype_to_create = txtype
        spend_txs = []
        for i in range(len(fund_txns)):
            # If standard and non-standard txns are required then create equal (in size) sets.
            if TxType.std_and_nonstd == txtype:
                if i % 2:
                    txtype_to_create = TxType.standard
                else:
                    txtype_to_create = TxType.nonstandard
            # Create a spend money txn with fund_txn_num_vouts number of inputs.
            spend_tx = make_spend_txn(txtype_to_create, fund_txns[i].sha256,
                                      fund_txn_num_vouts, out_value)
            # Create double spend txns if required
            if create_double_spends and len(spend_txs) < num_txns // 2:
                # The first half of the array are double spend txns
                spend_tx.vin.append(
                    CTxIn(
                        COutPoint(fund_txns[len(fund_txns) - i - 1].sha256, 0),
                        b''))
                sighash = SignatureHashForkId(
                    redeem_script, spend_tx, stxn_vin_size,
                    SIGHASH_ANYONECANPAY | SIGHASH_FORKID | SIGHASH_NONE,
                    out_value)
                sig = key.sign(sighash) + bytes(
                    bytearray([
                        SIGHASH_ANYONECANPAY | SIGHASH_FORKID | SIGHASH_NONE
                    ]))
                spend_tx.vin[stxn_vin_size].scriptSig = CScript(
                    [OP_0, sig, redeem_script])
                spend_tx.rehash()
            spend_txs.append(spend_tx)
        return spend_txs
示例#29
0
def make_unlock_modified10(tx, tx_to_spend):
    sighash = SignatureHashForkId(tx_to_spend.vout[0].scriptPubKey, tx, 0, SIGHASH_ALL | SIGHASH_FORKID,
                                  tx_to_spend.vout[0].nValue)
    sig = HandleTxsModified10Node.THE_KEY.sign(sighash) + bytes(bytearray([SIGHASH_ALL | SIGHASH_FORKID]))
    return CScript([sig])
    def run_test(self):
        self.bootstrap_p2p()  # Add one p2p connection to the node

        self.block_heights = {}
        self.coinbase_key = CECKey()
        self.coinbase_key.set_secretbytes(b"horsebattery")
        self.coinbase_pubkey = self.coinbase_key.get_pubkey()
        self.tip = None
        self.blocks = {}
        self.genesis_hash = int(self.nodes[0].getbestblockhash(), 16)
        self.block_heights[self.genesis_hash] = 0
        self.spendable_outputs = []

        # Create a new block
        b0 = self.next_block(0)
        self.save_spendable_output()
        self.sync_blocks([b0])

        # Allow the block to mature
        blocks = []
        for i in range(129):
            blocks.append(self.next_block(5000 + i))
            self.save_spendable_output()
        self.sync_blocks(blocks)

        # collect spendable outputs now to avoid cluttering the code later on
        out = []
        for i in range(33):
            out.append(self.get_spendable_output())

        # Start by building a block on top.
        #     setup -> b13 (0)
        b13 = self.next_block(13, spend=out[0])
        self.save_spendable_output()
        self.sync_blocks([b13])

        # Add a block with MAX_BLOCK_SIGOPS_PER_MB and one with one more sigop
        #     setup -> b13 (0) -> b15 (5) -> b16 (6)
        self.log.info("Accept a block with lots of checksigs")
        lots_of_checksigs = CScript([OP_CHECKSIG] *
                                    (MAX_BLOCK_SIGOPS_PER_MB - 1))
        self.move_tip(13)
        b15 = self.next_block(15, spend=out[5], script=lots_of_checksigs)
        self.save_spendable_output()
        self.sync_blocks([b15], True)

        self.log.info("Reject a block with too many checksigs")
        too_many_checksigs = CScript([OP_CHECKSIG] * (MAX_BLOCK_SIGOPS_PER_MB))
        b16 = self.next_block(16, spend=out[6], script=too_many_checksigs)
        self.sync_blocks([b16],
                         success=False,
                         reject_reason='bad-blk-sigops',
                         reconnect=True)

        self.move_tip(15)

        # ... skipped feature_block tests ...

        # b31 - b35 - check sigops of OP_CHECKMULTISIG / OP_CHECKMULTISIGVERIFY / OP_CHECKSIGVERIFY
        #
        #      setup -> ... b15 (5)   ->  b31 (8) -> b33 (9) -> b35 (10)
        #                                                                \-> b36 (11)
        #                                                    \-> b34 (10)
        #                                         \-> b32 (9)
        #

        # MULTISIG: each op code counts as 20 sigops.  To create the edge case,
        # pack another 19 sigops at the end.
        self.log.info(
            "Accept a block with the max number of OP_CHECKMULTISIG sigops")
        lots_of_multisigs = CScript([OP_CHECKMULTISIG] *
                                    ((MAX_BLOCK_SIGOPS_PER_MB - 1) // 20) +
                                    [OP_CHECKSIG] * 19)
        b31 = self.next_block(31, spend=out[8], script=lots_of_multisigs)
        assert_equal(get_legacy_sigopcount_block(b31), MAX_BLOCK_SIGOPS_PER_MB)
        self.sync_blocks([b31], True)
        self.save_spendable_output()

        # this goes over the limit because the coinbase has one sigop
        self.log.info("Reject a block with too many OP_CHECKMULTISIG sigops")
        too_many_multisigs = CScript([OP_CHECKMULTISIG] *
                                     (MAX_BLOCK_SIGOPS_PER_MB // 20))
        b32 = self.next_block(32, spend=out[9], script=too_many_multisigs)
        assert_equal(get_legacy_sigopcount_block(b32),
                     MAX_BLOCK_SIGOPS_PER_MB + 1)
        self.sync_blocks([b32],
                         success=False,
                         reject_reason='bad-blk-sigops',
                         reconnect=True)

        # CHECKMULTISIGVERIFY
        self.log.info(
            "Accept a block with the max number of OP_CHECKMULTISIGVERIFY sigops"
        )
        self.move_tip(31)
        lots_of_multisigs = CScript([OP_CHECKMULTISIGVERIFY] *
                                    ((MAX_BLOCK_SIGOPS_PER_MB - 1) // 20) +
                                    [OP_CHECKSIG] * 19)
        b33 = self.next_block(33, spend=out[9], script=lots_of_multisigs)
        self.sync_blocks([b33], True)
        self.save_spendable_output()

        self.log.info(
            "Reject a block with too many OP_CHECKMULTISIGVERIFY sigops")
        too_many_multisigs = CScript([OP_CHECKMULTISIGVERIFY] *
                                     (MAX_BLOCK_SIGOPS_PER_MB // 20))
        b34 = self.next_block(34, spend=out[10], script=too_many_multisigs)
        self.sync_blocks([b34],
                         success=False,
                         reject_reason='bad-blk-sigops',
                         reconnect=True)

        # CHECKSIGVERIFY
        self.log.info(
            "Accept a block with the max number of OP_CHECKSIGVERIFY sigops")
        self.move_tip(33)
        lots_of_checksigs = CScript([OP_CHECKSIGVERIFY] *
                                    (MAX_BLOCK_SIGOPS_PER_MB - 1))
        b35 = self.next_block(35, spend=out[10], script=lots_of_checksigs)
        self.sync_blocks([b35], True)
        self.save_spendable_output()

        self.log.info("Reject a block with too many OP_CHECKSIGVERIFY sigops")
        too_many_checksigs = CScript([OP_CHECKSIGVERIFY] *
                                     (MAX_BLOCK_SIGOPS_PER_MB))
        b36 = self.next_block(36, spend=out[11], script=too_many_checksigs)
        self.sync_blocks([b36],
                         success=False,
                         reject_reason='bad-blk-sigops',
                         reconnect=True)

        # ... skipped feature_block tests ...

        # Check P2SH SigOp counting
        #
        #
        #                                       ... -> b31 (8) -> b33 (9) -> b35 (10) -> b39 (11) -> b41 (12)
        #                                                                                        \-> b40 (12)
        #
        # b39 - create some P2SH outputs that will require 6 sigops to spend:
        #
        #           redeem_script = COINBASE_PUBKEY, (OP_2DUP+OP_CHECKSIGVERIFY) * 5, OP_CHECKSIG
        #           p2sh_script = OP_HASH160, ripemd160(sha256(script)), OP_EQUAL
        #
        self.log.info("Check P2SH SIGOPS are correctly counted")
        self.move_tip(35)
        b39 = self.next_block(39)
        b39_outputs = 0
        b39_sigops_per_output = 6

        # Build the redeem script, hash it, use hash to create the p2sh script
        redeem_script = CScript([self.coinbase_pubkey] +
                                [OP_2DUP, OP_CHECKSIGVERIFY] * 5 +
                                [OP_CHECKSIG])
        redeem_script_hash = hash160(redeem_script)
        p2sh_script = CScript([OP_HASH160, redeem_script_hash, OP_EQUAL])

        # Create a transaction that spends one satoshi to the p2sh_script, the rest to OP_TRUE
        # This must be signed because it is spending a coinbase
        spend = out[11]
        tx = self.create_tx(spend, 0, 1, p2sh_script)
        tx.vout.append(CTxOut(spend.vout[0].nValue - 1, CScript([OP_TRUE])))
        self.sign_tx(tx, spend)
        tx.rehash()
        b39 = self.update_block(39, [tx])
        b39_outputs += 1

        # Until block is full, add tx's with 1 satoshi to p2sh_script, the rest
        # to OP_TRUE
        tx_new = None
        tx_last = tx
        tx_last_n = len(tx.vout) - 1
        total_size = len(b39.serialize())
        while (total_size < LEGACY_MAX_BLOCK_SIZE):
            tx_new = self.create_tx(tx_last, tx_last_n, 1, p2sh_script)
            tx_new.vout.append(
                CTxOut(tx_last.vout[tx_last_n].nValue - 1, CScript([OP_TRUE])))
            tx_new.rehash()
            total_size += len(tx_new.serialize())
            if total_size >= LEGACY_MAX_BLOCK_SIZE:
                break
            b39.vtx.append(tx_new)  # add tx to block
            tx_last = tx_new
            tx_last_n = len(tx_new.vout) - 1
            b39_outputs += 1

        b39 = self.update_block(39, [])
        self.sync_blocks([b39], True)
        self.save_spendable_output()

        # Test sigops in P2SH redeem scripts
        #
        # b40 creates 3333 tx's spending the 6-sigop P2SH outputs from b39 for a total of 19998 sigops.
        # The first tx has one sigop and then at the end we add 2 more to put us just over the max.
        #
        # b41 does the same, less one, so it has the maximum sigops permitted.
        #
        self.log.info("Reject a block with too many P2SH sigops")
        self.move_tip(39)
        b40 = self.next_block(40, spend=out[12])
        sigops = get_legacy_sigopcount_block(b40)
        numTxs = (MAX_BLOCK_SIGOPS_PER_MB - sigops) // b39_sigops_per_output
        assert_equal(numTxs <= b39_outputs, True)

        lastOutpoint = COutPoint(b40.vtx[1].sha256, 0)
        lastAmount = b40.vtx[1].vout[0].nValue
        new_txs = []
        for i in range(1, numTxs + 1):
            tx = CTransaction()
            tx.vout.append(CTxOut(1, CScript([OP_TRUE])))
            tx.vin.append(CTxIn(lastOutpoint, b''))
            # second input is corresponding P2SH output from b39
            tx.vin.append(CTxIn(COutPoint(b39.vtx[i].sha256, 0), b''))
            # Note: must pass the redeem_script (not p2sh_script) to the
            # signature hash function
            sighash = SignatureHashForkId(redeem_script, tx, 1,
                                          SIGHASH_ALL | SIGHASH_FORKID,
                                          lastAmount)
            sig = self.coinbase_key.sign(sighash) + bytes(
                bytearray([SIGHASH_ALL | SIGHASH_FORKID]))
            scriptSig = CScript([sig, redeem_script])

            tx.vin[1].scriptSig = scriptSig
            pad_tx(tx)
            tx.rehash()
            new_txs.append(tx)
            lastOutpoint = COutPoint(tx.sha256, 0)
            lastAmount = tx.vout[0].nValue

        b40_sigops_to_fill = MAX_BLOCK_SIGOPS_PER_MB - \
            (numTxs * b39_sigops_per_output + sigops) + 1
        tx = CTransaction()
        tx.vin.append(CTxIn(lastOutpoint, b''))
        tx.vout.append(CTxOut(1, CScript([OP_CHECKSIG] * b40_sigops_to_fill)))
        pad_tx(tx)
        tx.rehash()
        new_txs.append(tx)
        self.update_block(40, new_txs)
        self.sync_blocks([b40],
                         success=False,
                         reject_reason='bad-blk-sigops',
                         reconnect=True)

        # same as b40, but one less sigop
        self.log.info("Accept a block with the max number of P2SH sigops")
        self.move_tip(39)
        b41 = self.next_block(41, spend=None)
        self.update_block(41, [b40tx for b40tx in b40.vtx[1:] if b40tx != tx])
        b41_sigops_to_fill = b40_sigops_to_fill - 1
        tx = CTransaction()
        tx.vin.append(CTxIn(lastOutpoint, b''))
        tx.vout.append(CTxOut(1, CScript([OP_CHECKSIG] * b41_sigops_to_fill)))
        pad_tx(tx)
        self.update_block(41, [tx])
        self.sync_blocks([b41], True)

        # ... skipped feature_block tests ...

        b72 = self.next_block(72)
        self.save_spendable_output()
        self.sync_blocks([b72])

        # Test some invalid scripts and MAX_BLOCK_SIGOPS_PER_MB
        #
        #                                                                   ..... -> b72
        #                                                                                    \-> b** (22)
        #

        # b73 - tx with excessive sigops that are placed after an excessively large script element.
        #       The purpose of the test is to make sure those sigops are counted.
        #
        #       script is a bytearray of size 20,526
        #
        #       bytearray[0-19,998]     : OP_CHECKSIG
        #       bytearray[19,999]       : OP_PUSHDATA4
        #       bytearray[20,000-20,003]: 521  (max_script_element_size+1, in little-endian format)
        #       bytearray[20,004-20,525]: unread data (script_element)
        # bytearray[20,526]       : OP_CHECKSIG (this puts us over the limit)
        self.log.info(
            "Reject a block containing too many sigops after a large script element"
        )
        self.move_tip(72)
        b73 = self.next_block(73)
        size = MAX_BLOCK_SIGOPS_PER_MB - 1 + MAX_SCRIPT_ELEMENT_SIZE + 1 + 5 + 1
        a = bytearray([OP_CHECKSIG] * size)
        a[MAX_BLOCK_SIGOPS_PER_MB - 1] = int("4e", 16)  # OP_PUSHDATA4

        element_size = MAX_SCRIPT_ELEMENT_SIZE + 1
        a[MAX_BLOCK_SIGOPS_PER_MB] = element_size % 256
        a[MAX_BLOCK_SIGOPS_PER_MB + 1] = element_size // 256
        a[MAX_BLOCK_SIGOPS_PER_MB + 2] = 0
        a[MAX_BLOCK_SIGOPS_PER_MB + 3] = 0

        tx = self.create_and_sign_transaction(out[22], 1, CScript(a))
        b73 = self.update_block(73, [tx])
        assert_equal(get_legacy_sigopcount_block(b73),
                     MAX_BLOCK_SIGOPS_PER_MB + 1)
        self.sync_blocks([b73],
                         success=False,
                         reject_reason='bad-blk-sigops',
                         reconnect=True)

        # b74/75 - if we push an invalid script element, all prevous sigops are counted,
        #          but sigops after the element are not counted.
        #
        #       The invalid script element is that the push_data indicates that
        #       there will be a large amount of data (0xffffff bytes), but we only
        #       provide a much smaller number.  These bytes are CHECKSIGS so they would
        #       cause b75 to fail for excessive sigops, if those bytes were counted.
        #
        #       b74 fails because we put MAX_BLOCK_SIGOPS_PER_MB+1 before the element
        # b75 succeeds because we put MAX_BLOCK_SIGOPS_PER_MB before the
        # element
        self.log.info(
            "Check sigops are counted correctly after an invalid script element"
        )
        self.move_tip(72)
        b74 = self.next_block(74)
        size = MAX_BLOCK_SIGOPS_PER_MB - 1 + \
            MAX_SCRIPT_ELEMENT_SIZE + 42  # total = 20,561
        a = bytearray([OP_CHECKSIG] * size)
        a[MAX_BLOCK_SIGOPS_PER_MB] = 0x4e
        a[MAX_BLOCK_SIGOPS_PER_MB + 1] = 0xfe
        a[MAX_BLOCK_SIGOPS_PER_MB + 2] = 0xff
        a[MAX_BLOCK_SIGOPS_PER_MB + 3] = 0xff
        a[MAX_BLOCK_SIGOPS_PER_MB + 4] = 0xff
        tx = self.create_and_sign_transaction(out[22], 1, CScript(a))
        b74 = self.update_block(74, [tx])
        self.sync_blocks([b74],
                         success=False,
                         reject_reason='bad-blk-sigops',
                         reconnect=True)

        self.move_tip(72)
        b75 = self.next_block(75)
        size = MAX_BLOCK_SIGOPS_PER_MB - 1 + MAX_SCRIPT_ELEMENT_SIZE + 42
        a = bytearray([OP_CHECKSIG] * size)
        a[MAX_BLOCK_SIGOPS_PER_MB - 1] = 0x4e
        a[MAX_BLOCK_SIGOPS_PER_MB] = 0xff
        a[MAX_BLOCK_SIGOPS_PER_MB + 1] = 0xff
        a[MAX_BLOCK_SIGOPS_PER_MB + 2] = 0xff
        a[MAX_BLOCK_SIGOPS_PER_MB + 3] = 0xff
        tx = self.create_and_sign_transaction(out[22], 1, CScript(a))
        b75 = self.update_block(75, [tx])
        self.sync_blocks([b75], True)
        self.save_spendable_output()

        # Check that if we push an element filled with CHECKSIGs, they are not
        # counted
        self.move_tip(75)
        b76 = self.next_block(76)
        size = MAX_BLOCK_SIGOPS_PER_MB - 1 + MAX_SCRIPT_ELEMENT_SIZE + 1 + 5
        a = bytearray([OP_CHECKSIG] * size)
        # PUSHDATA4, but leave the following bytes as just checksigs
        a[MAX_BLOCK_SIGOPS_PER_MB - 1] = 0x4e
        tx = self.create_and_sign_transaction(out[23], 1, CScript(a))
        b76 = self.update_block(76, [tx])
        self.sync_blocks([b76], True)
        self.save_spendable_output()