Пример #1
0
 def __init__(self, node=None):
     """Pass a node to use an address from that node's wallet.  Pass None to generate a local address"""
     if node is None:
         self.privkey = cashlib.randombytes(32)
     else:
         addr = node.getnewaddress()
         privb58 = node.dumpprivkey(addr)
         self.privkey = decodeBase58(privb58)[1:-5]
     self.pubkey = cashlib.pubkey(self.privkey)
     self.hash = cashlib.addrbin(self.pubkey)
Пример #2
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())
Пример #3
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
Пример #4
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