예제 #1
0
    def test_multiple_children(self):
        node = self.nodes[0]

        self.log.info(
            "Testmempoolaccept a package in which a transaction has two children within the package"
        )
        first_coin = self.coins.pop()
        value = (first_coin["amount"] - Decimal("0.0002")
                 ) / 2  # Deduct reasonable fee and make 2 outputs
        inputs = [{"txid": first_coin["txid"], "vout": 0}]
        outputs = [{self.address: value}, {ADDRESS_BCRT1_P2WSH_OP_TRUE: value}]
        rawtx = node.createrawtransaction(inputs, outputs)

        parent_signed = node.signrawtransactionwithkey(hexstring=rawtx,
                                                       privkeys=self.privkeys)
        assert parent_signed["complete"]
        parent_tx = tx_from_hex(parent_signed["hex"])
        parent_txid = parent_tx.rehash()
        assert node.testmempoolaccept([parent_signed["hex"]])[0]["allowed"]

        parent_locking_script_a = parent_tx.vout[0].scriptPubKey.hex()
        child_value = value - Decimal("0.0001")

        # Child A
        (_, tx_child_a_hex, _,
         _) = make_chain(node, self.address, self.privkeys, parent_txid,
                         child_value, 0, parent_locking_script_a)
        assert not node.testmempoolaccept([tx_child_a_hex])[0]["allowed"]

        # Child B
        rawtx_b = node.createrawtransaction([{
            "txid": parent_txid,
            "vout": 1
        }], {self.address: child_value})
        tx_child_b = tx_from_hex(rawtx_b)
        tx_child_b.wit.vtxinwit = [CTxInWitness()]
        tx_child_b.wit.vtxinwit[0].scriptWitness.stack = [CScript([OP_TRUE])]
        tx_child_b_hex = tx_child_b.serialize().hex()
        assert not node.testmempoolaccept([tx_child_b_hex])[0]["allowed"]

        self.log.info(
            "Testmempoolaccept with entire package, should work with children in either order"
        )
        testres_multiple_ab = node.testmempoolaccept(
            rawtxs=[parent_signed["hex"], tx_child_a_hex, tx_child_b_hex])
        testres_multiple_ba = node.testmempoolaccept(
            rawtxs=[parent_signed["hex"], tx_child_b_hex, tx_child_a_hex])
        assert all([
            testres["allowed"]
            for testres in testres_multiple_ab + testres_multiple_ba
        ])

        testres_single = []
        # Test accept and then submit each one individually, which should be identical to package testaccept
        for rawtx in [parent_signed["hex"], tx_child_a_hex, tx_child_b_hex]:
            testres = node.testmempoolaccept([rawtx])
            testres_single.append(testres[0])
            # Submit the transaction now so its child should have no problem validating
            node.sendrawtransaction(rawtx)
        assert_equal(testres_single, testres_multiple_ab)
예제 #2
0
    def buildDummySegwitNameUpdate(self, name, value, addr):
        """
    Builds a transaction that updates the given name to the given value and
    address.  We assume that the name is at a native segwit script.  The witness
    of the transaction will be set to two dummy stack elements so that the
    program itself is "well-formed" even if it won't execute successfully.
    """

        data = self.node.name_show(name)
        u = self.findUnspent(Decimal('0.01'))
        ins = [data, u]
        outs = {addr: Decimal('0.01')}

        txHex = self.node.createrawtransaction(ins, outs)
        nameOp = {"op": "name_update", "name": name, "value": value}
        txHex = self.node.namerawtransaction(txHex, 0, nameOp)['hex']
        txHex = self.node.signrawtransactionwithwallet(txHex)['hex']

        tx = CTransaction()
        tx.deserialize(io.BytesIO(hex_str_to_bytes(txHex)))
        tx.wit = CTxWitness()
        tx.wit.vtxinwit.append(CTxInWitness())
        tx.wit.vtxinwit[0].scriptWitness = CScriptWitness()
        tx.wit.vtxinwit[0].scriptWitness.stack = [b"dummy"] * 2
        txHex = tx.serialize().hex()

        return txHex
예제 #3
0
파일: wallet.py 프로젝트: jlopp/statoshi
    def create_self_transfer(self,
                             *,
                             fee_rate=Decimal("0.003"),
                             from_node=None,
                             utxo_to_spend=None,
                             mempool_valid=True,
                             locktime=0,
                             sequence=0):
        """Create and return a tx with the specified fee_rate. Fee may be exact or at most one satoshi higher than needed.
           Checking mempool validity via the testmempoolaccept RPC can be skipped by setting mempool_valid to False."""
        from_node = from_node or self._test_node
        utxo_to_spend = utxo_to_spend or self.get_utxo()
        if self._priv_key is None:
            vsize = Decimal(104)  # anyone-can-spend
        else:
            vsize = Decimal(
                168
            )  # P2PK (73 bytes scriptSig + 35 bytes scriptPubKey + 60 bytes other)
        send_value = int(COIN * (utxo_to_spend['value'] - fee_rate *
                                 (vsize / 1000)))
        assert send_value > 0

        tx = CTransaction()
        tx.vin = [
            CTxIn(COutPoint(int(utxo_to_spend['txid'], 16),
                            utxo_to_spend['vout']),
                  nSequence=sequence)
        ]
        tx.vout = [CTxOut(send_value, self._scriptPubKey)]
        tx.nLockTime = locktime
        if not self._address:
            # raw script
            if self._priv_key is not None:
                # P2PK, need to sign
                self.sign_tx(tx)
            else:
                # anyone-can-spend
                tx.vin[0].scriptSig = CScript([OP_NOP] *
                                              43)  # pad to identical size
        else:
            tx.wit.vtxinwit = [CTxInWitness()]
            tx.wit.vtxinwit[0].scriptWitness.stack = [
                CScript([OP_TRUE]),
                bytes([LEAF_VERSION_TAPSCRIPT]) + self._internal_key
            ]
        tx_hex = tx.serialize().hex()

        if mempool_valid:
            tx_info = from_node.testmempoolaccept([tx_hex])[0]
            assert_equal(tx_info['allowed'], True)
            assert_equal(tx_info['vsize'], vsize)
            assert_equal(tx_info['fees']['base'],
                         utxo_to_spend['value'] - Decimal(send_value) / COIN)

        return {
            'txid': tx.rehash(),
            'wtxid': tx.getwtxid(),
            'hex': tx_hex,
            'tx': tx
        }
예제 #4
0
파일: wallet.py 프로젝트: mword/elements
    def send_self_transfer(self,
                           *,
                           fee_rate=Decimal("0.003"),
                           from_node,
                           utxo_to_spend=None):
        """Create and send a tx with the specified fee_rate. Fee may be exact or at most one satoshi higher than needed."""
        self._utxos = sorted(self._utxos, key=lambda k: k['value'])
        utxo_to_spend = utxo_to_spend or self._utxos.pop(
        )  # Pick the largest utxo (if none provided) and hope it covers the fee
        vsize = Decimal(177)
        send_value = satoshi_round(utxo_to_spend['value'] - fee_rate *
                                   (vsize / 1000))
        fee = utxo_to_spend['value'] - send_value
        assert send_value > 0

        tx = CTransaction()
        tx.vin = [
            CTxIn(
                COutPoint(int(utxo_to_spend['txid'], 16),
                          utxo_to_spend['vout']))
        ]
        tx.vout = [
            CTxOut(int(send_value * COIN), self._scriptPubKey),
            CTxOut(int(fee * COIN))
        ]
        tx.wit.vtxinwit = [CTxInWitness()]
        tx.wit.vtxinwit[0].scriptWitness.stack = [CScript([OP_TRUE])]
        tx_hex = tx.serialize().hex()

        txid = from_node.sendrawtransaction(tx_hex)
        self._utxos.append({'txid': txid, 'vout': 0, 'value': send_value})
        tx_info = from_node.getmempoolentry(txid)
        assert_equal(tx_info['vsize'], vsize)
        assert_equal(tx_info['fee'], fee)
        return {'txid': txid, 'wtxid': tx_info['wtxid'], 'hex': tx_hex}
    def test_signing_with_csv(self):
        self.log.info("Test signing a transaction containing a fully signed CSV input")
        self.nodes[0].walletpassphrase("password", 9999)
        getcontext().prec = 8

        # Make sure CSV is active
        self.nodes[0].generate(500)

        # Create a P2WSH script with CSV
        script = CScript([1, OP_CHECKSEQUENCEVERIFY, OP_DROP])
        address = script_to_p2wsh(script)

        # Fund that address and make the spend
        txid = self.nodes[0].sendtoaddress(address, 1)
        vout = find_vout_for_address(self.nodes[0], txid, address)
        self.nodes[0].generate(1)
        utxo = self.nodes[0].listunspent()[0]
        amt = Decimal(1) + utxo["amount"] - Decimal(0.00001)
        tx = self.nodes[0].createrawtransaction(
            [{"txid": txid, "vout": vout, "sequence": 1},{"txid": utxo["txid"], "vout": utxo["vout"]}],
            [{self.nodes[0].getnewaddress(): amt}],
            self.nodes[0].getblockcount()
        )

        # Set the witness script
        ctx = CTransaction()
        ctx.deserialize(BytesIO(hex_str_to_bytes(tx)))
        ctx.wit.vtxinwit.append(CTxInWitness())
        ctx.wit.vtxinwit[0].scriptWitness.stack = [CScript([OP_TRUE]), script]
        tx = ctx.serialize_with_witness().hex()

        # Sign and send the transaction
        signed = self.nodes[0].signrawtransactionwithwallet(tx)
        assert_equal(signed["complete"], True)
        self.nodes[0].sendrawtransaction(signed["hex"])
예제 #6
0
    def create_self_transfer(self, *, fee_rate=Decimal("0.003"), from_node, utxo_to_spend=None, mempool_valid=True):
        """Create and return a tx with the specified fee_rate. Fee may be exact or at most one satoshi higher than needed."""
        self._utxos = sorted(self._utxos, key=lambda k: k['value'])
        utxo_to_spend = utxo_to_spend or self._utxos.pop()  # Pick the largest utxo (if none provided) and hope it covers the fee
        vsize = Decimal(96)
        send_value = satoshi_round(utxo_to_spend['value'] - fee_rate * (vsize / 1000))
        fee = utxo_to_spend['value'] - send_value
        assert send_value > 0

        tx = CTransaction()
        tx.vin = [CTxIn(COutPoint(int(utxo_to_spend['txid'], 16), utxo_to_spend['vout']))]
        tx.vout = [CTxOut(int(send_value * COIN), self._scriptPubKey)]
        if not self._address:
            # raw script
            tx.vin[0].scriptSig = CScript([OP_NOP] * 35)  # pad to identical size
        else:
            tx.wit.vtxinwit = [CTxInWitness()]
            tx.wit.vtxinwit[0].scriptWitness.stack = [CScript([OP_TRUE])]
        tx_hex = tx.serialize().hex()

        tx_info = from_node.testmempoolaccept([tx_hex])[0]
        assert_equal(mempool_valid, tx_info['allowed'])
        if mempool_valid:
            assert_equal(tx_info['vsize'], vsize)
            assert_equal(tx_info['fees']['base'], fee)
        return {'txid': tx_info['txid'], 'wtxid': tx_info['wtxid'], 'hex': tx_hex, 'tx': tx}
예제 #7
0
파일: wallet.py 프로젝트: schurteb/bitcoin
    def create_self_transfer(self, *, fee_rate=Decimal("0.003"), from_node, utxo_to_spend=None, mempool_valid=True, locktime=0, sequence=0):
        """Create and return a tx with the specified fee_rate. Fee may be exact or at most one satoshi higher than needed."""
        self._utxos = sorted(self._utxos, key=lambda k: (k['value'], -k['height']))
        utxo_to_spend = utxo_to_spend or self._utxos.pop()  # Pick the largest utxo (if none provided) and hope it covers the fee
        if self._priv_key is None:
            vsize = Decimal(96)  # anyone-can-spend
        else:
            vsize = Decimal(168)  # P2PK (73 bytes scriptSig + 35 bytes scriptPubKey + 60 bytes other)
        send_value = int(COIN * (utxo_to_spend['value'] - fee_rate * (vsize / 1000)))
        assert send_value > 0

        tx = CTransaction()
        tx.vin = [CTxIn(COutPoint(int(utxo_to_spend['txid'], 16), utxo_to_spend['vout']), nSequence=sequence)]
        tx.vout = [CTxOut(send_value, self._scriptPubKey)]
        tx.nLockTime = locktime
        if not self._address:
            # raw script
            if self._priv_key is not None:
                # P2PK, need to sign
                self.sign_tx(tx)
            else:
                # anyone-can-spend
                tx.vin[0].scriptSig = CScript([OP_NOP] * 35)  # pad to identical size
        else:
            tx.wit.vtxinwit = [CTxInWitness()]
            tx.wit.vtxinwit[0].scriptWitness.stack = [CScript([OP_TRUE])]
        tx_hex = tx.serialize().hex()

        tx_info = from_node.testmempoolaccept([tx_hex])[0]
        assert_equal(mempool_valid, tx_info['allowed'])
        if mempool_valid:
            assert_equal(tx_info['vsize'], vsize)
            assert_equal(tx_info['fees']['base'], utxo_to_spend['value'] - Decimal(send_value) / COIN)
        return {'txid': tx_info['txid'], 'wtxid': tx_info['wtxid'], 'hex': tx_hex, 'tx': tx}
예제 #8
0
    def test_signing_with_cltv(self):
        self.log.info("Test signing a transaction containing a fully signed CLTV input")
        self.nodes[0].walletpassphrase("password", 9999)
        getcontext().prec = 8

        # Make sure CLTV is active
        assert self.nodes[0].getblockchaininfo()['softforks']['bip65']['active']

        # Create a P2WSH script with CLTV
        script = CScript([100, OP_CHECKLOCKTIMEVERIFY, OP_DROP])
        address = script_to_p2wsh(script)

        # Fund that address and make the spend
        txid = self.nodes[0].sendtoaddress(address, 1)
        vout = find_vout_for_address(self.nodes[0], txid, address)
        self.generate(self.nodes[0], 1)
        utxo = self.nodes[0].listunspent()[0]
        amt = Decimal(1) + utxo["amount"] - Decimal(0.00001)
        tx = self.nodes[0].createrawtransaction(
            [{"txid": txid, "vout": vout},{"txid": utxo["txid"], "vout": utxo["vout"]}],
            [{self.nodes[0].getnewaddress(): amt}],
            self.nodes[0].getblockcount()
        )

        # Set the witness script
        ctx = tx_from_hex(tx)
        ctx.wit.vtxinwit.append(CTxInWitness())
        ctx.wit.vtxinwit[0].scriptWitness.stack = [CScript([OP_TRUE]), script]
        tx = ctx.serialize_with_witness().hex()

        # Sign and send the transaction
        signed = self.nodes[0].signrawtransactionwithwallet(tx)
        assert_equal(signed["complete"], True)
        self.nodes[0].sendrawtransaction(signed["hex"])
예제 #9
0
    def check_tx_relay(self):
        block_op_true = self.nodes[0].getblock(self.nodes[0].generatetoaddress(100, ADDRESS_BCRT1_P2WSH_OP_TRUE)[0])
        self.sync_all()

        self.log.debug("Create a connection from a whitelisted wallet that rebroadcasts raw txs")
        # A python mininode is needed to send the raw transaction directly. If a full node was used, it could only
        # rebroadcast via the inv-getdata mechanism. However, even for whitelisted connections, a full node would
        # currently not request a txid that is already in the mempool.
        self.restart_node(1, extra_args=["[email protected]"])
        p2p_rebroadcast_wallet = self.nodes[1].add_p2p_connection(P2PDataStore())

        self.log.debug("Send a tx from the wallet initially")
        tx = FromHex(
            CTransaction(),
            self.nodes[0].createrawtransaction(
                inputs=[{
                    'txid': block_op_true['tx'][0],
                    'vout': 0,
                }], outputs=[{
                    ADDRESS_BCRT1_P2WSH_OP_TRUE: 5,
                }]),
        )
        tx.wit.vtxinwit = [CTxInWitness()]
        tx.wit.vtxinwit[0].scriptWitness.stack = [CScript([OP_TRUE])]
        txid = tx.rehash()

        self.log.debug("Wait until tx is in node[1]'s mempool")
        p2p_rebroadcast_wallet.send_txs_and_test([tx], self.nodes[1])

        self.log.debug("Check that node[1] will send the tx to node[0] even though it is already in the mempool")
        connect_nodes(self.nodes[1], 0)
        with self.nodes[1].assert_debug_log(["Force relaying tx {} from whitelisted peer=0".format(txid)]):
            p2p_rebroadcast_wallet.send_txs_and_test([tx], self.nodes[1])
            wait_until(lambda: txid in self.nodes[0].getrawmempool())
예제 #10
0
    def check_tx_relay(self):
        block_op_true = self.nodes[0].getblock(self.nodes[0].generatetoaddress(100, ADDRESS_BCRT1_P2WSH_OP_TRUE)[0])
        self.sync_all()

        self.log.debug("Create a connection from a forcerelay peer that rebroadcasts raw txs")
        # A test framework p2p connection is needed to send the raw transaction directly. If a full node was used, it could only
        # rebroadcast via the inv-getdata mechanism. However, even for forcerelay connections, a full node would
        # currently not request a txid that is already in the mempool.
        self.restart_node(1, extra_args=["[email protected]"])
        p2p_rebroadcast_wallet = self.nodes[1].add_p2p_connection(P2PDataStore())

        self.log.debug("Send a tx from the wallet initially")
        tx = FromHex(
            CTransaction(),
            self.nodes[0].createrawtransaction(
                inputs=[{
                    'txid': block_op_true['tx'][0],
                    'vout': 0,
                }], outputs=[{
                    ADDRESS_BCRT1_P2WSH_OP_TRUE: 5,
                }, {
                    "fee": 45,
                }]),
        )
        tx.wit.vtxinwit = [CTxInWitness()]
        tx.wit.vtxinwit[0].scriptWitness.stack = [CScript([OP_TRUE])]
        txid = tx.rehash()

        self.log.debug("Wait until tx is in node[1]'s mempool")
        p2p_rebroadcast_wallet.send_txs_and_test([tx], self.nodes[1])

        self.log.debug("Check that node[1] will send the tx to node[0] even though it is already in the mempool")
        self.connect_nodes(1, 0)
        with self.nodes[1].assert_debug_log(["Force relaying tx {} from peer=0".format(txid)]):
            p2p_rebroadcast_wallet.send_txs_and_test([tx], self.nodes[1])
            self.wait_until(lambda: txid in self.nodes[0].getrawmempool())

        self.log.debug("Check that node[1] will not send an invalid tx to node[0]")
        tx.vout[0].nValue.setToAmount(tx.vout[0].nValue.getAmount() + 1)
        txid = tx.rehash()
        # Send the transaction twice. The first time, it'll be rejected by ATMP because it conflicts
        # with a mempool transaction. The second time, it'll be in the recentRejects filter.
        p2p_rebroadcast_wallet.send_txs_and_test(
            [tx],
            self.nodes[1],
            success=False,
            reject_reason='{} from peer=0 was not accepted: txn-mempool-conflict'.format(txid)
        )

        p2p_rebroadcast_wallet.send_txs_and_test(
            [tx],
            self.nodes[1],
            success=False,
            reject_reason='Not relaying non-mempool transaction {} from forcerelay peer=0'.format(txid)
        )
예제 #11
0
    def test_compactblock_reconstruction_multiple_peers(
            self, stalling_peer, delivery_peer):
        node = self.nodes[0]
        assert len(self.utxos)

        def announce_cmpct_block(node, peer):
            utxo = self.utxos.pop(0)
            block = self.build_block_with_transactions(node, utxo, 5)

            cmpct_block = HeaderAndShortIDs()
            cmpct_block.initialize_from_block(block)
            msg = msg_cmpctblock(cmpct_block.to_p2p())
            peer.send_and_ping(msg)
            with mininode_lock:
                assert "getblocktxn" in peer.last_message
            return block, cmpct_block

        block, cmpct_block = announce_cmpct_block(node, stalling_peer)

        for tx in block.vtx[1:]:
            delivery_peer.send_message(msg_tx(tx))
        delivery_peer.sync_with_ping()
        mempool = node.getrawmempool()
        for tx in block.vtx[1:]:
            assert tx.hash in mempool

        delivery_peer.send_and_ping(msg_cmpctblock(cmpct_block.to_p2p()))
        assert_equal(int(node.getbestblockhash(), 16), block.sha256)

        self.utxos.append(
            [block.vtx[-1].sha256, 0, block.vtx[-1].vout[0].nValue])

        # Now test that delivering an invalid compact block won't break relay

        block, cmpct_block = announce_cmpct_block(node, stalling_peer)
        for tx in block.vtx[1:]:
            delivery_peer.send_message(msg_tx(tx))
        delivery_peer.sync_with_ping()

        cmpct_block.prefilled_txn[0].tx.wit.vtxinwit = [CTxInWitness()]
        cmpct_block.prefilled_txn[0].tx.wit.vtxinwit[0].scriptWitness.stack = [
            ser_uint256(0)
        ]

        cmpct_block.use_witness = True
        delivery_peer.send_and_ping(msg_cmpctblock(cmpct_block.to_p2p()))
        assert int(node.getbestblockhash(), 16) != block.sha256

        msg = msg_no_witness_blocktxn()
        msg.block_transactions.blockhash = block.sha256
        msg.block_transactions.transactions = block.vtx[1:]
        stalling_peer.send_and_ping(msg)
        assert_equal(int(node.getbestblockhash(), 16), block.sha256)
예제 #12
0
    def issuance_test(self, sighash_ty):
        tx, prev_vout, spk, sec, pub, tweak = self.create_taproot_utxo()

        blind_addr = self.nodes[0].getnewaddress()
        nonblind_addr = self.nodes[0].validateaddress(
            blind_addr)['unconfidential']
        raw_tx = self.nodes[0].createrawtransaction([], [{nonblind_addr: 1}])
        raw_tx = FromHex(CTransaction(), raw_tx)

        # Need to taproot outputs later because fundrawtransaction cannot estimate fees
        # prev out has value 1.2 btc
        in_total = tx.vout[prev_vout].nValue.getAmount()
        fees = 100
        raw_tx.vin.append(CTxIn(COutPoint(tx.sha256, prev_vout)))
        raw_tx.vout.append(
            CTxOut(nValue=CTxOutValue(in_total - fees - 10**8),
                   scriptPubKey=spk))  # send back to self
        raw_tx.vout.append(CTxOut(nValue=CTxOutValue(fees)))

        # issued_tx = raw_tx.serialize().hex()
        blind_addr = self.nodes[0].getnewaddress()
        issue_addr = self.nodes[0].validateaddress(
            blind_addr)['unconfidential']
        issued_tx = self.nodes[0].rawissueasset(
            raw_tx.serialize().hex(), [{
                "asset_amount": 2,
                "asset_address": issue_addr,
                "blind": False
            }])[0]["hex"]
        # blind_tx = self.nodes[0].blindrawtransaction(issued_tx) # This is a no-op
        genesis_hash = uint256_from_str(
            bytes.fromhex(self.nodes[0].getblockhash(0))[::-1])
        issued_tx = FromHex(CTransaction(), issued_tx)
        issued_tx.wit.vtxoutwit = [CTxOutWitness()] * len(issued_tx.vout)
        issued_tx.wit.vtxinwit = [CTxInWitness()] * len(issued_tx.vin)
        msg = TaprootSignatureHash(issued_tx, [tx.vout[prev_vout]], sighash_ty,
                                   genesis_hash, 0)

        # compute the tweak
        tweak_sk = tweak_add_privkey(sec, tweak)
        sig = sign_schnorr(tweak_sk, msg)
        issued_tx.wit.vtxinwit[0].scriptWitness.stack = [
            taproot_pad_sighash_ty(sig, sighash_ty)
        ]
        pub_tweak = tweak_add_pubkey(pub, tweak)[0]
        assert (verify_schnorr(pub_tweak, sig, msg))
        # Since we add in/outputs the min feerate is no longer maintained.
        self.nodes[0].sendrawtransaction(hexstring=issued_tx.serialize().hex())
        self.nodes[0].generate(1)
        last_blk = self.nodes[0].getblock(self.nodes[0].getbestblockhash())
        issued_tx.rehash()
        assert (issued_tx.hash in last_blk['tx'])
예제 #13
0
    def test_signing_with_csv(self):
        self.log.info(
            "Test signing a transaction containing a fully signed CSV input")
        self.nodes[0].walletpassphrase("password", 9999)
        getcontext().prec = 8

        # Make sure CSV is active
        generate_to_height(self.nodes[0], CSV_ACTIVATION_HEIGHT)
        assert self.nodes[0].getblockchaininfo()['softforks']['csv']['active']

        # Create a P2WSH script with CSV
        script = CScript([1, OP_CHECKSEQUENCEVERIFY, OP_DROP])
        address = script_to_p2wsh(script)

        # Fund that address and make the spend
        txid = self.nodes[0].sendtoaddress(address, 1)
        vout = find_vout_for_address(self.nodes[0], txid, address)
        self.nodes[0].generate(1)
        utxo = self.nodes[0].listunspent()[0]
        amt = Decimal(1) + utxo["amount"] - Decimal(0.00001)
        tx = self.nodes[0].createrawtransaction([{
            "txid": txid,
            "vout": vout,
            "sequence": 1
        }, {
            "txid": utxo["txid"],
            "vout": utxo["vout"]
        }], [{
            self.nodes[0].getnewaddress(): amt
        }], self.nodes[0].getblockcount())

        # Set the witness script
        ctx = tx_from_hex(tx)
        ctx.wit.vtxinwit.append(CTxInWitness())
        ctx.wit.vtxinwit[0].scriptWitness.stack = [CScript([OP_TRUE]), script]
        # Namecoin uses version 1 as default (for non-name transactions),
        # but CSV only works with version >= 2.
        ctx.nVersion = 2
        tx = ctx.serialize_with_witness().hex()

        # Sign and send the transaction
        signed = self.nodes[0].signrawtransactionwithwallet(tx)
        assert_equal(signed["complete"], True)
        self.nodes[0].sendrawtransaction(signed["hex"])
예제 #14
0
파일: wallet.py 프로젝트: schurteb/bitcoin
def bulk_transaction(tx, node, target_weight, privkeys, prevtxs=None):
    """Pad a transaction with extra outputs until it reaches a target weight (or higher).
    returns CTransaction object
    """
    tx_heavy = deepcopy(tx)
    assert_greater_than_or_equal(target_weight, tx_heavy.get_weight())
    while tx_heavy.get_weight() < target_weight:
        random_spk = "6a4d0200"  # OP_RETURN OP_PUSH2 512 bytes
        for _ in range(512*2):
            random_spk += choice("0123456789ABCDEF")
        tx_heavy.vout.append(CTxOut(0, bytes.fromhex(random_spk)))
    # Re-sign the transaction
    if privkeys:
        signed = node.signrawtransactionwithkey(tx_heavy.serialize().hex(), privkeys, prevtxs)
        return tx_from_hex(signed["hex"])
    # OP_TRUE
    tx_heavy.wit.vtxinwit = [CTxInWitness()]
    tx_heavy.wit.vtxinwit[0].scriptWitness.stack = [CScript([OP_TRUE])]
    return tx_heavy
예제 #15
0
    def create_self_transfer(self, *, fee_rate=Decimal("0.003"), fee=Decimal("0"), utxo_to_spend=None, locktime=0, sequence=0, target_weight=0):
        """Create and return a tx with the specified fee. If fee is 0, use fee_rate, where the resulting fee may be exact or at most one satoshi higher than needed."""
        utxo_to_spend = utxo_to_spend or self.get_utxo()
        assert fee_rate >= 0
        assert fee >= 0
        if self._mode in (MiniWalletMode.RAW_OP_TRUE, MiniWalletMode.ADDRESS_OP_TRUE):
            vsize = Decimal(104)  # anyone-can-spend
        elif self._mode == MiniWalletMode.RAW_P2PK:
            vsize = Decimal(168)  # P2PK (73 bytes scriptSig + 35 bytes scriptPubKey + 60 bytes other)
        else:
            assert False
        send_value = utxo_to_spend["value"] - (fee or (fee_rate * vsize / 1000))
        assert send_value > 0

        tx = CTransaction()
        tx.vin = [CTxIn(COutPoint(int(utxo_to_spend['txid'], 16), utxo_to_spend['vout']), nSequence=sequence)]
        tx.vout = [CTxOut(int(COIN * send_value), bytearray(self._scriptPubKey))]
        tx.nLockTime = locktime
        if self._mode == MiniWalletMode.RAW_P2PK:
            self.sign_tx(tx)
        elif self._mode == MiniWalletMode.RAW_OP_TRUE:
            tx.vin[0].scriptSig = CScript([OP_NOP] * 43)  # pad to identical size
        elif self._mode == MiniWalletMode.ADDRESS_OP_TRUE:
            tx.wit.vtxinwit = [CTxInWitness()]
            tx.wit.vtxinwit[0].scriptWitness.stack = [CScript([OP_TRUE]), bytes([LEAF_VERSION_TAPSCRIPT]) + self._internal_key]
        else:
            assert False

        assert_equal(tx.get_vsize(), vsize)

        if target_weight:
            self._bulk_tx(tx, target_weight)

        tx_hex = tx.serialize().hex()
        new_utxo = self._create_utxo(txid=tx.rehash(), vout=0, value=send_value, height=0)

        return {"txid": new_utxo["txid"], "wtxid": tx.getwtxid(), "hex": tx_hex, "tx": tx, "new_utxo": new_utxo}
예제 #16
0
    def test_desc_count_limits(self):
        """Create an 'A' shaped package with 24 transactions in the mempool and 2 in the package:
                    M1
                   ^  ^
                 M2a  M2b
                .       .
               .         .
              .           .
             M12a          ^
            ^              M13b
           ^                 ^
          Pa                  Pb
        The top ancestor in the package exceeds descendant limits but only if the in-mempool and in-package
        descendants are all considered together (24 including in-mempool descendants and 26 including both
        package transactions).
        """
        node = self.nodes[0]
        assert_equal(0, node.getmempoolinfo()["size"])
        self.log.info(
            "Check that in-mempool and in-package descendants are calculated properly in packages"
        )
        # Top parent in mempool, M1
        first_coin = self.coins.pop()
        parent_value = (first_coin["amount"] - Decimal("0.0002")
                        ) / 2  # Deduct reasonable fee and make 2 outputs
        inputs = [{"txid": first_coin["txid"], "vout": 0}]
        outputs = [{
            self.address: parent_value
        }, {
            ADDRESS_BCRT1_P2WSH_OP_TRUE: parent_value
        }]
        rawtx = node.createrawtransaction(inputs, outputs)

        parent_signed = node.signrawtransactionwithkey(hexstring=rawtx,
                                                       privkeys=self.privkeys)
        assert parent_signed["complete"]
        parent_tx = tx_from_hex(parent_signed["hex"])
        parent_txid = parent_tx.rehash()
        node.sendrawtransaction(parent_signed["hex"])

        package_hex = []

        # Chain A
        spk = parent_tx.vout[0].scriptPubKey.hex()
        value = parent_value
        txid = parent_txid
        for i in range(12):
            (tx, txhex, value, spk) = make_chain(node, self.address,
                                                 self.privkeys, txid, value, 0,
                                                 spk)
            txid = tx.rehash()
            if i < 11:  # M2a... M12a
                node.sendrawtransaction(txhex)
            else:  # Pa
                package_hex.append(txhex)

        # Chain B
        value = parent_value - Decimal("0.0001")
        rawtx_b = node.createrawtransaction([{
            "txid": parent_txid,
            "vout": 1
        }], {self.address: value})
        tx_child_b = tx_from_hex(rawtx_b)  # M2b
        tx_child_b.wit.vtxinwit = [CTxInWitness()]
        tx_child_b.wit.vtxinwit[0].scriptWitness.stack = [CScript([OP_TRUE])]
        tx_child_b_hex = tx_child_b.serialize().hex()
        node.sendrawtransaction(tx_child_b_hex)
        spk = tx_child_b.vout[0].scriptPubKey.hex()
        txid = tx_child_b.rehash()
        for i in range(12):
            (tx, txhex, value, spk) = make_chain(node, self.address,
                                                 self.privkeys, txid, value, 0,
                                                 spk)
            txid = tx.rehash()
            if i < 11:  # M3b... M13b
                node.sendrawtransaction(txhex)
            else:  # Pb
                package_hex.append(txhex)

        assert_equal(24, node.getmempoolinfo()["size"])
        assert_equal(2, len(package_hex))
        testres_too_long = node.testmempoolaccept(rawtxs=package_hex)
        for txres in testres_too_long:
            assert_equal(txres["package-error"], "package-mempool-limits")

        # Clear mempool and check that the package passes now
        self.generate(node, 1)
        assert all([
            res["allowed"]
            for res in node.testmempoolaccept(rawtxs=package_hex)
        ])
예제 #17
0
    def run_test(self):
        parent = self.nodes[0]
        #parent2 = self.nodes[1]
        sidechain = self.nodes[2]
        sidechain2 = self.nodes[3]

        # If we're testing post-transition, force a fedpegscript transition and
        # getting rid of old fedpegscript by making at least another epoch pass by
        WSH_OP_TRUE = self.nodes[0].decodescript("51")["segwit"]["hex"]
        # We just randomize the keys a bit to get another valid fedpegscript
        new_fedpegscript = sidechain.tweakfedpegscript("f00dbabe")["script"]
        if self.options.post_transition:
            print("Running test post-transition")
            for _ in range(30):
                block_hex = sidechain.getnewblockhex(
                    0, {
                        "signblockscript": WSH_OP_TRUE,
                        "max_block_witness": 10,
                        "fedpegscript": new_fedpegscript,
                        "extension_space": []
                    })
                sidechain.submitblock(block_hex)
            assert_equal(sidechain.getsidechaininfo()["current_fedpegscripts"],
                         [new_fedpegscript] * 2)

        if self.options.pre_transition:
            print(
                "Running test pre-transition, dynafed activated from first block"
            )

        for node in self.nodes:
            node.importprivkey(privkey=node.get_deterministic_priv_key().key,
                               label="mining")
        util.node_fastmerkle = sidechain

        parent.generate(101)
        sidechain.generate(101)
        self.log.info("sidechain info: {}".format(
            sidechain.getsidechaininfo()))

        addrs = sidechain.getpeginaddress()
        addr = addrs["mainchain_address"]
        assert_equal(
            sidechain.decodescript(addrs["claim_script"])["type"],
            "witness_v0_keyhash")
        txid1 = parent.sendtoaddress(addr, 24)
        vout = find_vout_for_address(parent, txid1, addr)
        # 10+2 confirms required to get into mempool and confirm
        assert_equal(sidechain.getsidechaininfo()["pegin_confirmation_depth"],
                     10)
        parent.generate(1)
        time.sleep(2)
        proof = parent.gettxoutproof([txid1])

        raw = parent.gettransaction(txid1)["hex"]

        # Create a wallet in order to test that multi-wallet support works correctly for claimpegin
        #   (Regression test for https://github.com/ElementsProject/elements/issues/812 .)
        sidechain.createwallet("throwaway")
        # Set up our sidechain RPCs to use the first wallet (with empty name). We do this by
        #   overriding the RPC object in a hacky way, to avoid breaking a different hack on TestNode
        #   that enables generate() to work despite the deprecation of the generate RPC.
        sidechain.rpc = sidechain.get_wallet_rpc("")

        print("Attempting peg-ins")
        # First attempt fails the consensus check but gives useful result
        try:
            pegtxid = sidechain.claimpegin(raw, proof)
            raise Exception(
                "Peg-in should not be mature enough yet, need another block.")
        except JSONRPCException as e:
            assert (
                "Peg-in Bitcoin transaction needs more confirmations to be sent."
                in e.error["message"])

        # Second attempt simply doesn't hit mempool bar
        parent.generate(10)
        try:
            pegtxid = sidechain.claimpegin(raw, proof)
            raise Exception(
                "Peg-in should not be mature enough yet, need another block.")
        except JSONRPCException as e:
            assert (
                "Peg-in Bitcoin transaction needs more confirmations to be sent."
                in e.error["message"])

        try:
            pegtxid = sidechain.createrawpegin(raw, proof, 'AEIOU')
            raise Exception("Peg-in with non-hex claim_script should fail.")
        except JSONRPCException as e:
            assert ("Given claim_script is not hex." in e.error["message"])

        # Should fail due to non-matching wallet address
        try:
            scriptpubkey = sidechain.getaddressinfo(
                get_new_unconfidential_address(sidechain))["scriptPubKey"]
            pegtxid = sidechain.claimpegin(raw, proof, scriptpubkey)
            raise Exception(
                "Peg-in with non-matching claim_script should fail.")
        except JSONRPCException as e:
            assert (
                "Given claim_script does not match the given Bitcoin transaction."
                in e.error["message"])

        # 12 confirms allows in mempool
        parent.generate(1)

        # Make sure that a tx with a duplicate pegin claim input gets rejected.
        raw_pegin = sidechain.createrawpegin(raw, proof)["hex"]
        raw_pegin = FromHex(CTransaction(), raw_pegin)
        raw_pegin.vin.append(raw_pegin.vin[0])  # duplicate the pegin input
        raw_pegin = sidechain.signrawtransactionwithwallet(
            bytes_to_hex_str(raw_pegin.serialize()))["hex"]
        assert_raises_rpc_error(-26, "bad-txns-inputs-duplicate",
                                sidechain.sendrawtransaction, raw_pegin)
        # Also try including this tx in a block manually and submitting it.
        doublespendblock = FromHex(CBlock(), sidechain.getnewblockhex())
        doublespendblock.vtx.append(FromHex(CTransaction(), raw_pegin))
        doublespendblock.hashMerkleRoot = doublespendblock.calc_merkle_root()
        add_witness_commitment(doublespendblock)
        doublespendblock.solve()
        block_hex = bytes_to_hex_str(doublespendblock.serialize(True))
        assert_raises_rpc_error(-25, "bad-txns-inputs-duplicate",
                                sidechain.testproposedblock, block_hex, True)

        # Should succeed via wallet lookup for address match, and when given
        raw_pegin = sidechain.createrawpegin(raw, proof)['hex']
        signed_pegin = sidechain.signrawtransactionwithwallet(raw_pegin)

        # Find the address that the peg-in used
        outputs = []
        for pegin_vout in sidechain.decoderawtransaction(raw_pegin)['vout']:
            if pegin_vout['scriptPubKey']['type'] == 'witness_v0_keyhash':
                outputs.append({
                    pegin_vout['scriptPubKey']['addresses'][0]:
                    pegin_vout['value']
                })
            elif pegin_vout['scriptPubKey']['type'] == 'fee':
                outputs.append({"fee": pegin_vout['value']})

        # Check the createrawtransaction makes the same unsigned peg-in transaction
        raw_pegin2 = sidechain.createrawtransaction(
            [{
                "txid": txid1,
                "vout": vout,
                "pegin_bitcoin_tx": raw,
                "pegin_txout_proof": proof,
                "pegin_claim_script": addrs["claim_script"]
            }], outputs)
        assert_equal(raw_pegin, raw_pegin2)
        # Check that createpsbt makes the correct unsigned peg-in
        pegin_psbt = sidechain.createpsbt(
            [{
                "txid": txid1,
                "vout": vout,
                "pegin_bitcoin_tx": raw,
                "pegin_txout_proof": proof,
                "pegin_claim_script": addrs["claim_script"]
            }], outputs)
        decoded_psbt = sidechain.decodepsbt(pegin_psbt)
        # Check that pegin_bitcoin_tx == raw, but due to stripping witnesses, we need to compare their txids
        txid1 = parent.decoderawtransaction(
            decoded_psbt['inputs'][0]['pegin_bitcoin_tx'])['txid']
        txid2 = parent.decoderawtransaction(raw)['txid']
        assert_equal(txid1, txid2)
        # Check the rest
        assert_equal(decoded_psbt['inputs'][0]['pegin_claim_script'],
                     addrs["claim_script"])
        assert_equal(decoded_psbt['inputs'][0]['pegin_txout_proof'], proof)
        assert_equal(decoded_psbt['inputs'][0]['pegin_genesis_hash'],
                     parent.getblockhash(0))
        # Make a psbt without those peg-in data and merge them
        merge_pegin_psbt = sidechain.createpsbt([{
            "txid": txid1,
            "vout": vout
        }], outputs)
        decoded_psbt = sidechain.decodepsbt(merge_pegin_psbt)
        assert 'pegin_bitcoin_tx' not in decoded_psbt['inputs'][0]
        assert 'pegin_claim_script' not in decoded_psbt['inputs'][0]
        assert 'pegin_txout_proof' not in decoded_psbt['inputs'][0]
        assert 'pegin_genesis_hash' not in decoded_psbt['inputs'][0]
        merged_pegin_psbt = sidechain.combinepsbt(
            [pegin_psbt, merge_pegin_psbt])
        assert_equal(pegin_psbt, merged_pegin_psbt)
        # Now sign the psbt
        signed_psbt = sidechain.walletsignpsbt(pegin_psbt)
        # Finalize and extract and compare
        fin_psbt = sidechain.finalizepsbt(signed_psbt['psbt'])
        assert_equal(fin_psbt, signed_pegin)

        # Try funding a psbt with the peg-in
        assert_equal(sidechain.getbalance()['bitcoin'], 50)
        out_bal = 0
        outputs.append({sidechain.getnewaddress(): 49.999})
        for out in outputs:
            for val in out.values():
                out_bal += Decimal(val)
        assert_greater_than(out_bal, 50)
        pegin_psbt = sidechain.walletcreatefundedpsbt(
            [{
                "txid": txid1,
                "vout": vout,
                "pegin_bitcoin_tx": raw,
                "pegin_txout_proof": proof,
                "pegin_claim_script": addrs["claim_script"]
            }], outputs)
        signed_psbt = sidechain.walletsignpsbt(pegin_psbt['psbt'])
        fin_psbt = sidechain.finalizepsbt(signed_psbt['psbt'])
        assert fin_psbt['complete']

        sample_pegin_struct = FromHex(CTransaction(), signed_pegin["hex"])
        # Round-trip peg-in transaction using python serialization
        assert_equal(signed_pegin["hex"],
                     bytes_to_hex_str(sample_pegin_struct.serialize()))
        # Store this for later (evil laugh)
        sample_pegin_witness = sample_pegin_struct.wit.vtxinwit[0].peginWitness

        pegtxid1 = sidechain.claimpegin(raw, proof)
        # Make sure a second pegin claim does not get accepted in the mempool when
        # another mempool tx already claims that pegin.
        assert_raises_rpc_error(-4, "txn-mempool-conflict",
                                sidechain.claimpegin, raw, proof)

        # Will invalidate the block that confirms this transaction later
        self.sync_all(self.node_groups)
        blockhash = sidechain2.generate(1)
        self.sync_all(self.node_groups)
        sidechain.generate(5)

        tx1 = sidechain.gettransaction(pegtxid1)

        if "confirmations" in tx1 and tx1["confirmations"] == 6:
            print("Peg-in is confirmed: Success!")
        else:
            raise Exception("Peg-in confirmation has failed.")

        # Look at pegin fields
        decoded = sidechain.decoderawtransaction(tx1["hex"])
        assert decoded["vin"][0]["is_pegin"] == True
        assert len(decoded["vin"][0]["pegin_witness"]) > 0
        # Check that there's sufficient fee for the peg-in
        vsize = decoded["vsize"]
        fee_output = decoded["vout"][1]
        fallbackfee_pervbyte = Decimal("0.00001") / Decimal("1000")
        assert fee_output["scriptPubKey"]["type"] == "fee"
        assert fee_output["value"] >= fallbackfee_pervbyte * vsize

        # Quick reorg checks of pegs
        sidechain.invalidateblock(blockhash[0])
        if sidechain.gettransaction(pegtxid1)["confirmations"] != 0:
            raise Exception(
                "Peg-in didn't unconfirm after invalidateblock call.")

        # Re-org causes peg-ins to get booted(wallet will resubmit in 10 minutes)
        assert_equal(sidechain.getrawmempool(), [])
        sidechain.sendrawtransaction(tx1["hex"])

        # Create duplicate claim, put it in block along with current one in mempool
        # to test duplicate-in-block claims between two txs that are in the same block.
        raw_pegin = sidechain.createrawpegin(raw, proof)["hex"]
        raw_pegin = sidechain.signrawtransactionwithwallet(raw_pegin)["hex"]
        raw_pegin = FromHex(CTransaction(), raw_pegin)
        doublespendblock = FromHex(CBlock(), sidechain.getnewblockhex())
        assert (len(doublespendblock.vtx) == 2)  # coinbase and pegin
        doublespendblock.vtx.append(raw_pegin)
        doublespendblock.hashMerkleRoot = doublespendblock.calc_merkle_root()
        add_witness_commitment(doublespendblock)
        doublespendblock.solve()
        block_hex = bytes_to_hex_str(doublespendblock.serialize(True))
        assert_raises_rpc_error(-25, "bad-txns-double-pegin",
                                sidechain.testproposedblock, block_hex, True)

        # Re-enters block
        sidechain.generate(1)
        if sidechain.gettransaction(pegtxid1)["confirmations"] != 1:
            raise Exception("Peg-in should have one confirm on side block.")
        sidechain.reconsiderblock(blockhash[0])
        if sidechain.gettransaction(pegtxid1)["confirmations"] != 6:
            raise Exception("Peg-in should be back to 6 confirms.")

        # Now the pegin is already claimed in a confirmed tx.
        # In that case, a duplicate claim should (1) not be accepted in the mempool
        # and (2) not be accepted in a block.
        assert_raises_rpc_error(-4, "pegin-already-claimed",
                                sidechain.claimpegin, raw, proof)
        # For case (2), manually craft a block and include the tx.
        doublespendblock = FromHex(CBlock(), sidechain.getnewblockhex())
        doublespendblock.vtx.append(raw_pegin)
        doublespendblock.hashMerkleRoot = doublespendblock.calc_merkle_root()
        add_witness_commitment(doublespendblock)
        doublespendblock.solve()
        block_hex = bytes_to_hex_str(doublespendblock.serialize(True))
        assert_raises_rpc_error(-25, "bad-txns-double-pegin",
                                sidechain.testproposedblock, block_hex, True)

        # Do multiple claims in mempool
        n_claims = 6

        print("Flooding mempool with a few claims")
        pegtxs = []
        sidechain.generate(101)

        # Do mixture of raw peg-in and automatic peg-in tx construction
        # where raw creation is done on another node
        for i in range(n_claims):
            addrs = sidechain.getpeginaddress()
            txid = parent.sendtoaddress(addrs["mainchain_address"], 1)
            parent.generate(1)
            proof = parent.gettxoutproof([txid])
            raw = parent.gettransaction(txid)["hex"]
            if i % 2 == 0:
                parent.generate(11)
                pegtxs += [sidechain.claimpegin(raw, proof)]
            else:
                # The raw API doesn't check for the additional 2 confirmation buffer
                # So we only get 10 confirms then send off. Miners will add to block anyways.

                # Don't mature whole way yet to test signing immature peg-in input
                parent.generate(8)
                # Wallet in sidechain2 gets funds instead of sidechain
                raw_pegin = sidechain2.createrawpegin(
                    raw, proof, addrs["claim_script"])["hex"]
                # First node should also be able to make a valid transaction with or without 3rd arg
                # since this wallet originated the claim_script itself
                sidechain.createrawpegin(raw, proof, addrs["claim_script"])
                sidechain.createrawpegin(raw, proof)
                signed_pegin = sidechain.signrawtransactionwithwallet(
                    raw_pegin)
                assert (signed_pegin["complete"])
                assert ("warning"
                        in signed_pegin)  # warning for immature peg-in
                # fully mature them now
                parent.generate(1)
                pegtxs += [sidechain.sendrawtransaction(signed_pegin["hex"])]

        self.sync_all(self.node_groups)
        sidechain2.generate(1)
        for i, pegtxid in enumerate(pegtxs):
            if i % 2 == 0:
                tx = sidechain.gettransaction(pegtxid)
            else:
                tx = sidechain2.gettransaction(pegtxid)
            if "confirmations" not in tx or tx["confirmations"] == 0:
                raise Exception("Peg-in confirmation has failed.")

        print("Test pegouts")
        self.test_pegout(get_new_unconfidential_address(parent, "legacy"),
                         sidechain)
        self.test_pegout(get_new_unconfidential_address(parent, "p2sh-segwit"),
                         sidechain)
        self.test_pegout(get_new_unconfidential_address(parent, "bech32"),
                         sidechain)

        print("Test pegout P2SH")
        parent_chain_addr = get_new_unconfidential_address(parent)
        parent_pubkey = parent.getaddressinfo(parent_chain_addr)["pubkey"]
        parent_chain_p2sh_addr = parent.createmultisig(
            1, [parent_pubkey])["address"]
        self.test_pegout(parent_chain_p2sh_addr, sidechain)

        print("Test pegout Garbage")
        parent_chain_addr = "garbage"
        try:
            self.test_pegout(parent_chain_addr, sidechain)
            raise Exception("A garbage address should fail.")
        except JSONRPCException as e:
            assert ("Invalid Bitcoin address" in e.error["message"])

        print("Test pegout Garbage valid")
        prev_txid = sidechain.sendtoaddress(sidechain.getnewaddress(), 1)
        sidechain.generate(1)
        pegout_chain = 'a' * 64
        pegout_hex = 'b' * 500
        inputs = [{"txid": prev_txid, "vout": 0}]
        outputs = {"vdata": [pegout_chain, pegout_hex]}
        rawtx = sidechain.createrawtransaction(inputs, outputs)
        raw_pegout = sidechain.decoderawtransaction(rawtx)

        assert 'vout' in raw_pegout and len(raw_pegout['vout']) > 0
        pegout_tested = False
        for output in raw_pegout['vout']:
            scriptPubKey = output['scriptPubKey']
            if 'type' in scriptPubKey and scriptPubKey['type'] == 'nulldata':
                assert ('pegout_hex' in scriptPubKey
                        and 'pegout_asm' in scriptPubKey
                        and 'pegout_type' in scriptPubKey)
                assert ('pegout_chain' in scriptPubKey
                        and 'pegout_reqSigs' not in scriptPubKey
                        and 'pegout_addresses' not in scriptPubKey)
                assert scriptPubKey['pegout_type'] == 'nonstandard'
                assert scriptPubKey['pegout_chain'] == pegout_chain
                assert scriptPubKey['pegout_hex'] == pegout_hex
                pegout_tested = True
                break
        assert pegout_tested

        print(
            "Now test failure to validate peg-ins based on intermittent bitcoind rpc failure"
        )
        self.stop_node(1)
        txid = parent.sendtoaddress(addr, 1)
        parent.generate(12)
        proof = parent.gettxoutproof([txid])
        raw = parent.gettransaction(txid)["hex"]
        sidechain.claimpegin(raw, proof)  # stuck peg
        sidechain.generate(1)
        print("Waiting to ensure block is being rejected by sidechain2")
        time.sleep(5)

        assert (sidechain.getblockcount() != sidechain2.getblockcount())

        print("Restarting parent2")
        self.start_node(1)
        connect_nodes_bi(self.nodes, 0, 1)

        # Don't make a block, race condition when pegin-invalid block
        # is awaiting further validation, nodes reject subsequent blocks
        # even ones they create
        print(
            "Now waiting for node to re-evaluate peg-in witness failed block... should take a few seconds"
        )
        self.sync_all(self.node_groups)
        print("Completed!\n")
        print("Now send funds out in two stages, partial, and full")
        some_btc_addr = get_new_unconfidential_address(parent)
        bal_1 = sidechain.getwalletinfo()["balance"]['bitcoin']
        try:
            sidechain.sendtomainchain(some_btc_addr, bal_1 + 1)
            raise Exception("Sending out too much; should have failed")
        except JSONRPCException as e:
            assert ("Insufficient funds" in e.error["message"])

        assert (sidechain.getwalletinfo()["balance"]["bitcoin"] == bal_1)
        try:
            sidechain.sendtomainchain(some_btc_addr + "b", bal_1 - 1)
            raise Exception("Sending to invalid address; should have failed")
        except JSONRPCException as e:
            assert ("Invalid Bitcoin address" in e.error["message"])

        assert (sidechain.getwalletinfo()["balance"]["bitcoin"] == bal_1)
        try:
            sidechain.sendtomainchain("1Nro9WkpaKm9axmcfPVp79dAJU1Gx7VmMZ",
                                      bal_1 - 1)
            raise Exception(
                "Sending to mainchain address when should have been testnet; should have failed"
            )
        except JSONRPCException as e:
            assert ("Invalid Bitcoin address" in e.error["message"])

        assert (sidechain.getwalletinfo()["balance"]["bitcoin"] == bal_1)

        # Test superfluous peg-in witness data on regular spend before we have no funds
        raw_spend = sidechain.createrawtransaction(
            [], {sidechain.getnewaddress(): 1})
        fund_spend = sidechain.fundrawtransaction(raw_spend)
        sign_spend = sidechain.signrawtransactionwithwallet(fund_spend["hex"])
        signed_struct = FromHex(CTransaction(), sign_spend["hex"])
        # Non-witness tx has no witness serialized yet
        if len(signed_struct.wit.vtxinwit) == 0:
            signed_struct.wit.vtxinwit = [CTxInWitness()]
        signed_struct.wit.vtxinwit[
            0].peginWitness.stack = sample_pegin_witness.stack
        assert_equal(
            sidechain.testmempoolaccept(
                [bytes_to_hex_str(signed_struct.serialize())])[0]["allowed"],
            False)
        assert_equal(
            sidechain.testmempoolaccept([
                bytes_to_hex_str(signed_struct.serialize())
            ])[0]["reject-reason"], "68: extra-pegin-witness")
        signed_struct.wit.vtxinwit[0].peginWitness.stack = [b'\x00' * 100000
                                                            ]  # lol
        assert_equal(
            sidechain.testmempoolaccept(
                [bytes_to_hex_str(signed_struct.serialize())])[0]["allowed"],
            False)
        assert_equal(
            sidechain.testmempoolaccept([
                bytes_to_hex_str(signed_struct.serialize())
            ])[0]["reject-reason"], "68: extra-pegin-witness")

        peg_out_txid = sidechain.sendtomainchain(some_btc_addr, 1)

        peg_out_details = sidechain.decoderawtransaction(
            sidechain.getrawtransaction(peg_out_txid))
        # peg-out, change, fee
        assert (len(peg_out_details["vout"]) == 3)
        found_pegout_value = False
        for output in peg_out_details["vout"]:
            if "value" in output and output["value"] == 1:
                found_pegout_value = True
        assert (found_pegout_value)

        bal_2 = sidechain.getwalletinfo()["balance"]["bitcoin"]
        # Make sure balance went down
        assert (bal_2 + 1 < bal_1)

        # Send rest of coins using subtractfee from output arg
        sidechain.sendtomainchain(some_btc_addr, bal_2, True)

        assert (sidechain.getwalletinfo()["balance"]['bitcoin'] == 0)

        print('Test coinbase peg-in maturity rules')

        # Have bitcoin output go directly into a claim output
        pegin_info = sidechain.getpeginaddress()
        mainchain_addr = pegin_info["mainchain_address"]
        # Watch the address so we can get tx without txindex
        parent.importaddress(mainchain_addr)
        claim_block = parent.generatetoaddress(50, mainchain_addr)[0]
        self.sync_all(self.node_groups)
        block_coinbase = parent.getblock(claim_block, 2)["tx"][0]
        claim_txid = block_coinbase["txid"]
        claim_tx = block_coinbase["hex"]
        claim_proof = parent.gettxoutproof([claim_txid], claim_block)

        # Can't claim something even though it has 50 confirms since it's coinbase
        assert_raises_rpc_error(
            -8,
            "Peg-in Bitcoin transaction needs more confirmations to be sent.",
            sidechain.claimpegin, claim_tx, claim_proof)
        # If done via raw API, still doesn't work
        coinbase_pegin = sidechain.createrawpegin(claim_tx, claim_proof)
        assert_equal(coinbase_pegin["mature"], False)
        signed_pegin = sidechain.signrawtransactionwithwallet(
            coinbase_pegin["hex"])["hex"]
        assert_raises_rpc_error(
            -26, "bad-pegin-witness, Needs more confirmations.",
            sidechain.sendrawtransaction, signed_pegin)

        # 50 more blocks to allow wallet to make it succeed by relay and consensus
        parent.generatetoaddress(50, parent.getnewaddress())
        self.sync_all(self.node_groups)
        # Wallet still doesn't want to for 2 more confirms
        assert_equal(
            sidechain.createrawpegin(claim_tx, claim_proof)["mature"], False)
        # But we can just shoot it off
        claim_txid = sidechain.sendrawtransaction(signed_pegin)
        sidechain.generatetoaddress(1, sidechain.getnewaddress())
        self.sync_all(self.node_groups)
        assert_equal(sidechain.gettransaction(claim_txid)["confirmations"], 1)

        # Test a confidential pegin.
        print("Performing a confidential pegin.")
        # start pegin
        pegin_addrs = sidechain.getpeginaddress()
        assert_equal(
            sidechain.decodescript(pegin_addrs["claim_script"])["type"],
            "witness_v0_keyhash")
        pegin_addr = addrs["mainchain_address"]
        txid_fund = parent.sendtoaddress(pegin_addr, 10)
        # 10+2 confirms required to get into mempool and confirm
        parent.generate(11)
        self.sync_all(self.node_groups)
        proof = parent.gettxoutproof([txid_fund])
        raw = parent.gettransaction(txid_fund)["hex"]
        raw_pegin = sidechain.createrawpegin(raw, proof)['hex']
        pegin = FromHex(CTransaction(), raw_pegin)
        # add new blinding pubkey for the pegin output
        pegin.vout[0].nNonce = CTxOutNonce(
            hex_str_to_bytes(
                sidechain.getaddressinfo(sidechain.getnewaddress(
                    "", "blech32"))["confidential_key"]))
        # now add an extra input and output from listunspent; we need a blinded output for this
        blind_addr = sidechain.getnewaddress("", "blech32")
        sidechain.sendtoaddress(blind_addr, 15)
        sidechain.generate(6)
        # Make sure sidechain2 knows about the same input
        self.sync_all(self.node_groups)
        unspent = [
            u for u in sidechain.listunspent(6, 6) if u["amount"] == 15
        ][0]
        assert (unspent["spendable"])
        assert ("amountcommitment" in unspent)
        pegin.vin.append(
            CTxIn(COutPoint(int(unspent["txid"], 16), unspent["vout"])))
        # insert corresponding output before fee output
        new_destination = sidechain.getaddressinfo(
            sidechain.getnewaddress("", "blech32"))
        new_dest_script_pk = hex_str_to_bytes(new_destination["scriptPubKey"])
        new_dest_nonce = CTxOutNonce(
            hex_str_to_bytes(new_destination["confidential_key"]))
        new_dest_asset = pegin.vout[0].nAsset
        pegin.vout.insert(
            1,
            CTxOut(
                int(unspent["amount"] * COIN) - 10000, new_dest_script_pk,
                new_dest_asset, new_dest_nonce))
        # add the 10 ksat fee
        pegin.vout[2].nValue.setToAmount(pegin.vout[2].nValue.getAmount() +
                                         10000)
        pegin_hex = ToHex(pegin)
        # test with both blindraw and rawblindraw
        raw_pegin_blinded1 = sidechain.blindrawtransaction(pegin_hex)
        raw_pegin_blinded2 = sidechain.rawblindrawtransaction(
            pegin_hex, ["", unspent["amountblinder"]], [10, 15],
            [unspent["asset"]] * 2, ["", unspent["assetblinder"]], "", False)
        pegin_signed1 = sidechain.signrawtransactionwithwallet(
            raw_pegin_blinded1)
        pegin_signed2 = sidechain.signrawtransactionwithwallet(
            raw_pegin_blinded2)
        for pegin_signed in [pegin_signed1, pegin_signed2]:
            final_decoded = sidechain.decoderawtransaction(pegin_signed["hex"])
            assert (final_decoded["vin"][0]["is_pegin"])
            assert (not final_decoded["vin"][1]["is_pegin"])
            assert ("assetcommitment" in final_decoded["vout"][0])
            assert ("valuecommitment" in final_decoded["vout"][0])
            assert ("commitmentnonce" in final_decoded["vout"][0])
            assert ("value" not in final_decoded["vout"][0])
            assert ("asset" not in final_decoded["vout"][0])
            assert (final_decoded["vout"][0]["commitmentnonce_fully_valid"])
            assert ("assetcommitment" in final_decoded["vout"][1])
            assert ("valuecommitment" in final_decoded["vout"][1])
            assert ("commitmentnonce" in final_decoded["vout"][1])
            assert ("value" not in final_decoded["vout"][1])
            assert ("asset" not in final_decoded["vout"][1])
            assert (final_decoded["vout"][1]["commitmentnonce_fully_valid"])
            assert ("value" in final_decoded["vout"][2])
            assert ("asset" in final_decoded["vout"][2])
            # check that it is accepted in either mempool
            accepted = sidechain.testmempoolaccept([pegin_signed["hex"]])[0]
            if not accepted["allowed"]:
                raise Exception(accepted["reject-reason"])
            accepted = sidechain2.testmempoolaccept([pegin_signed["hex"]])[0]
            if not accepted["allowed"]:
                raise Exception(accepted["reject-reason"])
            print("Blinded transaction looks ok!"
                  )  # need this print to distinguish failures in for loop

        print('Success!')

        # Manually stop sidechains first, then the parent chains.
        self.stop_node(2)
        self.stop_node(3)
        self.stop_node(0)
        self.stop_node(1)
예제 #18
0
    def tapscript_satisfy_test(self,
                               script,
                               inputs=[],
                               add_issuance=False,
                               add_pegin=False,
                               fail=None,
                               add_prevout=False,
                               add_asset=False,
                               add_value=False,
                               add_spk=False,
                               seq=0,
                               add_out_spk=None,
                               add_out_asset=None,
                               add_out_value=None,
                               add_out_nonce=None,
                               ver=2,
                               locktime=0,
                               add_num_outputs=False,
                               add_weight=False,
                               blind=False):
        # Create a taproot utxo
        scripts = [("s0", script)]
        prev_tx, prev_vout, spk, sec, pub, tap = self.create_taproot_utxo(
            scripts)

        if add_pegin:
            fund_info = self.nodes[0].getpeginaddress()
            peg_id = self.nodes[0].sendtoaddress(
                fund_info["mainchain_address"], 1)
            raw_peg_tx = self.nodes[0].gettransaction(peg_id)["hex"]
            peg_txid = self.nodes[0].sendrawtransaction(raw_peg_tx)
            self.nodes[0].generate(101)
            peg_prf = self.nodes[0].gettxoutproof([peg_txid])
            claim_script = fund_info["claim_script"]

            raw_claim = self.nodes[0].createrawpegin(raw_peg_tx, peg_prf,
                                                     claim_script)
            tx = FromHex(CTransaction(), raw_claim['hex'])
        else:
            tx = CTransaction()

        tx.nVersion = ver
        tx.nLockTime = locktime
        # Spend the pegin and taproot tx together
        in_total = prev_tx.vout[prev_vout].nValue.getAmount()
        fees = 1000
        tap_in_pos = 0

        if blind:
            # Add an unrelated output
            key = ECKey()
            key.generate()
            tx.vout.append(
                CTxOut(nValue=CTxOutValue(10000),
                       scriptPubKey=spk,
                       nNonce=CTxOutNonce(key.get_pubkey().get_bytes())))

            tx_hex = self.nodes[0].fundrawtransaction(tx.serialize().hex())
            tx = FromHex(CTransaction(), tx_hex['hex'])

        tx.vin.append(
            CTxIn(COutPoint(prev_tx.sha256, prev_vout), nSequence=seq))
        tx.vout.append(
            CTxOut(nValue=CTxOutValue(in_total - fees),
                   scriptPubKey=spk))  # send back to self
        tx.vout.append(CTxOut(CTxOutValue(fees)))

        if add_issuance:
            blind_addr = self.nodes[0].getnewaddress()
            issue_addr = self.nodes[0].validateaddress(
                blind_addr)['unconfidential']
            # Issuances only require one fee output and that output must the last
            # one. However the way, the current code is structured, it is not possible
            # to this in a super clean without special casing.
            if add_pegin:
                tx.vout.pop()
                tx.vout.pop()
                tx.vout.insert(0,
                               CTxOut(nValue=CTxOutValue(in_total),
                                      scriptPubKey=spk))  # send back to self)
            issued_tx = self.nodes[0].rawissueasset(
                tx.serialize().hex(), [{
                    "asset_amount": 2,
                    "asset_address": issue_addr,
                    "blind": False
                }])[0]["hex"]
            tx = FromHex(CTransaction(), issued_tx)
        # Sign inputs
        if add_pegin:
            signed = self.nodes[0].signrawtransactionwithwallet(
                tx.serialize().hex())
            tx = FromHex(CTransaction(), signed['hex'])
            tap_in_pos += 1
        else:
            # Need to create empty witness when not deserializing from rpc
            tx.wit.vtxinwit.append(CTxInWitness())

        if blind:
            tx.vin[0], tx.vin[1] = tx.vin[1], tx.vin[0]
            utxo = self.get_utxo(tx, 1)
            zero_str = "0" * 64
            blinded_raw = self.nodes[0].rawblindrawtransaction(
                tx.serialize().hex(), [zero_str, utxo["amountblinder"]],
                [1.2, utxo['amount']], [utxo['asset'], utxo['asset']],
                [zero_str, utxo['assetblinder']])
            tx = FromHex(CTransaction(), blinded_raw)
            signed_raw_tx = self.nodes[0].signrawtransactionwithwallet(
                tx.serialize().hex())
            tx = FromHex(CTransaction(), signed_raw_tx['hex'])

        suffix_annex = []
        control_block = bytes([
            tap.leaves["s0"].version + tap.negflag
        ]) + tap.inner_pubkey + tap.leaves["s0"].merklebranch
        # Add the prevout to the top of inputs. The witness script will check for equality.
        if add_prevout:
            inputs = [
                prev_vout.to_bytes(4, 'little'),
                ser_uint256(prev_tx.sha256)
            ]
        if add_asset:
            assert blind  # only used with blinding in testing
            utxo = self.nodes[0].gettxout(
                ser_uint256(tx.vin[1].prevout.hash)[::-1].hex(),
                tx.vin[1].prevout.n)
            if "assetcommitment" in utxo:
                asset = bytes.fromhex(utxo["assetcommitment"])
            else:
                asset = b"\x01" + bytes.fromhex(utxo["asset"])[::-1]
            inputs = [asset[0:1], asset[1:33]]
        if add_value:
            utxo = self.nodes[0].gettxout(
                ser_uint256(tx.vin[1].prevout.hash)[::-1].hex(),
                tx.vin[1].prevout.n)
            if "valuecommitment" in utxo:
                value = bytes.fromhex(utxo["valuecommitment"])
                inputs = [value[0:1], value[1:33]]
            else:
                value = b"\x01" + int(
                    satoshi_round(utxo["value"]) * COIN).to_bytes(8, 'little')
                inputs = [value[0:1], value[1:9]]
        if add_spk:
            ver = CScriptOp.decode_op_n(int.from_bytes(spk[0:1], 'little'))
            inputs = [CScriptNum.encode(CScriptNum(ver))[1:],
                      spk[2:len(spk)]]  # always segwit

        # Add witness for outputs
        if add_out_asset is not None:
            asset = tx.vout[add_out_asset].nAsset.vchCommitment
            inputs = [asset[0:1], asset[1:33]]
        if add_out_value is not None:
            value = tx.vout[add_out_value].nValue.vchCommitment
            if len(value) == 9:
                inputs = [value[0:1], value[1:9][::-1]]
            else:
                inputs = [value[0:1], value[1:33]]
        if add_out_nonce is not None:
            nonce = tx.vout[add_out_nonce].nNonce.vchCommitment
            if len(nonce) == 1:
                inputs = [b'']
            else:
                inputs = [nonce]
        if add_out_spk is not None:
            out_spk = tx.vout[add_out_spk].scriptPubKey
            if len(out_spk) == 0:
                # Python upstream encoding CScriptNum interesting behaviour where it also encodes the length
                # This assumes the implicit wallet behaviour of using segwit outputs.
                # This is useful while sending scripts, but not while using CScriptNums in constructing scripts
                inputs = [
                    CScriptNum.encode(CScriptNum(-1))[1:],
                    sha256(out_spk)
                ]
            else:
                ver = CScriptOp.decode_op_n(
                    int.from_bytes(out_spk[0:1], 'little'))
                inputs = [
                    CScriptNum.encode(CScriptNum(ver))[1:],
                    out_spk[2:len(out_spk)]
                ]  # always segwit
        if add_num_outputs:
            num_outs = len(tx.vout)
            inputs = [CScriptNum.encode(CScriptNum(num_outs))[1:]]
        if add_weight:
            # Add a dummy input and check the overall weight
            inputs = [int(5).to_bytes(8, 'little')]
            wit = inputs + [bytes(tap.leaves["s0"].script), control_block
                            ] + suffix_annex
            tx.wit.vtxinwit[tap_in_pos].scriptWitness.stack = wit

            exp_weight = self.nodes[0].decoderawtransaction(
                tx.serialize().hex())["weight"]
            inputs = [exp_weight.to_bytes(8, 'little')]
        wit = inputs + [bytes(tap.leaves["s0"].script), control_block
                        ] + suffix_annex
        tx.wit.vtxinwit[tap_in_pos].scriptWitness.stack = wit

        if fail:
            assert_raises_rpc_error(-26, fail,
                                    self.nodes[0].sendrawtransaction,
                                    tx.serialize().hex())
            return

        self.nodes[0].sendrawtransaction(hexstring=tx.serialize().hex())
        self.nodes[0].generate(1)
        last_blk = self.nodes[0].getblock(self.nodes[0].getbestblockhash())
        tx.rehash()
        assert (tx.hash in last_blk['tx'])
예제 #19
0
파일: p2p_segwit2.py 프로젝트: ndb88/ain
    def test_witness_block_size(self):
        # TODO: Test that non-witness carrying blocks can't exceed 1MB
        # Skipping this test for now; this is covered in p2p-fullblocktest.py

        # Test that witness-bearing blocks are limited at ceil(base + wit/4) <= 1MB.
        block = self.build_next_block()

        assert len(self.utxo) > 0

        # Create a P2WSH transaction.
        # The witness program will be a bunch of OP_2DROP's, followed by OP_TRUE.
        # This should give us plenty of room to tweak the spending tx's
        # virtual size.
        NUM_DROPS = 200  # 201 max ops per script!
        NUM_OUTPUTS = 50

        witness_program = CScript([OP_2DROP] * NUM_DROPS + [OP_TRUE])
        witness_hash = uint256_from_str(sha256(witness_program))
        script_pubkey = CScript([OP_0, ser_uint256(witness_hash)])

        prevout = COutPoint(self.utxo[0].sha256, self.utxo[0].n)
        value = self.utxo[0].nValue

        parent_tx = CTransaction()
        parent_tx.vin.append(CTxIn(prevout, b""))
        child_value = int(value / NUM_OUTPUTS)
        for i in range(NUM_OUTPUTS):
            parent_tx.vout.append(CTxOut(child_value, script_pubkey))
        parent_tx.vout[0].nValue -= 50000
        assert parent_tx.vout[0].nValue > 0
        parent_tx.rehash()

        filler_size = 3150
        child_tx = CTransaction()
        for i in range(NUM_OUTPUTS):
            child_tx.vin.append(CTxIn(COutPoint(parent_tx.sha256, i), b""))
        child_tx.vout = [CTxOut(value - 100000, CScript([OP_TRUE]))]
        for i in range(NUM_OUTPUTS):
            child_tx.wit.vtxinwit.append(CTxInWitness())
            child_tx.wit.vtxinwit[-1].scriptWitness.stack = [
                b'a' * filler_size
            ] * (2 * NUM_DROPS) + [witness_program]
        child_tx.rehash()
        self.update_witness_block_with_transactions(block,
                                                    [parent_tx, child_tx])

        vsize = get_virtual_size(block)
        assert_greater_than(MAX_BLOCK_BASE_SIZE, vsize)
        additional_bytes = (MAX_BLOCK_BASE_SIZE - vsize) * 4
        i = 0
        while additional_bytes > 0:
            # Add some more bytes to each input until we hit MAX_BLOCK_BASE_SIZE+1
            extra_bytes = min(additional_bytes + 1, 55)
            block.vtx[-1].wit.vtxinwit[int(
                i / (2 * NUM_DROPS))].scriptWitness.stack[
                    i % (2 * NUM_DROPS)] = b'a' * (filler_size + extra_bytes)
            additional_bytes -= extra_bytes
            i += 1

        block.vtx[0].vout.pop()  # Remove old commitment
        add_witness_commitment(block)
        block.solve()
        vsize = get_virtual_size(block)
        assert_equal(vsize, MAX_BLOCK_BASE_SIZE + 1)
        # Make sure that our test case would exceed the old max-network-message
        # limit
        assert len(block.serialize()) > 2 * 1024 * 1024

        test_witness_block(self.nodes[0],
                           self.test_node,
                           block,
                           accepted=False)

        # Now resize the second transaction to make the block fit.
        cur_length = len(block.vtx[-1].wit.vtxinwit[0].scriptWitness.stack[0])
        block.vtx[-1].wit.vtxinwit[0].scriptWitness.stack[0] = b'a' * (
            cur_length - 1)
        block.vtx[0].vout.pop()
        add_witness_commitment(block)
        block.solve()
        assert get_virtual_size(block) == MAX_BLOCK_BASE_SIZE

        test_witness_block(self.nodes[0], self.test_node, block, accepted=True)

        # Update available utxo's
        self.utxo.pop(0)
        self.utxo.append(
            UTXO(block.vtx[-1].sha256, 0, block.vtx[-1].vout[0].nValue))
예제 #20
0
    def run_test(self):
        node = self.nodes[0]

        self.log.info('Start with empty mempool and 101 blocks')
        # The last 100 coinbase transactions are premature
        blockhash = node.generate(101)[0]
        txid = node.getblock(blockhash=blockhash, verbosity=2)["tx"][0]["txid"]
        assert_equal(node.getmempoolinfo()['size'], 0)

        self.log.info("Submit parent with multiple script branches to mempool")
        hashlock = hash160(b'Preimage')
        witness_script = CScript([
            OP_IF, OP_HASH160, hashlock, OP_EQUAL, OP_ELSE, OP_TRUE, OP_ENDIF
        ])
        witness_program = sha256(witness_script)
        script_pubkey = CScript([OP_0, witness_program])

        parent = CTransaction()
        parent.vin.append(CTxIn(COutPoint(int(txid, 16), 0), b""))
        parent.vout.append(CTxOut(int(9.99998 * COIN), script_pubkey))
        parent.rehash()

        privkeys = [node.get_deterministic_priv_key().key]
        raw_parent = node.signrawtransactionwithkey(
            hexstring=parent.serialize().hex(), privkeys=privkeys)['hex']
        parent_txid = node.sendrawtransaction(hexstring=raw_parent,
                                              maxfeerate=0)
        node.generate(1)

        peer_wtxid_relay = node.add_p2p_connection(P2PTxInvStore())

        # Create a new transaction with witness solving first branch
        child_witness_script = CScript([OP_TRUE])
        child_witness_program = sha256(child_witness_script)
        child_script_pubkey = CScript([OP_0, child_witness_program])

        child_one = CTransaction()
        child_one.vin.append(CTxIn(COutPoint(int(parent_txid, 16), 0), b""))
        child_one.vout.append(CTxOut(int(9.99996 * COIN), child_script_pubkey))
        child_one.wit.vtxinwit.append(CTxInWitness())
        child_one.wit.vtxinwit[0].scriptWitness.stack = [
            b'Preimage', b'\x01', witness_script
        ]
        child_one_wtxid = child_one.getwtxid()
        child_one_txid = child_one.rehash()

        # Create another identical transaction with witness solving second branch
        child_two = deepcopy(child_one)
        child_two.wit.vtxinwit[0].scriptWitness.stack = [b'', witness_script]
        child_two_wtxid = child_two.getwtxid()
        child_two_txid = child_two.rehash()

        assert_equal(child_one_txid, child_two_txid)
        assert child_one_wtxid != child_two_wtxid

        self.log.info("Submit child_one to the mempool")
        txid_submitted = node.sendrawtransaction(child_one.serialize().hex())
        assert_equal(
            node.getrawmempool(True)[txid_submitted]['wtxid'], child_one_wtxid)

        peer_wtxid_relay.wait_for_broadcast([child_one_wtxid])
        assert_equal(node.getmempoolinfo()["unbroadcastcount"], 0)

        # testmempoolaccept reports the "already in mempool" error
        assert_equal(node.testmempoolaccept([child_one.serialize().hex()]),
                     [{
                         "txid": child_one_txid,
                         "wtxid": child_one_wtxid,
                         "allowed": False,
                         "reject-reason": "txn-already-in-mempool"
                     }])
        assert_equal(
            node.testmempoolaccept([child_two.serialize().hex()])[0], {
                "txid": child_two_txid,
                "wtxid": child_two_wtxid,
                "allowed": False,
                "reject-reason": "txn-same-nonwitness-data-in-mempool"
            })

        # sendrawtransaction will not throw but quits early when the exact same transaction is already in mempool
        node.sendrawtransaction(child_one.serialize().hex())

        self.log.info("Connect another peer that hasn't seen child_one before")
        peer_wtxid_relay_2 = node.add_p2p_connection(P2PTxInvStore())

        self.log.info("Submit child_two to the mempool")
        # sendrawtransaction will not throw but quits early when a transaction with the same non-witness data is already in mempool
        node.sendrawtransaction(child_two.serialize().hex())

        # The node should rebroadcast the transaction using the wtxid of the correct transaction
        # (child_one, which is in its mempool).
        peer_wtxid_relay_2.wait_for_broadcast([child_one_wtxid])
        assert_equal(node.getmempoolinfo()["unbroadcastcount"], 0)
    def run_test(self):

        print("Testing wallet secret recovery")
        self.test_wallet_recovery()

        print("General Confidential tests")
        # Running balances
        node0 = self.nodes[0].getbalance()["bitcoin"]
        assert_equal(node0,
                     21000000)  # just making sure initialfreecoins is working
        node1 = 0
        node2 = 0

        self.nodes[0].generate(101)
        txid = self.nodes[0].sendtoaddress(self.nodes[0].getnewaddress(),
                                           node0, "", "", True)
        self.nodes[0].generate(101)
        self.sync_all()
        assert_equal(self.nodes[0].getbalance()["bitcoin"], node0)
        assert_equal(self.nodes[1].getbalance("*", 1, False, "bitcoin"), node1)
        assert_equal(self.nodes[2].getbalance("*", 1, False, "bitcoin"), node2)

        # Send 3 BTC from 0 to a new unconfidential address of 2 with
        # the sendtoaddress call
        address = self.nodes[2].getnewaddress()
        unconfidential_address = self.nodes[2].validateaddress(
            address)["unconfidential"]
        value0 = 3
        self.nodes[0].sendtoaddress(unconfidential_address, value0)
        self.nodes[0].generate(101)
        self.sync_all()

        node0 = node0 - value0
        node2 = node2 + value0

        assert_equal(self.nodes[0].getbalance()["bitcoin"], node0)
        assert_equal(self.nodes[1].getbalance("*", 1, False, "bitcoin"), node1)
        assert_equal(self.nodes[2].getbalance()["bitcoin"], node2)

        # Send 5 BTC from 0 to a new address of 2 with the sendtoaddress call
        address2 = self.nodes[2].getnewaddress()
        unconfidential_address2 = self.nodes[2].validateaddress(
            address2)["unconfidential"]
        value1 = 5
        confidential_tx_id = self.nodes[0].sendtoaddress(address2, value1)
        self.nodes[0].generate(101)
        self.sync_all()

        node0 = node0 - value1
        node2 = node2 + value1

        assert_equal(self.nodes[0].getbalance()["bitcoin"], node0)
        assert_equal(self.nodes[1].getbalance("*", 1, False, "bitcoin"), node1)
        assert_equal(self.nodes[2].getbalance()["bitcoin"], node2)

        # Send 7 BTC from 0 to the unconfidential address of 2 and 11 BTC to the
        # confidential address using the raw transaction interface
        change_address = self.nodes[0].getnewaddress()
        value2 = 7
        value3 = 11
        value23 = value2 + value3
        unspent = self.nodes[0].listunspent(1, 9999999, [], True,
                                            {"asset": "bitcoin"})
        unspent = [i for i in unspent if i['amount'] > value23]
        assert_equal(len(unspent), 1)
        fee = Decimal('0.0001')
        tx = self.nodes[0].createrawtransaction(
            [{
                "txid": unspent[0]["txid"],
                "vout": unspent[0]["vout"],
                "nValue": unspent[0]["amount"]
            }], {
                unconfidential_address: value2,
                address2: value3,
                change_address: unspent[0]["amount"] - value2 - value3 - fee,
                "fee": fee
            })
        tx = self.nodes[0].blindrawtransaction(tx)
        tx_signed = self.nodes[0].signrawtransactionwithwallet(tx)
        raw_tx_id = self.nodes[0].sendrawtransaction(tx_signed['hex'])
        self.nodes[0].generate(101)
        self.sync_all()

        node0 -= (value2 + value3)
        node2 += value2 + value3

        assert_equal(self.nodes[0].getbalance()["bitcoin"], node0)
        assert_equal(self.nodes[1].getbalance("*", 1, False, "bitcoin"), node1)
        assert_equal(self.nodes[2].getbalance()["bitcoin"], node2)

        # Check 2's listreceivedbyaddress
        received_by_address = self.nodes[2].listreceivedbyaddress(
            0, False, False, "", "bitcoin")
        validate_by_address = [(address2, {
            "bitcoin": value1 + value3
        }), (address, {
            "bitcoin": value0 + value2
        })]
        assert_equal(
            sorted([(ele['address'], ele['amount'])
                    for ele in received_by_address],
                   key=lambda t: t[0]),
            sorted(validate_by_address, key=lambda t: t[0]))

        # Give an auditor (node 1) a blinding key to allow her to look at
        # transaction values
        self.nodes[1].importaddress(address2)
        received_by_address = self.nodes[1].listreceivedbyaddress(
            1, False, True)
        #Node sees nothing unless it understands the values
        assert_equal(len(received_by_address), 0)
        assert_equal(
            len(self.nodes[1].listunspent(1, 9999999, [], True,
                                          {"asset": "bitcoin"})), 0)

        # Import the blinding key
        blindingkey = self.nodes[2].dumpblindingkey(address2)
        self.nodes[1].importblindingkey(address2, blindingkey)
        # Check the auditor's gettransaction and listreceivedbyaddress
        # Needs rescan to update wallet txns
        conf_tx = self.nodes[1].gettransaction(confidential_tx_id, True)
        assert_equal(conf_tx['amount']["bitcoin"], value1)

        # Make sure wallet can now deblind part of transaction
        deblinded_tx = self.nodes[1].unblindrawtransaction(
            conf_tx['hex'])['hex']
        for output in self.nodes[1].decoderawtransaction(deblinded_tx)["vout"]:
            if "value" in output and output["scriptPubKey"]["type"] != "fee":
                assert_equal(
                    output["scriptPubKey"]["addresses"][0],
                    self.nodes[1].validateaddress(address2)['unconfidential'])
                found_unblinded = True
        assert (found_unblinded)

        assert_equal(
            self.nodes[1].gettransaction(raw_tx_id, True)['amount']["bitcoin"],
            value3)
        list_unspent = self.nodes[1].listunspent(1, 9999999, [], True,
                                                 {"asset": "bitcoin"})
        assert_equal(list_unspent[0]['amount'] + list_unspent[1]['amount'],
                     value1 + value3)
        received_by_address = self.nodes[1].listreceivedbyaddress(
            1, False, True)
        assert_equal(len(received_by_address), 1)
        assert_equal((received_by_address[0]['address'],
                      received_by_address[0]['amount']['bitcoin']),
                     (unconfidential_address2, value1 + value3))

        # Spending a single confidential output and sending it to a
        # unconfidential output is not possible with CT. Test the
        # correct behavior of blindrawtransaction.
        unspent = self.nodes[0].listunspent(1, 9999999, [], True,
                                            {"asset": "bitcoin"})
        unspent = [i for i in unspent if i['amount'] > value23]
        assert_equal(len(unspent), 1)
        tx = self.nodes[0].createrawtransaction(
            [{
                "txid": unspent[0]["txid"],
                "vout": unspent[0]["vout"],
                "nValue": unspent[0]["amount"]
            }], {
                unconfidential_address: unspent[0]["amount"] - fee,
                "fee": fee
            })

        # Test that blindrawtransaction adds an OP_RETURN output to balance blinders
        temptx = self.nodes[0].blindrawtransaction(tx)
        decodedtx = self.nodes[0].decoderawtransaction(temptx)
        assert_equal(decodedtx["vout"][-1]["scriptPubKey"]["asm"], "OP_RETURN")
        assert_equal(len(decodedtx["vout"]), 3)

        # Create same transaction but with a change/dummy output.
        # It should pass the blinding step.
        value4 = 17
        change_address = self.nodes[0].getrawchangeaddress()
        tx = self.nodes[0].createrawtransaction(
            [{
                "txid": unspent[0]["txid"],
                "vout": unspent[0]["vout"],
                "nValue": unspent[0]["amount"]
            }], {
                unconfidential_address: value4,
                change_address: unspent[0]["amount"] - value4 - fee,
                "fee": fee
            })
        tx = self.nodes[0].blindrawtransaction(tx)
        tx_signed = self.nodes[0].signrawtransactionwithwallet(tx)
        txid = self.nodes[0].sendrawtransaction(tx_signed['hex'])
        decodedtx = self.nodes[0].decoderawtransaction(tx_signed["hex"])
        self.nodes[0].generate(101)
        self.sync_all()

        unblindfound = False
        for i in range(len(decodedtx["vout"])):
            txout = self.nodes[0].gettxout(txid, i)
            if txout is not None and "asset" in txout:
                unblindfound = True

        if unblindfound == False:
            raise Exception(
                "No unconfidential output detected when one should exist")

        node0 -= value4
        node2 += value4
        assert_equal(self.nodes[0].getbalance()["bitcoin"], node0)
        assert_equal(self.nodes[1].getbalance("*", 1, False, "bitcoin"), node1)
        assert_equal(self.nodes[2].getbalance()["bitcoin"], node2)

        # Testing wallet's ability to deblind its own outputs
        addr = self.nodes[0].getnewaddress()
        addr2 = self.nodes[0].getnewaddress()
        # We add two to-blind outputs, fundraw adds an already-blinded change output
        # If we only add one, the newly blinded will be 0-blinded because input = -output
        raw = self.nodes[0].createrawtransaction([], {
            addr: Decimal('1.1'),
            addr2: 1
        })
        funded = self.nodes[0].fundrawtransaction(raw)
        # fund again to make sure no blinded outputs were created (would fail)
        funded = self.nodes[0].fundrawtransaction(funded["hex"])
        blinded = self.nodes[0].blindrawtransaction(funded["hex"])
        # blind again to make sure we know output blinders
        blinded2 = self.nodes[0].blindrawtransaction(blinded)
        # then sign and send
        signed = self.nodes[0].signrawtransactionwithwallet(blinded2)
        self.nodes[0].sendrawtransaction(signed["hex"])

        # Aside: Check all outputs after fundraw are properly marked for blinding
        fund_decode = self.nodes[0].decoderawtransaction(funded["hex"])
        for output in fund_decode["vout"][:-1]:
            assert "asset" in output
            assert "value" in output
            assert output["scriptPubKey"]["type"] != "fee"
            assert output["commitmentnonce_fully_valid"]
        assert fund_decode["vout"][-1]["scriptPubKey"]["type"] == "fee"
        assert not fund_decode["vout"][-1]["commitmentnonce_fully_valid"]

        # Also check that all fundraw outputs marked for blinding are blinded later
        for blind_tx in [blinded, blinded2]:
            blind_decode = self.nodes[0].decoderawtransaction(blind_tx)
            for output in blind_decode["vout"][:-1]:
                assert "asset" not in output
                assert "value" not in output
                assert output["scriptPubKey"]["type"] != "fee"
                assert output["commitmentnonce_fully_valid"]
            assert blind_decode["vout"][-1]["scriptPubKey"]["type"] == "fee"
            assert "asset" in blind_decode["vout"][-1]
            assert "value" in blind_decode["vout"][-1]
            assert not blind_decode["vout"][-1]["commitmentnonce_fully_valid"]

        # Check createblindedaddress functionality
        blinded_addr = self.nodes[0].getnewaddress()
        validated_addr = self.nodes[0].validateaddress(blinded_addr)
        blinding_pubkey = self.nodes[0].validateaddress(
            blinded_addr)["confidential_key"]
        blinding_key = self.nodes[0].dumpblindingkey(blinded_addr)
        assert_equal(
            blinded_addr, self.nodes[1].createblindedaddress(
                validated_addr["unconfidential"], blinding_pubkey))

        # If a blinding key is over-ridden by a newly imported one, funds may be unaccounted for
        new_addr = self.nodes[0].getnewaddress()
        new_validated = self.nodes[0].validateaddress(new_addr)
        self.nodes[2].sendtoaddress(new_addr, 1)
        self.sync_all()
        diff_blind = self.nodes[1].createblindedaddress(
            new_validated["unconfidential"], blinding_pubkey)
        assert_equal(
            len(self.nodes[0].listunspent(0, 0,
                                          [new_validated["unconfidential"]])),
            1)
        self.nodes[0].importblindingkey(diff_blind, blinding_key)
        # CT values for this wallet transaction  have been cached via importblindingkey
        # therefore result will be same even though we change blinding keys
        assert_equal(
            len(self.nodes[0].listunspent(0, 0,
                                          [new_validated["unconfidential"]])),
            1)

        # Confidential Assets Tests

        print("Assets tests...")

        # Bitcoin is the first issuance
        assert_equal(self.nodes[0].listissuances()[0]["assetlabel"], "bitcoin")
        assert_equal(len(self.nodes[0].listissuances()), 1)

        # Unblinded issuance of asset
        issued = self.nodes[0].issueasset(1, 1, False)
        self.nodes[0].reissueasset(issued["asset"], 1)

        # Compare resulting fields with getrawtransaction
        raw_details = self.nodes[0].getrawtransaction(issued["txid"], 1)
        assert_equal(
            issued["entropy"],
            raw_details["vin"][issued["vin"]]["issuance"]["assetEntropy"])
        assert_equal(issued["asset"],
                     raw_details["vin"][issued["vin"]]["issuance"]["asset"])
        assert_equal(issued["token"],
                     raw_details["vin"][issued["vin"]]["issuance"]["token"])

        self.nodes[0].generate(1)
        self.sync_all()

        issued2 = self.nodes[0].issueasset(2, 1)
        test_asset = issued2["asset"]
        assert_equal(self.nodes[0].getwalletinfo()['balance'][test_asset],
                     Decimal(2))
        assert (test_asset not in self.nodes[1].getwalletinfo()['balance'])

        # Assets balance checking, note that accounts are completely ignored because
        # balance queries with accounts are horrifically broken upstream
        assert_equal(self.nodes[0].getbalance("*", 0, False, "bitcoin"),
                     self.nodes[0].getbalance("*", 0, False, "bitcoin"))
        assert_equal(self.nodes[0].getwalletinfo()['balance']['bitcoin'],
                     self.nodes[0].getbalance("*", 0, False, "bitcoin"))

        # Send some bitcoin and other assets over as well to fund wallet
        addr = self.nodes[2].getnewaddress()
        self.nodes[0].sendtoaddress(addr, 5)
        self.nodes[0].sendmany("", {
            addr: 1,
            self.nodes[2].getnewaddress(): 13
        }, 0, "", [], False, 1, "UNSET", {addr: test_asset})

        self.sync_all()

        # Should have exactly 1 in change(trusted, though not confirmed) after sending one off
        assert_equal(self.nodes[0].getbalance("*", 0, False, test_asset), 1)
        assert_equal(self.nodes[2].getunconfirmedbalance()[test_asset],
                     Decimal(1))

        b_utxos = self.nodes[2].listunspent(0, 0, [], True,
                                            {"asset": "bitcoin"})
        t_utxos = self.nodes[2].listunspent(0, 0, [], True,
                                            {"asset": test_asset})

        assert_equal(len(self.nodes[2].listunspent(0, 0, [])),
                     len(b_utxos) + len(t_utxos))

        # Now craft a blinded transaction via raw api
        rawaddrs = []
        for i in range(2):
            rawaddrs.append(self.nodes[1].getnewaddress())
        raw_assets = self.nodes[2].createrawtransaction(
            [{
                "txid": b_utxos[0]['txid'],
                "vout": b_utxos[0]['vout'],
                "nValue": b_utxos[0]['amount']
            }, {
                "txid": b_utxos[1]['txid'],
                "vout": b_utxos[1]['vout'],
                "nValue": b_utxos[1]['amount'],
                "asset": b_utxos[1]['asset']
            }, {
                "txid": t_utxos[0]['txid'],
                "vout": t_utxos[0]['vout'],
                "nValue": t_utxos[0]['amount'],
                "asset": t_utxos[0]['asset']
            }], {
                rawaddrs[1]:
                Decimal(t_utxos[0]['amount']),
                rawaddrs[0]:
                Decimal(b_utxos[0]['amount'] + b_utxos[1]['amount'] -
                        Decimal("0.01")),
                "fee":
                Decimal("0.01")
            }, 0, False, {
                rawaddrs[0]: b_utxos[0]['asset'],
                rawaddrs[1]: t_utxos[0]['asset'],
                "fee": b_utxos[0]['asset']
            })

        # Sign unblinded, then blinded
        signed_assets = self.nodes[2].signrawtransactionwithwallet(raw_assets)
        blind_assets = self.nodes[2].blindrawtransaction(raw_assets)
        signed_assets = self.nodes[2].signrawtransactionwithwallet(
            blind_assets)

        # And finally send
        self.nodes[2].sendrawtransaction(signed_assets['hex'])
        self.nodes[2].generate(101)
        self.sync_all()

        issuancedata = self.nodes[2].issueasset(
            0, Decimal('0.00000006'))  #0 of asset, 6 reissuance token

        # Node 2 will send node 1 a reissuance token, both will generate assets
        self.nodes[2].sendtoaddress(self.nodes[1].getnewaddress(),
                                    Decimal('0.00000001'), "", "", False,
                                    False, 1, "UNSET", issuancedata["token"])
        # node 1 needs to know about a (re)issuance to reissue itself
        self.nodes[1].importaddress(self.nodes[2].gettransaction(
            issuancedata["txid"])["details"][0]["address"])
        # also send some bitcoin
        self.nodes[2].generate(1)
        self.sync_all()

        self.nodes[1].reissueasset(issuancedata["asset"], Decimal('0.05'))
        self.nodes[2].reissueasset(issuancedata["asset"], Decimal('0.025'))
        self.nodes[1].generate(1)
        self.sync_all()

        # Check for value accounting when asset issuance is null but token not, ie unblinded
        # HACK: Self-send to sweep up bitcoin inputs into blinded output.
        # We were hitting https://github.com/ElementsProject/elements/issues/473 for the following issuance
        self.nodes[0].sendtoaddress(
            self.nodes[0].getnewaddress(),
            self.nodes[0].getwalletinfo()["balance"]["bitcoin"], "", "", True)
        issued = self.nodes[0].issueasset(0, 1, False)
        walletinfo = self.nodes[0].getwalletinfo()
        assert (issued["asset"] not in walletinfo["balance"])
        assert_equal(walletinfo["balance"][issued["token"]], Decimal(1))
        assert (issued["asset"] not in walletinfo["unconfirmed_balance"])
        assert (issued["token"] not in walletinfo["unconfirmed_balance"])

        # Check for value when receiving different assets by same address.
        self.nodes[0].sendtoaddress(unconfidential_address2,
                                    Decimal('0.00000001'), "", "", False,
                                    False, 1, "UNSET", test_asset)
        self.nodes[0].sendtoaddress(unconfidential_address2,
                                    Decimal('0.00000002'), "", "", False,
                                    False, 1, "UNSET", test_asset)
        self.nodes[0].generate(1)
        self.sync_all()
        received_by_address = self.nodes[1].listreceivedbyaddress(
            0, False, True)
        multi_asset_amount = [
            x for x in received_by_address
            if x['address'] == unconfidential_address2
        ][0]['amount']
        assert_equal(multi_asset_amount['bitcoin'], value1 + value3)
        assert_equal(multi_asset_amount[test_asset], Decimal('0.00000003'))

        # Check blinded multisig functionality and partial blinding functionality

        # Get two pubkeys
        blinded_addr = self.nodes[0].getnewaddress()
        pubkey = self.nodes[0].getaddressinfo(blinded_addr)["pubkey"]
        blinded_addr2 = self.nodes[1].getnewaddress()
        pubkey2 = self.nodes[1].getaddressinfo(blinded_addr2)["pubkey"]
        pubkeys = [pubkey, pubkey2]
        # Add multisig address
        unconfidential_addr = self.nodes[0].addmultisigaddress(
            2, pubkeys)["address"]
        self.nodes[1].addmultisigaddress(2, pubkeys)
        self.nodes[0].importaddress(unconfidential_addr)
        self.nodes[1].importaddress(unconfidential_addr)
        # Use blinding key from node 0's original getnewaddress call
        blinding_pubkey = self.nodes[0].getaddressinfo(
            blinded_addr)["confidential_key"]
        blinding_key = self.nodes[0].dumpblindingkey(blinded_addr)
        # Create blinded address from p2sh address and import corresponding privkey
        blinded_multisig_addr = self.nodes[0].createblindedaddress(
            unconfidential_addr, blinding_pubkey)
        self.nodes[0].importblindingkey(blinded_multisig_addr, blinding_key)

        # Issue new asset, to use different assets in one transaction when doing
        # partial blinding. Just to make these tests a bit more elaborate :-)
        issued3 = self.nodes[2].issueasset(1, 0)
        self.nodes[2].generate(1)
        self.sync_all()
        node2_balance = self.nodes[2].getbalance()
        assert (issued3['asset'] in node2_balance)
        assert_equal(node2_balance[issued3['asset']], Decimal(1))

        # Send asset to blinded multisig address and check that it was received
        self.nodes[2].sendtoaddress(address=blinded_multisig_addr,
                                    amount=1,
                                    assetlabel=issued3['asset'])
        self.sync_all()
        # We will use this multisig UTXO in our partially-blinded transaction,
        # and will also check that multisig UTXO can be successfully spent
        # after the transaction is signed by node1 and node0 in succession.
        unspent_asset = self.nodes[0].listunspent(0, 0, [unconfidential_addr],
                                                  True,
                                                  {"asset": issued3['asset']})
        assert_equal(len(unspent_asset), 1)
        assert (issued3['asset'] not in self.nodes[2].getbalance())

        # Create new UTXO on node0 to be used in our partially-blinded transaction
        blinded_addr = self.nodes[0].getnewaddress()
        addr = self.nodes[0].validateaddress(blinded_addr)["unconfidential"]
        self.nodes[0].sendtoaddress(blinded_addr, 0.1)
        unspent = self.nodes[0].listunspent(0, 0, [addr])
        assert_equal(len(unspent), 1)

        # Create new UTXO on node1 to be used in our partially-blinded transaction
        blinded_addr2 = self.nodes[1].getnewaddress()
        addr2 = self.nodes[1].validateaddress(blinded_addr2)["unconfidential"]
        self.nodes[1].sendtoaddress(blinded_addr2, 0.11)
        unspent2 = self.nodes[1].listunspent(0, 0, [addr2])
        assert_equal(len(unspent2), 1)

        # The transaction will have three non-fee outputs
        dst_addr = self.nodes[0].getnewaddress()
        dst_addr2 = self.nodes[1].getnewaddress()
        dst_addr3 = self.nodes[2].getnewaddress()

        # Inputs are selected up front
        inputs = [{
            "txid": unspent2[0]["txid"],
            "vout": unspent2[0]["vout"]
        }, {
            "txid": unspent[0]["txid"],
            "vout": unspent[0]["vout"]
        }, {
            "txid": unspent_asset[0]["txid"],
            "vout": unspent_asset[0]["vout"]
        }]

        # Create one part of the transaction to partially blind
        rawtx = self.nodes[0].createrawtransaction(
            inputs, {dst_addr2: Decimal("0.01")})

        # Create another part of the transaction to partially blind
        rawtx2 = self.nodes[0].createrawtransaction(
            inputs, {
                dst_addr: Decimal("0.1"),
                dst_addr3: Decimal("1.0")
            }, 0, False, {
                dst_addr: unspent[0]['asset'],
                dst_addr3: unspent_asset[0]['asset']
            })

        sum_i = unspent2[0]["amount"] + unspent[0]["amount"]
        sum_o = 0.01 + 0.10 + 0.1
        assert_equal(int(round(sum_i * COIN)), int(round(sum_o * COIN)))

        # Blind the first part of the transaction - we need to supply the
        # assetcommmitments for all of the inputs, for the surjectionproof
        # to be valid after we combine the transactions
        blindtx = self.nodes[1].blindrawtransaction(rawtx, True, [
            unspent2[0]['assetcommitment'], unspent[0]['assetcommitment'],
            unspent_asset[0]['assetcommitment']
        ])

        # Combine the transactions

        # Blinded, but incomplete transaction.
        # 3 inputs and 1 output, but no fee output, and
        # it was blinded with 3 asset commitments, that means
        # the final transaction should have 3 inputs.
        btx = CTransaction()
        btx.deserialize(io.BytesIO(hex_str_to_bytes(blindtx)))

        # Unblinded transaction, with 3 inputs and 2 outputs.
        # We will add them to the other transaction to make it complete.
        ubtx = CTransaction()
        ubtx.deserialize(io.BytesIO(hex_str_to_bytes(rawtx2)))

        # We will add outputs of unblinded transaction
        # on top of inputs and outputs of the blinded, but incomplete transaction.
        # We also append empty witness instances to make witness arrays match
        # vin/vout arrays
        btx.wit.vtxinwit.append(CTxInWitness())
        btx.vout.append(ubtx.vout[0])
        btx.wit.vtxoutwit.append(CTxOutWitness())
        btx.wit.vtxinwit.append(CTxInWitness())
        btx.vout.append(ubtx.vout[1])
        btx.wit.vtxoutwit.append(CTxOutWitness())
        # Add explicit fee output
        btx.vout.append(
            CTxOut(nValue=CTxOutValue(10000000),
                   nAsset=CTxOutAsset(BITCOIN_ASSET_OUT)))
        btx.wit.vtxoutwit.append(CTxOutWitness())

        # Input 0 is bitcoin asset (already blinded)
        # Input 1 is also bitcoin asset
        # Input 2 is our new asset

        # Blind with wrong order of assetcommitments - such transaction should be rejected
        blindtx = self.nodes[0].blindrawtransaction(
            bytes_to_hex_str(btx.serialize()), True, [
                unspent_asset[0]['assetcommitment'],
                unspent[0]['assetcommitment'], unspent2[0]['assetcommitment']
            ])

        stx2 = self.nodes[1].signrawtransactionwithwallet(blindtx)
        stx = self.nodes[0].signrawtransactionwithwallet(stx2['hex'])
        self.sync_all()

        assert_raises_rpc_error(-26, "bad-txns-in-ne-out",
                                self.nodes[2].sendrawtransaction, stx['hex'])

        # Blind with correct order of assetcommitments
        blindtx = self.nodes[0].blindrawtransaction(
            bytes_to_hex_str(btx.serialize()), True, [
                unspent2[0]['assetcommitment'], unspent[0]['assetcommitment'],
                unspent_asset[0]['assetcommitment']
            ])

        stx2 = self.nodes[1].signrawtransactionwithwallet(blindtx)
        stx = self.nodes[0].signrawtransactionwithwallet(stx2['hex'])
        txid = self.nodes[2].sendrawtransaction(stx['hex'])
        self.nodes[2].generate(1)
        assert self.nodes[2].getrawtransaction(txid, 1)['confirmations'] == 1
        self.sync_all()

        # Check that the sent asset has reached its destination
        unconfidential_dst_addr3 = self.nodes[2].validateaddress(
            dst_addr3)["unconfidential"]
        unspent_asset2 = self.nodes[2].listunspent(1, 1,
                                                   [unconfidential_dst_addr3],
                                                   True,
                                                   {"asset": issued3['asset']})
        assert_equal(len(unspent_asset2), 1)
        assert_equal(unspent_asset2[0]['amount'], Decimal(1))
        # And that the balance was correctly updated
        assert_equal(self.nodes[2].getbalance()[issued3['asset']], Decimal(1))

        # Basic checks of rawblindrawtransaction functionality
        blinded_addr = self.nodes[0].getnewaddress()
        addr = self.nodes[0].validateaddress(blinded_addr)["unconfidential"]
        self.nodes[0].sendtoaddress(blinded_addr, 1)
        self.nodes[0].sendtoaddress(blinded_addr, 3)
        unspent = self.nodes[0].listunspent(0, 0)
        rawtx = self.nodes[0].createrawtransaction(
            [{
                "txid": unspent[0]["txid"],
                "vout": unspent[0]["vout"]
            }, {
                "txid": unspent[1]["txid"],
                "vout": unspent[1]["vout"]
            }], {
                addr:
                unspent[0]["amount"] + unspent[1]["amount"] - Decimal("0.2"),
                "fee": Decimal("0.2")
            })
        # Blinding will fail with 2 blinded inputs and 0 blinded outputs
        # since it has no notion of a wallet to fill in a 0-value OP_RETURN output
        try:
            self.nodes[0].rawblindrawtransaction(
                rawtx,
                [unspent[0]["amountblinder"], unspent[1]["amountblinder"]],
                [unspent[0]["amount"], unspent[1]["amount"]],
                [unspent[0]["asset"], unspent[1]["asset"]],
                [unspent[0]["assetblinder"], unspent[1]["assetblinder"]])
            raise AssertionError(
                "Shouldn't be able to blind 2 input 0 output transaction via rawblindraw"
            )
        except JSONRPCException:
            pass

        # Blinded destination added, can blind, sign and send
        rawtx = self.nodes[0].createrawtransaction(
            [{
                "txid": unspent[0]["txid"],
                "vout": unspent[0]["vout"]
            }, {
                "txid": unspent[1]["txid"],
                "vout": unspent[1]["vout"]
            }], {
                blinded_addr:
                unspent[0]["amount"] + unspent[1]["amount"] - Decimal("0.002"),
                "fee":
                Decimal("0.002")
            })
        signtx = self.nodes[0].signrawtransactionwithwallet(rawtx)

        try:
            self.nodes[0].sendrawtransaction(signtx["hex"])
            raise AssertionError(
                "Shouldn't be able to send unblinded tx with emplaced pubkey in output without additional argument"
            )
        except JSONRPCException:
            pass

        blindtx = self.nodes[0].rawblindrawtransaction(
            rawtx, [unspent[0]["amountblinder"], unspent[1]["amountblinder"]],
            [unspent[0]["amount"], unspent[1]["amount"]],
            [unspent[0]["asset"], unspent[1]["asset"]],
            [unspent[0]["assetblinder"], unspent[1]["assetblinder"]])
        signtx = self.nodes[0].signrawtransactionwithwallet(blindtx)
        txid = self.nodes[0].sendrawtransaction(signtx["hex"])
        for output in self.nodes[0].decoderawtransaction(blindtx)["vout"]:
            if "asset" in output and output["scriptPubKey"]["type"] != "fee":
                raise AssertionError("An unblinded output exists")

        # Test fundrawtransaction with multiple assets
        issue = self.nodes[0].issueasset(1, 0)
        assetaddr = self.nodes[0].getnewaddress()
        rawtx = self.nodes[0].createrawtransaction(
            [], {
                assetaddr: 1,
                self.nodes[0].getnewaddress(): 2
            }, 0, False, {assetaddr: issue["asset"]})
        funded = self.nodes[0].fundrawtransaction(rawtx)
        blinded = self.nodes[0].blindrawtransaction(funded["hex"])
        signed = self.nodes[0].signrawtransactionwithwallet(blinded)
        txid = self.nodes[0].sendrawtransaction(signed["hex"])

        # Test fundrawtransaction with multiple inputs, creating > vout.size change
        rawtx = self.nodes[0].createrawtransaction(
            [{
                "txid": txid,
                "vout": 0
            }, {
                "txid": txid,
                "vout": 1
            }], {self.nodes[0].getnewaddress(): 5})
        funded = self.nodes[0].fundrawtransaction(rawtx)
        blinded = self.nodes[0].blindrawtransaction(funded["hex"])
        signed = self.nodes[0].signrawtransactionwithwallet(blinded)
        txid = self.nodes[0].sendrawtransaction(signed["hex"])

        # Test corner case where wallet appends a OP_RETURN output, yet doesn't blind it
        # due to the fact that the output value is 0-value and input pedersen commitments
        # self-balance. This is rare corner case, but ok.
        unblinded = self.nodes[0].validateaddress(
            self.nodes[0].getnewaddress())["unconfidential"]
        self.nodes[0].sendtoaddress(unblinded,
                                    self.nodes[0].getbalance()["bitcoin"], "",
                                    "", True)
        # Make tx with blinded destination and change outputs only
        self.nodes[0].sendtoaddress(self.nodes[0].getnewaddress(),
                                    self.nodes[0].getbalance()["bitcoin"] / 2)
        # Send back again, this transaction should have 3 outputs, all unblinded
        txid = self.nodes[0].sendtoaddress(
            unblinded, self.nodes[0].getbalance()["bitcoin"], "", "", True)
        outputs = self.nodes[0].getrawtransaction(txid, 1)["vout"]
        assert_equal(len(outputs), 3)
        assert ("value" in outputs[0] and "value" in outputs[1]
                and "value" in outputs[2])
        assert_equal(outputs[2]["scriptPubKey"]["type"], 'nulldata')

        # Test burn argument in createrawtransaction
        raw_burn1 = self.nodes[0].createrawtransaction(
            [], {
                self.nodes[0].getnewaddress(): 1,
                "burn": 2
            })
        decode_burn1 = self.nodes[0].decoderawtransaction(raw_burn1)
        assert_equal(len(decode_burn1["vout"]), 2)
        found_pay = False
        found_burn = False
        for output in decode_burn1["vout"]:
            if output["scriptPubKey"]["asm"] == "OP_RETURN":
                found_burn = True
                if output["asset"] != self.nodes[0].dumpassetlabels(
                )["bitcoin"]:
                    raise Exception(
                        "Burn should have been bitcoin(policyAsset)")
            if output["scriptPubKey"]["type"] == "scripthash":
                found_pay = True
        assert (found_pay and found_burn)

        raw_burn2 = self.nodes[0].createrawtransaction(
            [], {
                self.nodes[0].getnewaddress(): 1,
                "burn": 2
            }, 101, False, {"burn": "deadbeef" * 8})
        decode_burn2 = self.nodes[0].decoderawtransaction(raw_burn2)
        assert_equal(len(decode_burn2["vout"]), 2)
        found_pay = False
        found_burn = False
        for output in decode_burn2["vout"]:
            if output["scriptPubKey"]["asm"] == "OP_RETURN":
                found_burn = True
                if output["asset"] != "deadbeef" * 8:
                    raise Exception("Burn should have been deadbeef")
            if output["scriptPubKey"]["type"] == "scripthash":
                found_pay = True
        assert (found_pay and found_burn)
예제 #22
0
    def test_desc_count_limits_2(self):
        """Create a Package with 24 transaction in mempool and 2 transaction in package:
                      M1
                     ^  ^
                   M2    ^
                   .      ^
                  .        ^
                 .          ^
                M24          ^
                              ^
                              P1
                              ^
                              P2
        P1 has M1 as a mempool ancestor, P2 has no in-mempool ancestors, but when
        combined P2 has M1 as an ancestor and M1 exceeds descendant_limits(23 in-mempool
        descendants + 2 in-package descendants, a total of 26 including itself).
        """

        node = self.nodes[0]
        package_hex = []
        # M1
        first_coin_a = self.coins.pop()
        parent_value = (first_coin_a["amount"] - DEFAULT_FEE
                        ) / 2  # Deduct reasonable fee and make 2 outputs
        inputs = [{"txid": first_coin_a["txid"], "vout": 0}]
        outputs = [{
            self.address: parent_value
        }, {
            ADDRESS_BCRT1_P2WSH_OP_TRUE: parent_value
        }]
        rawtx = node.createrawtransaction(inputs, outputs)

        parent_signed = node.signrawtransactionwithkey(hexstring=rawtx,
                                                       privkeys=self.privkeys)
        assert parent_signed["complete"]
        parent_tx = tx_from_hex(parent_signed["hex"])
        parent_txid = parent_tx.rehash()
        node.sendrawtransaction(parent_signed["hex"])

        # Chain M2...M24
        spk = parent_tx.vout[0].scriptPubKey.hex()
        value = parent_value
        txid = parent_txid
        for i in range(23):  # M2...M24
            (tx, txhex, value, spk) = make_chain(node, self.address,
                                                 self.privkeys, txid, value, 0,
                                                 spk)
            txid = tx.rehash()
            node.sendrawtransaction(txhex)

        # P1
        value_p1 = (parent_value - DEFAULT_FEE)
        rawtx_p1 = node.createrawtransaction([{
            "txid": parent_txid,
            "vout": 1
        }], [{
            self.address: value_p1
        }])
        tx_child_p1 = tx_from_hex(rawtx_p1)
        tx_child_p1.wit.vtxinwit = [CTxInWitness()]
        tx_child_p1.wit.vtxinwit[0].scriptWitness.stack = [CScript([OP_TRUE])]
        tx_child_p1_hex = tx_child_p1.serialize().hex()
        txid_child_p1 = tx_child_p1.rehash()
        package_hex.append(tx_child_p1_hex)
        tx_child_p1_spk = tx_child_p1.vout[0].scriptPubKey.hex()

        # P2
        (_, tx_child_p2_hex, _, _) = make_chain(node, self.address,
                                                self.privkeys, txid_child_p1,
                                                value_p1, 0, tx_child_p1_spk)
        package_hex.append(tx_child_p2_hex)

        assert_equal(24, node.getmempoolinfo()["size"])
        assert_equal(2, len(package_hex))
        testres = node.testmempoolaccept(rawtxs=package_hex)
        assert_equal(len(testres), len(package_hex))
        for txres in testres:
            assert_equal(txres["package-error"], "package-mempool-limits")

        # Clear mempool and check that the package passes now
        self.generate(node, 1)
        assert all([
            res["allowed"]
            for res in node.testmempoolaccept(rawtxs=package_hex)
        ])
예제 #23
0
    def run_test(self):
        parent = self.nodes[0]
        #parent2 = self.nodes[1]
        sidechain = self.nodes[2]
        sidechain2 = self.nodes[3]
        for node in self.nodes:
            node.importprivkey(privkey=node.get_deterministic_priv_key().key, label="mining")
        util.node_fastmerkle = sidechain

        parent.generate(101)
        sidechain.generate(101)
        self.log.info("sidechain info: {}".format(sidechain.getsidechaininfo()))

        addrs = sidechain.getpeginaddress()
        addr = addrs["mainchain_address"]
        assert_equal(sidechain.decodescript(addrs["claim_script"])["type"], "witness_v0_keyhash")
        txid1 = parent.sendtoaddress(addr, 24)
        # 10+2 confirms required to get into mempool and confirm
        parent.generate(1)
        time.sleep(2)
        proof = parent.gettxoutproof([txid1])

        raw = parent.gettransaction(txid1)["hex"]

        print("Attempting peg-ins")
        # First attempt fails the consensus check but gives useful result
        try:
            pegtxid = sidechain.claimpegin(raw, proof)
            raise Exception("Peg-in should not be mature enough yet, need another block.")
        except JSONRPCException as e:
            assert("Peg-in Bitcoin transaction needs more confirmations to be sent." in e.error["message"])

        # Second attempt simply doesn't hit mempool bar
        parent.generate(10)
        try:
            pegtxid = sidechain.claimpegin(raw, proof)
            raise Exception("Peg-in should not be mature enough yet, need another block.")
        except JSONRPCException as e:
            assert("Peg-in Bitcoin transaction needs more confirmations to be sent." in e.error["message"])

        try:
            pegtxid = sidechain.createrawpegin(raw, proof, 'AEIOU')
            raise Exception("Peg-in with non-hex claim_script should fail.")
        except JSONRPCException as e:
            assert("Given claim_script is not hex." in e.error["message"])

        # Should fail due to non-matching wallet address
        try:
            scriptpubkey = sidechain.getaddressinfo(get_new_unconfidential_address(sidechain))["scriptPubKey"]
            pegtxid = sidechain.claimpegin(raw, proof, scriptpubkey)
            raise Exception("Peg-in with non-matching claim_script should fail.")
        except JSONRPCException as e:
            assert("Given claim_script does not match the given Bitcoin transaction." in e.error["message"])

        # 12 confirms allows in mempool
        parent.generate(1)

        # Make sure that a tx with a duplicate pegin claim input gets rejected.
        raw_pegin = sidechain.createrawpegin(raw, proof)["hex"]
        raw_pegin = FromHex(CTransaction(), raw_pegin)
        raw_pegin.vin.append(raw_pegin.vin[0]) # duplicate the pegin input
        raw_pegin = sidechain.signrawtransactionwithwallet(raw_pegin.serialize().hex())["hex"]
        assert_raises_rpc_error(-26, "bad-txns-inputs-duplicate", sidechain.sendrawtransaction, raw_pegin)
        # Also try including this tx in a block manually and submitting it.
        doublespendblock = FromHex(CBlock(), sidechain.getnewblockhex())
        doublespendblock.vtx.append(FromHex(CTransaction(), raw_pegin))
        doublespendblock.hashMerkleRoot = doublespendblock.calc_merkle_root()
        add_witness_commitment(doublespendblock)
        doublespendblock.solve()
        block_hex = bytes_to_hex_str(doublespendblock.serialize(True))
        assert_raises_rpc_error(-25, "bad-txns-inputs-duplicate", sidechain.testproposedblock, block_hex, True)

        # Should succeed via wallet lookup for address match, and when given
        raw_pegin = sidechain.createrawpegin(raw, proof)['hex']
        signed_pegin = sidechain.signrawtransactionwithwallet(raw_pegin)

        sample_pegin_struct = FromHex(CTransaction(), signed_pegin["hex"])
        # Round-trip peg-in transaction using python serialization
        assert_equal(signed_pegin["hex"], sample_pegin_struct.serialize().hex())
        # Store this for later (evil laugh)
        sample_pegin_witness = sample_pegin_struct.wit.vtxinwit[0].peginWitness

        pegtxid1 = sidechain.claimpegin(raw, proof)
        # Make sure a second pegin claim does not get accepted in the mempool when
        # another mempool tx already claims that pegin.
        assert_raises_rpc_error(-4, "txn-mempool-conflict", sidechain.claimpegin, raw, proof)

        # Will invalidate the block that confirms this transaction later
        self.sync_all(self.node_groups)
        blockhash = sidechain2.generate(1)
        self.sync_all(self.node_groups)
        sidechain.generate(5)

        tx1 = sidechain.gettransaction(pegtxid1)

        if "confirmations" in tx1 and tx1["confirmations"] == 6:
            print("Peg-in is confirmed: Success!")
        else:
            raise Exception("Peg-in confirmation has failed.")

        # Look at pegin fields
        decoded = sidechain.decoderawtransaction(tx1["hex"])
        assert decoded["vin"][0]["is_pegin"] == True
        assert len(decoded["vin"][0]["pegin_witness"]) > 0
        # Check that there's sufficient fee for the peg-in
        vsize = decoded["vsize"]
        fee_output = decoded["vout"][1]
        fallbackfee_pervbyte = Decimal("0.00001")/Decimal("1000")
        assert fee_output["scriptPubKey"]["type"] == "fee"
        assert fee_output["value"] >= fallbackfee_pervbyte*vsize

        # Quick reorg checks of pegs
        sidechain.invalidateblock(blockhash[0])
        if sidechain.gettransaction(pegtxid1)["confirmations"] != 0:
            raise Exception("Peg-in didn't unconfirm after invalidateblock call.")

        # Create duplicate claim, put it in block along with current one in mempool
        # to test duplicate-in-block claims between two txs that are in the same block.
        raw_pegin = sidechain.createrawpegin(raw, proof)["hex"]
        raw_pegin = sidechain.signrawtransactionwithwallet(raw_pegin)["hex"]
        raw_pegin = FromHex(CTransaction(), raw_pegin)
        doublespendblock = FromHex(CBlock(), sidechain.getnewblockhex())
        assert(len(doublespendblock.vtx) == 2) # coinbase and pegin
        doublespendblock.vtx.append(raw_pegin)
        doublespendblock.hashMerkleRoot = doublespendblock.calc_merkle_root()
        add_witness_commitment(doublespendblock)
        doublespendblock.solve()
        block_hex = bytes_to_hex_str(doublespendblock.serialize(True))
        assert_raises_rpc_error(-25, "bad-txns-double-pegin", sidechain.testproposedblock, block_hex, True)

        # Re-enters block
        sidechain.generate(1)
        if sidechain.gettransaction(pegtxid1)["confirmations"] != 1:
            raise Exception("Peg-in should have one confirm on side block.")
        sidechain.reconsiderblock(blockhash[0])
        if sidechain.gettransaction(pegtxid1)["confirmations"] != 6:
            raise Exception("Peg-in should be back to 6 confirms.")

        # Now the pegin is already claimed in a confirmed tx.
        # In that case, a duplicate claim should (1) not be accepted in the mempool
        # and (2) not be accepted in a block.
        assert_raises_rpc_error(-4, "pegin-already-claimed", sidechain.claimpegin, raw, proof)
        # For case (2), manually craft a block and include the tx.
        doublespendblock = FromHex(CBlock(), sidechain.getnewblockhex())
        doublespendblock.vtx.append(raw_pegin)
        doublespendblock.hashMerkleRoot = doublespendblock.calc_merkle_root()
        add_witness_commitment(doublespendblock)
        doublespendblock.solve()
        block_hex = bytes_to_hex_str(doublespendblock.serialize(True))
        assert_raises_rpc_error(-25, "bad-txns-double-pegin", sidechain.testproposedblock, block_hex, True)

        # Do multiple claims in mempool
        n_claims = 6

        print("Flooding mempool with a few claims")
        pegtxs = []
        sidechain.generate(101)

        # Do mixture of raw peg-in and automatic peg-in tx construction
        # where raw creation is done on another node
        for i in range(n_claims):
            addrs = sidechain.getpeginaddress()
            txid = parent.sendtoaddress(addrs["mainchain_address"], 1)
            parent.generate(1)
            proof = parent.gettxoutproof([txid])
            raw = parent.gettransaction(txid)["hex"]
            if i % 2 == 0:
                parent.generate(11)
                pegtxs += [sidechain.claimpegin(raw, proof)]
            else:
                # The raw API doesn't check for the additional 2 confirmation buffer
                # So we only get 10 confirms then send off. Miners will add to block anyways.

                # Don't mature whole way yet to test signing immature peg-in input
                parent.generate(8)
                # Wallet in sidechain2 gets funds instead of sidechain
                raw_pegin = sidechain2.createrawpegin(raw, proof, addrs["claim_script"])["hex"]
                # First node should also be able to make a valid transaction with or without 3rd arg
                # since this wallet originated the claim_script itself
                sidechain.createrawpegin(raw, proof, addrs["claim_script"])
                sidechain.createrawpegin(raw, proof)
                signed_pegin = sidechain.signrawtransactionwithwallet(raw_pegin)
                assert(signed_pegin["complete"])
                assert("warning" in signed_pegin) # warning for immature peg-in
                # fully mature them now
                parent.generate(1)
                pegtxs += [sidechain.sendrawtransaction(signed_pegin["hex"])]

        self.sync_all(self.node_groups)
        sidechain2.generate(1)
        for i, pegtxid in enumerate(pegtxs):
            if i % 2 == 0:
                tx = sidechain.gettransaction(pegtxid)
            else:
                tx = sidechain2.gettransaction(pegtxid)
            if "confirmations" not in tx or tx["confirmations"] == 0:
                raise Exception("Peg-in confirmation has failed.")

        print("Test pegouts")
        self.test_pegout(get_new_unconfidential_address(parent, "legacy"), sidechain)
        self.test_pegout(get_new_unconfidential_address(parent, "p2sh-segwit"), sidechain)
        self.test_pegout(get_new_unconfidential_address(parent, "bech32"), sidechain)

        print("Test pegout P2SH")
        parent_chain_addr = get_new_unconfidential_address(parent)
        parent_pubkey = parent.getaddressinfo(parent_chain_addr)["pubkey"]
        parent_chain_p2sh_addr = parent.createmultisig(1, [parent_pubkey])["address"]
        self.test_pegout(parent_chain_p2sh_addr, sidechain)

        print("Test pegout Garbage")
        parent_chain_addr = "garbage"
        try:
            self.test_pegout(parent_chain_addr, sidechain)
            raise Exception("A garbage address should fail.")
        except JSONRPCException as e:
            assert("Invalid Bitcoin address" in e.error["message"])

        print("Test pegout Garbage valid")
        prev_txid = sidechain.sendtoaddress(sidechain.getnewaddress(), 1)
        sidechain.generate(1)
        pegout_chain = 'a' * 64
        pegout_hex = 'b' * 500
        inputs = [{"txid": prev_txid, "vout": 0}]
        outputs = {"vdata": [pegout_chain, pegout_hex]}
        rawtx = sidechain.createrawtransaction(inputs, outputs)
        raw_pegout = sidechain.decoderawtransaction(rawtx)

        assert 'vout' in raw_pegout and len(raw_pegout['vout']) > 0
        pegout_tested = False
        for output in raw_pegout['vout']:
            scriptPubKey = output['scriptPubKey']
            if 'type' in scriptPubKey and scriptPubKey['type'] == 'nulldata':
                assert ('pegout_hex' in scriptPubKey and 'pegout_asm' in scriptPubKey and 'pegout_type' in scriptPubKey)
                assert ('pegout_chain' in scriptPubKey and 'pegout_reqSigs' not in scriptPubKey and 'pegout_addresses' not in scriptPubKey)
                assert scriptPubKey['pegout_type'] == 'nonstandard'
                assert scriptPubKey['pegout_chain'] == pegout_chain
                assert scriptPubKey['pegout_hex'] == pegout_hex
                pegout_tested = True
                break
        assert pegout_tested

        print("Now test failure to validate peg-ins based on intermittent bitcoind rpc failure")
        self.stop_node(1)
        txid = parent.sendtoaddress(addr, 1)
        parent.generate(12)
        proof = parent.gettxoutproof([txid])
        raw = parent.gettransaction(txid)["hex"]
        sidechain.claimpegin(raw, proof) # stuck peg
        sidechain.generate(1)
        print("Waiting to ensure block is being rejected by sidechain2")
        time.sleep(5)

        assert(sidechain.getblockcount() != sidechain2.getblockcount())

        print("Restarting parent2")
        self.start_node(1)
        connect_nodes_bi(self.nodes, 0, 1)

        # Don't make a block, race condition when pegin-invalid block
        # is awaiting further validation, nodes reject subsequent blocks
        # even ones they create
        print("Now waiting for node to re-evaluate peg-in witness failed block... should take a few seconds")
        self.sync_all(self.node_groups)
        print("Completed!\n")
        print("Now send funds out in two stages, partial, and full")
        some_btc_addr = get_new_unconfidential_address(parent)
        bal_1 = sidechain.getwalletinfo()["balance"]['bitcoin']
        try:
            sidechain.sendtomainchain(some_btc_addr, bal_1 + 1)
            raise Exception("Sending out too much; should have failed")
        except JSONRPCException as e:
            assert("Insufficient funds" in e.error["message"])

        assert(sidechain.getwalletinfo()["balance"]["bitcoin"] == bal_1)
        try:
            sidechain.sendtomainchain(some_btc_addr+"b", bal_1 - 1)
            raise Exception("Sending to invalid address; should have failed")
        except JSONRPCException as e:
            assert("Invalid Bitcoin address" in e.error["message"])

        assert(sidechain.getwalletinfo()["balance"]["bitcoin"] == bal_1)
        try:
            sidechain.sendtomainchain("1Nro9WkpaKm9axmcfPVp79dAJU1Gx7VmMZ", bal_1 - 1)
            raise Exception("Sending to mainchain address when should have been testnet; should have failed")
        except JSONRPCException as e:
            assert("Invalid Bitcoin address" in e.error["message"])

        assert(sidechain.getwalletinfo()["balance"]["bitcoin"] == bal_1)

        # Test superfluous peg-in witness data on regular spend before we have no funds
        raw_spend = sidechain.createrawtransaction([], {sidechain.getnewaddress():1})
        fund_spend = sidechain.fundrawtransaction(raw_spend)
        sign_spend = sidechain.signrawtransactionwithwallet(fund_spend["hex"])
        signed_struct = FromHex(CTransaction(), sign_spend["hex"])
        # Non-witness tx has no witness serialized yet
        if len(signed_struct.wit.vtxinwit) == 0:
            signed_struct.wit.vtxinwit = [CTxInWitness()]
        signed_struct.wit.vtxinwit[0].peginWitness.stack = sample_pegin_witness.stack
        assert_equal(sidechain.testmempoolaccept([signed_struct.serialize().hex()])[0]["allowed"], False)
        assert_equal(sidechain.testmempoolaccept([signed_struct.serialize().hex()])[0]["reject-reason"], "68: extra-pegin-witness")
        signed_struct.wit.vtxinwit[0].peginWitness.stack = [b'\x00'*100000] # lol
        assert_equal(sidechain.testmempoolaccept([signed_struct.serialize().hex()])[0]["allowed"], False)
        assert_equal(sidechain.testmempoolaccept([signed_struct.serialize().hex()])[0]["reject-reason"], "68: extra-pegin-witness")

        peg_out_txid = sidechain.sendtomainchain(some_btc_addr, 1)

        peg_out_details = sidechain.decoderawtransaction(sidechain.getrawtransaction(peg_out_txid))
        # peg-out, change, fee
        assert(len(peg_out_details["vout"]) == 3)
        found_pegout_value = False
        for output in peg_out_details["vout"]:
            if "value" in output and output["value"] == 1:
                found_pegout_value = True
        assert(found_pegout_value)

        bal_2 = sidechain.getwalletinfo()["balance"]["bitcoin"]
        # Make sure balance went down
        assert(bal_2 + 1 < bal_1)

        # Send rest of coins using subtractfee from output arg
        sidechain.sendtomainchain(some_btc_addr, bal_2, True)

        assert(sidechain.getwalletinfo()["balance"]['bitcoin'] == 0)

        print('Test coinbase peg-in maturity rules')

        # Have bitcoin output go directly into a claim output
        pegin_info = sidechain.getpeginaddress()
        mainchain_addr = pegin_info["mainchain_address"]
        # Watch the address so we can get tx without txindex
        parent.importaddress(mainchain_addr)
        claim_block = parent.generatetoaddress(50, mainchain_addr)[0]
        block_coinbase = parent.getblock(claim_block, 2)["tx"][0]
        claim_txid = block_coinbase["txid"]
        claim_tx = block_coinbase["hex"]
        claim_proof = parent.gettxoutproof([claim_txid], claim_block)

        # Can't claim something even though it has 50 confirms since it's coinbase
        assert_raises_rpc_error(-8, "Peg-in Bitcoin transaction needs more confirmations to be sent.", sidechain.claimpegin, claim_tx, claim_proof)
        # If done via raw API, still doesn't work
        coinbase_pegin = sidechain.createrawpegin(claim_tx, claim_proof)
        assert_equal(coinbase_pegin["mature"], False)
        signed_pegin = sidechain.signrawtransactionwithwallet(coinbase_pegin["hex"])["hex"]
        assert_raises_rpc_error(-26, "bad-pegin-witness, Needs more confirmations.", sidechain.sendrawtransaction, signed_pegin)

        # 50 more blocks to allow wallet to make it succeed by relay and consensus
        parent.generatetoaddress(50, parent.getnewaddress())
        # Wallet still doesn't want to for 2 more confirms
        assert_equal(sidechain.createrawpegin(claim_tx, claim_proof)["mature"], False)
        # But we can just shoot it off
        claim_txid = sidechain.sendrawtransaction(signed_pegin)
        sidechain.generatetoaddress(1, sidechain.getnewaddress())
        assert_equal(sidechain.gettransaction(claim_txid)["confirmations"], 1)

        print('Success!')

        # Manually stop sidechains first, then the parent chains.
        self.stop_node(2)
        self.stop_node(3)
        self.stop_node(0)
        self.stop_node(1)