예제 #1
0
        def create_fund_and_spend_tx():
            spendfrom = spendable_outputs.pop()

            script = CScript([OP_ADD])

            value = spendfrom.vout[0].nValue

            # Fund transaction
            txfund = create_transaction(spendfrom, 0, b'', value, script)
            pad_tx(txfund)
            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
            txspend.vin[0].scriptSig = CScript(
                b'\x01\x01\x51')  # PUSH1(0x01) OP_1
            pad_tx(txspend)
            txspend.rehash()

            return txspend
        def make_spend(sigcheckcount):
            # Add a funding tx to fundings, and return a tx spending that using
            # scriptsig.
            logging.debug("Gen tx with {} sigchecks.".format(sigcheckcount))

            def get_script_with_sigcheck(count):
                return CScript([cds_message, cds_pubkey] +
                               (count - 1) * [OP_3DUP, OP_CHECKDATASIGVERIFY] +
                               [OP_CHECKDATASIG])

            # get funds locked with OP_1
            sourcetx = self.spendable_outputs.popleft()
            # make funding that forwards to scriptpubkey
            last_sigcheck_count = ((sigcheckcount - 1) % 30) + 1
            fundtx = create_transaction(
                sourcetx, get_script_with_sigcheck(last_sigcheck_count))

            fill_sigcheck_script = get_script_with_sigcheck(30)

            remaining_sigcheck = sigcheckcount
            while remaining_sigcheck > 30:
                fundtx.vout[0].nValue -= 1000
                fundtx.vout.append(CTxOut(100, bytes(fill_sigcheck_script)))
                remaining_sigcheck -= 30

            fundtx.rehash()
            fundings.append(fundtx)

            # make the spending
            scriptsig = CScript([cds_signature])

            tx = CTransaction()
            tx.vin.append(CTxIn(COutPoint(fundtx.sha256, 1), scriptsig))

            input_index = 2
            remaining_sigcheck = sigcheckcount
            while remaining_sigcheck > 30:
                tx.vin.append(
                    CTxIn(COutPoint(fundtx.sha256, input_index), scriptsig))
                remaining_sigcheck -= 30
                input_index += 1

            tx.vout.append(CTxOut(0, CScript([OP_RETURN])))
            pad_tx(tx)
            tx.rehash()
            return tx
        def make_spend(scriptpubkey, scriptsig):
            # Add a funding tx to fundings, and return a tx spending that using
            # scriptsig.
            logging.debug(
                "Gen tx with locking script {} unlocking script {} .".format(
                    scriptpubkey.hex(), scriptsig.hex()))

            # get funds locked with OP_1
            sourcetx = self.spendable_outputs.popleft()
            # make funding that forwards to scriptpubkey
            fundtx = create_transaction(sourcetx, scriptpubkey)
            fundings.append(fundtx)

            # make the spending
            tx = CTransaction()
            tx.vin.append(CTxIn(COutPoint(fundtx.sha256, 1), scriptsig))
            tx.vout.append(CTxOut(0, CScript([OP_RETURN])))
            pad_tx(tx)
            tx.rehash()
            return tx
    def create_tx_chain(self, unspent, scriptpubkey, chain_len, num_outputs):
        assert (num_outputs > 0)

        tx_chain = [unspent]
        for i in range(chain_len):
            prev_tx = tx_chain[-1]
            prev_n = i % num_outputs

            amount = prev_tx.vout[prev_n].nValue // num_outputs

            tx = create_transaction(prev_tx,
                                    n=prev_n,
                                    value=[amount] * num_outputs,
                                    sig=CScript([OP_TRUE]),
                                    out=scriptpubkey)
            pad_tx(tx)
            tx_chain.append(tx)

        tx_chain.pop(0)  # the initial unspent is not part of the chain
        return tx_chain
def create_transaction(spendfrom, custom_script, amount=None):
    # Fund and sign a transaction to a given output.
    # spendfrom should be a CTransaction with first output to OP_TRUE.

    # custom output will go on position 1, after position 0 which will be
    # OP_TRUE (so it can be reused).
    customout = CTxOut(0, bytes(custom_script))
    # set output amount to required dust if not given
    customout.nValue = amount or (len(customout.serialize()) + 148) * 3

    ctx = CTransaction()
    ctx.vin.append(CTxIn(COutPoint(spendfrom.sha256, 0), bytes([OP_TRUE])))
    ctx.vout.append(CTxOut(0, bytes([OP_TRUE])))
    ctx.vout.append(customout)
    pad_tx(ctx)

    fee = len(ctx.serialize())
    ctx.vout[0].nValue = spendfrom.vout[0].nValue - customout.nValue - fee
    ctx.rehash()

    return ctx
    async def test_blockheight_confirmed(self, n, cli, unspent):
        # Just unique anyone-can-spend scriptpubkey
        scriptpubkey = CScript([OP_TRUE, OP_DROP, OP_NOP])
        scripthash = script_to_scripthash(scriptpubkey)

        # There should exist any history for scripthash
        assert_equal(0, len(await cli.call(GET_HISTORY, scripthash)))

        # Send tx to scripthash and confirm it
        tx = create_transaction(unspent,
                                n=0,
                                value=unspent.vout[0].nValue,
                                sig=CScript([OP_TRUE]),
                                out=scriptpubkey)
        pad_tx(tx)

        self.mine_blocks(n, 1, txns=[tx])
        sync_electrum_height(n)

        # History should now have 1 entry at current tip height
        res = await cli.call(GET_HISTORY, scripthash)
        assert_equal(1, len(res))
        assert_equal(n.getblockcount(), res[0]['height'])
        assert_equal(tx.hash, res[0]['tx_hash'])
    async def test_blockheight_unconfirmed(self, n, cli, unspent):
        # Another unique anyone-can-spend scriptpubkey
        scriptpubkey = CScript([OP_FALSE, OP_DROP, OP_NOP])
        scripthash = script_to_scripthash(scriptpubkey)

        # There should exist any history for scripthash
        assert_equal(0, len(await cli.call(GET_HISTORY, scripthash)))

        # Send a chain of three txs. We expect that:
        # tx1: height 0,  signaling unconfirmed with confirmed parents
        # tx2: height -1, signaling unconfirmed with unconfirmed parents
        # tx3: height -1, signaling unconfirmed with unconfirmed parents
        tx1 = create_transaction(unspent,
                                 n=0,
                                 value=unspent.vout[0].nValue,
                                 sig=CScript([OP_TRUE]),
                                 out=scriptpubkey)
        pad_tx(tx1)
        big_fee = 1
        tx2 = create_transaction(tx1,
                                 n=0,
                                 value=unspent.vout[0].nValue - big_fee,
                                 sig=CScript([OP_TRUE]),
                                 out=scriptpubkey)
        pad_tx(tx2)
        tx3 = create_transaction(tx2,
                                 n=0,
                                 value=unspent.vout[0].nValue - big_fee,
                                 sig=CScript([OP_TRUE]),
                                 out=scriptpubkey)
        pad_tx(tx3)

        self.p2p.send_txs_and_test([tx1, tx2, tx3], n)
        wait_for_electrum_mempool(n, count=3)

        res = await cli.call(GET_HISTORY, scripthash)
        assert_equal(3, len(res))

        def get_tx(txhash):
            for tx in res:
                if tx['tx_hash'] == txhash:
                    return tx
            assert (not "tx not in result")

        assert_equal(0, get_tx(tx1.hash)['height'])
        assert_equal(-1, get_tx(tx2.hash)['height'])
        assert_equal(-1, get_tx(tx3.hash)['height'])

        # Confirm tx1, see that
        # tx1: gets tipheight
        # tx2: gets height 0, tx3 keeps height -1
        self.mine_blocks(n, 1, [tx1])
        sync_electrum_height(n)
        res = await cli.call(GET_HISTORY, scripthash)

        assert_equal(n.getblockcount(), get_tx(tx1.hash)['height'])
        assert_equal(0, get_tx(tx2.hash)['height'])
        assert_equal(-1, get_tx(tx3.hash)['height'])

        # cleanup mempool for next test
        self.mine_blocks(n, 1, [tx2, tx3])
        sync_electrum_height(n)
        assert (len(n.getrawmempool()) == 0)
예제 #8
0
    def run_test(self):
        n = self.nodes[0]
        self.bootstrap_p2p()

        coinbases = self.mine_blocks(n, 104)

        # non-coinbase transactions
        prevtx = coinbases[0]
        nonstandard_tx = create_transaction(prevtx=prevtx,
                                            value=prevtx.vout[0].nValue,
                                            n=0,
                                            sig=CScript([OP_TRUE]),
                                            out=CScript([OP_FALSE, OP_DROP]))

        prevtx = coinbases[1]
        p2sh_tx = create_transaction(prevtx=prevtx,
                                     value=prevtx.vout[0].nValue,
                                     n=0,
                                     sig=CScript([OP_TRUE]),
                                     out=CScript(
                                         [OP_HASH160, DUMMY_HASH, OP_EQUAL]))

        prevtx = coinbases[2]
        p2pkh_tx = create_transaction(prevtx=prevtx,
                                      value=prevtx.vout[0].nValue,
                                      n=0,
                                      sig=CScript([OP_TRUE]),
                                      out=CScript([
                                          OP_DUP, OP_HASH160, DUMMY_HASH,
                                          OP_EQUALVERIFY, OP_CHECKSIG
                                      ]))

        prevtx = coinbases[3]
        unconfirmed_tx = create_transaction(prevtx=prevtx,
                                            value=prevtx.vout[0].nValue,
                                            n=0,
                                            sig=CScript([OP_TRUE]),
                                            out=CScript([
                                                OP_DUP, OP_HASH160, DUMMY_HASH,
                                                OP_EQUALVERIFY, OP_CHECKSIG
                                            ]))

        for tx in [nonstandard_tx, p2sh_tx, p2pkh_tx, unconfirmed_tx]:
            pad_tx(tx)

        coinbases.extend(
            self.mine_blocks(n, 1, [nonstandard_tx, p2sh_tx, p2pkh_tx]))
        self.sync_height()
        n.sendrawtransaction(ToHex(unconfirmed_tx))
        self.wait_for_mempool_count(count=1)

        async def async_tests(loop):
            cli = ElectrumConnection(loop)
            await cli.connect()

            return await asyncio.gather(
                self.test_verbose(n, cli, nonstandard_tx.hash, p2sh_tx.hash,
                                  p2pkh_tx.hash, unconfirmed_tx.hash),
                self.test_non_verbose(cli, coinbases, unconfirmed_tx))

        loop = asyncio.get_event_loop()
        loop.run_until_complete(async_tests(loop))