Browse Source

remove usages of wallet.unspent

master
undeath 8 years ago
parent
commit
705d41d299
  1. 28
      jmclient/jmclient/blockchaininterface.py
  2. 41
      jmclient/jmclient/electruminterface.py
  3. 19
      scripts/add-utxo.py
  4. 53
      scripts/jmtainter.py
  5. 2
      test/ygrunner.py

28
jmclient/jmclient/blockchaininterface.py

@ -51,7 +51,7 @@ class BlockchainInterface(object):
@staticmethod
def get_wallet_name(wallet):
return 'joinmarket-wallet-' + btc.dbl_sha256(wallet.keys[0][0])[:6]
return 'joinmarket-wallet-' + wallet.get_wallet_id()
@abc.abstractmethod
def sync_addresses(self, wallet):
@ -60,8 +60,7 @@ class BlockchainInterface(object):
@abc.abstractmethod
def sync_unspent(self, wallet):
"""Finds the unspent transaction outputs belonging to this wallet,
sets wallet.unspent """
"""Finds the unspent transaction outputs belonging to this wallet"""
def add_tx_notify(self, txd, unconfirmfun, confirmfun, notifyaddr,
wallet_name=None, timeoutfun=None, spentfun=None, txid_flag=True,
@ -642,7 +641,7 @@ class BitcoinCoreInterface(BlockchainInterface):
def sync_unspent(self, wallet):
st = time.time()
wallet_name = self.get_wallet_name(wallet)
wallet.unspent = {}
wallet.reset_utxos()
listunspent_args = []
if 'listunspent_args' in jm_single().config.options('POLICY'):
@ -655,16 +654,29 @@ class BitcoinCoreInterface(BlockchainInterface):
continue
if u['account'] != wallet_name:
continue
# TODO
if u['address'] not in wallet.addr_cache:
continue
wallet.unspent[u['txid'] + ':' + str(u['vout'])] = {
'address': u['address'],
'value': int(Decimal(str(u['amount'])) * Decimal('1e8'))
}
self._add_unspent_utxo(wallet, u)
et = time.time()
log.debug('bitcoind sync_unspent took ' + str((et - st)) + 'sec')
self.wallet_synced = True
@staticmethod
def _add_unspent_utxo(wallet, utxo):
"""
Add a UTXO as returned by rpc's listunspent call to the wallet.
params:
wallet: wallet
utxo: single utxo dict as returned by listunspent
"""
txid = binascii.unhexlify(utxo['txid'])
script = binascii.unhexlify(utxo['scriptPubKey'])
value = int(Decimal(str(utxo['amount'])) * Decimal('1e8'))
wallet.add_utxo(txid, int(utxo['vout']), script, value)
def get_deser_from_gettransaction(self, rpcretval):
"""Get full transaction deserialization from a call
to `gettransaction`

41
jmclient/jmclient/electruminterface.py

@ -6,11 +6,9 @@ import pprint
import random
import socket
import threading
import time
import sys
import ssl
from twisted.python.log import startLogging
from twisted.internet.protocol import ClientFactory, Protocol
import binascii
from twisted.internet.protocol import ClientFactory
from twisted.internet.ssl import ClientContextFactory
from twisted.protocols.basic import LineReceiver
from twisted.internet import reactor, task, defer
@ -328,10 +326,10 @@ class ElectrumInterface(BlockchainInterface):
def sync_unspent(self, wallet):
# finds utxos in the wallet
wallet.unspent = {}
wallet.reset_utxos()
#Prepare list of all used addresses
addrs = []
for m in range(wallet.max_mix_depth):
addrs = set()
for m in range(wallet.max_mixdepth):
for fc in [0, 1]:
branch_list = []
for k, v in self.temp_addr_history[m][fc].iteritems():
@ -339,7 +337,7 @@ class ElectrumInterface(BlockchainInterface):
continue
if v["used"]:
branch_list.append(v["addr"])
addrs.extend(branch_list)
addrs.update(branch_list)
if len(addrs) == 0:
log.debug('no tx used')
self.wallet_synced = True
@ -348,21 +346,28 @@ class ElectrumInterface(BlockchainInterface):
return
#make sure to add any addresses during the run (a subset of those
#added to the address cache)
addrs = list(set(self.wallet.addr_cache.keys()).union(set(addrs)))
self.listunspent_calls = 0
for md in range(wallet.max_mixdepth):
for internal in (True, False):
for index in range(wallet.get_next_unused_index(md, internal)):
addrs.add(wallet.get_addr(md, internal, index))
for path in wallet.get_imported_paths(md):
addrs.add(wallet.get_addr_path(path))
self.listunspent_calls = len(addrs)
for a in addrs:
# FIXME: update to protocol version 1.1 and use scripthash instead
script = wallet.address_to_script(a)
d = self.get_from_electrum('blockchain.address.listunspent', a)
d.addCallback(self.process_listunspent_data, wallet, a, len(addrs))
d.addCallback(self.process_listunspent_data, wallet, script)
def process_listunspent_data(self, unspent_info, wallet, address, n):
self.listunspent_calls += 1
def process_listunspent_data(self, unspent_info, wallet, script):
res = unspent_info['result']
for u in res:
wallet.unspent[str(u['tx_hash']) + ':' + str(
u['tx_pos'])] = {'address': address, 'value': int(u['value'])}
if self.listunspent_calls == n:
for u in wallet.spent_utxos:
wallet.unspent.pop(u, None)
txid = binascii.unhexlify(u['tx_hash'])
wallet.add_utxo(txid, int(u['tx_pos']), script, int(u['value']))
self.listunspent_calls -= 1
if self.listunspent_calls == 0:
self.wallet_synced = True
if self.synctype == "sync-only":
reactor.stop()

19
scripts/add-utxo.py

@ -9,6 +9,7 @@ the anti-snooping feature employed by makers.
import sys
import os
import json
import binascii
from pprint import pformat
from optparse import OptionParser
@ -173,20 +174,16 @@ def main():
#Three options (-w, -r, -R) for loading utxo and privkey pairs from a wallet,
#csv file or json file.
if options.loadwallet:
# TODO: new wallet has no unspent attribute
raise NotImplementedError("This is not yet implemented.")
wallet_path = get_wallet_path(options.loadwallet, None)
wallet = open_wallet(wallet_path, gap_limit=options.gaplimit)
sync_wallet(wallet, fast=options.fastsync)
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']))
for md, utxos in wallet.get_utxos_by_mixdepth_().items():
for (txid, index), utxo in utxos.items():
txhex = binascii.hexlify(txid) + ':' + str(index)
wif = wallet.get_wif_path(utxo['path'])
utxo_data.append((txhex, wif))
elif options.in_file:
with open(options.in_file, "rb") as f:
utxo_info = f.readlines()

53
scripts/jmtainter.py

@ -103,18 +103,24 @@ def serialize_derivation(roc, i):
return x
#=======================================================
def get_privkey_amount_from_utxo(wallet, utxo):
def get_script_amount_from_utxo(wallet, utxo):
"""Given a JM wallet and a utxo string, find
the corresponding private key and amount controlled
in satoshis.
"""
for k, v in wallet.unspent.iteritems():
if k == utxo:
print("Found utxo, its value is: ", v['value'])
return wallet.get_key_from_addr(v['address']), v['value']
return (None, None)
for md, utxos in wallet.get_utxos_by_mixdepth_().items():
for (txid, index), utxo in utxos.items():
txhex = binascii.hexlify(txid) + ':' + str(index)
if txhex != utxo:
continue
script = wallet.get_script_path(utxo['path'])
print("Found utxo, its value is: {}".format(utxo['value']))
return script, utxo['value']
return None, None
def create_single_acp_pair(utxo_in, priv, addr_out, amount, bump, segwit=False):
def create_single_acp_pair(wallet, utxo_in, script, addr_out, amount, bump, segwit=False):
"""Given a utxo and a signing key for it, and its amout in satoshis,
sign a "transaction" consisting of only 1 input and one output, signed
with single|acp sighash flags so it can be grafted into a bigger
@ -129,10 +135,9 @@ def create_single_acp_pair(utxo_in, priv, addr_out, amount, bump, segwit=False):
assert bump >= 0, "Output of single|acp pair must be bigger than input for safety."
out = {"address": addr_out, "value": amount + bump}
tx = btc.mktx([utxo_in], [out])
amt = amount if segwit else None
return btc.sign(tx, 0, priv,
hashcode=btc.SIGHASH_SINGLE|btc.SIGHASH_ANYONECANPAY,
amount=amt)
return wallet.sign_tx(tx, {0: (script, amount)},
hashcode=btc.SIGHASH_SINGLE|btc.SIGHASH_ANYONECANPAY)
def graft_onto_single_acp(wallet, txhex, amount, destaddr):
"""Given a serialized txhex which is checked to be of
@ -187,13 +192,15 @@ def graft_onto_single_acp(wallet, txhex, amount, destaddr):
df['ins'][0]['script'] = d['ins'][0]['script']
if 'txinwitness' in d['ins'][0]:
df['ins'][0]['txinwitness'] = d['ins'][0]['txinwitness']
fulltx = btc.serialize(df)
for i, iu in enumerate(input_utxos):
priv, inamt = get_privkey_amount_from_utxo(wallet, iu)
print("Signing index: ", i+1, " with privkey: ", priv, " and amount: ", inamt, " for utxo: ", iu)
fulltx = btc.sign(fulltx, i+1, priv, amount=inamt)
return (True, fulltx)
script, inamt = get_script_amount_from_utxo(wallet, iu)
print("Signing index: ", i+1, " with script: ", script, " and amount: ", inamt, " for utxo: ", iu)
fulltx = wallet.sign_tx(df, {i: (script, inamt)})
return True, btc.serialize(fulltx)
if __name__ == "__main__":
parser = get_parser()
(options, args) = parser.parse_args()
@ -214,22 +221,22 @@ if __name__ == "__main__":
"Use wallet-tool.py method 'showutxos' to select one")
exit(0)
utxo_in = args[2]
priv, amount = get_privkey_amount_from_utxo(wallet, utxo_in)
if not priv:
script, amount = get_script_amount_from_utxo(wallet, utxo_in)
if not script:
print("Failed to find the utxo's private key from the wallet; check "
"if this utxo is actually contained in the wallet using "
"wallet-tool.py showutxos")
exit(0)
#destination sourced from wallet
addr_out = wallet.get_new_addr((options.mixdepth+1)%options.amtmixdepths, 1)
serialized_single_acp = create_single_acp_pair(utxo_in, priv, addr_out, amount,
options.bump, segwit=True)
single_acp = create_single_acp_pair(wallet, utxo_in, script, addr_out, amount,
options.bump, segwit=True)
print("Created the following one-in, one-out transaction, which will not "
"be valid to broadcast itself (negative fee). Pass it to your "
"counterparty:")
print(pformat(btc.deserialize(serialized_single_acp)))
print(pformat(single_acp))
print("Pass the following raw hex to your counterparty:")
print(serialized_single_acp)
print(btc.serialize(single_acp))
exit(0)
elif args[1] == "take":
try:

2
test/ygrunner.py

@ -110,7 +110,7 @@ def test_start_ygs(setup_ygrunner, num_ygs, wallet_structures, mean_amt,
print("Seed : " + wallets[num_ygs]['seed'])
#useful to see the utxos on screen sometimes
sync_wallet(wallet, fast=True)
print(wallet.unspent)
print(wallet.get_utxos_by_mixdepth())
txfee = 1000
cjfee_a = 4200
cjfee_r = '0.001'

Loading…
Cancel
Save