Exemplo n.º 1
0
    def test_ed25519(self):
        assert (encodepoint(edf.B) == b'Xfffffffffffffffffffffffffffffff')

        assert (
            b2h(encodepoint(hashToEd25519(encodepoint(edf.B)))) ==
            '13b663e5e06bf5301c77473bb2fc5beb51e4046e9b7efef2f6d1a324cb8b1094')

        test_point_2 = '97ab9932634c2a71ded409c73e84d64487dcc224f9728fde24ef3327782e68c3'
        assert (
            b2h(encodepoint(hashToEd25519(h2b(test_point_2)))) ==
            'ade1232c101e6e42564b97ac2b38387a509df0a31d38e36bf4bdf4ad2f4f5573')
Exemplo n.º 2
0
    def test_04_follower_recover_b_lock_tx(self):
        ID_ALICE_SWAP = os.path.join(TEST_DIR,
                                     'test_04_alice_swap_state') + '.json'
        ID_BOB_SWAP = os.path.join(TEST_DIR,
                                   'test_04_bob_swap_state') + '.json'

        alice_btc_start = make_int(
            callnoderpc(ID_ALICE_PART, 'getbalances')['mine']['trusted'])
        bob_btc_start = make_int(
            callnoderpc(ID_BOB_PART, 'getbalances')['mine']['trusted'])
        alice_xmr_start = self.callxmrnodewallet(ID_ALICE_XMR,
                                                 'get_balance')['balance']
        bob_xmr_start = self.callxmrnodewallet(ID_BOB_XMR,
                                               'get_balance')['balance']

        logging.info(
            'Test start wallet states:\nalice_btc_start: %ld\nbob_btc_start: %ld\nalice_xmr_start: %ld\nbob_xmr_start: %ld',
            alice_btc_start, bob_btc_start, alice_xmr_start, bob_xmr_start)

        # Same steps as in test_01_swap_successful
        self.startSwap(ID_ALICE_SWAP, ID_BOB_SWAP, 3, 4)
        msg2f = callSwapTool(ID_ALICE_SWAP, 'msg2f')
        callSwapTool(ID_BOB_SWAP, 'processmsg', str_param=msg2f)
        msg3l = callSwapTool(ID_BOB_SWAP, 'msg3l')
        callSwapTool(ID_ALICE_SWAP, 'processmsg', str_param=msg3l)
        msg4f = callSwapTool(ID_ALICE_SWAP, 'msg4f')
        a_lock_txid = callSwapTool(ID_ALICE_SWAP, 'publishalocktx').strip()

        logging.info(
            'Bob verifies the lock spend tx and encrypted signature from Alice.'
        )
        callSwapTool(ID_BOB_SWAP, 'processmsg', str_param=msg4f)

        logging.info('Bob waits for the script-chain lock tx to confirm.')

        num_tries = 30
        for i in range(1 + num_tries):
            rv = callSwapTool(ID_BOB_SWAP, 'confirmalocktx')
            print('confirmalocktx', rv)
            if rv.strip() == 'True':
                break

            if i >= num_tries:
                raise ValueError(
                    'Timed out waiting for script-chain lock tx to confirm.')

        logging.info('Then publishes the second-chain lock tx.')
        b_lock_txid = callSwapTool(ID_BOB_SWAP, 'publishblocktx')

        logging.info(
            'Alice waits for the scriptless-chain lock tx to confirm.')

        num_tries = 120
        for i in range(1 + num_tries):
            rv = callSwapTool(ID_ALICE_SWAP, 'confirmblocktx')
            print('confirmblocktx', rv)
            if rv.strip() == 'True':
                break

            if i >= num_tries:
                raise ValueError(
                    'Timed out waiting for scriptless-chain lock tx to confirm.'
                )
            time.sleep(2)

        logging.info(
            'Alice detects a problem with the scriptless-chain lock tx and decides to cancel the swap'
        )

        a_lock_refund_txid = self.publishALockRefundTx(ID_ALICE_PART,
                                                       ID_ALICE_SWAP)

        # Import key to receive refund in wallet.  Simple method for testing.
        kal = callSwapTool(ID_ALICE_SWAP, 'getkal')
        kal_wif = bytes_to_wif(h2b(kal), prefix=0x2e)
        callnoderpc(ID_ALICE_PART, 'importprivkey', [kal_wif, 'swap refund'])

        alockrefundspendtxid = callSwapTool(ID_ALICE_SWAP,
                                            'publishalockrefundspendtx')

        rv = callnoderpc(ID_ALICE_PART, 'getbalances')
        print('getbalances', dumpj(rv))
        alice_btc = make_int(rv['mine']['trusted']) + make_int(
            rv['mine']['untrusted_pending'])
        logging.info('alice_btc %ld', alice_btc)

        logging.info('Bob waits for Alice to spend the lock refund tx.')

        num_tries = 20
        for i in range(1 + num_tries):
            rv = callSwapTool(ID_BOB_SWAP, 'findalockrefundspendtx')
            print('findalockrefundspendtx', rv)
            if rv.strip() == 'True':
                break
            if i >= num_tries:
                raise ValueError(
                    'Timed out waiting for script-chain lock refund spend tx to confirm.'
                )
            time.sleep(1)

        logging.info('Then he can recover his scriptless-chain lock tx coin.')

        self.callxmrnodewallet(ID_BOB_XMR, 'open_wallet',
                               {'filename': 'testwallet'})
        xmr_addr_bob = self.callxmrnodewallet(ID_BOB_XMR,
                                              'get_address')['address']

        rv = callSwapTool(ID_BOB_SWAP, 'redeemblocktx', str_param=xmr_addr_bob)
        print('redeemblocktx', rv)

        self.callxmrnodewallet(ID_BOB_XMR, 'close_wallet')
        self.callxmrnodewallet(ID_BOB_XMR, 'open_wallet',
                               {'filename': 'testwallet'})
Exemplo n.º 3
0
def initialiseSwap(swapinfo, data):
    try:
        a_coin = CoinIds[data['a_coin']]
    except Exception as e:
        raise ValueError('Unknown A coin type')

    # Coin A must have a script
    if a_coin == CoinIds.XMR:
        raise ValueError('Bad A coin type')

    try:
        b_coin = CoinIds[data['b_coin']]
    except Exception as e:
        raise ValueError('Unknown B coin type')

    swapinfo.a_connect = data['a_connect']
    swapinfo.b_connect = data['b_connect']
    ai = makeInterface(a_coin, swapinfo.a_connect)
    bi = makeInterface(b_coin, swapinfo.b_connect)

    a_amount = make_int(data['a_amount'], ai.exp())
    b_amount = make_int(data['b_amount'], bi.exp())

    a_feerate = make_int(data['a_feerate'], ai.exp())
    b_feerate = make_int(data['b_feerate'], bi.exp())

    if 'a_addr_f' in data:
        # Decode p2wpkh address
        addr = data['a_addr_f']
        addr_split = addr.split('1')
        if len(addr_split) != 2:
            raise ValueError('Invalid bech32 address')

        if addr_split[0] not in ['bc', 'pw', 'bcrt', 'rtpw']:
            raise ValueError('Unknown bech32 hrp')

        ignr, pkh = segwit_addr.decode(addr_split[0], addr)
        a_pkhash_f = bytes(pkh)
    else:
        a_pkhash_f = h2b(data['a_pkhash_f'])

    lock1 = data['lock1'] if 'lock1' in data else 100
    lock2 = data['lock2'] if 'lock2' in data else 101

    restore_height_b = data[
        'b_restore_height'] if 'b_restore_height' in data else 0

    check_a_lock_tx_inputs = data[
        'check_a_lock_tx_inputs'] if 'check_a_lock_tx_inputs' in data else True

    swapinfo.setSwapParameters(a_coin,
                               a_amount,
                               b_coin,
                               b_amount,
                               a_feerate,
                               b_feerate,
                               a_pkhash_f,
                               lock1=lock1,
                               lock2=lock2,
                               restore_height_b=restore_height_b,
                               check_a_lock_tx_inputs=check_a_lock_tx_inputs)

    if data['side'].lower() == 'a':
        swapinfo.initialiseLeader(ai, bi)
    elif data['side'].lower() == 'b':
        swapinfo.initialiseFollower(ai, bi)
    else:
        raise ValueError('Unknown swap side')
Exemplo n.º 4
0
    def test_02_leader_recover_a_lock_tx(self):
        ID_ALICE_SWAP = os.path.join(TEST_DIR,
                                     'test_02_alice_swap_state') + '.json'
        ID_BOB_SWAP = os.path.join(TEST_DIR,
                                   'test_02_bob_swap_state') + '.json'

        alice_btc_start = make_int(
            callnoderpc(ID_ALICE_PART, 'getbalances')['mine']['trusted'])
        bob_btc_start = make_int(
            callnoderpc(ID_BOB_PART, 'getbalances')['mine']['trusted'])

        alice_xmr_start = self.callxmrnodewallet(ID_ALICE_XMR,
                                                 'get_balance')['balance']
        bob_xmr_start = self.callxmrnodewallet(ID_BOB_XMR,
                                               'get_balance')['balance']

        logging.info(
            'Test start wallet states:\nalice_btc_start: %ld\nbob_btc_start: %ld\nalice_xmr_start: %ld\nbob_xmr_start: %ld',
            alice_btc_start, bob_btc_start, alice_xmr_start, bob_xmr_start)

        self.startSwap(ID_ALICE_SWAP, ID_BOB_SWAP, 2, 3)

        logging.info(
            'Alice creates the script-chain lock and refund txns and signs the refund tx, sends to Bob.'
        )
        msg2f = callSwapTool(ID_ALICE_SWAP, 'msg2f')

        logging.info(
            'Bob verifies the txns and signs the refund tx and creates an encrypted signature for the refund spend tx encumbered by Alice\'s coin B key share.'
        )
        callSwapTool(ID_BOB_SWAP, 'processmsg', str_param=msg2f)
        msg3l = callSwapTool(ID_BOB_SWAP, 'msg3l')

        logging.info(
            'Alice verifies the signature and encrypted signature from Bob.')
        callSwapTool(ID_ALICE_SWAP, 'processmsg', str_param=msg3l)

        logging.info(
            'Creates the lock spend tx and signs an encrypted signature encumbered by Bob\'s coin B key share'
        )
        msg4f = callSwapTool(ID_ALICE_SWAP, 'msg4f')

        logging.info('Publishes the script-chain lock tx.')
        a_lock_txid = callSwapTool(ID_ALICE_SWAP, 'publishalocktx').strip()

        # Wait for the mining node to receive the tx
        for i in range(10):
            try:
                callnoderpc(0, 'getrawtransaction', [a_lock_txid])
                break
            except Exception as e:
                print('Waiting for node 0 to see tx', str(e))
            time.sleep(1)

        logging.info('Bob stops responding here.')

        alice_btc = make_int(
            callnoderpc(ID_ALICE_PART, 'getbalances')['mine']['trusted'])
        logging.info('alice_btc %ld', alice_btc)

        a_lock_refund_txid = self.publishALockRefundTx(ID_ALICE_PART,
                                                       ID_ALICE_SWAP)

        # Import key to receive refund in wallet.  Simple method for testing.
        kal = callSwapTool(ID_ALICE_SWAP, 'getkal')
        kal_wif = bytes_to_wif(h2b(kal), prefix=0x2e)
        callnoderpc(ID_ALICE_PART, 'importprivkey', [kal_wif, 'swap refund'])

        alockrefundspendtxid = callSwapTool(ID_ALICE_SWAP,
                                            'publishalockrefundspendtx')

        rv = callnoderpc(ID_ALICE_PART, 'getbalances')
        alice_btc_end = make_int(rv['mine']['trusted']) + make_int(
            rv['mine']['untrusted_pending'])
        logging.info('alice_btc_end %ld', alice_btc_end)

        assert (alice_btc_end > alice_btc)
Exemplo n.º 5
0
def main():

    parser = argparse.ArgumentParser(
        formatter_class=argparse.RawDescriptionHelpFormatter, epilog=__doc__)
    parser.add_argument(
        '-v',
        '--version',
        action='version',
        version='%(prog)s {version}'.format(version=__version__))
    parser.add_argument('swap_state_file', help='Path to the swap state file')
    parser.add_argument('opts', nargs=argparse.REMAINDER)
    args = parser.parse_args()

    swapinfo = SwapInfo()

    if os.path.isfile(args.swap_state_file):
        swapinfo.importFromFile(args.swap_state_file)

    if len(args.opts) == 0:
        method = 'info'
    else:
        method = args.opts[0]

    if method == 'info':
        printSwapInfo(swapinfo)
        return 0
    elif method == 'init':
        data = toJSON(args.opts[1])
        initialiseSwap(swapinfo, data)
        print('success')
    elif method == 'processmsg':
        msg = h2b(args.opts[1])
        swapinfo.processMessage(msg)
        print('success')
    elif method == 'msg1f':
        msg = swapinfo.packageInitMsgToFollower()
        print(b2h(msg))
    elif method == 'msg1l':
        msg = swapinfo.packageInitMsgToLeader()
        print(b2h(msg))
    elif method == 'msg2f':
        msg = swapinfo.packageMSG2F()
        print(b2h(msg))
    elif method == 'msg3l':
        msg = swapinfo.packageMSG3L()
        print(b2h(msg))
    elif method == 'msg4f':
        msg = swapinfo.packageMSG4F()
        print(b2h(msg))
    elif method == 'msg5f':
        msg = swapinfo.packageMSG5F()
        print(b2h(msg))
    elif method == 'publishalocktx':
        txid = swapinfo.publishALockTx()
        print(txid)
    elif method == 'publishalockrefundtx':
        txid = swapinfo.publishALockRefundTx()
        print(txid)
    elif method == 'confirmalocktx':
        rv = swapinfo.hasALockTxConfirmed()
        print('True' if rv else 'False')
        return 0
    elif method == 'publishblocktx':
        txid = swapinfo.publishBLockTx()
        print(txid)
    elif method == 'confirmblocktx':
        rv = swapinfo.hasBLockTxConfirmed()
        print('True' if rv else 'False')
        return 0
    elif method == 'publishalockspendtx':
        txid = swapinfo.publishALockSpendTx()
        print(txid)
    elif method == 'findalockspendtx':
        rv = swapinfo.findALockSpendTx()
        print('True' if rv else 'False')
    elif method == 'redeemblocktx':
        dest = args.opts[1]
        txid = swapinfo.redeemBLockTx(dest)
        print(txid)
    elif method == 'publishalockrefundspendtx':
        txid = swapinfo.publishALockRefundSpendTx()
        print(txid)
    elif method == 'getkal':
        print(i2h(swapinfo.kal))
        return 0
    elif method == 'publishalockrefundspendftx':
        dest = h2b(args.opts[1])
        txid = swapinfo.publishALockRefundSpendToFTx(dest)
        print(txid)
    elif method == 'findalockrefundspendtx':
        rv = swapinfo.findALockRefundSpendTx()
        print('True' if rv else 'False')
    else:
        raise ValueError('Invalid method')

    swapinfo.exportToFile(args.swap_state_file)

    return 0