Skip to content

Instantly share code, notes, and snippets.

@AdamISZ
Created May 24, 2016 21:27
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save AdamISZ/cdc221143407efba38ff1296c409c368 to your computer and use it in GitHub Desktop.
Save AdamISZ/cdc221143407efba38ff1296c409c368 to your computer and use it in GitHub Desktop.
electrum joinmarket snippets
blockchain interface:
class ElectrumWalletInterface(BlockchainInterface):
"""A pseudo-blockchain interface using the existing
Electrum server connection in an Electrum wallet.
Usage requires calling set_wallet with a valid Electrum
wallet instance.
"""
def __init__(self, testnet=False):
super(ElectrumWalletInterface, self).__init__()
if testnet:
raise NotImplementedError("Electrum doesnt yet have a testnet interface")
#self.server_domain = electrum_server.split(':')[0]
self.last_sync_unspent = 0
def set_wallet(self, wallet):
self.wallet = wallet
def sync_addresses(self, wallet):
log.debug("Dummy electrum interface, no sync address")
def sync_unspent(self, wallet):
log.debug("Dummy electrum interface, no sync unspent")
def add_tx_notify(self, txd, unconfirmfun, confirmfun, notifyaddr):
log.debug("Dummy electrum interface, no add tx notify")
def pushtx(self, txhex):
#synchronous send
log.debug("About to push over electrum")
from electrum.transaction import Transaction
etx = Transaction(txhex)
etx.deserialize()
retval = self.wallet.sendtx(etx)
#returns (True, txhex) or (False, None)
log.debug("Pushed via electrum result: " + str(retval[1]))
return retval[0]
def query_utxo_set(self, txout):
"""Needed even for a simple dummy interface.
"""
if not isinstance(txout, list):
txout = [txout]
log.debug("Starting query utxo set with: " + str(txout))
utxos = [[t[:64],int(t[65:])] for t in txout]
result = []
for ut in utxos:
log.debug("About to try to get an address for ut: " + str(ut))
address = self.wallet.network.synchronous_get(
('blockchain.utxo.get_address', ut))
log.debug("Got address: " + str(address))
try:
utxo_info = self.wallet.network.synchronous_get(
("blockchain.address.listunspent", [address]))
except Exception as e:
log.debug("Got exception calling listunspent: " + repr(e))
raise
log.debug("Got utxo info: " + str(utxo_info))
utxo = None
for u in utxo_info:
if u['tx_hash'] == ut[0] and u['tx_pos'] == ut[1]:
utxo = u
if utxo is None:
log.debug("Utxo was none")
raise Exception("UTXO Not Found")
r = {
'value': u['value'],
'address': address,
'script': btc.address_to_script(address)
}
result.append(r)
log.debug("Got results, returning: " + str(result))
return result
#######
#wallet implementation:
class ElectrumWrapWallet(AbstractWallet):
"""A thin wrapper class over Electrum's own
wallet for joinmarket compatibility
"""
def __init__(self, ewallet, account):
self.ewallet = ewallet
self.account = account
# None is valid for unencrypted electrum wallets;
# calling functions must set the password otherwise
# for private key operations to work
self.password = None
super(ElectrumWrapWallet, self).__init__()
def get_key_from_addr(self, addr):
if self.ewallet.use_encryption and self.password is None:
raise Exception("Cannot extract private key without password")
key = self.ewallet.get_private_key(addr, self.password)
#TODO remove after testing!
log.debug("Got WIF key: " + str(key))
#Convert from wif compressed to hex compressed
#TODO check if compressed
hex_key = btc.from_wif_privkey(key[0], vbyte=get_p2pk_vbyte())
log.debug("Got hex key: " + str(hex_key))
return hex_key
def get_internal_addr(self, mixdepth):
addr = self.ewallet.get_unused_address(self.account)
log.debug("Retrieved unused: " + addr)
return addr
def sign_tx(self, tx):
if not self.password:
raise Exception("No password, cannot sign")
log.debug("starting ewwallet with password: " + self.password)
log.debug("trying to sign in wrap wallet with tx: " + str(tx))
from electrum.transaction import Transaction
etx = Transaction(tx)
log.debug("made etx")
etx.deserialize()
self.ewallet.sign_transaction(etx, self.password)
log.debug("Signed the etx")
log.debug("Got tx: " + str(etx.raw))
return etx.raw
def sign_message(self, address, message):
#TODO: is this necessary, or more: can we use it for auth?
return self.ewallet.sign_message(address, message, self.password)
def get_utxos_by_mixdepth(self):
"""Initial version: all underlying utxos are mixdepth 0.
Format of return is therefore: {0:
{txid:n : {"address": addr, "value": value},
txid:n: {"address": addr, "value": value},..}}
"""
ubym = {0:{}}
coins = self.ewallet.get_spendable_coins()
log.debug(pprint.pformat(coins))
"""
output = {
'address':addr,
'value':value,
'prevout_n':int(prevout_n),
'prevout_hash':prevout_hash,
'height':tx_height,
'coinbase':is_cb
}
"""
for c in coins:
utxo = c["prevout_hash"] + ":" + str(c["prevout_n"])
ubym[0][utxo] = {"address": c["address"], "value": c["value"]}
return ubym
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment