Exemple #1
0
 def setUp(self):
     self.n = 2
     #create n new random wallets.
     #put coins into the first mixdepth for each
     #The amount is 1btc + 300,000 satoshis, to account
     #for a 0.2% fee for 1 counterparty + a large tx fee.
     #(but not large enough to handle the bad wallet)
     wallet_structures = [[1, 0, 0, 0, 0]] * (self.n)
     self.wallets = make_wallets(self.n,
                                 wallet_structures=wallet_structures,
                                 mean_amt=1.00300000)
     #the sender is wallet (n), i.e. index wallets[n-1]
     #we need a counterparty with a huge set of utxos.
     bad_wallet_struct = [[1, 0, 0, 0, 0]]
     self.wallets.update(
         make_wallets(1,
                      wallet_structures=bad_wallet_struct,
                      mean_amt=0.01,
                      start_index=2))
     #having created the bad wallet, add lots of utxos to
     #the same mixdepth
     print 'creating a crazy amount of utxos in one wallet...'
     r_addr = self.wallets[2]['wallet'].get_external_addr(0)
     for i in range(60):
         jm_single().bc_interface.grab_coins(r_addr, 0.02)
         time.sleep(1)
     #for sweep, create a yg wallet with enough for the mix
     #of the bad wallet above (acting as sender)
     self.wallets.update(
         make_wallets(1,
                      wallet_structures=[[1, 0, 0, 0, 0]],
                      mean_amt=3,
                      start_index=3))
Exemple #2
0
 def setUp(self):
     self.n = 2
     #create n new random wallets.
     #put coins into the first mixdepth for each
     #The amount is 1btc + 300,000 satoshis, to account
     #for a 0.2% fee for 1 counterparty + a large tx fee.
     #(but not large enough to handle the bad wallet)
     wallet_structures = [[1, 0, 0, 0, 0]] * (self.n)
     self.wallets = make_wallets(self.n,
                                 wallet_structures=wallet_structures,
                                 mean_amt=1.00300000)
     #the sender is wallet (n), i.e. index wallets[n-1]
     #we need a counterparty with a huge set of utxos.
     bad_wallet_struct = [[1, 0, 0, 0, 0]]
     self.wallets.update(make_wallets(1,
                                      wallet_structures=bad_wallet_struct,
                                      mean_amt=0.01,
                                      start_index=2))
     #having created the bad wallet, add lots of utxos to 
     #the same mixdepth
     print 'creating a crazy amount of utxos in one wallet...'
     r_addr = self.wallets[2]['wallet'].get_external_addr(0)
     for i in range(60):
         jm_single().bc_interface.grab_coins(r_addr, 0.02)
         time.sleep(1)
     #for sweep, create a yg wallet with enough for the mix
     #of the bad wallet above (acting as sender)
     self.wallets.update(make_wallets(1,
                                      wallet_structures=[[1, 0, 0, 0, 0]],
                                      mean_amt=3,
                                      start_index=3))
Exemple #3
0
def test_simple_payjoin(monkeypatch, tmpdir, setup_cj, wallet_cls,
                        wallet_structures, mean_amt):
    def raise_exit(i):
        raise Exception("sys.exit called")
    monkeypatch.setattr(sys, 'exit', raise_exit)
    wallet_services = []
    wallet_services.append(make_wallets_to_list(make_wallets(
        1, wallet_structures=[wallet_structures[0]],
        mean_amt=mean_amt, wallet_cls=wallet_cls[0]))[0])
    wallet_services.append(make_wallets_to_list(make_wallets(
            1, wallet_structures=[wallet_structures[1]],
            mean_amt=mean_amt, wallet_cls=wallet_cls[1]))[0])
    jm_single().bc_interface.tickchain()
    sync_wallets(wallet_services)

    # For accounting purposes, record the balances
    # at the start.
    msb = getbals(wallet_services[0], 0)
    tsb = getbals(wallet_services[1], 0)

    cj_amount = int(1.1 * 10**8)
    maker = P2EPMaker(wallet_services[0], 0, cj_amount)
    destaddr = maker.destination_addr
    monkeypatch.setattr(maker, 'user_check', dummy_user_check)
    # TODO use this to sanity check behaviour
    # in presence of the rest of the joinmarket orderbook.
    orderbook = create_orderbook([maker])
    assert len(orderbook) == 1
    # mixdepth, amount, counterparties, dest_addr, waittime;
    # in payjoin we only pay attention to the first two entries.
    schedule = [(0, cj_amount, 1, destaddr, 0)]
    taker = create_taker(wallet_services[-1], schedule, monkeypatch)
    monkeypatch.setattr(taker, 'user_check', dummy_user_check)
    init_data = taker.initialize(orderbook)
    # the P2EPTaker.initialize() returns:
    # (True, self.cjamount, "p2ep", "p2ep", {self.p2ep_receiver_nick:{}})
    assert init_data[0], "taker.initialize error"
    active_orders = init_data[4]
    assert len(active_orders.keys()) == 1
    response = taker.receive_utxos(list(active_orders.keys()))
    assert response[0], "taker receive_utxos error"
    # test for validity of signed fallback transaction; requires 0.17;
    # note that we count this as an implicit test of fallback mode.
    res = jm_single().bc_interface.rpc('testmempoolaccept', [[response[2]]])
    assert res[0]["allowed"], "Proposed transaction was rejected from mempool."
    maker_response = maker.on_tx_received("faketaker", response[2])
    if not maker_response[0]:
        print("maker on_tx_received failed, reason: ", maker_response[1])
        assert False
    taker_response = taker.on_tx_received("fakemaker", maker_response[2])
    if not taker_response[1] == "OK":
        print("Failure in taker on_tx_received, reason: ", taker_response[1])
        assert False
    # Although the above OK is proof that a transaction went through,
    # it doesn't prove it was a good transaction! Here do balance checks:
    assert final_checks(wallet_services, cj_amount, taker.total_txfee, tsb, msb)
Exemple #4
0
    def do_test_payment(self, wc1, wc2, amt=1.1):
        wallet_structures = [self.wallet_structure] * 2
        wallet_cls = (wc1, wc2)
        self.wallet_services = []
        self.wallet_services.append(make_wallets_to_list(make_wallets(
            1, wallet_structures=[wallet_structures[0]],
            mean_amt=self.mean_amt, wallet_cls=wallet_cls[0]))[0])
        self.wallet_services.append(make_wallets_to_list(make_wallets(
                1, wallet_structures=[wallet_structures[1]],
                mean_amt=self.mean_amt, wallet_cls=wallet_cls[1]))[0])
        jm_single().bc_interface.tickchain()
        sync_wallets(self.wallet_services)

        # For accounting purposes, record the balances
        # at the start.
        self.rsb = getbals(self.wallet_services[0], 0)
        self.ssb = getbals(self.wallet_services[1], 0)

        self.cj_amount = int(amt * 10**8)
        def cbStopListening():
            return self.port.stopListening()
        b78rm = JMBIP78ReceiverManager(self.wallet_services[0], 0,
                                       self.cj_amount, 47083)
        resource = DummyBIP78ReceiverResource(jmprint, cbStopListening, b78rm)
        self.site = Site(resource)
        self.site.displayTracebacks = False
        # NB The connectivity aspects of the onion-based BIP78 setup
        # are time heavy. This server is TCP only.
        self.port = reactor.listenTCP(47083, self.site)
        self.addCleanup(cbStopListening)

        # setup of spender
        bip78_btc_amount = amount_to_btc(amount_to_sat(self.cj_amount))
        bip78_uri = encode_bip21_uri(str(b78rm.receiving_address),
                                {"amount": bip78_btc_amount,
                                 "pj": b"http://127.0.0.1:47083"},
                                safe=":/")
        self.manager = parse_payjoin_setup(bip78_uri, self.wallet_services[1], 0)
        self.manager.mode = "testing"
        success, msg = make_payment_psbt(self.manager)
        assert success, msg
        params = make_payjoin_request_params(self.manager)
        # avoiding backend daemon (testing only jmclient code here),
        # we send the http request manually:
        serv = b"http://127.0.0.1:47083"
        agent = get_nontor_agent()
        body = BytesProducer(self.manager.initial_psbt.to_base64().encode("utf-8"))
        url_parts = list(wrapped_urlparse(serv))
        url_parts[4] = urlencode(params).encode("utf-8")
        destination_url = urlparse.urlunparse(url_parts)
        d = agent.request(b"POST", destination_url,
                          Headers({"Content-Type": ["text/plain"]}),
                          bodyProducer=body)
        d.addCallback(bip78_receiver_response, self.manager)
        return d
Exemple #5
0
def test_coinjoin_mixed_maker_addresses(monkeypatch, tmpdir, setup_cj,
                                        wallet_cls, wallet_cls_sec):
    set_commitment_file(str(tmpdir.join('commitments.json')))

    MAKER_NUM = 2
    wallet_services = make_wallets_to_list(
        make_wallets(MAKER_NUM + 1,
                     wallet_structures=[[1, 0, 0, 0, 0]] * MAKER_NUM +
                     [[3, 0, 0, 0, 0]],
                     mean_amt=1,
                     wallet_cls=wallet_cls))
    wallet_services_sec = make_wallets_to_list(
        make_wallets(MAKER_NUM,
                     wallet_structures=[[1, 0, 0, 0, 0]] * MAKER_NUM,
                     mean_amt=1,
                     wallet_cls=wallet_cls_sec))

    for i in range(MAKER_NUM):
        wif = wallet_services_sec[i].get_wif(0, False, 0)
        wallet_services[i].wallet.import_private_key(
            0, wif, key_type=wallet_services_sec[i].wallet.TYPE)

    jm_single().bc_interface.tickchain()
    jm_single().bc_interface.tickchain()

    sync_wallets(wallet_services, fast=False)

    makers = [
        YieldGeneratorBasic(wallet_services[i],
                            [0, 2000, 0, 'swabsoffer', 10**7])
        for i in range(MAKER_NUM)
    ]

    orderbook = create_orderbook(makers)

    cj_amount = int(1.1 * 10**8)
    # mixdepth, amount, counterparties, dest_addr, waittime, rounding
    schedule = [(0, cj_amount, MAKER_NUM, 'INTERNAL', 0, NO_ROUNDING)]
    taker = create_taker(wallet_services[-1], schedule, monkeypatch)

    active_orders, maker_data = init_coinjoin(taker, makers, orderbook,
                                              cj_amount)

    txdata = taker.receive_utxos(maker_data)
    assert txdata[0], "taker.receive_utxos error"

    taker_final_result = do_tx_signing(taker, makers, active_orders, txdata)
    assert taker_final_result is not False
    assert taker.on_finished_callback.status is not False
Exemple #6
0
def test_direct_send(setup_regtest, wallet_structures, mean_amt, mixdepth,
                     amount, valid):
    log = get_log()
    wallets = make_wallets(1,
                           wallet_structures=wallet_structures,
                           mean_amt=mean_amt)
    wallet = wallets[0]['wallet']
    sync_wallet(wallet)
    destaddr = btc.privkey_to_address(
        os.urandom(32),  #TODO deterministic-ise
        from_hex=False,
        magicbyte=get_p2pk_vbyte())
    addr_valid, errormsg = validate_address(destaddr)
    assert addr_valid, "Invalid destination address: " + destaddr + \
               ", error message: " + errormsg
    if not valid:
        with pytest.raises(Exception) as e_info:
            sendpayment.direct_send(wallet,
                                    amount,
                                    mixdepth,
                                    destaddr,
                                    answeryes=True)
    else:
        sendpayment.direct_send(wallet,
                                amount,
                                mixdepth,
                                destaddr,
                                answeryes=True)
Exemple #7
0
def create_wallet_for_sync(wallet_file, password, wallet_structure, a):
    #Prepare a testnet wallet file for this wallet
    password_key = bitcoin.bin_dbl_sha256(password)
    #We need a distinct seed for each run so as not to step over each other;
    #make it through a deterministic hash
    seedh = bitcoin.sha256("".join([str(x) for x in a]))[:32]
    encrypted_seed = encryptData(password_key, seedh.decode('hex'))
    timestamp = datetime.datetime.now().strftime("%Y/%m/%d %H:%M:%S")
    walletfilejson = {
        'creator': 'joinmarket project',
        'creation_time': timestamp,
        'encrypted_seed': encrypted_seed.encode('hex'),
        'network': get_network()
    }
    walletfile = json.dumps(walletfilejson)
    if not os.path.exists('wallets'):
        os.makedirs('wallets')
    with open(os.path.join('wallets', wallet_file), "wb") as f:
        f.write(walletfile)
    #The call to Wallet() in make_wallets should now find the file
    #and read from it:
    return make_wallets(1, [wallet_structure],
                        fixed_seeds=[wallet_file],
                        test_wallet=True,
                        passwords=[password])[0]['wallet']
 def setUp(self):
     load_test_config()
     self.clean_out_wallet_files()
     jm_single().bc_interface.tick_forward_chain_interval = 5
     jm_single().bc_interface.simulate_blocks()
     # a client connnection object which is often but not always
     # instantiated:
     self.client_connector = None
     # start the daemon; note we are using tcp connections
     # to avoid storing certs in the test env.
     # TODO change that.
     self.daemon = JMWalletDaemonT(self.dport, self.wss_port, tls=False)
     self.daemon.auth_disabled = False
     # because we sync and start the wallet service manually here
     # (and don't use wallet files yet), we won't have set a wallet name,
     # so we set it here:
     self.daemon.wallet_name = self.get_wallet_file_name(1)
     r, s = self.daemon.startService()
     self.listener_rpc = r
     self.listener_ws = s
     wallet_structures = [self.wallet_structure] * 2
     # note: to test fidelity bond wallets we should add the argument
     # `wallet_cls=SegwitWalletFidelityBonds` here, but it slows the
     # test down from 9 seconds to 1 minute 40s, which is too slow
     # to be acceptable. TODO: add a test with FB by speeding up
     # the sync for test, by some means or other.
     self.daemon.services["wallet"] = make_wallets_to_list(
         make_wallets(1,
                      wallet_structures=[wallet_structures[0]],
                      mean_amt=self.mean_amt,
                      wallet_cls=SegwitWalletFidelityBonds))[0]
     jm_single().bc_interface.tickchain()
     sync_wallets([self.daemon.services["wallet"]])
     # dummy tx example to force a notification event:
     self.test_tx = CTransaction.deserialize(hextobin(test_tx_hex_1))
def test_spend_p2wpkh(setup_tx_creation):
    #make 3 p2wpkh outputs from 3 privs
    privs = [struct.pack(b'B', x) * 32 + b'\x01' for x in range(1, 4)]
    pubs = [bitcoin.privkey_to_pubkey(priv) for priv in privs]
    scriptPubKeys = [bitcoin.pubkey_to_p2wpkh_script(pub) for pub in pubs]
    addresses = [str(bitcoin.CCoinAddress.from_scriptPubKey(
        spk)) for spk in scriptPubKeys]
    #pay into it
    wallet_service = make_wallets(1, [[3, 0, 0, 0, 0]], 3)[0]['wallet']
    wallet_service.sync_wallet(fast=True)
    amount = 35000000
    p2wpkh_ins = []
    for i, addr in enumerate(addresses):
        ins_full = wallet_service.select_utxos(0, amount)
        txid = make_sign_and_push(ins_full, wallet_service, amount, output_addr=addr)
        assert txid
        p2wpkh_ins.append((txid, 0))
        txhex = jm_single().bc_interface.get_transaction(txid)
        #wait for mining
        jm_single().bc_interface.tick_forward_chain(1)
    #random output address
    output_addr = wallet_service.get_internal_addr(1)
    amount2 = amount*3 - 50000
    outs = [{'value': amount2, 'address': output_addr}]
    tx = bitcoin.mktx(p2wpkh_ins, outs)

    for i, priv in enumerate(privs):
        # sign each of 3 inputs; note that bitcoin.sign
        # automatically validates each signature it creates.
        sig, msg = bitcoin.sign(tx, i, priv, amount=amount, native="p2wpkh")
        if not sig:
            assert False, msg
    txid = jm_single().bc_interface.pushtx(tx.serialize())
    assert txid
def test_verify_tx_input(setup_tx_creation):
    priv = b"\xaa" * 32 + b"\x01"
    pub = bitcoin.privkey_to_pubkey(priv)
    script = bitcoin.pubkey_to_p2sh_p2wpkh_script(pub)
    addr = str(bitcoin.CCoinAddress.from_scriptPubKey(script))
    wallet_service = make_wallets(1, [[2, 0, 0, 0, 0]], 1)[0]['wallet']
    wallet_service.sync_wallet(fast=True)
    insfull = wallet_service.select_utxos(0, 110000000)
    outs = [{"address": addr, "value": 1000000}]
    ins = list(insfull.keys())
    tx = bitcoin.mktx(ins, outs)
    scripts = {0: (insfull[ins[0]]["script"], bitcoin.coins_to_satoshi(1))}
    success, msg = wallet_service.sign_tx(tx, scripts)
    assert success, msg
    # testing Joinmarket's ability to verify transaction inputs
    # of others: pretend we don't have a wallet owning the transaction,
    # and instead verify an input using the (sig, pub, scriptCode) data
    # that is sent by counterparties:
    cScrWit = tx.wit.vtxinwit[0].scriptWitness
    sig = cScrWit.stack[0]
    pub = cScrWit.stack[1]
    scriptSig = tx.vin[0].scriptSig
    tx2 = bitcoin.mktx(ins, outs)
    res = bitcoin.verify_tx_input(tx2,
                                  0,
                                  scriptSig,
                                  bitcoin.pubkey_to_p2wpkh_script(pub),
                                  amount=bitcoin.coins_to_satoshi(1),
                                  witness=bitcoin.CScriptWitness([sig, pub]))
    assert res
Exemple #11
0
def test_utxo_selection(setup_wallets, nw, wallet_structures, mean_amt,
                        sdev_amt, amount):
    """Check that all the utxo selection algorithms work with a random
    variety of wallet contents.
    """
    wallets = make_wallets(nw, wallet_structures, mean_amt, sdev_amt)
    for w in wallets.values():
        jm_single().bc_interface.wallet_synced = False
        sync_wallet(w['wallet'])
    for k, w in enumerate(wallets.values()):
        for algo in [select_gradual, select_greedy, select_greediest, None]:
            wallet = w['wallet']
            if algo:
                wallet.utxo_selector = algo
            if k == 0:
                with pytest.raises(Exception) as e_info:
                    selected = wallet.select_utxos(1, amount)
            else:
                selected = wallet.select_utxos(1, amount)
                algostr = algo.__name__ if algo else "default"
                print 'selected these for algo ' + algostr + ':'
                print selected
                #basic check:
                #does this algo actually generate sufficient coins?
                total_selected = sum([x['value'] for x in selected.values()])
                assert total_selected > amount, "Selection algo: " + algo + \
                       "failed to select sufficient coins, total: " + \
                       str(total_selected) + ", should be: " + str(amount)
Exemple #12
0
def test_wallet_sync_from_scratch(setup_wallets, wallet_structure,
                                  wallet_file, password, ic):
    """Simulate a scenario in which we use a new bitcoind, thusly:
    generate a new wallet and simply pretend that it has an existing
    index_cache. This will force import of all addresses up to
    the index_cache values.
    """
    setup_import(mainnet=False)
    wallet = make_wallets(1,[wallet_structure],
                              fixed_seeds=[wallet_file],
                              test_wallet=True, passwords=[password])[0]['wallet']
    sync_count = 0
    jm_single().bc_interface.wallet_synced = False
    wallet.index_cache = ic
    while not jm_single().bc_interface.wallet_synced:
        wallet.index = []
        for i in range(5):
            wallet.index.append([0, 0])
        jm_single().bc_interface.sync_wallet(wallet)
        sync_count += 1
        #avoid infinite loop
        assert sync_count < 10
        log.debug("Tried " + str(sync_count) + " times")
    #after #586 we expect to ALWAYS succeed within 2 rounds
    assert sync_count == 2
    #for each external branch, the new index may be higher than
    #the original index_cache if there was a higher used address
    expected_wallet_index = []
    for i, val in enumerate(wallet_structure):
        if val > wallet.index_cache[i][0]:
            expected_wallet_index.append([val, wallet.index_cache[i][1]])
        else:
            expected_wallet_index.append([wallet.index_cache[i][0],
                                          wallet.index_cache[i][1]])
    assert wallet.index == expected_wallet_index
Exemple #13
0
def test_junk_messages(setup_messaging):
    #start a yg bot just to receive messages
    wallets = make_wallets(1, wallet_structures=[[1, 0, 0, 0, 0]], mean_amt=1)
    wallet = wallets[0]['wallet']
    ygp = local_command([python_cmd, yg_cmd,\
                             str(wallets[0]['seed'])], bg=True)

    #time.sleep(90)
    #start a raw IRCMessageChannel instance in a thread;
    #then call send_* on it with various errant messages
    mc = DummyMC("irc_ping_test")
    mc.register_orderbookwatch_callbacks(on_order_seen=on_order_seen)
    mc.register_taker_callbacks(on_pubkey=on_pubkey)
    RawIRCThread(mc).start()
    time.sleep(1)
    mc._IRCMessageChannel__pubmsg("!orderbook")
    time.sleep(1)
    mc._IRCMessageChannel__pubmsg("!orderbook!orderbook")
    time.sleep(1)
    mc._IRCMessageChannel__pubmsg("junk and crap" * 20)
    time.sleep(5)
    #try:
    with pytest.raises(CJPeerError) as e_info:
        mc.send_error(yg_name, "fly you fools!")
    #except CJPeerError:
    #    print "CJPeerError raised"
    #    pass
    time.sleep(5)
    mc.shutdown()
    ygp.send_signal(signal.SIGINT)
    ygp.wait()
Exemple #14
0
def test_start_ygs(setup_ygrunner, num_ygs, wallet_structures, mean_amt):
    """Set up some wallets, for the ygs and 1 sp.
    Then start the ygs in background and publish
    the seed of the sp wallet for easy import into -qt
    """
    wallets = make_wallets(num_ygs + 1,
                           wallet_structures=wallet_structures,
                           mean_amt=mean_amt)
    #the sendpayment bot uses the last wallet in the list
    wallet = wallets[num_ygs]['wallet']
    print "Seed : " + wallets[num_ygs]['seed']
    #useful to see the utxos on screen sometimes
    sync_wallet(wallet)
    print wallet.unspent

    yigen_procs = []
    for i in range(num_ygs):
        ygp = local_command([python_cmd, yg_cmd,\
                             str(wallets[i]['seed'])], bg=True)
        time.sleep(2)  #give it a chance
        yigen_procs.append(ygp)
    try:
        while True:
            time.sleep(20)
            print 'waiting'   
    finally:
        if any(yigen_procs):
            for ygp in yigen_procs:
                #NB *GENTLE* shutdown is essential for
                #test coverage reporting!
                ygp.send_signal(signal.SIGINT)
                ygp.wait()
Exemple #15
0
def test_start_ygs(setup_ygrunner, num_ygs, wallet_structures, mean_amt):
    """Set up some wallets, for the ygs and 1 sp.
    Then start the ygs in background and publish
    the seed of the sp wallet for easy import into -qt
    """
    wallets = make_wallets(num_ygs + 1,
                           wallet_structures=wallet_structures,
                           mean_amt=mean_amt)
    #the sendpayment bot uses the last wallet in the list
    wallet = wallets[num_ygs]['wallet']
    print "Seed : " + wallets[num_ygs]['seed']
    #useful to see the utxos on screen sometimes
    sync_wallet(wallet)
    print wallet.unspent

    yigen_procs = []
    for i in range(num_ygs):
        ygp = local_command([python_cmd, yg_cmd,\
                             str(wallets[i]['seed'])], bg=True)
        time.sleep(2)  #give it a chance
        yigen_procs.append(ygp)
    try:
        while True:
            time.sleep(20)
            print 'waiting'
    finally:
        if any(yigen_procs):
            for ygp in yigen_procs:
                #NB *GENTLE* shutdown is essential for
                #test coverage reporting!
                ygp.send_signal(signal.SIGINT)
                ygp.wait()
def test_utxo_selection(setup_wallets, nw, wallet_structures, mean_amt,
                        sdev_amt, amount):
    """Check that all the utxo selection algorithms work with a random
    variety of wallet contents.
    """
    wallets = make_wallets(nw, wallet_structures, mean_amt, sdev_amt)
    for w in wallets.values():
        jm_single().bc_interface.wallet_synced = False
        sync_wallet(w['wallet'])
    for k, w in enumerate(wallets.values()):
        for algo in [select_gradual, select_greedy, select_greediest, None]:
            wallet = w['wallet']
            if algo:
                wallet.utxo_selector = algo
            if k == 0:
                with pytest.raises(Exception) as e_info:
                    selected = wallet.select_utxos(1, amount)
            else:
                selected = wallet.select_utxos(1, amount)
                algostr = algo.__name__ if algo else "default"
                print 'selected these for algo ' + algostr + ':'
                print selected
                #basic check:
                #does this algo actually generate sufficient coins?
                total_selected = sum([x['value'] for x in selected.values()])
                assert total_selected > amount, "Selection algo: " + str(algo) + \
                       "failed to select sufficient coins, total: " + \
                       str(total_selected) + ", should be: " + str(amount)
Exemple #17
0
def test_spend_p2sh_utxos(setup_tx_creation):
    #make a multisig address from 3 privs
    privs = [chr(x) * 32 + '\x01' for x in range(1, 4)]
    pubs = [btc.privkey_to_pubkey(binascii.hexlify(priv)) for priv in privs]
    script = btc.mk_multisig_script(pubs, 2)
    msig_addr = btc.scriptaddr(script, magicbyte=196)
    #pay into it
    wallet = make_wallets(1, [[2, 0, 0, 0, 1]], 3)[0]['wallet']
    jm_single().bc_interface.sync_wallet(wallet)
    amount = 350000000
    ins_full = wallet.select_utxos(0, amount)
    txid = make_sign_and_push(ins_full, wallet, amount, output_addr=msig_addr)
    assert txid
    #wait for mining
    time.sleep(4)
    #spend out; the input can be constructed from the txid of previous
    msig_in = txid + ":0"
    ins = [msig_in]
    #random output address and change addr
    output_addr = wallet.get_new_addr(1, 1)
    amount2 = amount - 50000
    outs = [{'value': amount2, 'address': output_addr}]
    tx = btc.mktx(ins, outs)
    sigs = []
    for priv in privs[:2]:
        sigs.append(btc.multisign(tx, 0, script, binascii.hexlify(priv)))
    tx = btc.apply_multisignatures(tx, 0, script, sigs)
    txid = jm_single().bc_interface.pushtx(tx)
    assert txid
Exemple #18
0
def test_create_sighash_txs(setup_tx_creation):
    #non-standard hash codes:
    for sighash in [
            bitcoin.SIGHASH_ANYONECANPAY + bitcoin.SIGHASH_SINGLE,
            bitcoin.SIGHASH_NONE, bitcoin.SIGHASH_SINGLE
    ]:
        wallet = make_wallets(1, [[2, 0, 0, 0, 1]], 3)[0]['wallet']
        sync_wallet(wallet)
        amount = 350000000
        ins_full = wallet.select_utxos(0, amount)
        print "using hashcode: " + str(sighash)
        txid = make_sign_and_push(ins_full, wallet, amount, hashcode=sighash)
        assert txid

    #Create an invalid sighash single (too many inputs)
    extra = wallet.select_utxos(4, 100000000)  #just a few more inputs
    ins_full.update(extra)
    with pytest.raises(Exception) as e_info:
        txid = make_sign_and_push(ins_full,
                                  wallet,
                                  amount,
                                  hashcode=bitcoin.SIGHASH_SINGLE)

    #trigger insufficient funds
    with pytest.raises(Exception) as e_info:
        fake_utxos = wallet.select_utxos(4, 1000000000)
def make_tx_add_notify():
    wallet_dict = make_wallets(1, [[1, 0, 0, 0, 0]], mean_amt=4, sdev_amt=0)[0]
    amount = 250000000
    txfee = 10000
    wallet = wallet_dict['wallet']
    sync_wallet(wallet)
    inputs = wallet.select_utxos(0, amount)
    ins = inputs.keys()
    input_value = sum([i['value'] for i in inputs.values()])
    output_addr = wallet.get_new_addr(1, 0)
    change_addr = wallet.get_new_addr(0, 1)
    outs = [{
        'value': amount,
        'address': output_addr
    }, {
        'value': input_value - amount - txfee,
        'address': change_addr
    }]
    tx = btc.mktx(ins, outs)
    de_tx = btc.deserialize(tx)
    for index, ins in enumerate(de_tx['ins']):
        utxo = ins['outpoint']['hash'] + ':' + str(ins['outpoint']['index'])
        addr = inputs[utxo]['address']
        priv = wallet.get_key_from_addr(addr)
        tx = btc.sign(tx, index, priv)

    unconfirm_called[0] = confirm_called[0] = False
    timeout_unconfirm_called[0] = timeout_confirm_called[0] = False
    jm_single().bc_interface.add_tx_notify(btc.deserialize(tx),
                                           unconfirm_callback,
                                           confirm_callback, output_addr,
                                           timeout_callback)
    return tx
Exemple #20
0
def runcase(alice_class,
            carol_class,
            fail_alice_state=None,
            fail_carol_state=None):
    options_server = Options()
    wallets = make_wallets(num_alices + 1,
                           wallet_structures=wallet_structures,
                           mean_amt=funding_amount)
    args_server = ["dummy"]
    test_data_server = (wallets[num_alices]['seed'], args_server,
                        options_server, False, None, carol_class, None,
                        fail_carol_state)
    carol_bbmb = main_cs(test_data_server)
    options_alice = Options()
    options_alice.serve = False
    alices = []
    for i in range(num_alices):
        args_alice = ["dummy", amounts[i]]
        if dest_addr:
            args_alice.append(dest_addr)
        test_data_alice = (wallets[i]['seed'], args_alice, options_alice,
                           False, alice_class, None, fail_alice_state, None)
        alices.append(main_cs(test_data_alice))
    l = task.LoopingCall(miner)
    reactor.callWhenRunning(start_mining, l)
    reactor.run()
    return (alices, carol_bbmb, wallets[num_alices]['wallet'])
Exemple #21
0
def test_simple_coinjoin(monkeypatch, tmpdir, setup_cj, wallet_cls):
    def raise_exit(i):
        raise Exception("sys.exit called")
    monkeypatch.setattr(sys, 'exit', raise_exit)
    set_commitment_file(str(tmpdir.join('commitments.json')))

    MAKER_NUM = 3
    wallets = make_wallets_to_list(make_wallets(
        MAKER_NUM + 1, wallet_structures=[[4, 0, 0, 0, 0]] * (MAKER_NUM + 1),
        mean_amt=1, wallet_cls=wallet_cls))

    jm_single().bc_interface.tickchain()
    sync_wallets(wallets)

    makers = [YieldGeneratorBasic(
        wallets[i],
        [0, 2000, 0, 'swabsoffer', 10**7]) for i in range(MAKER_NUM)]

    orderbook = create_orderbook(makers)
    assert len(orderbook) == MAKER_NUM

    cj_amount = int(1.1 * 10**8)
    # mixdepth, amount, counterparties, dest_addr, waittime
    schedule = [(0, cj_amount, MAKER_NUM, 'INTERNAL', 0)]
    taker = create_taker(wallets[-1], schedule, monkeypatch)

    active_orders, maker_data = init_coinjoin(taker, makers,
                                              orderbook, cj_amount)

    txdata = taker.receive_utxos(maker_data)
    assert txdata[0], "taker.receive_utxos error"

    taker_final_result = do_tx_signing(taker, makers, active_orders, txdata)
    assert taker_final_result is not False
    assert taker.on_finished_callback.status is not False
def test_junk_messages(setup_messaging):
    #start a yg bot just to receive messages
    wallets = make_wallets(1,
                           wallet_structures=[[1,0,0,0,0]],
                           mean_amt=1)
    wallet = wallets[0]['wallet']
    ygp = local_command([python_cmd, yg_cmd,\
                             str(wallets[0]['seed'])], bg=True)
    
    #time.sleep(90)
    #start a raw IRCMessageChannel instance in a thread;
    #then call send_* on it with various errant messages
    mc = DummyMC("irc_ping_test")
    mc.register_orderbookwatch_callbacks(on_order_seen=on_order_seen)
    mc.register_taker_callbacks(on_pubkey=on_pubkey)    
    RawIRCThread(mc).start()
    time.sleep(1)
    mc._IRCMessageChannel__pubmsg("!orderbook")
    time.sleep(1)
    mc._IRCMessageChannel__pubmsg("!orderbook!orderbook")
    time.sleep(1)
    mc._IRCMessageChannel__pubmsg("junk and crap"*20)
    time.sleep(5)
    #try:
    with pytest.raises(CJPeerError) as e_info:
        mc.send_error(yg_name, "fly you fools!")
    #except CJPeerError:
    #    print "CJPeerError raised"
    #    pass
    time.sleep(5)
    mc.shutdown()
    ygp.send_signal(signal.SIGINT)
    ygp.wait()
def make_tx_add_notify():
    wallet_dict = make_wallets(1, [[1, 0, 0, 0, 0]], mean_amt=4, sdev_amt=0)[0]
    amount = 250000000
    txfee = 10000
    wallet = wallet_dict['wallet']
    sync_wallet(wallet)
    inputs = wallet.select_utxos(0, amount)
    ins = inputs.keys()
    input_value = sum([i['value'] for i in inputs.values()])
    output_addr = wallet.get_new_addr(1, 0)
    change_addr = wallet.get_new_addr(0, 1)
    outs = [{'value': amount, 'address': output_addr},
            {'value': input_value - amount - txfee, 'address': change_addr}]
    tx = btc.mktx(ins, outs)
    de_tx = btc.deserialize(tx)
    for index, ins in enumerate(de_tx['ins']):
        utxo = ins['outpoint']['hash'] + ':' + str(ins['outpoint']['index'])
        addr = inputs[utxo]['address']
        priv = wallet.get_key_from_addr(addr)
        tx = btc.sign(tx, index, priv)

    unconfirm_called[0] = confirm_called[0] = False
    timeout_unconfirm_called[0] = timeout_confirm_called[0] = False
    jm_single().bc_interface.add_tx_notify(
        btc.deserialize(tx), unconfirm_callback,
        confirm_callback, output_addr, timeout_callback)
    return tx
def test_coinjoin_mixdepth_wrap_taker(monkeypatch, tmpdir, setup_cj):
    def raise_exit(i):
        raise Exception("sys.exit called")

    monkeypatch.setattr(sys, 'exit', raise_exit)
    set_commitment_file(str(tmpdir.join('commitments.json')))

    MAKER_NUM = 3
    wallet_services = make_wallets_to_list(
        make_wallets(MAKER_NUM + 1,
                     wallet_structures=[[4, 0, 0, 0, 0]] * MAKER_NUM +
                     [[0, 0, 0, 0, 3]],
                     mean_amt=1))

    for wallet_service in wallet_services:
        assert wallet_service.max_mixdepth == 4

    jm_single().bc_interface.tickchain()
    jm_single().bc_interface.tickchain()

    sync_wallets(wallet_services)

    cj_fee = 2000
    makers = [
        YieldGeneratorBasic(
            wallet_services[i],
            [0, cj_fee, 0, absoffer_type_map[SegwitWallet], 10**7])
        for i in range(MAKER_NUM)
    ]
    create_orders(makers)

    orderbook = create_orderbook(makers)
    assert len(orderbook) == MAKER_NUM

    cj_amount = int(1.1 * 10**8)
    # mixdepth, amount, counterparties, dest_addr, waittime, rounding
    schedule = [(4, cj_amount, MAKER_NUM, 'INTERNAL', 0, NO_ROUNDING)]
    taker = create_taker(wallet_services[-1], schedule, monkeypatch)

    active_orders, maker_data = init_coinjoin(taker, makers, orderbook,
                                              cj_amount)

    txdata = taker.receive_utxos(maker_data)
    assert txdata[0], "taker.receive_utxos error"

    taker_final_result = do_tx_signing(taker, makers, active_orders, txdata)
    assert taker_final_result is not False

    tx = btc.CMutableTransaction.deserialize(hextobin(txdata[2]))

    wallet_service = wallet_services[-1]
    # TODO change for new tx monitoring:
    wallet_service.remove_old_utxos(tx)
    wallet_service.add_new_utxos(tx)

    balances = wallet_service.get_balance_by_mixdepth()
    assert balances[0] == cj_amount
    # <= because of tx fee
    assert balances[4] <= 3 * 10**8 - cj_amount - (cj_fee * MAKER_NUM)
Exemple #25
0
def test_donation_address(setup_donations, tx_type, tx_id, tx_hex, address):
    wallets = make_wallets(1, wallet_structures=[[1,1,1,0,0]],
                               mean_amt=0.5)
    wallet = wallets[0]['wallet']
    priv, addr = donation_address(tx_hex, wallet)
    print addr
    #just a check that it doesn't throw
    sign_donation_tx(tx_hex, 0, priv)
Exemple #26
0
 def setUp(self):
     self.n = 2
     #create n+1 new random wallets.
     #put 10 coins into the first receive address
     #to allow that bot to start.
     wallet_structures = [[1, 0, 0, 0, 0]] * 3
     self.wallets = commontest.make_wallets(
         3, wallet_structures=wallet_structures, mean_amt=10)
    def setUp(self):
	self.n = 2
        #create n+1 new random wallets.
        #put 10 coins into the first receive address
        #to allow that bot to start.
	wallet_structures = [[1,0,0,0,0]]*3
	self.wallets = commontest.make_wallets(3, wallet_structures=wallet_structures,
	                                       mean_amt=10)
 def setUp(self):
     #create 2 new random wallets.
     #put 10 coins into the first receive address
     #to allow that bot to start.
     self.wallets = make_wallets(
         2,
         wallet_structures=[[1, 0, 0, 0, 0], [1, 0, 0, 0, 0]],
         mean_amt=10)
Exemple #29
0
 def setUp(self):
     #create 2 new random wallets.
     #put 10 coins into the first receive address
     #to allow that bot to start.
     self.wallets = commontest.make_wallets(
         2,
         wallet_structures=[[1, 0, 0, 0, 0], [1, 0, 0, 0, 0]],
         mean_amt=10)
def test_coinjoin_mixdepth_wrap_maker(monkeypatch, tmpdir, setup_cj):
    def raise_exit(i):
        raise Exception("sys.exit called")

    monkeypatch.setattr(sys, 'exit', raise_exit)
    set_commitment_file(str(tmpdir.join('commitments.json')))

    MAKER_NUM = 2
    wallet_services = make_wallets_to_list(
        make_wallets(MAKER_NUM + 1,
                     wallet_structures=[[0, 0, 0, 0, 4]] * MAKER_NUM +
                     [[3, 0, 0, 0, 0]],
                     mean_amt=1))

    for wallet_service in wallet_services:
        assert wallet_service.max_mixdepth == 4

    jm_single().bc_interface.tickchain()
    jm_single().bc_interface.tickchain()

    sync_wallets(wallet_services)

    cj_fee = 2000
    makers = [
        YieldGeneratorBasic(wallet_services[i],
                            [0, cj_fee, 0, 'swabsoffer', 10**7])
        for i in range(MAKER_NUM)
    ]

    orderbook = create_orderbook(makers)
    assert len(orderbook) == MAKER_NUM

    cj_amount = int(1.1 * 10**8)
    # mixdepth, amount, counterparties, dest_addr, waittime, rounding
    schedule = [(0, cj_amount, MAKER_NUM, 'INTERNAL', 0, NO_ROUNDING)]
    taker = create_taker(wallet_services[-1], schedule, monkeypatch)

    active_orders, maker_data = init_coinjoin(taker, makers, orderbook,
                                              cj_amount)

    txdata = taker.receive_utxos(maker_data)
    assert txdata[0], "taker.receive_utxos error"

    taker_final_result = do_tx_signing(taker, makers, active_orders, txdata)
    assert taker_final_result is not False

    tx = btc.deserialize(txdata[2])
    binarize_tx(tx)

    for i in range(MAKER_NUM):
        wallet_service = wallet_services[i]
        # TODO as above re: monitoring
        wallet_service.remove_old_utxos_(tx)
        wallet_service.add_new_utxos_(tx, b'\x00' * 32)  # fake txid

        balances = wallet_service.get_balance_by_mixdepth()
        assert balances[0] == cj_amount
        assert balances[4] == 4 * 10**8 - cj_amount + cj_fee
Exemple #31
0
def test_donation_address(setup_donations, tx_type, tx_id, tx_hex, address):
    wallets = make_wallets(1,
                           wallet_structures=[[1, 1, 1, 0, 0]],
                           mean_amt=0.5)
    wallet = wallets[0]['wallet']
    priv, addr = donation_address(tx_hex, wallet)
    print addr
    #just a check that it doesn't throw
    sign_donation_tx(tx_hex, 0, priv)
Exemple #32
0
def test_spend_p2wsh(setup_tx_creation):
    #make 2 x 2 of 2multisig outputs; will need 4 privs
    privs = [struct.pack(b'B', x) * 32 + b'\x01' for x in range(1, 5)]
    privs = [binascii.hexlify(priv).decode('ascii') for priv in privs]
    pubs = [bitcoin.privkey_to_pubkey(priv) for priv in privs]
    redeemScripts = [
        bitcoin.mk_multisig_script(pubs[i:i + 2], 2) for i in [0, 2]
    ]
    scriptPubKeys = [
        bitcoin.pubkeys_to_p2wsh_script(pubs[i:i + 2]) for i in [0, 2]
    ]
    addresses = [
        bitcoin.pubkeys_to_p2wsh_address(pubs[i:i + 2]) for i in [0, 2]
    ]
    #pay into it
    wallet_service = make_wallets(1, [[3, 0, 0, 0, 0]], 3)[0]['wallet']
    wallet_service.sync_wallet(fast=True)
    amount = 35000000
    p2wsh_ins = []
    for addr in addresses:
        ins_full = wallet_service.select_utxos(0, amount)
        txid = make_sign_and_push(ins_full,
                                  wallet_service,
                                  amount,
                                  output_addr=addr)
        assert txid
        p2wsh_ins.append(txid + ":0")
        #wait for mining
        time.sleep(1)
    #random output address and change addr
    output_addr = wallet_service.get_internal_addr(1)
    amount2 = amount * 2 - 50000
    outs = [{'value': amount2, 'address': output_addr}]
    tx = bitcoin.mktx(p2wsh_ins, outs)
    sigs = []
    for i in range(2):
        sigs = []
        for priv in privs[i * 2:i * 2 + 2]:
            # sign input j with each of 2 keys
            sig = bitcoin.multisign(tx,
                                    i,
                                    redeemScripts[i],
                                    priv,
                                    amount=amount)
            sigs.append(sig)
            # check that verify_tx_input correctly validates;
            assert bitcoin.verify_tx_input(tx,
                                           i,
                                           scriptPubKeys[i],
                                           sig,
                                           bitcoin.privkey_to_pubkey(priv),
                                           scriptCode=redeemScripts[i],
                                           amount=amount)
        tx = bitcoin.apply_p2wsh_multisignatures(tx, i, redeemScripts[i], sigs)
    txid = jm_single().bc_interface.pushtx(tx)
    assert txid
Exemple #33
0
def test_spend_p2wpkh(setup_tx_creation):
    #make 3 p2wpkh outputs from 3 privs
    privs = [struct.pack(b'B', x) * 32 + b'\x01' for x in range(1, 4)]
    pubs = [
        bitcoin.privkey_to_pubkey(binascii.hexlify(priv).decode('ascii'))
        for priv in privs
    ]
    scriptPubKeys = [bitcoin.pubkey_to_p2wpkh_script(pub) for pub in pubs]
    addresses = [bitcoin.pubkey_to_p2wpkh_address(pub) for pub in pubs]
    #pay into it
    wallet_service = make_wallets(1, [[3, 0, 0, 0, 0]], 3)[0]['wallet']
    wallet_service.sync_wallet(fast=True)
    amount = 35000000
    p2wpkh_ins = []
    for addr in addresses:
        ins_full = wallet_service.select_utxos(0, amount)
        txid = make_sign_and_push(ins_full,
                                  wallet_service,
                                  amount,
                                  output_addr=addr)
        assert txid
        p2wpkh_ins.append(txid + ":0")
        #wait for mining
        time.sleep(1)
    #random output address
    output_addr = wallet_service.get_internal_addr(1)
    amount2 = amount * 3 - 50000
    outs = [{'value': amount2, 'address': output_addr}]
    tx = bitcoin.mktx(p2wpkh_ins, outs)
    sigs = []
    for i, priv in enumerate(privs):
        # sign each of 3 inputs
        tx = bitcoin.p2wpkh_sign(tx,
                                 i,
                                 binascii.hexlify(priv),
                                 amount,
                                 native=True)
        # check that verify_tx_input correctly validates;
        # to do this, we need to extract the signature and get the scriptCode
        # of this pubkey
        scriptCode = bitcoin.pubkey_to_p2pkh_script(pubs[i])
        witness = bitcoin.deserialize(tx)['ins'][i]['txinwitness']
        assert len(witness) == 2
        assert witness[1] == pubs[i]
        sig = witness[0]
        assert bitcoin.verify_tx_input(tx,
                                       i,
                                       scriptPubKeys[i],
                                       sig,
                                       pubs[i],
                                       scriptCode=scriptCode,
                                       amount=amount)
    txid = jm_single().bc_interface.pushtx(tx)
    assert txid
def test_create_and_sign_psbt_with_legacy(setup_psbt_wallet):
    """ The purpose of this test is to check that we can create and
    then partially sign a PSBT where we own one input and the other input
    is of legacy p2pkh type.
    """
    wallet_service = make_wallets(1, [[1, 0, 0, 0, 0]], 1)[0]['wallet']
    wallet_service.sync_wallet(fast=True)
    utxos = wallet_service.select_utxos(0, bitcoin.coins_to_satoshi(0.5))
    assert len(utxos) == 1
    # create a legacy address and make a payment into it
    legacy_addr = bitcoin.CCoinAddress.from_scriptPubKey(
        bitcoin.pubkey_to_p2pkh_script(bitcoin.privkey_to_pubkey(b"\x01" *
                                                                 33)))
    tx = direct_send(wallet_service,
                     bitcoin.coins_to_satoshi(0.3),
                     0,
                     str(legacy_addr),
                     accept_callback=dummy_accept_callback,
                     info_callback=dummy_info_callback,
                     return_transaction=True)
    assert tx
    # this time we will have one utxo worth <~ 0.7
    my_utxos = wallet_service.select_utxos(0, bitcoin.coins_to_satoshi(0.5))
    assert len(my_utxos) == 1
    # find the outpoint for the legacy address we're spending
    n = -1
    for i, t in enumerate(tx.vout):
        if bitcoin.CCoinAddress.from_scriptPubKey(
                t.scriptPubKey) == legacy_addr:
            n = i
    assert n > -1
    utxos = copy.deepcopy(my_utxos)
    utxos[(tx.GetTxid()[::-1], n)] = {
        "script": legacy_addr.to_scriptPubKey(),
        "value": bitcoin.coins_to_satoshi(0.3)
    }
    outs = [{
        "value": bitcoin.coins_to_satoshi(0.998),
        "address": wallet_service.get_addr(0, 0, 0)
    }]
    tx2 = bitcoin.mktx(list(utxos.keys()), outs)
    spent_outs = wallet_service.witness_utxos_to_psbt_utxos(my_utxos)
    spent_outs.append(tx)
    new_psbt = wallet_service.create_psbt_from_tx(tx2,
                                                  spent_outs,
                                                  force_witness_utxo=False)
    signed_psbt_and_signresult, err = wallet_service.sign_psbt(
        new_psbt.serialize(), with_sign_result=True)
    assert err is None
    signresult, signed_psbt = signed_psbt_and_signresult
    assert signresult.num_inputs_signed == 1
    assert signresult.num_inputs_final == 1
    assert not signresult.is_final
def test_junk_messages(setup_messaging):
    #start a yg bot just to receive messages
    wallets = make_wallets(1, wallet_structures=[[1, 0, 0, 0, 0]], mean_amt=1)
    wallet = wallets[0]['wallet']
    ygp = local_command([python_cmd, yg_cmd,\
                             str(wallets[0]['seed'])], bg=True)

    #time.sleep(90)
    #start a raw IRCMessageChannel instance in a thread;
    #then call send_* on it with various errant messages
    mc = DummyMC("irc_ping_test")
    mc.register_orderbookwatch_callbacks(on_order_seen=on_order_seen)
    mc.register_taker_callbacks(on_pubkey=on_pubkey)
    RawIRCThread(mc).start()
    time.sleep(1)
    mc.request_orderbook()
    time.sleep(1)
    #now try directly
    mc.pubmsg("!orderbook")
    time.sleep(1)
    #should be ignored; can we check?
    mc.pubmsg("!orderbook!orderbook")
    time.sleep(1)
    #assuming MAX_PRIVMSG_LEN is not something crazy
    #big like 550, this should fail
    with pytest.raises(AssertionError) as e_info:
        mc.pubmsg("junk and crap" * 40)
    time.sleep(1)
    #assuming MAX_PRIVMSG_LEN is not something crazy
    #small like 180, this should succeed
    mc.pubmsg("junk and crap" * 15)
    time.sleep(2)
    #try a long order announcement in public
    #because we don't want to build a real orderbook,
    #call the underlying IRC announce function.
    #TODO: how to test that the sent format was correct?
    mc._announce_orders(["!abc def gh 0001"] * 30, None)
    time.sleep(5)
    #send a fill with an invalid pubkey to the existing yg;
    #this should trigger a NaclError but should NOT kill it.
    mc._IRCMessageChannel__privmsg(yg_name, "fill", "0 10000000 abcdef")
    time.sleep(1)
    #try:
    with pytest.raises(CJPeerError) as e_info:
        mc.send_error(yg_name, "fly you fools!")
    #except CJPeerError:
    #    print "CJPeerError raised"
    #    pass
    time.sleep(5)
    mc.shutdown()
    ygp.send_signal(signal.SIGINT)
    ygp.wait()
Exemple #36
0
def test_absurd_fees(setup_tx_creation):
    """Test triggering of ValueError exception
    if the transaction fees calculated from the blockchain
    interface exceed the limit set in the config.
    """
    jm_single().bc_interface.absurd_fees = True
    #pay into it
    wallet = make_wallets(1, [[2, 0, 0, 0, 1]], 3)[0]['wallet']
    jm_single().bc_interface.sync_wallet(wallet)
    amount = 350000000
    ins_full = wallet.select_utxos(0, amount)
    with pytest.raises(ValueError) as e_info:
        txid = make_sign_and_push(ins_full, wallet, amount, estimate_fee=True)
def test_create_sighash_txs(setup_tx_creation):
    #non-standard hash codes:
    for sighash in [bitcoin.SIGHASH_ANYONECANPAY + bitcoin.SIGHASH_SINGLE,
                    bitcoin.SIGHASH_NONE, bitcoin.SIGHASH_SINGLE]:
        wallet_service = make_wallets(1, [[2, 0, 0, 0, 1]], 3)[0]['wallet']
        wallet_service.sync_wallet(fast=True)
        amount = 350000000
        ins_full = wallet_service.select_utxos(0, amount)
        txid = make_sign_and_push(ins_full, wallet_service, amount, hashcode=sighash)
        assert txid

    #trigger insufficient funds
    with pytest.raises(Exception) as e_info:
        fake_utxos = wallet_service.select_utxos(4, 1000000000)
Exemple #38
0
def test_all_same_priv(setup_tx_creation):
    #recipient
    priv = "aa" * 32 + "01"
    addr = bitcoin.privkey_to_address(priv, magicbyte=get_p2pk_vbyte())
    wallet = make_wallets(1, [[1, 0, 0, 0, 0]], 1)[0]['wallet']
    #make another utxo on the same address
    addrinwallet = wallet.get_addr(0, 0, 0)
    jm_single().bc_interface.grab_coins(addrinwallet, 1)
    sync_wallet(wallet)
    insfull = wallet.select_utxos(0, 110000000)
    outs = [{"address": addr, "value": 1000000}]
    ins = insfull.keys()
    tx = bitcoin.mktx(ins, outs)
    tx = bitcoin.signall(tx, wallet.get_key_from_addr(addrinwallet))
Exemple #39
0
def test_verify_tx_input(setup_tx_creation, signall, mktxlist):
    priv = "aa" * 32 + "01"
    addr = bitcoin.privkey_to_address(priv, magicbyte=get_p2pk_vbyte())
    wallet = make_wallets(1, [[2, 0, 0, 0, 0]], 1)[0]['wallet']
    sync_wallet(wallet)
    insfull = wallet.select_utxos(0, 110000000)
    print(insfull)
    if not mktxlist:
        outs = [{"address": addr, "value": 1000000}]
        ins = insfull.keys()
        tx = bitcoin.mktx(ins, outs)
    else:
        out1 = addr + ":1000000"
        ins0, ins1 = insfull.keys()
        print("INS0 is: " + str(ins0))
        print("INS1 is: " + str(ins1))
        tx = bitcoin.mktx(ins0, ins1, out1)
    desertx = bitcoin.deserialize(tx)
    print(desertx)
    if signall:
        privdict = {}
        for index, ins in enumerate(desertx['ins']):
            utxo = ins['outpoint']['hash'] + ':' + str(
                ins['outpoint']['index'])
            ad = insfull[utxo]['address']
            priv = wallet.get_key_from_addr(ad)
            privdict[utxo] = priv
        tx = bitcoin.signall(tx, privdict)
    else:
        for index, ins in enumerate(desertx['ins']):
            utxo = ins['outpoint']['hash'] + ':' + str(
                ins['outpoint']['index'])
            ad = insfull[utxo]['address']
            priv = wallet.get_key_from_addr(ad)
            if index % 2:
                tx = binascii.unhexlify(tx)
            tx = bitcoin.sign(tx, index, priv)
            if index % 2:
                tx = binascii.hexlify(tx)
    desertx2 = bitcoin.deserialize(tx)
    print(desertx2)
    sig, pub = bitcoin.deserialize_script(desertx2['ins'][0]['script'])
    print(sig, pub)
    pubscript = bitcoin.address_to_script(
        bitcoin.pubkey_to_address(pub, magicbyte=get_p2pk_vbyte()))
    sig = binascii.unhexlify(sig)
    pub = binascii.unhexlify(pub)
    sig_good = bitcoin.verify_tx_input(tx, 0, pubscript, sig, pub)
    assert sig_good
def test_create_p2sh_output_tx(setup_tx_creation, nw, wallet_structures,
                               mean_amt, sdev_amt, amount, pubs, k):
    wallets = make_wallets(nw, wallet_structures, mean_amt, sdev_amt)
    for w in wallets.values():
        jm_single().bc_interface.sync_wallet(w['wallet'])
    for k, w in enumerate(wallets.values()):
        wallet = w['wallet']
        ins_full = wallet.select_utxos(0, amount)
        script = btc.mk_multisig_script(pubs, k)
        #try the alternative argument passing
        pubs.append(k)
        script2 = btc.mk_multisig_script(*pubs)
        assert script2 == script
        output_addr = btc.scriptaddr(script, magicbyte=196)
        txid = make_sign_and_push(ins_full,
                                  wallet,
                                  amount,
                                  output_addr=output_addr)
        assert txid
def test_direct_send(setup_regtest, wallet_structures, mean_amt, mixdepth,
                     amount, valid):
    log = get_log()
    wallets = make_wallets(1,
                           wallet_structures=wallet_structures,
                           mean_amt=mean_amt)
    wallet = wallets[0]['wallet']
    sync_wallet(wallet)
    destaddr = btc.privkey_to_address(
                os.urandom(32), #TODO deterministic-ise
                from_hex=False,
                magicbyte=get_p2pk_vbyte())
    addr_valid, errormsg = validate_address(destaddr)
    assert addr_valid, "Invalid destination address: " + destaddr + \
               ", error message: " + errormsg
    if not valid:
        with pytest.raises(Exception) as e_info:
            sendpayment.direct_send(wallet,
                                    amount, mixdepth, destaddr, answeryes=True)
    else:
        sendpayment.direct_send(wallet,
                                amount, mixdepth, destaddr, answeryes=True)
def test_create_sighash_txs(setup_tx_creation):
    #non-standard hash codes:
    for sighash in [btc.SIGHASH_ANYONECANPAY + btc.SIGHASH_SINGLE,
                    btc.SIGHASH_NONE, btc.SIGHASH_SINGLE]:
        wallet = make_wallets(1, [[2, 0, 0, 0, 1]], 3)[0]['wallet']
        jm_single().bc_interface.sync_wallet(wallet)
        amount = 350000000
        ins_full = wallet.select_utxos(0, amount)
        print "using hashcode: " + str(sighash)
        txid = make_sign_and_push(ins_full, wallet, amount, hashcode=sighash)
        assert txid

    #Create an invalid sighash single (too many inputs)
    extra = wallet.select_utxos(4, 100000000)  #just a few more inputs
    ins_full.update(extra)
    with pytest.raises(Exception) as e_info:
        txid = make_sign_and_push(ins_full,
                                  wallet,
                                  amount,
                                  hashcode=btc.SIGHASH_SINGLE)

    #trigger insufficient funds
    with pytest.raises(Exception) as e_info:
        fake_utxos = wallet.select_utxos(4, 1000000000)
Exemple #43
0
def test_donation_address(setup_donations, amount):
    wallets = make_wallets(1, wallet_structures=[[1,1,1,0,0]],
                               mean_amt=0.5)
    wallet = wallets[0]['wallet']
    jm_single().bc_interface.sync_wallet(wallet)
    #make a rdp from a simple privkey
    rdp_priv = "\x01"*32
    reusable_donation_pubkey = binascii.hexlify(secp256k1.PrivateKey(
        privkey=rdp_priv, raw=True, ctx=btc.ctx).pubkey.serialize())    
    dest_addr, sign_k = donation_address(reusable_donation_pubkey)
    print dest_addr
    jm_single().bc_interface.rpc('importaddress',
                                [dest_addr, '', False])    
    ins_full = wallet.unspent
    total = sum(x['value'] for x in ins_full.values())
    ins = ins_full.keys()
    output_addr = wallet.get_new_addr(1, 1)
    fee_est = 10000
    outs = [{'value': amount,
             'address': dest_addr}, {'value': total - amount - fee_est,
                                       'address': output_addr}]

    tx = btc.mktx(ins, outs)
    de_tx = btc.deserialize(tx)
    for index, ins in enumerate(de_tx['ins']):
        utxo = ins['outpoint']['hash'] + ':' + str(ins['outpoint']['index'])
        addr = ins_full[utxo]['address']
        priv = wallet.get_key_from_addr(addr)
        priv = binascii.unhexlify(priv)
        usenonce = binascii.unhexlify(sign_k) if index == 0 else None
        if index == 0:
            log.debug("Applying rdp to input: " + str(ins))
        tx = btc.sign(tx, index, priv, usenonce=usenonce)
    #pushtx returns False on any error
    push_succeed = jm_single().bc_interface.pushtx(tx)
    if push_succeed:
        log.debug(btc.txhash(tx))
    else:
        assert False
    #Role of receiver: regenerate the destination private key,
    #and address, from the nonce of the first input; check it has
    #received the coins.
    detx = btc.deserialize(tx)
    first_utxo_script = detx['ins'][0]['script']
    sig, pub = btc.deserialize_script(first_utxo_script)
    log.debug(sig)
    sig = binascii.unhexlify(sig)
    kGlen = ord(sig[3])
    kG = sig[4:4+kGlen]
    log.debug(binascii.hexlify(kG))
    if kG[0] == "\x00":
        kG = kG[1:]
    #H(rdp private key * K) + rdp should be ==> dest addr
    #Open issue: re-introduce recovery without ECC shenanigans
    #Just cheat by trying both signs for pubkey
    coerced_kG_1 = "02" + binascii.hexlify(kG)
    coerced_kG_2 = "03" + binascii.hexlify(kG)
    for coerc in [coerced_kG_1, coerced_kG_2]:
        c = btc.sha256(btc.multiply(binascii.hexlify(rdp_priv), coerc, True))
        pub_check = btc.add_pubkeys([reusable_donation_pubkey,
                                     btc.privtopub(c+'01', True)], True)
        addr_check = btc.pubtoaddr(pub_check, get_p2pk_vbyte())
        log.debug("Found checked address: " + addr_check)
        if addr_check == dest_addr:
            time.sleep(3)
            received = jm_single().bc_interface.get_received_by_addr(
                    [dest_addr], None)['data'][0]['balance']
            assert received == amount
            return
    assert False
Exemple #44
0
def test_external_commitment_used(setup_podle):
    tries = jm_single().config.getint("POLICY","taker_utxo_retries")
    #Don't want to wait too long, but must account for possible
    #throttling with !auth
    jm_single().maker_timeout_sec = 12
    amount = 50000000
    wallets = make_wallets(3,
                        wallet_structures=[[1,0,0,0,0],[1,0,0,0,0],[1,1,0,0,0]],
                        mean_amt=1)
    #the sendpayment bot uses the last wallet in the list
    wallet = wallets[2]['wallet']
    yigen_procs = []
    for i in range(2):
        ygp = local_command([python_cmd, yg_cmd,\
                             str(wallets[i]['seed'])], bg=True)
        time.sleep(2)  #give it a chance
        yigen_procs.append(ygp)

    #A significant delay is needed to wait for the yield generators to sync
    time.sleep(10)
    destaddr = btc.privkey_to_address(
            binascii.hexlify(os.urandom(32)),
            magicbyte=get_p2pk_vbyte())
    addr_valid, errormsg = validate_address(destaddr)
    assert addr_valid, "Invalid destination address: " + destaddr + \
           ", error message: " + errormsg

    log.debug('starting sendpayment')

    jm_single().bc_interface.sync_wallet(wallet)
    
    #Trigger PING LAG sending artificially
    joinmarket.irc.PING_INTERVAL = 3
    
    mcs = [IRCMessageChannel(c) for c in get_irc_mchannels()]
    mcc = MessageChannelCollection(mcs)
    #add all utxo in mixdepth 0 to 'used' list of commitments,
    utxos = wallet.get_utxos_by_mixdepth()[0]
    for u, addrval in utxos.iteritems():
        priv = wallet.get_key_from_addr(addrval['address'])
        podle = btc.PoDLE(u, priv)
        for i in range(tries):
            #loop because we want to use up all retries of this utxo
            commitment = podle.generate_podle(i)['commit']
            btc.update_commitments(commitment=commitment)

    #create a new utxo, notionally from an external source; to make life a little
    #easier we'll pay to another mixdepth, but this is OK because
    #taker does not source from here currently, only from the utxos chosen
    #for the transaction, not the whole wallet. So we can treat it as if
    #external (don't access its privkey).
    utxos = wallet.get_utxos_by_mixdepth()[1]
    ecs = {}
    for u, addrval in utxos.iteritems():
        priv = wallet.get_key_from_addr(addrval['address'])
        ecs[u] = {}
        ecs[u]['reveal']={}
        for j in range(tries):
            P, P2, s, e, commit = generate_single_podle_sig(
                binascii.unhexlify(priv), j)
            if 'P' not in ecs[u]:
                ecs[u]['P'] = P
            ecs[u]['reveal'][j] = {'P2':P2, 's':s, 'e':e}
    btc.update_commitments(external_to_add=ecs)
    #Now the conditions described above hold. We do a normal single
    #sendpayment.
    taker = sendpayment.SendPayment(mcc, wallet, destaddr, amount, 2,
                                    5000, 3, 0, True,
                                    weighted_order_choose)
    try:
        log.debug('starting message channels')
        mcc.run()
    finally:
        if any(yigen_procs):
            for ygp in yigen_procs:
                #NB *GENTLE* shutdown is essential for
                #test coverage reporting!
                ygp.send_signal(signal.SIGINT)
                ygp.wait()
    #wait for block generation
    time.sleep(5)
    received = jm_single().bc_interface.get_received_by_addr(
        [destaddr], None)['data'][0]['balance']
    assert received == amount, "sendpayment failed - coins not arrived, " +\
           "received: " + str(received)
    #Cleanup - remove the external commitments added
    btc.update_commitments(external_to_remove=ecs)
Exemple #45
0
def test_tx_commitments_used(setup_podle, consume_tx, age_required, cmt_age):
    tries = jm_single().config.getint("POLICY","taker_utxo_retries")
    #remember and reset at the end
    taker_utxo_age = jm_single().config.getint("POLICY", "taker_utxo_age")
    jm_single().config.set("POLICY", "taker_utxo_age", str(age_required))
    #Don't want to wait too long, but must account for possible
    #throttling with !auth
    jm_single().maker_timeout_sec = 12
    amount = 0
    wallets = make_wallets(3,
                        wallet_structures=[[1,2,1,0,0],[1,2,0,0,0],[2,2,1,0,0]],
                        mean_amt=1)
    #the sendpayment bot uses the last wallet in the list
    wallet = wallets[2]['wallet']

    #make_wallets calls grab_coins which mines 1 block per individual payout,
    #so the age of the coins depends on where they are in that list. The sendpayment
    #is the last wallet in the list, and we choose the non-tx utxos which are in
    #mixdepth 1 and 2 (2 and 1 utxos in each respectively). We filter for those
    #that have sufficient age, so to get 1 which is old enough, it will be the oldest,
    #which will have an age of 2 + 1 (the first utxo spent to that wallet).
    #So if we need an age of 6, we need to mine 3 more blocks.
    blocks_reqd = cmt_age - 3
    jm_single().bc_interface.tick_forward_chain(blocks_reqd)
    yigen_procs = []
    for i in range(2):
        ygp = local_command([python_cmd, yg_cmd,\
                             str(wallets[i]['seed'])], bg=True)
        time.sleep(2)  #give it a chance
        yigen_procs.append(ygp)

    time.sleep(5)
    destaddr = btc.privkey_to_address(
            binascii.hexlify(os.urandom(32)),
            magicbyte=get_p2pk_vbyte())
    addr_valid, errormsg = validate_address(destaddr)
    assert addr_valid, "Invalid destination address: " + destaddr + \
           ", error message: " + errormsg

    log.debug('starting sendpayment')

    jm_single().bc_interface.sync_wallet(wallet)
    log.debug("Here is the whole wallet: \n" + str(wallet.unspent))
    #Trigger PING LAG sending artificially
    joinmarket.irc.PING_INTERVAL = 3

    mcs = [IRCMessageChannel(c) for c in get_irc_mchannels()]
    mcc = MessageChannelCollection(mcs)
    if consume_tx:
        #add all utxo in mixdepth 0 to 'used' list of commitments,
        utxos = wallet.get_utxos_by_mixdepth()[0]
        for u, addrval in utxos.iteritems():
            priv = wallet.get_key_from_addr(addrval['address'])
            podle = btc.PoDLE(u, priv)
            for i in range(tries):
                #loop because we want to use up all retries of this utxo
                commitment = podle.generate_podle(i)['commit']
                btc.update_commitments(commitment=commitment)

    #Now test a sendpayment from mixdepth 0 with all the depth 0 utxos
    #used up, so that the other utxos in the wallet get used.
    taker = sendpayment.SendPayment(mcc, wallet, destaddr, amount, 2,
                                    5000, 3, 0, True,
                                    weighted_order_choose)
    try:
        log.debug('starting message channels')
        mcc.run()
    finally:
        if any(yigen_procs):
            for ygp in yigen_procs:
                #NB *GENTLE* shutdown is essential for
                #test coverage reporting!
                ygp.send_signal(signal.SIGINT)
                ygp.wait()
    #wait for block generation
    time.sleep(5)
    received = jm_single().bc_interface.get_received_by_addr(
        [destaddr], None)['data'][0]['balance']
    jm_single().config.set("POLICY", "taker_utxo_age", str(taker_utxo_age))
    if cmt_age < age_required:
        assert received == 0, "Coins arrived but shouldn't"
    else:
        assert received != 0, "sendpayment failed - coins not arrived, " +\
           "received: " + str(received)
Exemple #46
0
def test_tumbler(setup_tumbler, num_ygs, wallet_structures, mean_amt, sdev_amt,
                 yg_excess):
    """Test of tumbler code, with yield generators in background.
    """
    log = get_log()
    options = Options()
    options.mixdepthsrc = 0
    options.mixdepthcount = 4
    options.minmakercount = 2
    options.makercountrange = (num_ygs, 0)
    options.maxcjfee = (0.01, 10000)
    options.txfee = 5000
    options.addrcount = 3
    options.donateamount = 0.5
    options.txcountparams = (4, 1)
    options.mintxcount = 1
    options.amountpower = 100
    options.timelambda = 0.2
    options.waittime = 10
    options.mincjamount = 1000000
    options.liquiditywait = 5
    options.maxbroadcasts = 4
    options.maxcreatetx = 9
    options = vars(options)

    wallets = make_wallets(num_ygs + 1,
                           wallet_structures=wallet_structures,
                           mean_amt=mean_amt, sdev_amt=sdev_amt)
    #need to make sure that at least some ygs have substantially
    #more coins for last stages of sweep/spend in tumble:
    for i in range(num_ygs):
        jm_single().bc_interface.grab_coins(
                            wallets[i]['wallet'].get_external_addr(0), yg_excess)    
    #the tumbler bot uses the last wallet in the list
    wallet = wallets[num_ygs]['wallet']

    yigen_procs = []
    for i in range(num_ygs):
        ygp = local_command([python_cmd, yg_cmd,\
                             str(wallets[i]['seed'])], bg=True)
        time.sleep(2)  #give it a chance
        yigen_procs.append(ygp)

    #A significant delay is needed to wait for the yield generators to sync
    time.sleep(20)
    destaddrs = []
    for i in range(3):
        if btc.secp_present:
            destaddr = btc.privkey_to_address(
                os.urandom(32),
                from_hex=False,
                magicbyte=get_p2pk_vbyte())
        else:
            destaddr = btc.privkey_to_address(
                os.urandom(32),
                magicbyte=get_p2pk_vbyte())
        addr_valid, errormsg = validate_address(destaddr)
        assert addr_valid, "Invalid destination address: " + destaddr + \
                   ", error message: " + errormsg
        destaddrs.append(destaddr)
    tx_list = tumbler.generate_tumbler_tx(destaddrs, options)
    pprint(tx_list)
    if options['addrcount'] + 1 > options['mixdepthcount']:
        print('not enough mixing depths to pay to all destination addresses, '
              'increasing mixdepthcount')
        options['mixdepthcount'] = options['addrcount'] + 1

    tx_list2 = copy.deepcopy(tx_list)
    tx_dict = {}
    for tx in tx_list2:
        srcmixdepth = tx['srcmixdepth']
        tx.pop('srcmixdepth')
        if srcmixdepth not in tx_dict:
            tx_dict[srcmixdepth] = []
        tx_dict[srcmixdepth].append(tx)
    dbg_tx_list = []
    for srcmixdepth, txlist in tx_dict.iteritems():
        dbg_tx_list.append({'srcmixdepth': srcmixdepth, 'tx': txlist})
    log.debug('tumbler transaction list')
    pprint(dbg_tx_list)

    total_wait = sum([tx['wait'] for tx in tx_list])
    print('creates ' + str(len(tx_list)) + ' transactions in total')
    print('waits in total for ' + str(len(tx_list)) + ' blocks and ' + str(
            total_wait) + ' minutes')
    total_block_and_wait = len(tx_list) * 10 + total_wait
    print('estimated time taken ' + str(total_block_and_wait) + ' minutes or ' +
          str(round(total_block_and_wait / 60.0, 2)) + ' hours')

    jm_single().nickname = random_nick()

    log.debug('starting tumbler')

    jm_single().bc_interface.sync_wallet(wallet)
    jm_single().bc_interface.pushtx_failure_prob = 0.4
    irc = IRCMessageChannel(jm_single().nickname)
    tumbler_bot = tumbler.Tumbler(irc, wallet, tx_list, options)
    try:
        log.debug('starting irc')
        irc.run()
    except:
        log.debug('CRASHING, DUMPING EVERYTHING')
        debug_dump_object(wallet, ['addr_cache', 'keys', 'wallet_name', 'seed'])
        debug_dump_object(tumbler_bot)
        import traceback
        log.debug(traceback.format_exc())
    finally:
        if any(yigen_procs):
            for ygp in yigen_procs:
                #NB *GENTLE* shutdown is essential for
                #test coverage reporting!
                ygp.send_signal(signal.SIGINT)
                ygp.wait()
    #wait for block generation
    time.sleep(5)
    received = jm_single().bc_interface.get_received_by_addr(
        [destaddr], None)['data'][0]['balance']
    assert received != 0
    """TODO: figure out a sensible assertion check for the destination
Exemple #47
0
def test_failed_sendpayment(setup_podle, num_ygs, wallet_structures, mean_amt,
                     mixdepth, sending_amt):
    """Test of initiating joins, but failing to complete,
    to see commitment usage. YGs in background as per test_regtest.
    Use sweeps to avoid recover_from_nonrespondants without intruding
    into sendpayment code.
    """
    makercount = num_ygs
    answeryes = True
    txfee = 5000
    waittime = 3
    #Don't want to wait too long, but must account for possible
    #throttling with !auth
    jm_single().maker_timeout_sec = 12
    amount = 0
    wallets = make_wallets(makercount + 1,
                           wallet_structures=wallet_structures,
                           mean_amt=mean_amt)
    #the sendpayment bot uses the last wallet in the list
    wallet = wallets[makercount]['wallet']

    yigen_procs = []
    for i in range(makercount):
        ygp = local_command([python_cmd, yg_cmd,\
                             str(wallets[i]['seed'])], bg=True)
        time.sleep(2)  #give it a chance
        yigen_procs.append(ygp)

    #A significant delay is needed to wait for the yield generators to sync
    time.sleep(20)
    destaddr = btc.privkey_to_address(
            os.urandom(32),
            from_hex=False,
            magicbyte=get_p2pk_vbyte())

    addr_valid, errormsg = validate_address(destaddr)
    assert addr_valid, "Invalid destination address: " + destaddr + \
           ", error message: " + errormsg

    #TODO paramatetrize this as a test variable
    chooseOrdersFunc = weighted_order_choose

    log.debug('starting sendpayment')

    jm_single().bc_interface.sync_wallet(wallet)
    
    #Trigger PING LAG sending artificially
    joinmarket.irc.PING_INTERVAL = 3
    
    mcs = [IRCMessageChannel(c) for c in get_irc_mchannels()]
    mcc = MessageChannelCollection(mcs)

    #Allow taker more retries than makers allow, so as to trigger
    #blacklist failure case
    jm_single().config.set("POLICY", "taker_utxo_retries", "4")
    #override ioauth receipt with a dummy do-nothing callback:
    def on_ioauth(*args):
        log.debug("Taker received: " + ','.join([str(x) for x in args]))

    class DummySendPayment(sendpayment.SendPayment):
        def __init__(self, msgchan, wallet, destaddr, amount, makercount, txfee,
                 waittime, mixdepth, answeryes, chooseOrdersFunc, on_ioauth):
            self.on_ioauth = on_ioauth
            self.podle_fails = 0
            self.podle_allowed_fails = 3 #arbitrary; but do it more than once
            self.retries = 0
            super(DummySendPayment, self).__init__(msgchan, wallet,
                    destaddr, amount, makercount, txfee, waittime,
                    mixdepth, answeryes, chooseOrdersFunc)
        def on_welcome(self):
            Taker.on_welcome(self)
            DummyPaymentThread(self).start()        

    class DummyPaymentThread(sendpayment.PaymentThread):
        def finishcallback(self, coinjointx):
            #Don't ignore makers and just re-start
            self.taker.retries += 1
            if self.taker.podle_fails == self.taker.podle_allowed_fails:
                self.taker.msgchan.shutdown()
                return
            self.create_tx()
        def create_tx(self):
            try:
                super(DummyPaymentThread, self).create_tx()
            except btc.PoDLEError:
                log.debug("Got one commit failure, continuing")
                self.taker.podle_fails += 1

    taker = DummySendPayment(mcc, wallet, destaddr, amount, makercount,
                                    txfee, waittime, mixdepth, answeryes,
                                    chooseOrdersFunc, on_ioauth)
    try:
        log.debug('starting message channels')
        mcc.run()
    finally:
        if any(yigen_procs):
            for ygp in yigen_procs:
                #NB *GENTLE* shutdown is essential for
                #test coverage reporting!
                ygp.send_signal(signal.SIGINT)
                ygp.wait()
    #We should have been able to try (tur -1) + podle_allowed_fails times
    assert taker.retries == jm_single().config.getint(
        "POLICY", "taker_utxo_retries") + taker.podle_allowed_fails
    #wait for block generation
    time.sleep(2)
    received = jm_single().bc_interface.get_received_by_addr(
        [destaddr], None)['data'][0]['balance']
    #Sanity check no transaction succeeded
    assert received == 0
def test_sendpayment(setup_regtest, num_ygs, wallet_structures, mean_amt,
                     mixdepth, sending_amt, ygcfs, fails, donate, rpcwallet):
    """Test of sendpayment code, with yield generators in background.
    """
    log = get_log()
    makercount = num_ygs
    answeryes = True
    txfee = 5000
    waittime = 5
    amount = sending_amt
    wallets = make_wallets(makercount + 1,
                           wallet_structures=wallet_structures,
                           mean_amt=mean_amt)
    #the sendpayment bot uses the last wallet in the list
    if not rpcwallet:
        wallet = wallets[makercount]['wallet']
    else:
        wallet = BitcoinCoreWallet(fromaccount="")

    yigen_procs = []
    if ygcfs:
        assert makercount == len(ygcfs)
    for i in range(makercount):
        if ygcfs:
            #back up default config, overwrite before start
            os.rename("joinmarket.cfg", "joinmarket.cfg.bak")
            shutil.copy2(ygcfs[i], "joinmarket.cfg")
        ygp = local_command([python_cmd, yg_cmd,\
                             str(wallets[i]['seed'])], bg=True)
        time.sleep(2)  #give it a chance
        yigen_procs.append(ygp)
        if ygcfs:
            #Note: in case of using multiple configs,
            #the starting config is what is used by sendpayment
            os.rename("joinmarket.cfg.bak", "joinmarket.cfg")

    #A significant delay is needed to wait for the yield generators to sync
    time.sleep(20)
    if donate:
        destaddr = None
    else:
        destaddr = btc.privkey_to_address(
            os.urandom(32),
            from_hex=False,
            magicbyte=get_p2pk_vbyte())
        addr_valid, errormsg = validate_address(destaddr)
        assert addr_valid, "Invalid destination address: " + destaddr + \
           ", error message: " + errormsg

    #TODO paramatetrize this as a test variable
    chooseOrdersFunc = weighted_order_choose

    log.debug('starting sendpayment')

    sync_wallet(wallet)
    
    #Trigger PING LAG sending artificially
    joinmarket.irc.PING_INTERVAL = 3
    
    mcs = [IRCMessageChannel(c) for c in get_irc_mchannels()]
    mcc = MessageChannelCollection(mcs)
    #hack fix for #356 if multiple orders per counterparty
    #removed for now.
    #if amount==0: makercount=2
    taker = sendpayment.SendPayment(mcc, wallet, destaddr, amount, makercount-2,
                                    txfee, waittime, mixdepth, answeryes,
                                    chooseOrdersFunc)
    try:
        log.debug('starting message channels')
        mcc.run(failures=fails)
    finally:
        if any(yigen_procs):
            for ygp in yigen_procs:
                #NB *GENTLE* shutdown is essential for
                #test coverage reporting!
                ygp.send_signal(signal.SIGINT)
                ygp.wait()
    #wait for block generation
    time.sleep(5)
    if not donate:
        received = jm_single().bc_interface.get_received_by_addr(
            [destaddr], None)['data'][0]['balance']
        if amount != 0:
            assert received == amount, "sendpayment failed - coins not arrived, " +\
               "received: " + str(received)
        #TODO: how to check success for sweep case?
        else:
            assert received != 0
def test_wallet_sync_with_fast(setup_wallets, num_txs, fake_count,
                     wallet_structure, amount, wallet_file, password):
    setup_import(mainnet=False)
    wallet = make_wallets(1,[wallet_structure],
                          fixed_seeds=[wallet_file],
                          test_wallet=True, passwords=[password])[0]['wallet']
    sync_count = 0
    jm_single().bc_interface.wallet_synced = False
    while not jm_single().bc_interface.wallet_synced:
        sync_wallet(wallet)
        sync_count += 1
        #avoid infinite loop
        assert sync_count < 10
        log.debug("Tried " + str(sync_count) + " times")

    assert jm_single().bc_interface.wallet_synced
    assert not jm_single().bc_interface.fast_sync_called
    #do some transactions with the wallet, then close, then resync
    for i in range(num_txs):
        do_tx(wallet, amount)
        log.debug("After doing a tx, index is now: " + str(wallet.index))
        #simulate a spammer requesting a bunch of transactions. This
        #mimics what happens in CoinJoinOrder.__init__()
        for j in range(fake_count):
            #Note that as in a real script run,
            #the initial call to sync_wallet will
            #have set wallet_synced to True, so these will
            #trigger actual imports.
            cj_addr = wallet.get_internal_addr(0)
            change_addr = wallet.get_internal_addr(0)
            wallet.update_cache_index()
            log.debug("After doing a spam, index is now: " + str(wallet.index))

    assert wallet.index[0][1] == num_txs+fake_count*2*num_txs

    #Attempt re-sync, simulating a script restart.

    jm_single().bc_interface.wallet_synced = False
    sync_count = 0
    #Probably should be fixed in main code:
    #wallet.index_cache is only assigned in Wallet.__init__(),
    #meaning a second sync in the same script, after some transactions,
    #will not know about the latest index_cache value (see is_index_ahead_of_cache),
    #whereas a real re-sync will involve reading the cache from disk.
    #Hence, simulation of the fact that the cache index will
    #be read from the file on restart:
    wallet.index_cache = wallet.index

    while not jm_single().bc_interface.wallet_synced:
        #Wallet.__init__() resets index to zero.
        wallet.index = []
        for i in range(5):
            wallet.index.append([0, 0])
        #Wallet.__init__() also updates the cache index
        #from file, but we can reuse from the above pre-loop setting,
        #since nothing else in sync will overwrite the cache.

        #for regtest add_watchonly_addresses does not exit(), so can
        #just repeat as many times as possible. This might
        #be usable for non-test code (i.e. no need to restart the
        #script over and over again)?
        sync_count += 1
        log.debug("TRYING SYNC NUMBER: " + str(sync_count))
        sync_wallet(wallet, fast=True)
        assert jm_single().bc_interface.fast_sync_called
        #avoid infinite loop on failure.
        assert sync_count < 10
    #Wallet should recognize index_cache on fast sync, so should not need to
    #run sync process more than once.
    assert sync_count == 1
    #validate the wallet index values after sync
    for i, ws in enumerate(wallet_structure):
        assert wallet.index[i][0] == ws #spends into external only
    #Same number as above; note it includes the spammer's extras.
    assert wallet.index[0][1] == num_txs+fake_count*2*num_txs
    assert wallet.index[1][1] == num_txs #one change per transaction
    for i in range(2,5):
        assert wallet.index[i][1] == 0 #unused

    #Now try to do more transactions as sanity check.
    do_tx(wallet, 50000000)
Exemple #50
0
def test_sendpayment(setup_regtest, num_ygs, wallet_structures, mean_amt,
                     mixdepth, sending_amt):
    """Test of sendpayment code, with yield generators in background.
    """
    log = get_log()
    makercount = num_ygs
    answeryes = True
    txfee = 5000
    waittime = 5
    amount = sending_amt
    wallets = make_wallets(makercount + 1,
                           wallet_structures=wallet_structures,
                           mean_amt=mean_amt)
    #the sendpayment bot uses the last wallet in the list
    wallet = wallets[makercount]['wallet']

    yigen_procs = []
    for i in range(makercount):
        ygp = local_command([python_cmd, yg_cmd,\
                             str(wallets[i]['seed'])], bg=True)
        time.sleep(2)  #give it a chance
        yigen_procs.append(ygp)

    #A significant delay is needed to wait for the yield generators to sync
    time.sleep(20)
    if btc.secp_present:
        destaddr = btc.privkey_to_address(
            os.urandom(32),
            from_hex=False,
            magicbyte=get_p2pk_vbyte())
    else:
        destaddr = btc.privkey_to_address(
            os.urandom(32),
            magicbyte=get_p2pk_vbyte())

    addr_valid, errormsg = validate_address(destaddr)
    assert addr_valid, "Invalid destination address: " + destaddr + \
           ", error message: " + errormsg

    #TODO paramatetrize this as a test variable
    chooseOrdersFunc = weighted_order_choose

    jm_single().nickname = random_nick()

    log.debug('starting sendpayment')

    jm_single().bc_interface.sync_wallet(wallet)
    
    #Trigger PING LAG sending artificially
    joinmarket.irc.PING_INTERVAL = 3
    
    irc = IRCMessageChannel(jm_single().nickname)
    taker = sendpayment.SendPayment(irc, wallet, destaddr, amount, makercount,
                                    txfee, waittime, mixdepth, answeryes,
                                    chooseOrdersFunc)
    try:
        log.debug('starting irc')
        irc.run()
    finally:
        if any(yigen_procs):
            for ygp in yigen_procs:
                #NB *GENTLE* shutdown is essential for
                #test coverage reporting!
                ygp.send_signal(signal.SIGINT)
                ygp.wait()
    #wait for block generation
    time.sleep(5)
    received = jm_single().bc_interface.get_received_by_addr(
        [destaddr], None)['data'][0]['balance']
    if amount != 0:
        assert received == amount, "sendpayment failed - coins not arrived, " +\
           "received: " + str(received)
    #TODO: how to check success for sweep case?
    else:
        assert received != 0