Пример #1
0
def createConflictingTx(dests, source, count, fee=1):
    """ Create "count" conflicting transactions that spend the "source" to "dests" evenly.  Conflicting tx are created
    by varying the fee.  Change the base "fee" if you want which is actually the fee PER dest.

    source: a dictionary in RPC listunspent format, with additional "privkey" field which is the private key in bytes
    dests: a list of PayDest objects.
    count: the number of conflicting tx to return
    fee: what to deduct as the fee (in Satoshi)
    """
    generatedTx = []
    hexOP_DUP = OP_DUP.toHex()
    binOP_DUP = ord(OP_DUP.toBin())

    for c in range(count):
        w = source
        if 1:
            tx = CTransaction()
            tx.vin.append(
                CTxIn(COutPoint(w["txid"], w["vout"]), b"", 0xffffffff))

            amt = int(w["satoshi"] / len(dests)) - (
                fee + c)  # really total fee ends up fee*dest

            i = 0
            for d in dests:
                script = CScript(
                    [OP_DUP, OP_HASH160, d.hash, OP_EQUALVERIFY, OP_CHECKSIG])
                tx.vout.append(CTxOut(amt, script))
                i += 1

            sighashtype = 0x41
            sig = cashlib.signTxInput(tx, 0, w["satoshi"], w["scriptPubKey"],
                                      w["privkey"], sighashtype)
            # construct the signature script -- it may be one of 2 types
            if w["scriptPubKey"][0:2] == hexOP_DUP or w["scriptPubKey"][
                    0] == binOP_DUP:  # P2PKH starts with OP_DUP
                tx.vin[0].scriptSig = cashlib.spendscript(sig,
                                                          w["pubkey"])  # P2PKH
            else:
                tx.vin[0].scriptSig = cashlib.spendscript(sig)  # P2PK

            generatedTx.append(tx)

    return generatedTx
Пример #2
0
def createTx(dests,
             sources,
             node,
             maxx=None,
             fee=1,
             nextWallet=None,
             generatedTx=None):
    """ Create "maxx" transactions that spend from individual "sources" to every "dests" evenly (many fan-out 
    transactions).  If "generatedTx" is a list the created transactions are put into it.  Otherwise they are
    sent to "node".  If "nextWallet" is a list the outputs of all these created tx are put into it in a format
    compatible with "sources" (you can use nextWallet as the sources input in a subsequent call to this function).

    Change the base "fee" if you want which is actually the fee PER dest.

    sources: list of dictionaries in RPC listunspent format, with optional additional "privkey" field which 
       is the private key in bytes.  If "privkey" does not exist, "node" is asked for it.
    dests: a list of PayDest objects.
    fee: what to deduct as the fee (in Satoshi)
    nextWallet: [output] pass an empty list to get a valid wallet if all the createdTx are committed.
    generatedTx: [output] pass an empty list to skip submitting the tx to node, and instead return them in this list.

    returns the number of transactions created.
    """

    hexOP_DUP = OP_DUP.toHex()
    binOP_DUP = ord(OP_DUP.toBin())
    count = 0
    for w in sources:
        nextOuts = []
        if not count is None and count == maxx:
            break

        # if sources is from a bitcoind wallet, I need to grab some info in order to sign
        if not "privkey" in w:
            privb58 = node.dumpprivkey(w["address"])
            privkey = decodeBase58(privb58)[1:-5]
            pubkey = cashlib.pubkey(privkey)
            w["privkey"] = privkey
            w["pubkey"] = pubkey

        tx = CTransaction()
        tx.vin.append(CTxIn(COutPoint(w["txid"], w["vout"]), b"", 0xffffffff))

        amt = int(
            w["satoshi"] / len(dests)) - fee  # really fee ends up fee*dest

        i = 0
        for d in dests:
            script = CScript(
                [OP_DUP, OP_HASH160, d.hash, OP_EQUALVERIFY, OP_CHECKSIG])
            tx.vout.append(CTxOut(amt, script))
            nextOuts.append({
                "vout": i,
                "privkey": d.privkey,
                "scriptPubKey": script,
                "satoshi": amt,
                "pubkey": d.pubkey
            })
            i += 1

        sighashtype = 0x41
        n = 0
        # print("amountin: %d amountout: %d outscript: %s" % (w["satoshi"], amt, w["scriptPubKey"]))
        sig = cashlib.signTxInput(tx, n, w["satoshi"], w["scriptPubKey"],
                                  w["privkey"], sighashtype)

        if w["scriptPubKey"][0:2] == hexOP_DUP or w["scriptPubKey"][
                0] == binOP_DUP:  # P2PKH starts with OP_DUP
            tx.vin[n].scriptSig = cashlib.spendscript(sig,
                                                      w["pubkey"])  # P2PKH
        else:
            tx.vin[n].scriptSig = cashlib.spendscript(sig)  # P2PK

        if not type(generatedTx) is list:  # submit these tx to the node
            txhex = hexlify(tx.serialize()).decode("utf-8")
            txid = None
            try:
                txid = node.enqueuerawtransaction(txhex)
            except JSONRPCException as e:
                logging.error("TX submission failed because %s" % str(e))
                logging.error("tx was: %s" % txhex)
                logging.error("amountin: %d amountout: %d outscript: %s" %
                              (w["satoshi"], amt, w["scriptPubKey"]))
                raise
        else:  # return them in generatedTx
            generatedTx.append(tx)

        for out in nextOuts:
            tx.rehash()
            out["txid"] = tx.hash
            # I've already filled nextOuts with all the other needed fields

        if type(nextWallet) is list:
            nextWallet += nextOuts
        count += 1
    return count
Пример #3
0
    def run_test(self):
        self.basicSchnorrSigning()

        self.nodes[0].generate(15)
        self.sync_blocks()
        self.nodes[1].generate(15)
        self.sync_blocks()
        self.nodes[2].generate(15)
        self.sync_blocks()
        self.nodes[0].generate(100)
        self.sync_blocks()

        logging.info("Schnorr signature transaction generation and commitment")

        resultWallet = []
        alltx = []

        wallets = [self.nodes[0].listunspent(), self.nodes[1].listunspent()]
        for txcount in range(0, 2):
            inputs = [x[0] for x in wallets]
            for x in wallets:  # Remove this utxo so we don't use it in the next time around
                del x[0]
            privb58 = [
                self.nodes[0].dumpprivkey(inputs[0]["address"]),
                self.nodes[1].dumpprivkey(inputs[1]["address"])
            ]

            privkeys = [decodeBase58(x)[1:-5] for x in privb58]
            pubkeys = [cashlib.pubkey(x) for x in privkeys]

            for doubleSpend in range(0, 2):  # Double spend this many times
                tx = CTransaction()
                for i in inputs:
                    tx.vin.append(
                        CTxIn(COutPoint(i["txid"], i["vout"]), b"",
                              0xffffffff - doubleSpend)
                    )  # subtracting doubleSpend changes the tx slightly

                destPrivKey = cashlib.randombytes(32)
                destPubKey = cashlib.pubkey(destPrivKey)
                destHash = cashlib.addrbin(destPubKey)

                output = CScript([
                    OP_DUP, OP_HASH160, destHash, OP_EQUALVERIFY, OP_CHECKSIG
                ])

                amt = int(sum([x["amount"] for x in inputs]) * cashlib.BCH)
                tx.vout.append(CTxOut(amt, output))

                sighashtype = 0x41
                n = 0
                for i, priv in zip(inputs, privkeys):
                    sig = cashlib.signTxInputSchnorr(tx, n, i["amount"],
                                                     i["scriptPubKey"], priv,
                                                     sighashtype)
                    tx.vin[n].scriptSig = cashlib.spendscript(sig)  # P2PK
                    n += 1

                txhex = hexlify(tx.serialize()).decode("utf-8")
                txid = self.nodes[0].enqueuerawtransaction(txhex)

                if doubleSpend == 0:
                    resultWallet.append([
                        destPrivKey, destPubKey, amt,
                        PlaceHolder(txid), 0, output
                    ])
                    alltx.append(txhex)

        # because enqueuerawtransaction and propagation is asynchronous we need to wait for it
        waitFor(10,
                lambda: self.nodes[1].getmempoolinfo()['size'] == txcount + 1)
        mp = [i.getmempoolinfo() for i in self.nodes]
        assert txcount + 1 == mp[0]['size'] == mp[1]['size']

        nonSchnorrBlkHash = self.nodes[0].getbestblockhash()
        self.nodes[0].generate(1)

        assert self.nodes[0].getmempoolinfo()['size'] == 0
        waitFor(
            10, lambda: self.nodes[0].getbestblockhash() == self.nodes[1].
            getbestblockhash())

        FEEINSAT = 5000
        # now spend all the new utxos again
        for spendLoop in range(0, 2):
            incomingWallet = resultWallet
            resultWallet = []

            logging.info("spend iteration %d, num transactions %d" %
                         (spendLoop, len(incomingWallet)))
            for w in incomingWallet:
                txidHolder = PlaceHolder()
                tx = CTransaction()
                tx.vin.append(
                    CTxIn(COutPoint(w[3].data, w[4]), b"", 0xffffffff))

                NOUTS = 10 - spendLoop * 2
                if NOUTS < 0:
                    NOUTS = 1
                amtPerOut = int((w[2] - FEEINSAT) / NOUTS)
                for outIdx in range(0, NOUTS):
                    destPrivKey = cashlib.randombytes(32)
                    destPubKey = cashlib.pubkey(destPrivKey)
                    destHash = cashlib.addrbin(destPubKey)
                    output = CScript([
                        OP_DUP, OP_HASH160, destHash, OP_EQUALVERIFY,
                        OP_CHECKSIG
                    ])
                    tx.vout.append(CTxOut(amtPerOut, output))
                    resultWallet.append([
                        destPrivKey, destPubKey, amtPerOut, txidHolder, outIdx,
                        output
                    ])

                sighashtype = 0x41
                n = 0
                sig = cashlib.signTxInputSchnorr(tx, n, w[2], w[5], w[0],
                                                 sighashtype)
                tx.vin[n].scriptSig = cashlib.spendscript(sig, w[1])  # P2PKH

                txhex = hexlify(tx.serialize()).decode("utf-8")
                txid = self.nodes[1].enqueuerawtransaction(txhex)
                alltx.append(txhex)
                txidHolder.data = txid

            # because enqueuerawtransaction and propagation is asynchronous we need to wait for it
            waitFor(
                10, lambda: self.nodes[0].getmempoolinfo()['size'] == len(
                    incomingWallet))
            while self.nodes[0].getmempoolinfo()['size'] != 0:
                self.nodes[0].generate(1)
            waitFor(
                10, lambda: self.nodes[0].getbestblockhash() == self.nodes[1].
                getbestblockhash())
Пример #4
0
    def run_test(self):
        faulted = False
        try:
            cashlib.spendscript(OP_1)
        except AssertionError:
            faulted = True
            pass
        assert faulted, "only data in spend scripts"

        try:
            cashlib.signTxInput(b"", 0, 5, b"", b"", cashlib.SIGHASH_ALL)
        except AssertionError:
            faulted = True
            pass
        assert faulted, "not signing with bitcoin cash forkid"

        # grab inputs from 2 different full nodes and sign a single tx that spends them both
        wallets = [self.nodes[0].listunspent(), self.nodes[1].listunspent()]
        inputs = [x[0] for x in wallets]
        privb58 = [self.nodes[0].dumpprivkey(inputs[0]["address"]), self.nodes[1].dumpprivkey(inputs[1]["address"])]

        privkeys = [decodeBase58(x)[1:-5] for x in privb58]
        pubkeys = [cashlib.pubkey(x) for x in privkeys]

        tx = CTransaction()
        for i in inputs:
            tx.vin.append(CTxIn(COutPoint(i["txid"], i["vout"]), b"", 0xffffffff))

        destPrivKey = cashlib.randombytes(32)
        destPubKey = cashlib.pubkey(destPrivKey)
        destHash = cashlib.addrbin(destPubKey)

        output = CScript([OP_DUP, OP_HASH160, destHash, OP_EQUALVERIFY, OP_CHECKSIG])

        amt = int(sum([x["amount"] for x in inputs]) * BCH)
        tx.vout.append(CTxOut(amt, output))

        sighashtype = 0x41
        n = 0
        for i, priv in zip(inputs, privkeys):
            sig = cashlib.signTxInput(tx, n, i["amount"], i["scriptPubKey"], priv, sighashtype)
            tx.vin[n].scriptSig = cashlib.spendscript(sig)  # P2PK
            n += 1

        txhex = hexlify(tx.serialize()).decode("utf-8")
        txid = self.nodes[0].enqueuerawtransaction(txhex)

        assert txid == hexlify(cashlib.txid(txhex)[::-1]).decode("utf-8")

        # Now spend the created output to an anyone can spend address
        tx2 = CTransaction()
        tx2.vin.append(CTxIn(COutPoint(cashlib.txid(txhex), 0), b"", 0xffffffff))
        tx2.vout.append(CTxOut(amt, CScript([OP_1])))
        sig2 = cashlib.signTxInput(tx2, 0, amt, output, destPrivKey, sighashtype)
        tx2.vin[0].scriptSig = cashlib.spendscript(sig2, destPubKey)

        tx2id = self.nodes[0].enqueuerawtransaction(hexlify(tx2.serialize()).decode("utf-8"))
        # Check that all tx were created, and commit them
        waitFor(20, lambda: self.nodes[0].getmempoolinfo()["size"] == 2)
        blk = self.nodes[0].generate(1)
        self.sync_blocks()
        assert self.nodes[0].getmempoolinfo()["size"] == 0
        assert self.nodes[1].getmempoolinfo()["size"] == 0
Пример #5
0
    def run_test(self):
        self.runScriptMachineTests()

        faulted = False
        try:
            cashlib.spendscript(OP_1)
        except AssertionError:
            faulted = True
            pass
        assert faulted, "only data in spend scripts"

        try:
            cashlib.signTxInput(b"", 0, 5, b"", b"", cashlib.SIGHASH_ALL)
        except AssertionError:
            faulted = True
            pass
        assert faulted, "not signing with bitcoin cash forkid"

        # grab inputs from 2 different full nodes and sign a single tx that spends them both
        wallets = [self.nodes[0].listunspent(), self.nodes[1].listunspent()]
        inputs = [x[0] for x in wallets]
        privb58 = [
            self.nodes[0].dumpprivkey(inputs[0]["address"]),
            self.nodes[1].dumpprivkey(inputs[1]["address"])
        ]

        privkeys = [decodeBase58(x)[1:-5] for x in privb58]
        pubkeys = [cashlib.pubkey(x) for x in privkeys]

        tx = CTransaction()
        for i in inputs:
            tx.vin.append(
                CTxIn(COutPoint(i["txid"], i["vout"]), b"", 0xffffffff))

        destPrivKey = cashlib.randombytes(32)
        destPubKey = cashlib.pubkey(destPrivKey)
        destHash = cashlib.addrbin(destPubKey)

        output = CScript(
            [OP_DUP, OP_HASH160, destHash, OP_EQUALVERIFY, OP_CHECKSIG])

        amt = int(sum([x["amount"] for x in inputs]) * cashlib.BCH)
        tx.vout.append(CTxOut(amt, output))

        sighashtype = 0x41
        n = 0
        for i, priv in zip(inputs, privkeys):
            sig = cashlib.signTxInput(tx, n, i["amount"], i["scriptPubKey"],
                                      priv, sighashtype)
            tx.vin[n].scriptSig = cashlib.spendscript(sig)  # P2PK
            n += 1

        txhex = hexlify(tx.serialize()).decode("utf-8")
        txid = self.nodes[0].enqueuerawtransaction(txhex)

        assert txid == hexlify(cashlib.txid(txhex)[::-1]).decode("utf-8")

        # Now spend the created output to an anyone can spend address
        tx2 = CTransaction()
        tx2.vin.append(
            CTxIn(COutPoint(cashlib.txid(txhex), 0), b"", 0xffffffff))
        tx2.vout.append(CTxOut(amt, CScript([OP_1])))
        sig2 = cashlib.signTxInput(tx2, 0, amt, output, destPrivKey,
                                   sighashtype)
        tx2.vin[0].scriptSig = cashlib.spendscript(sig2, destPubKey)

        # Local script interpreter:
        # Check that the spend works in a transaction-aware script machine
        txbad = copy.deepcopy(tx2)
        badsig = list(sig2)
        badsig[10] = 1  # mess up the sig
        badsig[11] = 2
        txbad.vin[0].scriptSig = cashlib.spendscript(bytes(badsig), destPubKey)

        # try a bad script (sig check should fail)
        sm = cashlib.ScriptMachine(tx=tx2,
                                   inputIdx=0,
                                   inputAmount=tx.vout[0].nValue)
        ret = sm.eval(txbad.vin[0].scriptSig)
        assert (ret)
        ret = sm.eval(tx.vout[0].scriptPubKey)
        assert (not ret)
        assert (sm.error()[0] == cashlib.ScriptError.SCRIPT_ERR_SIG_NULLFAIL)

        # try a good spend script
        sm.reset()
        ret = sm.eval(tx2.vin[0].scriptSig)
        assert (ret)
        ret = sm.eval(tx.vout[0].scriptPubKey)
        assert (ret)

        # commit the created transaction
        tx2id = self.nodes[0].enqueuerawtransaction(
            hexlify(tx2.serialize()).decode("utf-8"))

        # Check that all tx were created, and commit them
        waitFor(20, lambda: self.nodes[0].getmempoolinfo()["size"] == 2)
        blk = self.nodes[0].generate(1)
        self.sync_blocks()
        assert self.nodes[0].getmempoolinfo()["size"] == 0
        assert self.nodes[1].getmempoolinfo()["size"] == 0