Created
May 24, 2016 21:27
-
-
Save AdamISZ/cdc221143407efba38ff1296c409c368 to your computer and use it in GitHub Desktop.
electrum joinmarket snippets
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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