def get_imported_privkey_branch(wallet, m, showprivkey):
    if m in wallet.imported_privkeys:
        entries = []
        for i, privkey in enumerate(wallet.imported_privkeys[m]):
            pub = btc.privkey_to_pubkey(privkey)
            addr = btc.pubkey_to_p2sh_p2wpkh_address(
                pub, magicbyte=get_p2sh_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')
            if showprivkey:
                wip_privkey = btc.wif_compressed_privkey(
                    privkey, get_p2pk_vbyte())
            else:
                wip_privkey = ''
            entries.append(
                WalletViewEntry("m/0",
                                m,
                                -1,
                                i,
                                addr, [balance, balance],
                                used=used,
                                priv=wip_privkey))
        return WalletViewBranch("m/0", m, -1, branchentries=entries)
    return None
Exemple #2
0
    def on_JM_TX_RECEIVED(self, nick, txhex, offer):
        # "none" flags p2ep protocol; pass through to the generic
        # on_tx handler for that:
        if offer == "none":
            return self.on_p2ep_tx_received(nick, txhex)

        offer = json.loads(offer)
        retval = self.client.on_tx_received(nick, txhex, offer)
        if not retval[0]:
            jlog.info("Maker refuses to continue on receipt of tx")
        else:
            sigs = retval[1]
            self.finalized_offers[nick] = offer
            tx = btc.deserialize(txhex)
            self.finalized_offers[nick]["txd"] = tx
            jm_single().bc_interface.add_tx_notify(
                tx,
                self.unconfirm_callback,
                self.confirm_callback,
                offer["cjaddr"],
                wallet_name=jm_single().bc_interface.get_wallet_name(
                    self.client.wallet),
                txid_flag=False,
                vb=get_p2sh_vbyte())
            d = self.callRemote(commands.JMTXSigs,
                                nick=nick,
                                sigs=json.dumps(sigs))
            self.defaultCallbacks(d)
        return {"accepted": True}
Exemple #3
0
def wallet_importprivkey(wallet, mixdepth):
    print('WARNING: This imported key will not be recoverable with your 12 ' +
          'word mnemonic phrase. Make sure you have backups.')
    print('WARNING: Handling of raw ECDSA bitcoin private keys can lead to '
          'non-intuitive behaviour and loss of funds.\n  Recommended instead '
          'is to use the \'sweep\' feature of sendpayment.py ')
    privkeys = raw_input('Enter private key(s) to import: ')
    privkeys = privkeys.split(',') if ',' in privkeys else privkeys.split()
    # TODO read also one key for each line
    for privkey in privkeys:
        # TODO is there any point in only accepting wif format? check what
        # other wallets do
        privkey_bin = btc.from_wif_privkey(privkey,
                                        vbyte=get_p2sh_vbyte()).decode('hex')[:-1]
        encrypted_privkey = encryptData(wallet.password_key, privkey_bin)
        if 'imported_keys' not in wallet.walletdata:
            wallet.walletdata['imported_keys'] = []
        wallet.walletdata['imported_keys'].append(
            {'encrypted_privkey': encrypted_privkey.encode('hex'),
             'mixdepth': mixdepth})
    if wallet.walletdata['imported_keys']:
        fd = open(wallet.path, 'w')
        fd.write(json.dumps(wallet.walletdata))
        fd.close()
        print('Private key(s) successfully imported')
def validate_utxo_data(utxo_datas, retrieve=False, segwit=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())
        if segwit:
            addr = btc.pubkey_to_p2sh_p2wpkh_address(
                btc.privkey_to_pubkey(hexpriv), get_p2sh_vbyte())
        else:
            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 or None in res:
            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: {}".format(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
Exemple #5
0
 def build_outs_from_template(self):
     """Build the outputs for this transaction based on
     the template, which must exist due to the constructor.
     Unlike build_ins, this has no dependencies but
     constructs appropriate output scripts based on the
     text flag "p2sh-p2wpkh" or "NN" in the template.
     It is necessary to fill out the keys template
     self.keys, before calling this.
     """
     for i, t in enumerate(self.template.outs):
         if t.spk_type == "p2sh-p2wpkh":
             self.outs.append({
                 "address":
                 btc.pubkey_to_p2sh_p2wpkh_address(
                     self.keys["outs"][i][t.counterparty],
                     get_p2sh_vbyte()),
                 "value":
                 t.amount
             })
         elif t.spk_type == "NN":
             #check if all the necessary keys are available
             if not all([
                     j in self.keys["outs"][i]
                     for j in range(self.n_counterparties)
             ]):
                 raise Exception("Incomplete key data to construct outputs")
             self.outs.append({
                 "address":
                 btc.pubkeys_to_p2wsh_address(self.keys["outs"][i].values(),
                                              vbyte=100),
                 "value":
                 t.amount
             })
Exemple #6
0
def wallet_dumpprivkey(wallet, hdpath):
    pathlist = bip32pathparse(hdpath)
    print('got pathlist: ' + str(pathlist))
    if pathlist and len(pathlist) == 5:
        cointype, purpose, m, forchange, k = pathlist
        key = wallet.get_key(m, forchange, k)
        wifkey = btc.wif_compressed_privkey(key, vbyte=get_p2sh_vbyte())
        return wifkey
    else:
        return hdpath + " is not a valid hd wallet path"
Exemple #7
0
def msig_data_from_pubkeys(pubkeys, N):
    """Create a p2sh address for the list of pubkeys given, N signers required.
    Return both the multisig redeem script and the p2sh address created.
    Order of pubkeys is respected (see TODO).
    """
    #TODO: lexicographical ordering is better
    multisig_script = btc.mk_multisig_script(pubkeys, N)
    p2sh_address = btc.p2sh_scriptaddr(multisig_script,
                                       magicbyte=get_p2sh_vbyte())
    return (multisig_script, p2sh_address)
Exemple #8
0
def wallet_signmessage(wallet, hdpath, message):
    if hdpath.startswith(wallet.get_root_path()):
        m, forchange, k = [int(y) for y in hdpath[4:].split('/')]
        key = wallet.get_key(m, forchange, k)
        addr = btc.privkey_to_address(key, magicbyte=get_p2sh_vbyte())
        print('Using address: ' + addr)
    else:
        print('%s is not a valid hd wallet path' % hdpath)
        return None
    sig = btc.ecdsa_sign(message, key, formsg=True)
    retval = "Signature: " + str(sig) + "\n"
    retval += "To verify this in Bitcoin Core use the RPC command 'verifymessage'"
    return retval
Exemple #9
0
def wallet_display(wallet, gaplimit, showprivkey, displayall=False,
                   serialized=True):
    """build the walletview object,
    then return its serialization directly if serialized,
    else return the WalletView object.
    """
    acctlist = []
    rootpath = wallet.get_root_path()
    for m in range(wallet.max_mix_depth):
        branchlist = []
        for forchange in [0, 1]:
            entrylist = []
            if forchange == 0:
                xpub_key = btc.bip32_privtopub(wallet.keys[m][forchange])
            else:
                xpub_key = ""

            for k in range(wallet.index[m][forchange] + gaplimit):
                addr = wallet.get_addr(m, forchange, k)
                balance = 0
                for addrvalue in wallet.unspent.values():
                    if addr == addrvalue['address']:
                        balance += addrvalue['value']
                used = 'used' if k < wallet.index[m][forchange] else 'new'
                if showprivkey:
                    privkey = btc.wif_compressed_privkey(
                        wallet.get_key(m, forchange, k), get_p2sh_vbyte())
                else:
                    privkey = ''
                if (displayall or balance > 0 or
                    (used == 'new' and forchange == 0)):
                    entrylist.append(WalletViewEntry(rootpath, m, forchange, k,
                                                 addr, [balance, balance],
                                                 priv=privkey, used=used))
            branchlist.append(WalletViewBranch(rootpath, m, forchange, entrylist,
                                               xpub=xpub_key))
        ipb = get_imported_privkey_branch(wallet, m, showprivkey)
        if ipb:
            branchlist.append(ipb)
        #get the xpub key of the whole account
        xpub_account = btc.bip32_privtopub(
            wallet.get_mixing_depth_keys(wallet.get_master_key())[m])
        acctlist.append(WalletViewAccount(rootpath, m, branchlist,
                                          xpub=xpub_account))
    walletview = WalletView(rootpath, acctlist)
    if serialized:
        return walletview.serialize()
    else:
        return walletview
 def query_utxo_set(self, txouts,includeconf=False):
     if self.qusfail:
         #simulate failure to find the utxo
         return [None]
     if self.fake_query_results:
         result = []
         for x in self.fake_query_results:
             for y in txouts:
                 if y == x['utxo']:
                     result.append(x)
         return result
     result = []
     #external maker utxos
     known_outs = {"03243f4a659e278a1333f8308f6aaf32db4692ee7df0340202750fd6c09150f6:1": "03a2d1cbe977b1feaf8d0d5cc28c686859563d1520b28018be0c2661cf1ebe4857",
                   "498faa8b22534f3b443c6b0ce202f31e12f21668b4f0c7a005146808f250d4c3:0": "02b4b749d54e96b04066b0803e372a43d6ffa16e75a001ae0ed4b235674ab286be",
                   "3f3ea820d706e08ad8dc1d2c392c98facb1b067ae4c671043ae9461057bd2a3c:1": "023bcbafb4f68455e0d1d117c178b0e82a84e66414f0987453d78da034b299c3a9"}
     #our wallet utxos, faked, for podle tests: utxos are doctored (leading 'f'),
     #and the lists are (amt, age)
     wallet_outs = {'f34b635ed8891f16c4ec5b8236ae86164783903e8e8bb47fa9ef2ca31f3c2d7a:0': [10000000, 2],
                    'f780d6e5e381bff01a3519997bb4fcba002493103a198fde334fd264f9835d75:1': [20000000, 6],
                    'fe574db96a4d43a99786b3ea653cda9e4388f377848f489332577e018380cff1:0': [50000000, 3],
                    'fd9711a2ef340750db21efb761f5f7d665d94b312332dc354e252c77e9c48349:0': [50000000, 6]}
     
     if includeconf and set(txouts).issubset(set(wallet_outs)):
         #includeconf used as a trigger for a podle check;
         #here we simulate a variety of amount/age returns
         results = []
         for to in txouts:
             results.append({'value': wallet_outs[to][0],
                             'confirms': wallet_outs[to][1]})
         return results
     if txouts[0] in known_outs:
         addr = btc.pubkey_to_p2sh_p2wpkh_address(
                     known_outs[txouts[0]], get_p2sh_vbyte())
         return [{'value': 200000000,
                  'address': addr,
                  'script': btc.address_to_script(addr),
                  'confirms': 20}]
     for t in txouts:
         result_dict = {'value': 10000000000,
                        'address': "mrcNu71ztWjAQA6ww9kHiW3zBWSQidHXTQ",
                        'script': '76a91479b000887626b294a914501a4cd226b58b23598388ac'}
         if includeconf:
             result_dict['confirms'] = 20
         result.append(result_dict)        
     return result
Exemple #11
0
def create_recipient_address(bob_pubkey, tweak=None, segwit=False):
    """Create a p2pkh receiving address
    from an existing pubkey, tweaked by a random 32 byte scalar.
    Returns the tweak, the new pubkey point and the new address.
    The recipient can set the tweak parameter.
    """
    if not tweak:
        tweak = binascii.hexlify(os.urandom(32))
    tweak_point = btc.privkey_to_pubkey(tweak + "01")
    destination_point = btc.add_pubkeys([tweak_point, bob_pubkey], True)
    if segwit:
        destination_address = btc.pubkey_to_p2sh_p2wpkh_address(
            destination_point, magicbyte=get_p2sh_vbyte())
    else:
        destination_address = btc.pubkey_to_address(destination_point,
                                                    magicbyte=get_p2pk_vbyte())
    return (tweak, destination_point, destination_address)
Exemple #12
0
 def final_checks(self):
     """Check that our keys have received the right funds
     in the wallet (all the single-owned outpoints to p2sh-p2wpkh
     outpoints should contain utxos that own the intended number
     of coins).
     """
     match = True
     total_coins = 0
     for i, tx in enumerate(self.template.txs):
         txid = self.realtxs[i].txid
         for j, tout in enumerate(tx.outs):
             if tout.counterparty == 0:
                 expected_amount = tout.amount
                 print("We expected this amount out: ", expected_amount)
                 actual_key = self.realtxs[i].keys["outs"][j][0]
                 actual_address = btc.pubkey_to_p2sh_p2wpkh_address(
                     actual_key, get_p2sh_vbyte())
                 #direct query on blockchain for the transaction,
                 #then check if it pays to our address and in what amount
                 res = cjxt_single().bc_interface.rpc(
                     'gettxout', [txid, j, True])
                 if not ("scriptPubKey" in res
                         and "addresses" in res["scriptPubKey"]):
                     print("Failed to query the tx: ", txid)
                 found_address = str(res["scriptPubKey"]["addresses"][0])
                 if not found_address == actual_address:
                     print("Error, transaction, vout: ", txid, j,
                           "has address: ", found_address,
                           ", but should have been address: ",
                           actual_address)
                 print("Amount received was: ", res["value"],
                       " at address: ", actual_address)
                 sat_value = btc_to_satoshis(res["value"])
                 total_coins += res["value"]
                 if not sat_value == expected_amount or not actual_address == found_address:
                     match = False
     if match:
         print("Success! Received back total coins: ", total_coins)
     else:
         print(
             "Failure! Not all expected coins received, see above summary.")
     reactor.stop()
Exemple #13
0
def wallet_showutxos(wallet, showprivkey):
    unsp = {}
    max_tries = jm_single().config.getint("POLICY", "taker_utxo_retries")
    for u, av in wallet.unspent.iteritems():
        key = wallet.get_key_from_addr(av['address'])
        tries = podle.get_podle_tries(u, key, max_tries)
        tries_remaining = max(0, max_tries - tries)
        unsp[u] = {'address': av['address'], 'value': av['value'],
                   'tries': tries, 'tries_remaining': tries_remaining,
                   'external': False}
        if showprivkey:
            wifkey = btc.wif_compressed_privkey(key, vbyte=get_p2sh_vbyte())
            unsp[u]['privkey'] = wifkey

    used_commitments, external_commitments = podle.get_podle_commitments()
    for u, ec in external_commitments.iteritems():
        tries = 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}

    return json.dumps(unsp, indent=4)
Exemple #14
0
def wallet_fetch_history(wallet, options):
    # sort txes in a db because python can be really bad with large lists
    con = sqlite3.connect(":memory:")
    con.row_factory = sqlite3.Row
    tx_db = con.cursor()
    tx_db.execute("CREATE TABLE transactions(txid TEXT, "
            "blockhash TEXT, blocktime INTEGER);")
    jm_single().debug_silence[0] = True
    wallet_name = jm_single().bc_interface.get_wallet_name(wallet)
    for wn in [wallet_name, ""]:
        buf = range(1000)
        t = 0
        while len(buf) == 1000:
            buf = jm_single().bc_interface.rpc('listtransactions', [wn,
                1000, t, True])
            t += len(buf)
            tx_data = ((tx['txid'], tx['blockhash'], tx['blocktime']) for tx
                    in buf if 'txid' in tx and 'blockhash' in tx and 'blocktime'
                    in tx)
            tx_db.executemany('INSERT INTO transactions VALUES(?, ?, ?);',
                    tx_data)
            txes = tx_db.execute('SELECT DISTINCT txid, blockhash, blocktime '
                    'FROM transactions ORDER BY blocktime').fetchall()
            wallet_addr_cache = wallet.addr_cache
    wallet_addr_set = set(wallet_addr_cache.keys())

    def s():
        return ',' if options.csv else ' '
    def sat_to_str(sat):
        return '%.8f'%(sat/1e8)
    def sat_to_str_p(sat):
        return '%+.8f'%(sat/1e8)
    def skip_n1(v):
        return '% 2s'%(str(v)) if v != -1 else ' #'
    def skip_n1_btc(v):
        return sat_to_str(v) if v != -1 else '#' + ' '*10
    def print_row(index, time, tx_type, amount, delta, balance, cj_n,
                  miner_fees, utxo_count, mixdepth_src, mixdepth_dst, txid):
        data = [index, datetime.fromtimestamp(time).strftime("%Y-%m-%d %H:%M"),
                tx_type, sat_to_str(amount), sat_to_str_p(delta),
                sat_to_str(balance), skip_n1(cj_n), sat_to_str(miner_fees),
                '% 3d' % utxo_count, skip_n1(mixdepth_src), skip_n1(mixdepth_dst)]
        if options.verbosity % 2 == 0: data += [txid]
        print(s().join(map('"{}"'.format, data)))


    field_names = ['tx#', 'timestamp', 'type', 'amount/btc',
            'balance-change/btc', 'balance/btc', 'coinjoin-n', 'total-fees',
            'utxo-count', 'mixdepth-from', 'mixdepth-to']
    if options.verbosity % 2 == 0: field_names += ['txid']
    if options.csv:
        print('Bumping verbosity level to 4 due to --csv flag')
        options.verbosity = 1
    if options.verbosity > 0: print(s().join(field_names))
    if options.verbosity <= 2: cj_batch = [0]*8 + [[]]*2
    balance = 0
    utxo_count = 0
    deposits = []
    deposit_times = []
    for i, tx in enumerate(txes):
        rpctx = jm_single().bc_interface.rpc('gettransaction', [tx['txid']])
        txhex = str(rpctx['hex'])
        txd = btc.deserialize(txhex)
        output_addr_values = dict(((btc.script_to_address(sv['script'],
            get_p2sh_vbyte()), sv['value']) for sv in txd['outs']))
        our_output_addrs = wallet_addr_set.intersection(
                output_addr_values.keys())

        from collections import Counter
        value_freq_list = sorted(Counter(output_addr_values.values())
                .most_common(), key=lambda x: -x[1])
        non_cj_freq = 0 if len(value_freq_list)==1 else sum(zip(
            *value_freq_list[1:])[1])
        is_coinjoin = (value_freq_list[0][1] > 1 and value_freq_list[0][1] in
                [non_cj_freq, non_cj_freq+1])
        cj_amount = value_freq_list[0][0]
        cj_n = value_freq_list[0][1]

        rpc_inputs = []
        for ins in txd['ins']:
            try:
                wallet_tx = jm_single().bc_interface.rpc('gettransaction',
                        [ins['outpoint']['hash']])
            except JsonRpcError:
                continue
            input_dict = btc.deserialize(str(wallet_tx['hex']))['outs'][ins[
                'outpoint']['index']]
            rpc_inputs.append(input_dict)

        rpc_input_addrs = set((btc.script_to_address(ind['script'],
            get_p2sh_vbyte()) for ind in rpc_inputs))
        our_input_addrs = wallet_addr_set.intersection(rpc_input_addrs)
        our_input_values = [ind['value'] for ind in rpc_inputs if btc.
                script_to_address(ind['script'], get_p2sh_vbyte()) in
                our_input_addrs]
        our_input_value = sum(our_input_values)
        utxos_consumed = len(our_input_values)

        tx_type = None
        amount = 0
        delta_balance = 0
        fees = 0
        mixdepth_src = -1
        mixdepth_dst = -1
        #TODO this seems to assume all the input addresses are from the same
        # mixdepth, which might not be true
        if len(our_input_addrs) == 0 and len(our_output_addrs) > 0:
            #payment to us
            amount = sum([output_addr_values[a] for a in our_output_addrs])
            tx_type = 'deposit    '
            cj_n = -1
            delta_balance = amount
            mixdepth_dst = tuple(wallet_addr_cache[a][0] for a in
                    our_output_addrs)
            if len(mixdepth_dst) == 1:
                mixdepth_dst = mixdepth_dst[0]
        elif len(our_input_addrs) == 0 and len(our_output_addrs) == 0:
            continue            # skip those that don't belong to our wallet
        elif len(our_input_addrs) > 0 and len(our_output_addrs) == 0:
            # we swept coins elsewhere
            if is_coinjoin:
                tx_type = 'cj sweepout'
                amount = cj_amount
                fees = our_input_value - cj_amount
            else:
                tx_type = 'sweep out  '
                amount = sum([v for v in output_addr_values.values()])
                fees = our_input_value - amount
            delta_balance = -our_input_value
            mixdepth_src = wallet_addr_cache[list(our_input_addrs)[0]][0]
        elif len(our_input_addrs) > 0 and len(our_output_addrs) == 1:
            # payment to somewhere with our change address getting the remaining
            change_value = output_addr_values[list(our_output_addrs)[0]]
            if is_coinjoin:
                tx_type = 'cj withdraw'
                amount = cj_amount
            else:
                tx_type = 'withdraw'
                #TODO does tx_fee go here? not my_tx_fee only?
                amount = our_input_value - change_value
                cj_n = -1
            delta_balance = change_value - our_input_value
            fees = our_input_value - change_value - cj_amount
            mixdepth_src = wallet_addr_cache[list(our_input_addrs)[0]][0]
        elif len(our_input_addrs) > 0 and len(our_output_addrs) == 2:
            #payment to self
            out_value = sum([output_addr_values[a] for a in our_output_addrs])
            if not is_coinjoin:
                print('this is wrong TODO handle non-coinjoin internal')
            tx_type = 'cj internal'
            amount = cj_amount
            delta_balance = out_value - our_input_value
            mixdepth_src = wallet_addr_cache[list(our_input_addrs)[0]][0]
            cj_addr = list(set([a for a,v in output_addr_values.iteritems()
                if v == cj_amount]).intersection(our_output_addrs))[0]
            mixdepth_dst = wallet_addr_cache[cj_addr][0]
        else:
            tx_type = 'unknown type'
            print('our utxos: ' + str(len(our_input_addrs)) \
                  + ' in, ' + str(len(our_output_addrs)) + ' out')
        balance += delta_balance
        utxo_count += (len(our_output_addrs) - utxos_consumed)
        index = '% 4d'%(i)
        timestamp = datetime.fromtimestamp(rpctx['blocktime']
                ).strftime("%Y-%m-%d %H:%M")
        utxo_count_str = '% 3d' % (utxo_count)
        if options.verbosity > 0:
            if options.verbosity <= 2:
                n = cj_batch[0]
                if tx_type == 'cj internal':
                    cj_batch[0] += 1
                    cj_batch[1] += rpctx['blocktime']
                    cj_batch[2] += amount
                    cj_batch[3] += delta_balance
                    cj_batch[4] = balance
                    cj_batch[5] += cj_n
                    cj_batch[6] += fees
                    cj_batch[7] += utxo_count
                    cj_batch[8] += [mixdepth_src]
                    cj_batch[9] += [mixdepth_dst]
                elif tx_type != 'unknown type':
                    if n > 0:
                        # print the previously-accumulated batch
                        print_row('N='+"%2d"%n, cj_batch[1]/n, 'cj batch   ',
                                  cj_batch[2], cj_batch[3], cj_batch[4],
                                  cj_batch[5]/n, cj_batch[6], cj_batch[7]/n,
                                  min(cj_batch[8]), max(cj_batch[9]), '...')
                    cj_batch = [0]*8 + [[]]*2 # reset the batch collector
                    # print batch terminating row
                    print_row(index, rpctx['blocktime'], tx_type, amount,
                              delta_balance, balance, cj_n, fees, utxo_count,
                              mixdepth_src, mixdepth_dst, tx['txid'])
            elif options.verbosity >= 5 or \
                 (options.verbosity >= 3 and tx_type != 'unknown type'):
                print_row(index, rpctx['blocktime'], tx_type, amount,
                          delta_balance, balance, cj_n, fees, utxo_count,
                          mixdepth_src, mixdepth_dst, tx['txid'])

        if tx_type != 'cj internal':
            deposits.append(delta_balance)
            deposit_times.append(rpctx['blocktime'])

    # we could have a leftover batch!
    if options.verbosity <= 2:
        n = cj_batch[0]
        if n > 0:
            print_row('N='+"%2d"%n, cj_batch[1]/n, 'cj batch   ', cj_batch[2],
                      cj_batch[3], cj_batch[4], cj_batch[5]/n, cj_batch[6],
                      cj_batch[7]/n, min(cj_batch[8]), max(cj_batch[9]), '...')


    bestblockhash = jm_single().bc_interface.rpc('getbestblockhash', [])
    try:
        #works with pruning enabled, but only after v0.12
        now = jm_single().bc_interface.rpc('getblockheader', [bestblockhash]
                )['time']
    except JsonRpcError:
        now = jm_single().bc_interface.rpc('getblock', [bestblockhash])['time']
    print('     %s best block is %s' % (datetime.fromtimestamp(now)
        .strftime("%Y-%m-%d %H:%M"), bestblockhash))
    print('total profit = ' + str(float(balance - sum(deposits)) / float(100000000)) + ' BTC')
    try:
        # https://gist.github.com/chris-belcher/647da261ce718fc8ca10
        import numpy as np
        from scipy.optimize import brentq
        deposit_times = np.array(deposit_times)
        now -= deposit_times[0]
        deposit_times -= deposit_times[0]
        deposits = np.array(deposits)
        def f(r, deposits, deposit_times, now, final_balance):
            return np.sum(np.exp((now - deposit_times) / 60.0 / 60 / 24 /
                365)**r * deposits) - final_balance
        r = brentq(f, a=1, b=-1, args=(deposits, deposit_times, now, balance))
        print('continuously compounded equivalent annual interest rate = ' +
              str(r * 100) + ' %')
        print('(as if yield generator was a bank account)')
    except ImportError:
        print('numpy/scipy not installed, unable to calculate effective ' +
                'interest rate')

    total_wallet_balance = sum(wallet.get_balance_by_mixdepth().values())
    if balance != total_wallet_balance:
        print(('BUG ERROR: wallet balance (%s) does not match balance from ' +
            'history (%s)') % (sat_to_str(total_wallet_balance),
                sat_to_str(balance)))
    if utxo_count != len(wallet.unspent):
        print(('BUG ERROR: wallet utxo count (%d) does not match utxo count from ' +
            'history (%s)') % (len(wallet.unspent), utxo_count))
Exemple #15
0
 def get_vbyte(self):
     return get_p2sh_vbyte()
Exemple #16
0
def address_p2sh_generator():
    return get_address_generator(b'\xa9\x14', b'\x87', get_p2sh_vbyte())
Exemple #17
0
def scan_for_coinjoins(privkey, amount, filename):
    """Given a file which contains encrypted coinjoin proposals,
    and a private key for a pubkey with a known utxo existing
    which we can spend, scan the entries in the file, all assumed
    to be ECIES encrypted to a pubkey, for one which is encrypted
    to *this* pubkey, if found, output the retrieved partially signed
    transaction, and destination key, address to a list which is
    returned to the caller.
    Only if the retrieved coinjoin transaction passes basic checks
    on validity in terms of amount paid, is it returned.
    This is an elementary implementation that will obviously fail
    any performance test (i.e. moderately large lists).
    Note that the tweaked output address must be of type p2sh/p2wpkh.
    """
    try:
        with open(filename, "rb") as f:
            msgs = f.readlines()
    except:
        print("Failed to read from file: ", filename)
        return
    valid_coinjoins = []
    for msg in msgs:
        try:
            decrypted_msg = decrypt_message(msg, privkey)
            tweak, tx = deserialize_coinjoin_proposal(decrypted_msg)
        except:
            print("Could not decrypt message, skipping")
            continue
        if not tweak:
            print("Could not decrypt message, reason: " + str(tx))
            continue
        #We analyse the content of the transaction to check if it follows
        #our requirements
        try:
            deserialized_tx = btc.deserialize(tx)
        except:
            print("Proposed transaction is not correctly formatted, skipping.")
            continue
        #construct our receiving address according to the tweak
        pubkey = btc.privkey_to_pubkey(privkey)
        tweak, destnpt, my_destn_addr = create_recipient_address(pubkey,
                                                                 tweak=tweak,
                                                                 segwit=True)
        #add_privkeys requires both inputs to be compressed (or un-) consistently.
        tweak_priv = tweak + "01"
        my_destn_privkey = btc.add_privkeys(tweak_priv, privkey, True)
        my_output_index = -1
        for i, o in enumerate(deserialized_tx['outs']):
            addr = btc.script_to_address(o['script'], get_p2sh_vbyte())
            if addr == my_destn_addr:
                print('found our output address: ', my_destn_addr)
                my_output_index = i
                break
        if my_output_index == -1:
            print("Proposal doesn't contain our output address, rejecting")
            continue
        my_output_amount = deserialized_tx['outs'][i]['value']
        required_amount = amount - 2 * estimate_tx_fee(3, 3, 'p2sh-p2wpkh')
        if my_output_amount < required_amount:
            print("Proposal pays too little, difference is: ",
                  required_amount - my_output_amount)
            continue
        #now we know output is acceptable to us, we should check that the
        #ctrprty input is signed and the other input is ours, but will do this
        #later; if it's not, it just won't work so NBD for now.
        valid_coinjoins.append((my_destn_addr, my_destn_privkey, tx))
    return valid_coinjoins