def validate_utxo_data(utxo_datas, retrieve=False):
    """For each txid: N, privkey, first
    convert the privkey and convert to address,
    then use the blockchain instance to look up
    the utxo and check that its address field matches.
    If retrieve is True, return the set of utxos and their values.
    """
    results = []
    for u, priv in utxo_datas:
        print 'validating this utxo: ' + str(u)
        hexpriv = btc.from_wif_privkey(priv, vbyte=get_p2pk_vbyte())
        addr = btc.privkey_to_address(hexpriv, magicbyte=get_p2pk_vbyte())
        print 'claimed address: ' + addr
        res = jm_single().bc_interface.query_utxo_set([u])
        print 'blockchain shows this data: ' + str(res)
        if len(res) != 1:
            print "utxo not found on blockchain: " + str(u)
            return False
        if res[0]['address'] != addr:
            print "privkey corresponds to the wrong address for utxo: " + str(u)
            print "blockchain returned address: " + res[0]['address']
            print "your privkey gave this address: " + addr
            return False
        if retrieve:
            results.append((u, res[0]['value']))
    print 'all utxos validated OK'
    if retrieve:
        return results
    return True
Example #2
0
def test_p2p_broadcast(setup_tx_notify):
    #listen up kids, dont do this to generate private
    #keys that hold real money, or else you'll be robbed
    src_privkey = random.getrandbits(256)
    src_privkey = btc.encode(src_privkey, 16, 64) + '01'
    src_addr = btc.privtoaddr(src_privkey, magicbyte=get_p2pk_vbyte())
    dst_addr = btc.pubtoaddr('03' + btc.encode(random.getrandbits(256), 16),
                             get_p2pk_vbyte())

    jm_single().bc_interface.rpc('importaddress', [src_addr, "", False])
    jm_single().bc_interface.rpc('importaddress', [dst_addr, "", False])
    jm_single().bc_interface.rpc('generatetoaddress', [1, src_addr])
    jm_single().bc_interface.rpc('generate', [101])
    src_utxos = jm_single().bc_interface.rpc('listunspent',
                                             [0, 500, [src_addr]])

    inputs = [{
        'output': src_utxos[0]['txid'] + ':' + str(src_utxos[0]['vout'])
    }]
    miner_fee = 10000
    outs = [{
        'address': dst_addr,
        'value': int(src_utxos[0]['amount'] * 1e8) - miner_fee
    }]
    tx = btc.mktx(inputs, outs)
    tx = btc.sign(tx, 0, src_privkey)

    bad_tx = random.getrandbits(len(tx) * 4)
    bad_tx = btc.encode(bad_tx, 16, len(tx))

    utxo_before = jm_single().bc_interface.rpc('listunspent',
                                               [0, 500, [dst_addr]])

    #jm_single().bc_interface.rpc('sendrawtransaction', [tx])
    pushed = tor_broadcast_tx(tx,
                              None,
                              'regtest',
                              remote_hostport=('localhost', 18444))
    assert pushed

    pushed = tor_broadcast_tx(tx,
                              None,
                              'regtest',
                              remote_hostport=('localhost', 18444))
    assert not pushed  #node should already have the same tx, reject

    pushed = tor_broadcast_tx(bad_tx,
                              None,
                              'regtest',
                              remote_hostport=('localhost', 18444))
    assert not pushed  #bad tx should be rejected

    jm_single().bc_interface.rpc('generate', [1])
    utxo_after = jm_single().bc_interface.rpc('listunspent',
                                              [0, 500, [dst_addr]])

    return len(utxo_after) - 1 == len(utxo_before)
Example #3
0
    def run_send(self, bad=False):
        yigen_procs = []
        if bad:
            i = 2
        else:
            i = 0
        ygp = local_command([python_cmd,yg_cmd,\
                                 str(self.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)

        #run a single sendpayment call
        amt = 100000000  #in satoshis
        dest_address = btc.privkey_to_address(os.urandom(32), get_p2pk_vbyte())
        try:
            sp_proc = local_command([python_cmd, 'sendpayment.py', '--yes',
                                     '-N', '1', self.wallets[1]['seed'], str(
                                         amt), dest_address])
        except subprocess.CalledProcessError, e:
            for ygp in yigen_procs:
                ygp.kill()
            print e.returncode
            print e.message
            raise
Example #4
0
    def run_tumble(self, amt):
        yigen_procs = []
        for i in range(6):
            ygp = local_command([python_cmd, yg_cmd,\
                                 str(self.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)

        #start a tumbler
        amt = amt * 1e8  #in satoshis
        #send to any old address
        dest_address = btc.privkey_to_address(os.urandom(32), get_p2pk_vbyte())
        try:
            print 'taker seed: ' + self.wallets[6]['seed']
            while True:
                print 'hello'
                time.sleep(80)
        except subprocess.CalledProcessError, e:
            for ygp in yigen_procs:
                ygp.kill()
            print e.returncode
            print e.message
            raise
Example #5
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)
    def run_tumble(self, amt):
        yigen_procs = []
        for i in range(6):
            ygp = local_command([python_cmd, yg_cmd,\
                                 str(self.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)

        #start a tumbler
        amt = amt * 1e8  #in satoshis
        #send to any old address
        dest_address = btc.privkey_to_address(os.urandom(32), get_p2pk_vbyte())
        try:
            print 'taker seed: '+self.wallets[6]['seed']
            while True:
                print 'hello'
                time.sleep(80)
        except subprocess.CalledProcessError, e:
            for ygp in yigen_procs:
                ygp.kill()
            print e.returncode
            print e.message
            raise
Example #7
0
    def run_send(self, bad=False):
        yigen_procs = []
        if bad:
            i = 2
        else:
            i = 0
        ygp = local_command([python_cmd,yg_cmd,\
                                 str(self.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)

        #run a single sendpayment call
        amt = 100000000  #in satoshis
        dest_address = btc.privkey_to_address(os.urandom(32), get_p2pk_vbyte())
        try:
            sp_proc = local_command([
                python_cmd, 'sendpayment.py', '--yes', '-N', '1',
                self.wallets[1]['seed'],
                str(amt), dest_address
            ])
        except subprocess.CalledProcessError, e:
            for ygp in yigen_procs:
                ygp.kill()
            print e.returncode
            print e.message
            raise
Example #8
0
def test_blockr_sync(setup_blockr, net, seed, gaplimit, showprivkey, method):
    jm_single().config.set("BLOCKCHAIN", "network", net)
    wallet = Wallet(seed, max_mix_depth=5)
    jm_single().bc_interface.sync_wallet(wallet)

    #copy pasted from wallet-tool; some boiled down form of
    #this should really be in wallet.py in the joinmarket module.
    def cus_print(s):
        print s

    total_balance = 0
    for m in range(wallet.max_mix_depth):
        cus_print('mixing depth %d m/0/%d/' % (m, m))
        balance_depth = 0
        for forchange in [0, 1]:
            cus_print(' ' + ('external' if forchange == 0 else 'internal') +
                      ' addresses m/0/%d/%d/' % (m, forchange))

            for k in range(wallet.index[m][forchange] + gaplimit):
                addr = wallet.get_addr(m, forchange, k)
                balance = 0.0
                for addrvalue in wallet.unspent.values():
                    if addr == addrvalue['address']:
                        balance += addrvalue['value']
                balance_depth += balance
                used = ('used' if k < wallet.index[m][forchange] else ' new')
                if showprivkey:
                    if btc.secp_present:
                        privkey = btc.wif_compressed_privkey(
                            wallet.get_key(m, forchange, k), get_p2pk_vbyte())
                    else:
                        privkey = btc.encode_privkey(
                            wallet.get_key(m, forchange, k), 'wif_compressed',
                            get_p2pk_vbyte())
                else:
                    privkey = ''
                if (method == 'displayall' or balance > 0
                        or (used == ' new' and forchange == 0)):
                    cus_print(
                        '  m/0/%d/%d/%03d %-35s%s %.8f btc %s' %
                        (m, forchange, k, addr, used, balance / 1e8, privkey))
        total_balance += balance_depth
        print('for mixdepth=%d balance=%.8fbtc' % (m, balance_depth / 1e8))
    assert total_balance == 96143257
Example #9
0
def test_blockr_sync(setup_blockr, net, seed, gaplimit, showprivkey, method):
    jm_single().config.set("BLOCKCHAIN", "network", net)
    wallet = Wallet(seed, max_mix_depth = 5)
    jm_single().bc_interface.sync_wallet(wallet)
    
    #copy pasted from wallet-tool; some boiled down form of
    #this should really be in wallet.py in the joinmarket module.
    def cus_print(s):
            print s

    total_balance = 0
    for m in range(wallet.max_mix_depth):
        cus_print('mixing depth %d m/0/%d/' % (m, m))
        balance_depth = 0
        for forchange in [0, 1]:
            cus_print(' ' + ('external' if forchange == 0 else 'internal') +
                      ' addresses m/0/%d/%d/' % (m, forchange))

            for k in range(wallet.index[m][forchange] + gaplimit):
                addr = wallet.get_addr(m, forchange, k)
                balance = 0.0
                for addrvalue in wallet.unspent.values():
                    if addr == addrvalue['address']:
                        balance += addrvalue['value']
                balance_depth += balance
                used = ('used' if k < wallet.index[m][forchange] else ' new')
                if showprivkey:
                    if btc.secp_present:
                        privkey = btc.wif_compressed_privkey(
                    wallet.get_key(m, forchange, k), get_p2pk_vbyte())
                    else:
                        privkey = btc.encode_privkey(wallet.get_key(m,
                                forchange, k), 'wif_compressed', get_p2pk_vbyte())
                else:
                    privkey = ''
                if (method == 'displayall' or balance > 0 or
                    (used == ' new' and forchange == 0)):
                    cus_print('  m/0/%d/%d/%03d %-35s%s %.8f btc %s' %
                              (m, forchange, k, addr, used, balance / 1e8,
                               privkey))
        total_balance += balance_depth
        print('for mixdepth=%d balance=%.8fbtc' % (m, balance_depth / 1e8))
    assert total_balance == 96143257    
Example #10
0
 def generate_single_podle_sig(u, priv, i):
     """Make a podle entry for key priv at index i, using a dummy utxo value.
     This calls the underlying 'raw' code based on the class PoDLE, not the
     library 'generate_podle' which intelligently searches and updates commitments.
     """
     #Convert priv to hex
     hexpriv = btc.from_wif_privkey(priv, vbyte=get_p2pk_vbyte())
     podle = btc.PoDLE(u, hexpriv)
     r = podle.generate_podle(i)
     return (r['P'], r['P2'], r['sig'], r['e'], r['commit'])
Example #11
0
def get_next_address(send_job):
    if 'addresses' in send_job:
        this_index = send_job['index']
        send_job['index'] = (send_job['index'] + 1) % len(send_job['addresses'])
        return send_job['addresses'][this_index]
    elif 'xpub' in send_job:
        send_job['index'] += 1
        return btc.pubtoaddr(btc.bip32_extract_key(btc.bip32_ckd(
            send_job['xpub'], send_job['index']-1)), get_p2pk_vbyte())
    else:
        assert False
Example #12
0
 def generate_single_podle_sig(u, priv, i):
     """Make a podle entry for key priv at index i, using a dummy utxo value.
     This calls the underlying 'raw' code based on the class PoDLE, not the
     library 'generate_podle' which intelligently searches and updates commitments.
     """
     #Convert priv to hex
     hexpriv = btc.from_wif_privkey(priv, vbyte=get_p2pk_vbyte())
     podle = btc.PoDLE(u, hexpriv)
     r = podle.generate_podle(i)
     return (r['P'], r['P2'], r['sig'],
             r['e'], r['commit'])
Example #13
0
    def donation_address(tx, wallet):
        from bitcoin.main import multiply, G, deterministic_generate_k, add_pubkeys
        reusable_donation_pubkey = ('02be838257fbfddabaea03afbb9f16e852'
                                    '9dfe2de921260a5c46036d97b5eacf2a')

        privkey = wallet.get_key_from_addr(wallet.get_new_addr(0, 0))
        msghash = btc.bin_txhash(tx, btc.SIGHASH_ALL)
        # generate unpredictable k
        global sign_k
        sign_k = deterministic_generate_k(msghash, privkey)
        c = btc.sha256(multiply(reusable_donation_pubkey, sign_k))
        sender_pubkey = add_pubkeys(reusable_donation_pubkey, multiply(G, c))
        sender_address = btc.pubtoaddr(sender_pubkey, get_p2pk_vbyte())
        log.debug('sending coins to ' + sender_address)
        return privkey, sender_address
Example #14
0
    def donation_address(cjtx, wallet):
	privkey = wallet.get_key_from_addr(wallet.get_new_addr(0,0))
	reusable_donation_pubkey = '02be838257fbfddabaea03afbb9f16e8529dfe2de921260a5c46036d97b5eacf2a'
	global sign_k
	import os
	import binascii
	sign_k = os.urandom(32)
	log.debug("Using the following nonce value: "+binascii.hexlify(sign_k))
	c = btc.sha256(btc.multiply(binascii.hexlify(sign_k),
                                    reusable_donation_pubkey, True))
	sender_pubkey = btc.add_pubkeys([reusable_donation_pubkey,
                                         btc.privtopub(c+'01', True)], True)
	sender_address = btc.pubtoaddr(sender_pubkey, get_p2pk_vbyte())
	log.debug('sending coins to ' + sender_address)
	return privkey, sender_address
Example #15
0
    def donation_address(tx, wallet):
	from bitcoin.main import multiply, G, deterministic_generate_k, add_pubkeys
	reusable_donation_pubkey = ('02be838257fbfddabaea03afbb9f16e852'
	                            '9dfe2de921260a5c46036d97b5eacf2a')
    
	privkey = wallet.get_key_from_addr(wallet.get_new_addr(0,0))
	msghash = btc.bin_txhash(tx, btc.SIGHASH_ALL)
	# generate unpredictable k
	global sign_k
	sign_k = deterministic_generate_k(msghash, privkey)
	c = btc.sha256(multiply(reusable_donation_pubkey, sign_k))
	sender_pubkey = add_pubkeys(
	        reusable_donation_pubkey, multiply(
	                G, c))
	sender_address = btc.pubtoaddr(sender_pubkey, get_p2pk_vbyte())
	log.debug('sending coins to ' + sender_address)
	return privkey, sender_address
Example #16
0
 def donation_address(cjtx, wallet):
     privkey = wallet.get_key_from_addr(wallet.get_new_addr(0, 0))
     reusable_donation_pubkey = '02be838257fbfddabaea03afbb9f16e8529dfe2de921260a5c46036d97b5eacf2a'
     global sign_k
     import os
     import binascii
     sign_k = os.urandom(32)
     log.debug("Using the following nonce value: " +
               binascii.hexlify(sign_k))
     c = btc.sha256(
         btc.multiply(binascii.hexlify(sign_k), reusable_donation_pubkey,
                      True))
     sender_pubkey = btc.add_pubkeys(
         [reusable_donation_pubkey,
          btc.privtopub(c + '01', True)], True)
     sender_address = btc.pubtoaddr(sender_pubkey, get_p2pk_vbyte())
     log.debug('sending coins to ' + sender_address)
     return privkey, sender_address
Example #17
0
def get_utxo_info(upriv):
    """Verify that the input string parses correctly as (utxo, priv)
    and return that.
    """
    try:
        u, priv = upriv.split(',')
        u = u.strip()
        priv = priv.strip()
        txid, n = u.split(':')
        assert len(txid)==64
        assert len(n) in range(1, 4)
        n = int(n)
        assert n in range(256)
    except:
        #not sending data to stdout in case privkey info
        print "Failed to parse utxo information for utxo"
    try:
        hexpriv = btc.from_wif_privkey(priv, vbyte=get_p2pk_vbyte())
    except:
        print "failed to parse privkey, make sure it's WIF compressed format."
    return u, priv
Example #18
0
    def run_simple_send(self, n, m):
        #start yield generator with wallet1
        yigen_proc = local_command(
            [python_cmd, yg_cmd, str(self.wallets[0]['seed'])],
            bg=True)

        #A significant delay is needed to wait for the yield generator to sync its wallet
        time.sleep(20)

        #run a single sendpayment call with wallet2
        amt = n * 100000000  #in satoshis
        dest_address = btc.privkey_to_address(os.urandom(32), get_p2pk_vbyte())
        try:
            for i in range(m):
                sp_proc = local_command([python_cmd,'sendpayment.py','--yes','-N','1', self.wallets[1]['seed'],\
                                                      str(amt), dest_address])
        except subprocess.CalledProcessError, e:
            if yigen_proc:
                yigen_proc.terminate()
            print e.returncode
            print e.message
            raise
Example #19
0
    def run_simple_send(self, n, m):
        #start yield generator with wallet1
        yigen_proc = local_command(
            [python_cmd, yg_cmd,
             str(self.wallets[0]['seed'])], bg=True)

        #A significant delay is needed to wait for the yield generator to sync its wallet
        time.sleep(20)

        #run a single sendpayment call with wallet2
        amt = n * 100000000  #in satoshis
        dest_address = btc.privkey_to_address(os.urandom(32), get_p2pk_vbyte())
        try:
            for i in range(m):
                sp_proc = local_command([python_cmd,'sendpayment.py','--yes','-N','1', self.wallets[1]['seed'],\
                                                      str(amt), dest_address])
        except subprocess.CalledProcessError, e:
            if yigen_proc:
                yigen_proc.terminate()
            print e.returncode
            print e.message
            raise
Example #20
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)
Example #21
0
def sign(utxo, priv, destaddrs):
    """Sign a tx sending the amount amt, from utxo utxo,
    equally to each of addresses in list destaddrs,
    after fees; the purpose is to create a large
    number of utxos.
    """
    results = validate_utxo_data([(utxo, priv)], retrieve=True)
    if not results:
        return False
    assert results[0][0] == utxo
    amt = results[0][1]
    ins = [utxo]
    estfee = estimate_tx_fee(1, len(destaddrs))
    outs = []
    share = int((amt - estfee) / len(destaddrs))
    fee = amt - share*len(destaddrs)
    assert fee >= estfee
    log.debug("Using fee: " + str(fee))
    for i, addr in enumerate(destaddrs):
        outs.append({'address': addr, 'value': share})
    unsigned_tx = btc.mktx(ins, outs)
    return btc.sign(unsigned_tx, 0, btc.from_wif_privkey(
        priv, vbyte=get_p2pk_vbyte()))
Example #22
0
def sign(utxo, priv, destaddrs):
    """Sign a tx sending the amount amt, from utxo utxo,
    equally to each of addresses in list destaddrs,
    after fees; the purpose is to create a large
    number of utxos.
    """
    results = validate_utxo_data([(utxo, priv)], retrieve=True)
    if not results:
        return False
    assert results[0][0] == utxo
    amt = results[0][1]
    ins = [utxo]
    estfee = estimate_tx_fee(1, len(destaddrs))
    outs = []
    share = int((amt - estfee) / len(destaddrs))
    fee = amt - share * len(destaddrs)
    assert fee >= estfee
    log.info("Using fee: " + str(fee))
    for i, addr in enumerate(destaddrs):
        outs.append({'address': addr, 'value': share})
    unsigned_tx = btc.mktx(ins, outs)
    return btc.sign(unsigned_tx, 0,
                    btc.from_wif_privkey(priv, vbyte=get_p2pk_vbyte()))
Example #23
0
    def run_sweep(self):
        #currently broken due to flooding; to make it work
        #change the 60 loop for the bad wallet to 20
        yigen_procs = []
        ygp = local_command([python_cmd,yg_cmd,\
                                     str(self.wallets[3]['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)

        dest_address = btc.privkey_to_address(os.urandom(32), get_p2pk_vbyte())
        try:
            sp_proc = local_command([python_cmd, 'sendpayment.py', '--yes',
                                     '-N', '1', self.wallets[2][
                                         'seed'], '0', dest_address])
        except subprocess.CalledProcessError, e:
            for ygp in yigen_procs:
                ygp.kill()
            print e.returncode
            print e.message
            raise
Example #24
0
    def run_tumble(self, amt):
        yigen_procs = []
        for i in range(6):
            ygp = local_command([python_cmd, yg_cmd,\
                                 str(self.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(60)

        #start a tumbler
        amt = amt * 1e8  #in satoshis
        #send to any old address
        dest_address = btc.privkey_to_address(os.urandom(32), get_p2pk_vbyte())
        try:
            #default mixdepth source is zero, so will take coins from m 0.
            #see tumbler.py --h for details
            expected = ['tumble with these tx']
            test_in = ['y']
            p = pexpect.spawn(python_cmd,
                              ['tumbler.py', '-N', '2', '0', '-a', '0', '-M',
                               '5', '-w', '10', '-l', '0.2', '-s', '1000000',
                               '-q', '5', self.wallets[6]['seed'], dest_address])
            interact(p, test_in, expected)
            p.expect(pexpect.EOF, timeout=100000)
            p.close()
            if p.exitstatus != 0:
                print 'failed due to exit status: ' + str(p.exitstatus)
                return False
        except subprocess.CalledProcessError, e:
            for ygp in yigen_procs:
                ygp.kill()
            print e.returncode
            print e.message
            raise
Example #25
0
    def run_sweep(self):
        #currently broken due to flooding; to make it work
        #change the 60 loop for the bad wallet to 20
        yigen_procs = []
        ygp = local_command([python_cmd,yg_cmd,\
                                     str(self.wallets[3]['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)

        dest_address = btc.privkey_to_address(os.urandom(32), get_p2pk_vbyte())
        try:
            sp_proc = local_command([
                python_cmd, 'sendpayment.py', '--yes', '-N', '1',
                self.wallets[2]['seed'], '0', dest_address
            ])
        except subprocess.CalledProcessError, e:
            for ygp in yigen_procs:
                ygp.kill()
            print e.returncode
            print e.message
            raise
Example #26
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
Example #27
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
Example #28
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
Example #29
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
Example #30
0
def main():
    parser = OptionParser(
        usage='usage: %prog [options] [auth utxo] [cjamount] [cjaddr] ['
        'changeaddr] [utxos..]',
        description=('Creates an unsigned coinjoin transaction. Outputs '
                     'a partially signed transaction hex string. The user '
                     'must sign their inputs independently and broadcast '
                     'them. The JoinMarket protocol requires the taker to '
                     'have a single p2pk UTXO input to use to '
                     'authenticate the  encrypted messages. For this '
                     'reason you must pass auth utxo and the '
                     'corresponding private key'))

    # for cjamount=0 do a sweep, and ignore change address
    parser.add_option('-f',
                      '--txfee',
                      action='store',
                      type='int',
                      dest='txfee',
                      default=10000,
                      help='total miner fee in satoshis, default=10000')
    parser.add_option(
        '-w',
        '--wait-time',
        action='store',
        type='float',
        dest='waittime',
        help='wait time in seconds to allow orders to arrive, default=5',
        default=5)
    parser.add_option('-N',
                      '--makercount',
                      action='store',
                      type='int',
                      dest='makercount',
                      help='how many makers to coinjoin with, default=2',
                      default=2)
    parser.add_option(
        '-C',
        '--choose-cheapest',
        action='store_true',
        dest='choosecheapest',
        default=False,
        help='override weightened offers picking and choose cheapest')
    parser.add_option(
        '-P',
        '--pick-orders',
        action='store_true',
        dest='pickorders',
        default=False,
        help='manually pick which orders to take. doesn\'t work while sweeping.'
    )
    parser.add_option('--yes',
                      action='store_true',
                      dest='answeryes',
                      default=False,
                      help='answer yes to everything')
    # TODO implement parser.add_option('-n', '--no-network',
    # action='store_true', dest='nonetwork', default=False, help='dont query
    # the blockchain interface, instead user must supply value of UTXOs on '
    # + ' command line in the format txid:output/value-in-satoshi')
    (options, args) = parser.parse_args()

    if len(args) < 3:
        parser.error('Needs a wallet, amount and destination address')
        sys.exit(0)
    auth_utxo = args[0]
    cjamount = int(args[1])
    destaddr = args[2]
    changeaddr = args[3]
    cold_utxos = args[4:]

    load_program_config()
    addr_valid1, errormsg1 = validate_address(destaddr)
    errormsg2 = None
    # if amount = 0 dont bother checking changeaddr so user can write any junk
    if cjamount != 0:
        addr_valid2, errormsg2 = validate_address(changeaddr)
    else:
        addr_valid2 = True
    if not addr_valid1 or not addr_valid2:
        if not addr_valid1:
            print 'ERROR: Address invalid. ' + errormsg1
        else:
            print 'ERROR: Address invalid. ' + errormsg2
        return

    all_utxos = [auth_utxo] + cold_utxos
    query_result = jm_single().bc_interface.query_utxo_set(all_utxos)
    if None in query_result:
        print query_result
    utxo_data = {}
    for utxo, data in zip(all_utxos, query_result):
        utxo_data[utxo] = {'address': data['address'], 'value': data['value']}
    auth_privkey = raw_input('input private key for ' +
                             utxo_data[auth_utxo]['address'] + ' :')
    if utxo_data[auth_utxo]['address'] != btc.privtoaddr(
            auth_privkey, magicbyte=get_p2pk_vbyte()):
        print 'ERROR: privkey does not match auth utxo'
        return

    if options.pickorders and cjamount != 0:  # cant use for sweeping
        chooseOrdersFunc = pick_order
    elif options.choosecheapest:
        chooseOrdersFunc = cheapest_order_choose
    else:  # choose randomly (weighted)
        chooseOrdersFunc = weighted_order_choose

    jm_single().nickname = random_nick()
    log.debug('starting sendpayment')

    class UnsignedTXWallet(AbstractWallet):
        def get_key_from_addr(self, addr):
            log.debug('getting privkey of ' + addr)
            if btc.privtoaddr(auth_privkey,
                              magicbyte=get_p2pk_vbyte()) != addr:
                raise RuntimeError('privkey doesnt match given address')
            return auth_privkey

    wallet = UnsignedTXWallet()
    irc = IRCMessageChannel(jm_single().nickname)
    taker = CreateUnsignedTx(irc, wallet, auth_utxo, cjamount, destaddr,
                             changeaddr, utxo_data, options, chooseOrdersFunc)
    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(taker)
        import traceback
        log.debug(traceback.format_exc())
Example #31
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
 def get_key_from_addr(self, addr):
     log.debug('getting privkey of ' + addr)
     if btc.privtoaddr(auth_privkey, get_p2pk_vbyte()) != addr:
         raise RuntimeError('privkey doesnt match given address')
     return auth_privkey
Example #33
0
def main():
    parser = OptionParser(
        usage=
        'usage: %prog [options] [txid:n]',
        description="Adds one or more utxos to the list that can be used to make "
                    "commitments for anti-snooping. Note that this utxo, and its "
                    "PUBkey, will be revealed to makers, so consider the privacy "
                    "implication. "
                    
                    "It may be useful to those who are having trouble making "
                    "coinjoins due to several unsuccessful attempts (especially "
                    "if your joinmarket wallet is new). "
                    
                    "'Utxo' means unspent transaction output, it must not "
                    "already be spent. "
                    "The options -w, -r and -R offer ways to load these utxos "
                    "from a file or wallet. "
                    "If you enter a single utxo without these options, you will be "
                    "prompted to enter the private key here - it must be in "
                    "WIF compressed format. "

                    "BE CAREFUL about handling private keys! "
                    "Don't do this in insecure environments. "
                    
                    "Also note this ONLY works for standard (p2pkh) utxos."
    )
    parser.add_option(
        '-r',
        '--read-from-file',
        action='store',
        type='str',
        dest='in_file',
        help='name of plain text csv file containing utxos, one per line, format: '
        'txid:N, WIF-compressed-privkey'
    )
    parser.add_option(
        '-R',
        '--read-from-json',
        action='store',
        type='str',
        dest='in_json',
        help='name of json formatted file containing utxos with private keys, as '
        'output from "python wallet-tool.py -u -p walletname showutxos"'
        )
    parser.add_option(
        '-w',
        '--load-wallet',
        action='store',
        type='str',
        dest='loadwallet',
        help='name of wallet from which to load utxos and use as commitments.'
        )
    parser.add_option(
        '-g',
        '--gap-limit',
        action='store',
        type='int',
        dest='gaplimit',
        default = 6,
        help='Only to be used with -w; gap limit for Joinmarket wallet, default 6.'
    )
    parser.add_option(
        '-M',
        '--max-mixdepth',
        action='store',
        type='int',
        dest='maxmixdepth',
        default=5,
        help='Only to be used with -w; number of mixdepths for wallet, default 5.'
    )
    parser.add_option(
        '-d',
        '--delete-external',
        action='store_true',
        dest='delete_ext',
        help='deletes the current list of external commitment utxos',
        default=False
        )
    parser.add_option(
        '-v',
        '--validate-utxos',
        action='store_true',
        dest='validate',
        help='validate the utxos and pubkeys provided against the blockchain',
        default=False
    )
    parser.add_option(
        '-o',
        '--validate-only',
        action='store_true',
        dest='vonly',
        help='only validate the provided utxos (file or command line), not add',
        default=False
    )
    (options, args) = parser.parse_args()
    load_program_config()
    utxo_data = []
    if options.delete_ext:
        other = options.in_file or options.in_json or options.loadwallet
        if len(args) > 0 or other:
            if raw_input("You have chosen to delete commitments, other arguments "
                         "will be ignored; continue? (y/n)") != 'y':
                print "Quitting"
                sys.exit(0)
        c, e = btc.get_podle_commitments()
        print pformat(e)
        if raw_input(
            "You will remove the above commitments; are you sure? (y/n): ") != 'y':
            print "Quitting"
            sys.exit(0)
        btc.update_commitments(external_to_remove=e)
        print "Commitments deleted."
        sys.exit(0)

    #Three options (-w, -r, -R) for loading utxo and privkey pairs from a wallet,
    #csv file or json file.
    if options.loadwallet:
        os.chdir('..') #yuck (see earlier comment about package)
        wallet = Wallet(options.loadwallet,
                            options.maxmixdepth,
                            options.gaplimit)
        os.chdir(os.path.join(os.getcwd(), 'cmttools'))
        jm_single().bc_interface.sync_wallet(wallet)
        unsp = {}
        for u, av in wallet.unspent.iteritems():
                    addr = av['address']
                    key = wallet.get_key_from_addr(addr)
                    wifkey = btc.wif_compressed_privkey(key, vbyte=get_p2pk_vbyte())
                    unsp[u] = {'address': av['address'],
                               'value': av['value'], 'privkey': wifkey}
        for u, pva  in unsp.iteritems():
            utxo_data.append((u, pva['privkey']))
    elif options.in_file:
        with open(options.in_file, "rb") as f:
            utxo_info = f.readlines()
        for ul in utxo_info:
            ul = ul.rstrip()
            if ul:
                u, priv = get_utxo_info(ul)
                if not u:
                    quit(parser, "Failed to parse utxo info: " + str(ul))
                utxo_data.append((u, priv))
    elif options.in_json:
        if not os.path.isfile(options.in_json):
            print "File: " + options.in_json + " not found."
            sys.exit(0)
        with open(options.in_json, "rb") as f:
            try:
                utxo_json = json.loads(f.read())
            except:
                print "Failed to read json from " + options.in_json
                sys.exit(0)
        for u, pva in utxo_json.iteritems():
            utxo_data.append((u, pva['privkey']))
    elif len(args) == 1:
        u = args[0]
        priv = raw_input(
            'input private key for ' + u + ', in WIF compressed format : ')
        u, priv = get_utxo_info(','.join([u, priv]))
        if not u:
            quit(parser, "Failed to parse utxo info: " + u)
        utxo_data.append((u, priv))
    else:
        quit(parser, 'Invalid syntax')
    if options.validate or options.vonly:
        if not validate_utxo_data(utxo_data):
            quit(parser, "Utxos did not validate, quitting")
    if options.vonly:
        sys.exit(0)
    
    #We are adding utxos to the external list
    assert len(utxo_data)
    add_external_commitments(utxo_data)
Example #34
0
        balance_depth = 0
        for forchange in [0, 1]:
            cus_print(' ' + ('external' if forchange == 0 else 'internal') +
                      ' addresses m/0/%d/%d/' % (m, forchange))

            for k in range(wallet.index[m][forchange] + options.gaplimit):
                addr = wallet.get_addr(m, forchange, k)
                balance = 0.0
                for addrvalue in wallet.unspent.values():
                    if addr == addrvalue['address']:
                        balance += addrvalue['value']
                balance_depth += balance
                used = ('used' if k < wallet.index[m][forchange] else ' new')
                privkey = btc.encode_privkey(
                    wallet.get_key(m, forchange, k), 'wif_compressed',
                    get_p2pk_vbyte()) if options.showprivkey else ''
                if (method == 'displayall' or balance > 0 or
                    (used == ' new' and forchange == 0)):
                    cus_print('  m/0/%d/%d/%03d %-35s%s %.8f btc %s' %
                              (m, forchange, k, addr, used, balance / 1e8,
                               privkey))
        if m in wallet.imported_privkeys:
            cus_print(' import addresses')
            for privkey in wallet.imported_privkeys[m]:
                addr = btc.privtoaddr(privkey, get_p2pk_vbyte())
                balance = 0.0
                for addrvalue in wallet.unspent.values():
                    if addr == addrvalue['address']:
                        balance += addrvalue['value']
                used = (' used' if balance > 0.0 else 'empty')
                balance_depth += balance
def main():
    parser = OptionParser(
            usage='usage: %prog [options] [auth utxo] [cjamount] [cjaddr] ['
                  'changeaddr] [utxos..]',
            description=('Creates an unsigned coinjoin transaction. Outputs '
                         'a partially signed transaction hex string. The user '
                         'must sign their inputs independently and broadcast '
                         'them. The JoinMarket protocol requires the taker to '
                         'have a single p2pk UTXO input to use to '
                         'authenticate the  encrypted messages. For this '
                         'reason you must pass auth utxo and the '
                         'corresponding private key'))

    # for cjamount=0 do a sweep, and ignore change address
    parser.add_option(
            '-f',
            '--txfee',
            action='store',
            type='int',
            dest='txfee',
            default=10000,
            help='total miner fee in satoshis, default=10000')
    parser.add_option(
            '-w',
            '--wait-time',
            action='store',
            type='float',
            dest='waittime',
            help='wait time in seconds to allow orders to arrive, default=5',
            default=5)
    parser.add_option(
            '-N',
            '--makercount',
            action='store',
            type='int',
            dest='makercount',
            help='how many makers to coinjoin with, default=2',
            default=2)
    parser.add_option(
            '-C',
            '--choose-cheapest',
            action='store_true',
            dest='choosecheapest',
            default=False,
            help='override weightened offers picking and choose cheapest')
    parser.add_option(
            '-P',
            '--pick-orders',
            action='store_true',
            dest='pickorders',
            default=False,
            help=
            'manually pick which orders to take. doesn\'t work while sweeping.')
    parser.add_option(
            '--yes',
            action='store_true',
            dest='answeryes',
            default=False,
            help='answer yes to everything')
    # TODO implement parser.add_option('-n', '--no-network',
    # action='store_true', dest='nonetwork', default=False, help='dont query
    # the blockchain interface, instead user must supply value of UTXOs on '
    # + ' command line in the format txid:output/value-in-satoshi')
    (options, args) = parser.parse_args()

    if len(args) < 3:
        parser.error('Needs a wallet, amount and destination address')
        sys.exit(0)
    auth_utxo = args[0]
    cjamount = int(args[1])
    destaddr = args[2]
    changeaddr = args[3]
    cold_utxos = args[4:]

    load_program_config()
    addr_valid1, errormsg1 = validate_address(destaddr)
    errormsg2 = None
    # if amount = 0 dont bother checking changeaddr so user can write any junk
    if cjamount != 0:
        addr_valid2, errormsg2 = validate_address(changeaddr)
    else:
        addr_valid2 = True
    if not addr_valid1 or not addr_valid2:
        if not addr_valid1:
            print 'ERROR: Address invalid. ' + errormsg1
        else:
            print 'ERROR: Address invalid. ' + errormsg2
        return

    all_utxos = [auth_utxo] + cold_utxos
    query_result = jm_single().bc_interface.query_utxo_set(all_utxos)
    if None in query_result:
        print query_result
    utxo_data = {}
    for utxo, data in zip(all_utxos, query_result):
        utxo_data[utxo] = {'address': data['address'], 'value': data['value']}
    auth_privkey = raw_input('input private key for ' + utxo_data[auth_utxo][
        'address'] + ' :')
    if utxo_data[auth_utxo]['address'] != btc.privtoaddr(
            auth_privkey, get_p2pk_vbyte()):
        print 'ERROR: privkey does not match auth utxo'
        return

    if options.pickorders and cjamount != 0:  # cant use for sweeping
        chooseOrdersFunc = pick_order
    elif options.choosecheapest:
        chooseOrdersFunc = cheapest_order_choose
    else:  # choose randomly (weighted)
        chooseOrdersFunc = weighted_order_choose

    jm_single().nickname = random_nick()
    log.debug('starting sendpayment')

    class UnsignedTXWallet(AbstractWallet):

        def get_key_from_addr(self, addr):
            log.debug('getting privkey of ' + addr)
            if btc.privtoaddr(auth_privkey, get_p2pk_vbyte()) != addr:
                raise RuntimeError('privkey doesnt match given address')
            return auth_privkey

    wallet = UnsignedTXWallet()
    irc = IRCMessageChannel(jm_single().nickname)
    taker = CreateUnsignedTx(irc, wallet, auth_utxo, cjamount, destaddr,
                             changeaddr, utxo_data, options, chooseOrdersFunc)
    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(taker)
        import traceback
        log.debug(traceback.format_exc())
Example #36
0
def test_sendpayment(setup_regtest, num_ygs, wallet_structures, mean_amt,
                     mixdepth, sending_amt, ygcfs, fails, donate):
    """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 = []
    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')

    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)
    #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
Example #37
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)
Example #38
0
def test_blockr_sync(setup_blockr, net, seed, gaplimit, showprivkey, method):
    jm_single().config.set("BLOCKCHAIN", "network", net)
    wallet = Wallet(seed, max_mix_depth=5)
    jm_single().bc_interface.sync_wallet(wallet)

    # copy pasted from wallet-tool; some boiled down form of
    # this should really be in wallet.py in the joinmarket module.
    def cus_print(s):
        print s

    total_balance = 0
    for m in range(wallet.max_mix_depth):
        cus_print("mixing depth %d m/0/%d/" % (m, m))
        balance_depth = 0
        for forchange in [0, 1]:
            cus_print(" " + ("external" if forchange == 0 else "internal") + " addresses m/0/%d/%d/" % (m, forchange))

            for k in range(wallet.index[m][forchange] + gaplimit):
                addr = wallet.get_addr(m, forchange, k)
                balance = 0.0
                for addrvalue in wallet.unspent.values():
                    if addr == addrvalue["address"]:
                        balance += addrvalue["value"]
                balance_depth += balance
                used = "used" if k < wallet.index[m][forchange] else " new"
                if showprivkey:
                    privkey = btc.wif_compressed_privkey(wallet.get_key(m, forchange, k), get_p2pk_vbyte())
                else:
                    privkey = ""
                if method == "displayall" or balance > 0 or (used == " new" and forchange == 0):
                    cus_print(
                        "  m/0/%d/%d/%03d %-35s%s %.8f btc %s" % (m, forchange, k, addr, used, balance / 1e8, privkey)
                    )
        total_balance += balance_depth
        print ("for mixdepth=%d balance=%.8fbtc" % (m, balance_depth / 1e8))
    assert total_balance == 96085297
Example #39
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
Example #40
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
        balance_depth = 0
        for forchange in [0, 1]:
            cus_print(' ' + ('external' if forchange == 0 else 'internal') +
                      ' addresses m/0/%d/%d/' % (m, forchange))

            for k in range(wallet.index[m][forchange] + options.gaplimit):
                addr = wallet.get_addr(m, forchange, k)
                balance = 0.0
                for addrvalue in wallet.unspent.values():
                    if addr == addrvalue['address']:
                        balance += addrvalue['value']
                balance_depth += balance
                used = ('used' if k < wallet.index[m][forchange] else ' new')
                privkey = btc.encode_privkey(
                    wallet.get_key(m, forchange, k), 'wif_compressed',
                    get_p2pk_vbyte()) if options.showprivkey else ''
                if (method == 'displayall' or balance > 0 or
                    (used == ' new' and forchange == 0)):
                    cus_print('  m/0/%d/%d/%03d %-35s%s %.8f btc %s' %
                              (m, forchange, k, addr, used, balance / 1e8,
                               privkey))
        if m in wallet.imported_privkeys:
            cus_print(' import addresses')
            for privkey in wallet.imported_privkeys[m]:
                addr = btc.privtoaddr(privkey, get_p2pk_vbyte())
                balance = 0.0
                for addrvalue in wallet.unspent.values():
                    if addr == addrvalue['address']:
                        balance += addrvalue['value']
                used = (' used' if balance > 0.0 else 'empty')
                balance_depth += balance
Example #42
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)
Example #43
0
            key = wallet.get_key_from_addr(av['address'])
            tries = btc.podle.get_podle_tries(u, key, max_tries)
            tries_remaining = max(0, max_tries - tries)

            unsp[u] = {
                'mixdepth': mixdepth,
                'address': av['address'],
                'value': av['value'],
                'tries': tries,
                'tries_remaining': tries_remaining,
                'external': False
            }

            if options.showprivkey:
                wifkey = btc.wif_compressed_privkey(key,
                                                    vbyte=get_p2pk_vbyte())
                unsp[u]['privkey'] = wifkey

    used_commitments, external_commitments = btc.podle.get_podle_commitments()
    for u, ec in external_commitments.iteritems():
        tries = btc.podle.get_podle_tries(utxo=u,
                                          max_tries=max_tries,
                                          external=True)
        tries_remaining = max(0, max_tries - tries)
        unsp[u] = {
            'tries': tries,
            'tries_remaining': tries_remaining,
            'external': True
        }

    print(json.dumps(unsp, indent=4))
Example #44
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)
Example #45
0
 def get_key_from_addr(self, addr):
     log.debug('getting privkey of ' + addr)
     if btc.privtoaddr(auth_privkey,
                       magicbyte=get_p2pk_vbyte()) != addr:
         raise RuntimeError('privkey doesnt match given address')
     return auth_privkey
Example #46
0
                xpub_key = ''
            cus_print(' ' + ('external' if forchange == 0 else 'internal') +
                      ' addresses m/0/%d/%d' % (m, forchange) + ' ' + xpub_key)

            for k in range(wallet.index[m][forchange] + options.gaplimit):
                addr = wallet.get_addr(m, forchange, k)
                balance = 0.0
                for addrvalue in wallet.unspent.values():
                    if addr == addrvalue['address']:
                        balance += addrvalue['value']
                balance_depth += balance
                used = ('used' if k < wallet.index[m][forchange] else ' new')
                if options.showprivkey:
                    if btc.secp_present:
                        privkey = btc.wif_compressed_privkey(
                    wallet.get_key(m, forchange, k), get_p2pk_vbyte())
                    else:
                        privkey = btc.encode_privkey(wallet.get_key(m,
                                forchange, k), 'wif_compressed', get_p2pk_vbyte())
                else:
                    privkey = ''
                if (method == 'displayall' or balance > 0 or
                    (used == ' new' and forchange == 0)):
                    cus_print('  m/0/%d/%d/%03d %-35s%s %.8f btc %s' %
                              (m, forchange, k, addr, used, balance / 1e8,
                               privkey))
        if m in wallet.imported_privkeys:
            cus_print(' import addresses')
            for privkey in wallet.imported_privkeys[m]:
                addr = btc.privtoaddr(privkey, magicbyte=get_p2pk_vbyte())
                balance = 0.0
Example #47
0
    for m in range(wallet.max_mix_depth):
        cus_print("mixing depth %d m/0/%d/" % (m, m))
        balance_depth = 0
        for forchange in [0, 1]:
            cus_print(" " + ("external" if forchange == 0 else "internal") + " addresses m/0/%d/%d/" % (m, forchange))

            for k in range(wallet.index[m][forchange] + options.gaplimit):
                addr = wallet.get_addr(m, forchange, k)
                balance = 0.0
                for addrvalue in wallet.unspent.values():
                    if addr == addrvalue["address"]:
                        balance += addrvalue["value"]
                balance_depth += balance
                used = "used" if k < wallet.index[m][forchange] else " new"
                privkey = (
                    btc.encode_privkey(wallet.get_key(m, forchange, k), "wif_compressed", get_p2pk_vbyte())
                    if options.showprivkey
                    else ""
                )
                if method == "displayall" or balance > 0 or (used == " new" and forchange == 0):
                    cus_print(
                        "  m/0/%d/%d/%03d %-35s%s %.8f btc %s" % (m, forchange, k, addr, used, balance / 1e8, privkey)
                    )
        if m in wallet.imported_privkeys:
            cus_print(" import addresses")
            for privkey in wallet.imported_privkeys[m]:
                addr = btc.privtoaddr(privkey, get_p2pk_vbyte())
                balance = 0.0
                for addrvalue in wallet.unspent.values():
                    if addr == addrvalue["address"]:
                        balance += addrvalue["value"]
Example #48
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
Example #49
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)
Example #50
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):
        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
        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
    mcs = [
        IRCMessageChannel(c,
                          jm_single().nickname) for c in get_irc_mchannels()
    ]
    mcc = MessageChannelCollection(mcs)
    tumbler_bot = tumbler.Tumbler(mcc, wallet, tx_list, options)
    try:
        log.debug('starting message channels')
        mcc.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