Example #1
0
 def test_clone(self):
     outpoint = COutPoint(
         lx('4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b'
            ), 0)
     txin = CTxIn(prevout=outpoint,
                  scriptSig=CScript(b'\x03abc'),
                  nSequence=0xffffffff)
     self.assertEqual(txin.serialize(), txin.clone().serialize())
 def create_test_txs(self, scriptSig, scriptPubKey, witness, nValue):
     txCredit = CTransaction([CTxIn(COutPoint(), CScript([OP_0, OP_0]), nSequence=0xFFFFFFFF)],
                             [CTxOut(nValue, scriptPubKey)],
                             witness=CTxWitness(),
                             nLockTime=0, nVersion=1)
     txSpend = CTransaction([CTxIn(COutPoint(txCredit.GetTxid(), 0), scriptSig, nSequence=0xFFFFFFFF)],
                            [CTxOut(nValue, CScript())],
                            nLockTime=0, nVersion=1,
                            witness=CTxWitness([CTxInWitness(witness)]))
     return (txCredit, txSpend)
    def test_is_coinbase(self):
        tx = CMutableTransaction()
        self.assertFalse(tx.is_coinbase())

        tx.vin.append(CMutableTxIn())

        # IsCoinBase() in reference client doesn't check if vout is empty
        self.assertTrue(tx.is_coinbase())

        tx.vin[0].prevout.n = 0
        self.assertFalse(tx.is_coinbase())

        tx.vin[0] = CTxIn()
        tx.vin.append(CTxIn())
        self.assertFalse(tx.is_coinbase())
    def test_repr(self):
        def T(txin, expected):
            actual = repr(txin)
            self.assertEqual(actual, expected)

        T(CTxIn(),
          'CBitcoinTxIn(CBitcoinOutPoint(), CBitcoinScript([]), 0xffffffff)')
    def test_mutable_tx_creation_with_immutable_parts_specified(self) -> None:
        tx = CElementsMutableTransaction(
            vin=[CTxIn(prevout=COutPoint(hash=b'a' * 32, n=0))],
            vout=[CTxOut()],
            witness=CTxWitness(vtxinwit=[CTxInWitness()],
                               vtxoutwit=[CTxOutWitness()]))

        self.assertIsInstance(tx, CElementsMutableTransaction)

        def check_mutable_parts(tx: CElementsMutableTransaction) -> None:
            self.assertTrue(tx.vin[0].is_mutable())
            self.assertTrue(tx.vin[0].prevout.is_mutable())
            self.assertTrue(tx.vout[0].is_mutable())
            self.assertTrue(tx.wit.is_mutable())
            self.assertTrue(tx.wit.vtxinwit[0].is_mutable())
            self.assertTrue(tx.wit.vtxoutwit[0].is_mutable())

        check_mutable_parts(tx)

        # Test that if we deserialize with CMutableTransaction,
        # all the parts are mutable
        tx = CElementsMutableTransaction.deserialize(tx.serialize())
        check_mutable_parts(tx)

        # Test some parts separately, because when created via
        # CMutableTransaction instantiation, they are created with from_*
        # methods, and not directly

        txin = CMutableTxIn(prevout=COutPoint(hash=b'a' * 32, n=0))
        self.assertTrue(txin.prevout.is_mutable())

        wit = CElementsMutableTxWitness((CElementsTxInWitness(), ),
                                        (CElementsTxOutWitness(), ))
        self.assertTrue(wit.vtxinwit[0].is_mutable())
        self.assertTrue(wit.vtxoutwit[0].is_mutable())
    def test_immutable_tx_creation_with_mutable_parts_specified(self):
        tx = CTransaction(
            vin=[CMutableTxIn(prevout=COutPoint(hash=b'a' * 32, n=0))],
            vout=[CMutableTxOut(nValue=1)],
            witness=CMutableTxWitness(
                [CMutableTxInWitness(CScriptWitness([CScript([0])]))]))

        def check_immutable_parts(tx):
            self.assertTrue(tx.vin[0].is_immutable())
            self.assertTrue(tx.vin[0].is_immutable())
            self.assertTrue(tx.vout[0].is_immutable())
            self.assertTrue(tx.wit.is_immutable())
            self.assertTrue(tx.wit.vtxinwit[0].is_immutable())

        check_immutable_parts(tx)

        # Test that if we deserialize with CTransaction,
        # all the parts are immutable
        tx = CTransaction.deserialize(tx.serialize())
        check_immutable_parts(tx)

        # Test some parts separately, because when created via
        # CMutableTransaction instantiation, they are created with from_*
        # methods, and not directly

        txin = CTxIn(prevout=CMutableOutPoint(hash=b'a' * 32, n=0))
        self.assertTrue(txin.prevout.is_immutable())

        wit = CTxWitness((CMutableTxInWitness(), ))
        self.assertTrue(wit.vtxinwit[0].is_immutable())
Example #7
0
    def test_repr(self):
        def T(txin, expected):
            actual = repr(txin)
            self.assertEqual(actual, expected)

        T(
            CTxIn(),
            'CElementsTxIn(CElementsOutPoint(), CElementsScript([]), 0xffffffff, CAssetIssuance(), is_pegin=False)'
        )
    def test_immutable(self):
        tx = CTransaction()
        self.assertFalse(tx.is_coinbase())

        with self.assertRaises(AttributeError):
            tx.nVersion = 2
        with self.assertRaises(AttributeError):
            tx.vin.append(CTxIn())

        mtx = tx.to_mutable()
        mtx.nVersion = 2
        mtx.vin.append(CTxIn())

        itx = tx.to_immutable()

        with self.assertRaises(AttributeError):
            itx.nVersion = 2
        with self.assertRaises(AttributeError):
            itx.vin.append(CTxIn())
    def test_immutable(self) -> None:
        tx = CTransaction()
        self.assertFalse(tx.is_coinbase())

        # check that immutable property holds
        with self.assertRaises(AttributeError):
            tx.nVersion = 2  # type: ignore
        with self.assertRaises(AttributeError):
            tx.vin.append(CTxIn())  # type: ignore

        mtx = tx.to_mutable()
        mtx.nVersion = 2
        mtx.vin.append(CMutableTxIn())

        itx = tx.to_immutable()

        with self.assertRaises(AttributeError):
            itx.nVersion = 2  # type: ignore
        with self.assertRaises(AttributeError):
            itx.vin.append(CTxIn())  # type: ignore
Example #10
0
def create_btc_spend_tx(dst_addr,
                        txid,
                        vout_n,
                        btc_contract,
                        spend_key=None,
                        branch_condition=True):

    # In real application, the fees should not be static, of course
    out_amount = (coins_to_satoshi(pre_agreed_amount) -
                  coins_to_satoshi(fixed_fee_amount))

    tx = CMutableTransaction(
        vin=[CTxIn(prevout=COutPoint(hash=lx(txid), n=vout_n))],
        vout=[
            CTxOut(nValue=out_amount, scriptPubKey=dst_addr.to_scriptPubKey())
        ])

    if branch_condition is True:
        cond = b'\x01'
    else:
        tx.vin[0].nSequence = bitcoin_contract_timeout
        cond = b''

    in_amount = coins_to_satoshi(pre_agreed_amount)
    # We used P2WSHCoinAddress to create the address that we sent bitcoin to,
    # so we know that we need to use SIGVERSION_WITNESS_V0
    sighash = btc_contract.sighash(tx,
                                   0,
                                   SIGHASH_ALL,
                                   amount=in_amount,
                                   sigversion=SIGVERSION_WITNESS_V0)

    spend_sig = spend_key.sign(sighash) + bytes([SIGHASH_ALL])

    # This is script witness, not script. The condition for OP_IF
    # in our script is directly encoded as data in the witness.
    # We cannot use OP_TRUE/OP_FALSE here. We use DATA guard is to ensure that.
    witness = CScriptWitness([spend_sig, DATA(cond), btc_contract])

    # empty scriptSig, because segwit
    tx.vin[0].scriptSig = CBitcoinScript([])
    # all data to check the spend conditions is in the witness
    tx.wit.vtxinwit[0] = CTxInWitness(witness)

    # Cannot use VerifyScript for now,
    # because it does not support CHECKSEQUENCEVERIFY yet
    #
    # from_addr = P2WSHBitcoinAddress.from_redeemScript(btc_contract)
    # VerifyScript(tx.vin[0].scriptSig, from_addr.to_scriptPubKey(),
    #              tx, 0, amount=in_amount)

    return tx
Example #11
0
    def test_sighash(self) -> None:
        spent_amount = 1100
        pub = CKey.from_secret_bytes(os.urandom(32)).pub
        spk_legacy = P2PKHCoinAddress.from_pubkey(pub).to_scriptPubKey()
        spk_segwit = P2WPKHCoinAddress.from_pubkey(pub).to_scriptPubKey()

        tx = CTransaction([
            CTxIn(
                COutPoint(b'\x00' * 32, 0), CScript([]), nSequence=0xFFFFFFFF)
        ], [CTxOut(1000, spk_legacy)],
                          nLockTime=0,
                          nVersion=1)

        # no exceptions should be raised with these two calls
        spk_legacy.sighash(tx,
                           0,
                           SIGHASH_ALL,
                           amount=spent_amount,
                           sigversion=SIGVERSION_WITNESS_V0)
        spk_segwit.sighash(tx,
                           0,
                           SIGHASH_ALL,
                           amount=spent_amount,
                           sigversion=SIGVERSION_WITNESS_V0)

        with self.assertRaises(ValueError):
            # unknown sigversion
            spk_segwit.sighash(tx,
                               0,
                               SIGHASH_ALL,
                               amount=spent_amount,
                               sigversion=SIGVERSION_WITNESS_V0 +
                               1)  # type: ignore

        assert spk_segwit.is_witness_scriptpubkey()
        with self.assertRaises(ValueError):
            # incorect sigversion for segwit
            spk_segwit.sighash(tx,
                               0,
                               SIGHASH_ALL,
                               amount=spent_amount,
                               sigversion=SIGVERSION_BASE)

        with self.assertRaises(ValueError):
            # inIdx > len(tx.vin) - non-raw sighash function should raise
            # ValueError (raw_sighash can return HASH_ONE)
            spk_legacy.sighash(tx,
                               10,
                               SIGHASH_ALL,
                               amount=spent_amount,
                               sigversion=SIGVERSION_BASE)
Example #12
0
        redeemScript.to_p2sh_scriptPubKey(): COutPoint(b'\x00' * 32, i)
        for i, (scriptSig, redeemScript) in enumerate(scripts)
    }
    logging.debug('Payments: %r' % payments)
    logging.info(
        'Total cost: %s BTC' %
        str_money_value(sum(amount for addr, amount in payments.items())))

# Create unsigned tx for SignatureHash
vout = [CTxOut(0, CScript([OP_RETURN]))]

unsigned_vin = []
for scriptSig, redeemScript in scripts:
    scriptPubKey = redeemScript.to_p2sh_scriptPubKey()

    txin = CTxIn(prevouts_by_scriptPubKey[scriptPubKey])
    unsigned_vin.append(txin)
unsigned_tx = CTransaction(unsigned_vin, vout)

# Sign!
signed_vin = []
for i, (scriptSig, redeemScript) in enumerate(scripts):
    sighash = redeemScript.sighash(unsigned_tx, i, SIGHASH_NONE)
    sig = args.privkey.sign(sighash) + bytes([SIGHASH_NONE])

    signed_scriptSig = CScript([sig] + list(scriptSig))

    txin = CTxIn(unsigned_vin[i].prevout, signed_scriptSig)

    signed_vin.append(txin)
Example #13
0
def create_elt_spend_tx(dst_addr,
                        txid,
                        vout_n,
                        elt_contract,
                        die,
                        spend_key=None,
                        contract_key=None,
                        blinding_key=None,
                        blinding_factor=None,
                        asset_blinding_factor=None,
                        branch_condition=True):

    fee_satoshi = coins_to_satoshi(fixed_fee_amount)
    out_amount = coins_to_satoshi(pre_agreed_amount) - fee_satoshi

    # Single blinded output is not allowed, so we add
    # dummy OP_RETURN output, and we need dummy pubkey for it
    dummy_key = CKey.from_secret_bytes(os.urandom(32))

    tx = CMutableTransaction(
        vin=[CTxIn(prevout=COutPoint(hash=lx(txid), n=vout_n))],
        vout=[
            CTxOut(nValue=CConfidentialValue(out_amount),
                   nAsset=CConfidentialAsset(bitcoin_asset),
                   scriptPubKey=dst_addr.to_scriptPubKey(),
                   nNonce=CConfidentialNonce(dst_addr.blinding_pubkey)),
            CTxOut(nValue=CConfidentialValue(0),
                   nAsset=CConfidentialAsset(bitcoin_asset),
                   nNonce=CConfidentialNonce(dummy_key.pub),
                   scriptPubKey=CElementsScript([OP_RETURN])),
            CTxOut(nValue=CConfidentialValue(fee_satoshi),
                   nAsset=CConfidentialAsset(bitcoin_asset))
        ])

    output_pubkeys = [dst_addr.blinding_pubkey, dummy_key.pub]

    in_amount = coins_to_satoshi(pre_agreed_amount)

    input_descriptors = [
        BlindingInputDescriptor(asset=bitcoin_asset,
                                amount=in_amount,
                                blinding_factor=blinding_factor,
                                asset_blinding_factor=asset_blinding_factor)
    ]

    blind_result = tx.blind(input_descriptors=input_descriptors,
                            output_pubkeys=output_pubkeys)

    # The blinding must succeed!
    if blind_result.error:
        die('blind failed: {}'.format(blind_result.error))

    if branch_condition is False:
        # Must set nSequence before we calculate signature hash,
        # because it is included in it
        tx.vin[0].nSequence = elements_contract_timeout

    # We used P2SHCoinAddress to create the address that
    # we sent Elements-BTC to, so we know that we need
    # to use SIGVERSION_BASE

    sighash = elt_contract.sighash(tx,
                                   0,
                                   SIGHASH_ALL,
                                   amount=CConfidentialValue(in_amount),
                                   sigversion=SIGVERSION_BASE)

    spend_sig = spend_key.sign(sighash) + bytes([SIGHASH_ALL])

    if branch_condition is True:
        prepare_elt_spend_reveal_branch(tx, elt_contract, spend_sig,
                                        contract_key, blinding_key)
    else:
        tx.vin[0].scriptSig = CElementsScript(
            [spend_sig, OP_FALSE, elt_contract])

    return tx
 def test_immutable(self):
     """CTxIn shall not be mutable"""
     txin = CTxIn()
     with self.assertRaises(AttributeError):
         txin.nSequence = 1
        except FileNotFoundError as exp:
            if len(f) / 2 in (20, 32):
                digests.append(x(f))
            else:
                raise exp
        except IOError as exp:
            print(exp, file=sys.stderr)
            continue

    for digest in digests:
        txouts = []

        unspent = sorted(rpc.listunspent(0), key=lambda x: hash(x['amount']))

        txins = [
            CTxIn(COutPoint(lx(unspent[-1]['txid']), int(unspent[-1]['vout'])))
        ]
        value_in = coins_to_satoshi(unspent[-1]['amount'])

        change_addr = rpc.getnewaddress()
        change_pubkey_hex = rpc.getaddressinfo(change_addr)['pubkey']
        change_out = CMutableTxOut(
            CoreCoinParams.MAX_MONEY,
            CScript([x(change_pubkey_hex), OP_CHECKSIG]))

        digest_outs = [CMutableTxOut(0, CScript([OP_RETURN, digest]))]

        txouts = [change_out] + digest_outs

        tx = CTransaction(txins, txouts).to_mutable()
 def test_is_final(self):
     self.assertTrue(CTxIn().is_final())
     self.assertTrue(CTxIn(nSequence=0xffffffff).is_final())
     self.assertFalse(CTxIn(nSequence=0).is_final())
Example #17
0
def claim_funds_back(say, utxos, die, rpc):
    """Try to claim our funds by sending our UTXO to our own addresses"""

    # The transaction-building code here does not introduce anything new
    # compared to the code in participant functions, so it will not be
    # commented too much.

    input_descriptors = []
    # It is better to prepare the claw-back transaction beforehand, to avoid
    # the possibility of unexpected problems arising at the critical time when
    # we need to send claw-back tx ASAP, but that would clutter the earlier
    # part of the example with details that are not very relevant there.
    tx = CMutableTransaction()
    for utxo in utxos:
        tx.vin.append(
            CTxIn(prevout=COutPoint(hash=lx(utxo['txid']), n=utxo['vout'])))
        input_descriptors.append(
            BlindingInputDescriptor(
                asset=CAsset(lx(utxo['asset'])),
                amount=coins_to_satoshi(utxo['amount']),
                blinding_factor=Uint256(lx(utxo['amountblinder'])),
                asset_blinding_factor=Uint256(lx(utxo['assetblinder']))))

    asset_amounts = {}
    # If some assets are the same, we want them to be sent to one address
    for idesc in input_descriptors:
        if idesc.asset == fee_asset:
            amount = idesc.amount - FIXED_FEE_SATOSHI
            assert amount >= FIXED_FEE_SATOSHI  # enforced at find_utxo_for_fee
        else:
            amount = idesc.amount

        asset_amounts[idesc.asset] = amount

    output_pubkeys = []
    for asset, amount in asset_amounts.items():
        dst_addr, _ = get_dst_addr(None, rpc)
        tx.vout.append(
            CTxOut(nValue=CConfidentialValue(amount),
                   nAsset=CConfidentialAsset(asset),
                   scriptPubKey=dst_addr.to_scriptPubKey()))
        output_pubkeys.append(dst_addr.blinding_pubkey)

    # Add the explicit fee output
    tx.vout.append(
        CTxOut(nValue=CConfidentialValue(FIXED_FEE_SATOSHI),
               nAsset=CConfidentialAsset(fee_asset)))
    # Add dummy pubkey for non-blinded fee output
    output_pubkeys.append(CPubKey())

    # We used immutable objects for transaction components like CTxIn,
    # just for our convenience. Convert them all to mutable.
    tx = tx.to_immutable().to_mutable()

    # And blind the combined transaction
    blind_result = tx.blind(input_descriptors=input_descriptors,
                            output_pubkeys=output_pubkeys)

    assert (not blind_result.error
            and blind_result.num_successfully_blinded == len(utxos))

    for n, utxo in enumerate(utxos):
        sign_input(tx, n, utxo)

    # It is possible that Bob has actually sent the swap transaction.
    # We will get an error if our node has received this transaction.
    # In real application, we might handle this case, too, but
    # here we will just ignore it.
    txid = rpc.sendrawtransaction(b2x(tx.serialize()))

    rpc.generatetoaddress(1, rpc.getnewaddress())
    wait_confirm(say, txid, die, rpc)
Example #18
0
def bob(say, recv, send, die, rpc):
    """A function that implements the logic
    of the second participant of an asset atomic swap"""

    # Issue an asset that we are going to swap
    asset_str, asset_utxo = issue_asset(say, 1.0, rpc)
    asset_amount_satoshi = coins_to_satoshi(asset_utxo['amount'])

    say('Setting up communication with Alice')

    # Wait for Alice to start communication
    recv('ready')
    # To avoid mempool synchronization problems in two-node regtest setup,
    # in our example Alice is the one in charge of generating test blocks.
    # Send txid of asset issuance to alice so she can ensure it is confirmed.
    send('wait-txid-confirm', asset_utxo['txid'])

    say('Waiting for Alice to send us an offer array')

    alice_offers = recv('offer')

    # We unconditionally accept Alice's offer - her assets are
    # equally worthless as our asset :-)

    say("Alice's offers are {}, sending my offer".format(alice_offers))

    my_offer = AtomicSwapOffer(amount=asset_amount_satoshi, asset=asset_str)

    send('offer', my_offer)

    say('Waiting for Alice\'s address and assetcommitments')

    alice_addr_str, alice_assetcommitments = recv('addr_and_assetcommitments')

    print_asset_balances(say, alice_offers + [my_offer], rpc)

    # Convert Alice's address to address object.
    # If Alice passes invalid address, we die with we die with exception.
    alice_addr = CCoinAddress(alice_addr_str)

    say('Alice\'s address: {}'.format(alice_addr))
    say('Alice\'s assetcommitments: {}'.format(alice_assetcommitments))

    # Create asset commitments array. First goes our own asset commitment,
    # because our UTXO will be first.
    assetcommitments = [x(asset_utxo['assetcommitment'])]
    for ac in alice_assetcommitments:
        # If Alice sends non-hex data, we will die while converting.
        assetcommitments.append(x(ac))

    # Let's create our part of the transaction. We need to create
    # mutable transaction, because blind() method only works for mutable.
    partial_tx = CMutableTransaction(
        vin=[
            CTxIn(prevout=COutPoint(hash=lx(asset_utxo['txid']),
                                    n=asset_utxo['vout']))
        ],
        vout=[
            CTxOut(nValue=CConfidentialValue(asset_amount_satoshi),
                   nAsset=CConfidentialAsset(CAsset(lx(asset_str))),
                   scriptPubKey=alice_addr.to_scriptPubKey())
        ])

    # Blind our part of transaction, specifying assetcommitments
    # (Incliding those received from Alice) as auxiliary_generators.

    # Note that we could get the blinding factors if we retrieve
    # the transaction that we spend from, deserialize it, and unblind
    # the output that we are going to spend.
    # We could do everything here (besides issuing the asset and sending
    # the transactions) without using Elements RPC, if we get our data
    # from files or database, etc. But to simplify our demonstration,
    # we will use the values we got from RPC.

    # See 'spend-to-confidential-address.py' example for the code
    # that does the unblinding itself, and uses the unblinded values
    # to create a spending transaction.

    blind_result = partial_tx.blind(
        input_descriptors=[
            BlindingInputDescriptor(
                asset=CAsset(lx(asset_utxo['asset'])),
                amount=asset_amount_satoshi,
                blinding_factor=Uint256(lx(asset_utxo['amountblinder'])),
                asset_blinding_factor=Uint256(lx(asset_utxo['assetblinder'])))
        ],
        output_pubkeys=[alice_addr.blinding_pubkey],
        auxiliary_generators=assetcommitments)

    # The blinding must succeed!
    if blind_result.error:
        die('blind failed: {}'.format(blind_result.error))

    # And must blind exactly one output
    if blind_result.num_successfully_blinded != 1:
        die('blinded {} outputs, expected to be 1'.format(
            blind_result.num_successfully_blinded))

    say('Successfully blinded partial transaction, sending it to Alice')

    send('partial_blinded_tx', partial_tx.serialize())

    say("Generating addresses to receive Alice's assets")
    # Generate as many destination addresses as there are assets
    # in Alice's offer. Record blinding keys for the addresses.
    our_addrs = []
    blinding_keys = []
    for _ in alice_offers:
        addr, blinding_key = get_dst_addr(say, rpc)
        our_addrs.append(str(addr))
        blinding_keys.append(blinding_key)

    say("Sending my addresses and assetcommitment to Alice")
    send('addr_list_and_assetcommitment',
         (our_addrs, asset_utxo['assetcommitment']))

    semi_signed_tx_bytes = recv('partially_signed_tx')

    say('Got partially signed tx of size {} bytes from Alice'.format(
        len(semi_signed_tx_bytes)))

    semi_signed_tx = CTransaction.deserialize(semi_signed_tx_bytes)

    # Transaction should have 3 extra outputs - one output to Alice,
    # fee output, and fee asset change output
    if len(semi_signed_tx.vout) != len(alice_offers) + 3:
        die('unexpected number of outputs in tx from Alice: '
            'expected {}, got {}'.format(
                len(alice_offers) + 3, len(semi_signed_tx.vout)))

    if not semi_signed_tx.vout[-1].is_fee():
        die('Last output in tx from Alice '
            'is expected to be fee output, but it is not')

    # Unblind outputs that should be directed to us and check
    # that they match the offer. We use n+1 as output index
    # because we skip our own output, which is at index 0.
    for n, offer in enumerate(alice_offers):
        result = semi_signed_tx.vout[n + 1].unblind_confidential_pair(
            blinding_keys[n], semi_signed_tx.wit.vtxoutwit[n + 1].rangeproof)

        if result.error:
            die('cannot unblind output {} that should have been '
                'directed to us: {}'.format(n + 1, result.error))

        if result.asset.to_hex() != offer.asset:
            die("asset at position {} (vout {}) in partial transaction "
                "from Alice {} is not the same as asset in Alice's "
                "initial offer ({})".format(n, n + 1, result.asset.to_hex(),
                                            offer.asset))

        if result.amount != offer.amount:
            die("amount at position {} (vout {}) in partial transaction "
                "from Alice {} is not the same as amount in Alice's "
                "initial offer ({})".format(n, n + 1, result.amount,
                                            offer.amount))

    say("Assets and amounts in partially signed transaction "
        "match Alice's offer")

    # Signing will change the tx, so i
    tx = semi_signed_tx.to_mutable()

    # Our input is at index 0
    sign_input(tx, 0, asset_utxo)

    # Note that at this point both participants can still opt out of the swap:
    # Bob by not broadcasting the transaction, and Alice by double-spending
    # her inputs to the transaction. Bob still have tiny advantage, because
    # he can pretend to have 'difficulties' in broadcasting and try to exploit
    # Alice's patience

    say('Signed the transaction from my side, ready to send')

    tx_hex = b2x(tx.serialize())

    if bob_be_sneaky:
        say('Hey! I am now in control of the final transaction. '
            'I have the option to exectue the swap or abort. ')
        say('Why not wait a bit and watch asset prices, and execute '
            'the swap only if it is profitable')
        say('I will reduce my risk a bit by doing that.')
        # Bob takes his time and is not sending the final
        # transaction to Alice for some time...
        time.sleep(ALICE_PATIENCE_LIMIT + 2)
        say('OK, I am willing to execute the swap now')

    # Send the final transaction to Alice, so she can be sure that
    # we is not cheating
    send('final-signed-tx', tx_hex)

    txid = rpc.sendrawtransaction(tx_hex)

    say('Sent with txid {}'.format(txid))

    # Wait for alice to politely end the conversation
    recv('thanks-goodbye')
    print_asset_balances(say, alice_offers + [my_offer], rpc)

    for i, offer in enumerate(alice_offers):
        balance = coins_to_satoshi(rpc.getbalance("*", 1, False, offer.asset))
        if balance != offer.amount:
            die('something went wrong, asset{} balance after swap should be '
                '{} satoshi, but it is {} satoshi'.format(
                    i, balance, offer.amount))

    say('Asset atomic swap completed successfully')
Example #19
0
    # An array of blinding pubkeys that we will supply to tx.blind()
    # It should cover all the outputs of the resulting transaction.
    output_pubkeys = []

    if isinstance(dst_addr, CCoinConfidentialAddress):
        output_pubkeys.append(dst_addr.blinding_pubkey)
    else:
        output_pubkeys.append(CPubKey())

    # Construct a transaction that spends the output we found
    # to the given destination address.
    # Note that the CTransaction is just a frontend for convenience,
    # and the created object will be the instance of the
    # CElementsTransaction class. The same with CTxIn, CTxOut, etc.
    tx = CElementsTransaction(
        vin=[CTxIn(prevout=COutPoint(hash=input_tx.GetTxid(), n=utxo_n))],
        vout=[
            CElementsTxOut(nValue=CConfidentialValue(dst_value),
                           nAsset=CConfidentialAsset(asset_to_spend),
                           scriptPubKey=dst_addr.to_scriptPubKey()),
            # Fee output must be explicit in Elements
            CElementsTxOut(nValue=CConfidentialValue(fee_value),
                           nAsset=fee_asset)
        ])

    # Add empty pubkey for fee output
    output_pubkeys.append(CPubKey())

    # We cannot blind an immutable transaction. Make it mutable.
    tx = tx.to_mutable()