json rpc daemon
This commit is contained in:
parent
989a95bf25
commit
d4fbe85d7d
71
electrum
71
electrum
|
@ -105,15 +105,34 @@ def print_help_cb(self, opt, value, parser):
|
|||
|
||||
|
||||
def run_command(cmd, password=None, args=[]):
|
||||
import xmlrpclib, socket
|
||||
cmd_runner = Commands(wallet, network)
|
||||
func = getattr(cmd_runner, cmd)
|
||||
func = getattr(cmd_runner, cmd.name)
|
||||
cmd_runner.password = password
|
||||
|
||||
if cmd.requires_network and not options.offline:
|
||||
cmd_runner.network = xmlrpclib.ServerProxy('http://localhost:8000')
|
||||
if wallet:
|
||||
wallet.start_threads(cmd_runner.network)
|
||||
wallet.update()
|
||||
else:
|
||||
cmd_runner.network = None
|
||||
|
||||
try:
|
||||
result = func(*args[1:])
|
||||
except socket.error:
|
||||
print "Network server not found."
|
||||
sys.exit(1)
|
||||
except Exception:
|
||||
traceback.print_exc(file=sys.stdout)
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
if cmd.requires_network and not options.offline:
|
||||
if wallet:
|
||||
wallet.stop_threads()
|
||||
|
||||
|
||||
if type(result) == str:
|
||||
util.print_msg(result)
|
||||
elif result is not None:
|
||||
|
@ -201,6 +220,11 @@ if __name__ == '__main__':
|
|||
print_msg("Type 'electrum create' to create a new wallet, or provide a path to a wallet with the -w option")
|
||||
sys.exit(0)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
if cmd.name in ['create', 'restore']:
|
||||
if storage.file_exists:
|
||||
sys.exit("Error: Remove the existing wallet first!")
|
||||
|
@ -345,19 +369,41 @@ if __name__ == '__main__':
|
|||
print_msg("Warning: Final argument was reconstructed from several arguments:", repr(message))
|
||||
args = args[0:cmd.min_args] + [message]
|
||||
|
||||
# open session
|
||||
if cmd.requires_network and not options.offline:
|
||||
|
||||
if cmd.name == 'start_network':
|
||||
pid = os.fork()
|
||||
if (pid == 0): # The first child.
|
||||
os.chdir("/")
|
||||
os.setsid()
|
||||
os.umask(0)
|
||||
pid2 = os.fork()
|
||||
if (pid2 == 0): # Second child
|
||||
from SimpleXMLRPCServer import SimpleXMLRPCServer
|
||||
# start the daemon
|
||||
network = Network(config)
|
||||
if not network.start(wait=True):
|
||||
print_msg("Not connected, aborting.")
|
||||
sys.exit(1)
|
||||
print_error("Connected to " + network.interface.connection_msg)
|
||||
|
||||
if wallet:
|
||||
wallet.start_threads(network)
|
||||
wallet.update()
|
||||
print_msg("Connected to " + network.interface.connection_msg)
|
||||
server = SimpleXMLRPCServer(('localhost',8000), allow_none=True, logRequests=False)
|
||||
server.register_function(network.synchronous_get, 'synchronous_get')
|
||||
server.register_function(network.get_servers, 'get_servers')
|
||||
server.register_function(network.main_server, 'main_server')
|
||||
server.register_function(network.send, 'send')
|
||||
server.register_function(network.subscribe, 'subscribe')
|
||||
server.register_function(network.is_connected, 'is_connected')
|
||||
server.register_function(network.is_up_to_date, 'is_up_to_date')
|
||||
server.register_function(lambda: setattr(server,'running', False), 'stop')
|
||||
server.running = True
|
||||
while server.running:
|
||||
server.handle_request()
|
||||
print_msg("Server stopped")
|
||||
sys.exit(0)
|
||||
else:
|
||||
network = None
|
||||
sys.exit(0)
|
||||
else:
|
||||
sys.exit(0)
|
||||
|
||||
|
||||
# run the command
|
||||
if cmd.name == 'deseed':
|
||||
|
@ -394,11 +440,8 @@ if __name__ == '__main__':
|
|||
wallet.update_password(password, new_password)
|
||||
|
||||
else:
|
||||
run_command(cmd.name, password, args)
|
||||
run_command(cmd, password, args)
|
||||
|
||||
|
||||
if network:
|
||||
if wallet:
|
||||
wallet.stop_threads()
|
||||
network.stop()
|
||||
time.sleep(0.1)
|
||||
sys.exit(0)
|
||||
|
|
|
@ -68,8 +68,8 @@ register_command('freeze', 1, 1, False, True, True, 'Freeze the
|
|||
register_command('getbalance', 0, 1, True, True, False, 'Return the balance of your wallet, or of one account in your wallet', 'getbalance [<account>]')
|
||||
register_command('getservers', 0, 0, True, False, False, 'Return the list of available servers')
|
||||
register_command('getversion', 0, 0, False, False, False, 'Return the version of your client', 'getversion')
|
||||
register_command('getaddressbalance', 1, 1, True, True, False, 'Return the balance of an address', 'getaddressbalance <address>')
|
||||
register_command('getaddresshistory', 1, 1, True, True, False, 'Return the transaction history of a wallet address', 'getaddresshistory <address>')
|
||||
register_command('getaddressbalance', 1, 1, True, False, False, 'Return the balance of an address', 'getaddressbalance <address>')
|
||||
register_command('getaddresshistory', 1, 1, True, False, False, 'Return the transaction history of a wallet address', 'getaddresshistory <address>')
|
||||
register_command('getconfig', 1, 1, False, False, False, 'Return a configuration variable', 'getconfig <name>')
|
||||
register_command('getpubkeys', 1, 1, False, True, False, 'Return the public keys for a wallet address', 'getpubkeys <bitcoin address>')
|
||||
register_command('getrawtransaction', 1, 1, True, False, False, 'Retrieve a transaction', 'getrawtransaction <txhash>')
|
||||
|
@ -79,7 +79,8 @@ register_command('help', 0, 1, False, False, False, 'Prints this
|
|||
register_command('history', 0, 0, True, True, False, 'Returns the transaction history of your wallet')
|
||||
register_command('importprivkey', 1, 1, False, True, True, 'Import a private key', 'importprivkey <privatekey>')
|
||||
register_command('listaddresses', 2, 2, False, True, False, 'Returns your list of addresses.', '', listaddr_options)
|
||||
register_command('listunspent', 0, 0, True, True, False, 'Returns the list of unspent inputs in your wallet.')
|
||||
register_command('listunspent', 0, 0, True, False, False, 'Returns the list of unspent inputs in your wallet.')
|
||||
register_command('getaddressunspent', 1, 1, True, False, False, 'Returns the list of unspent inputs in your wallet.')
|
||||
register_command('mktx', 5, 5, False, True, True, 'Create a signed transaction', 'mktx <recipient> <amount> [label]', payto_options)
|
||||
register_command('mksendmanytx', 4, 4, False, True, True, 'Create a signed transaction', mksendmany_syntax, payto_options)
|
||||
register_command('payto', 5, 5, True, True, True, 'Create and broadcast a transaction.', payto_syntax, payto_options)
|
||||
|
@ -95,6 +96,8 @@ register_command('unfreeze', 1, 1, False, True, False, 'Unfreeze th
|
|||
register_command('validateaddress', 1, 1, False, False, False, 'Check that the address is valid', 'validateaddress <address>')
|
||||
register_command('verifymessage', 3,-1, False, False, False, 'Verifies a signature', verifymessage_syntax)
|
||||
|
||||
register_command('start_network', 0, 0, False, False, False, 'start the daemon')
|
||||
register_command('stop_network', 0, 0, True, False, False, 'stop the daemon')
|
||||
|
||||
|
||||
|
||||
|
@ -106,6 +109,7 @@ class Commands:
|
|||
self._callback = callback
|
||||
self.password = None
|
||||
|
||||
|
||||
def _run(self, method, args, password_getter):
|
||||
cmd = known_commands[method]
|
||||
if cmd.requires_password and self.wallet.use_encryption:
|
||||
|
@ -117,11 +121,14 @@ class Commands:
|
|||
apply(self._callback, ())
|
||||
return result
|
||||
|
||||
|
||||
def getaddresshistory(self, addr):
|
||||
assert self.wallet.is_mine(addr)
|
||||
h = self.wallet.get_history(addr)
|
||||
if h is None: h = self.network.synchronous_get([ ('blockchain.address.get_history',[addr]) ])[0]
|
||||
return h
|
||||
return self.network.synchronous_get([ ('blockchain.address.get_history',[addr]) ])[0]
|
||||
|
||||
|
||||
def stop_network(self):
|
||||
return self.network.stop()
|
||||
|
||||
|
||||
def listunspent(self):
|
||||
import copy
|
||||
|
@ -129,6 +136,11 @@ class Commands:
|
|||
for i in l: i["value"] = str(Decimal(i["value"])/100000000)
|
||||
return l
|
||||
|
||||
|
||||
def getaddressunspent(self, addr):
|
||||
return self.network.synchronous_get([ ('blockchain.address.getunspent',[addr]) ])[0]
|
||||
|
||||
|
||||
def createrawtransaction(self, inputs, outputs):
|
||||
# convert to own format
|
||||
for i in inputs:
|
||||
|
@ -199,10 +211,11 @@ class Commands:
|
|||
return out
|
||||
|
||||
def getaddressbalance(self, addr):
|
||||
c, u = self.wallet.get_addr_balance(addr)
|
||||
out = { "confirmed": str(Decimal(c)/100000000) }
|
||||
if u: out["unconfirmed"] = str(Decimal(u)/100000000)
|
||||
return out
|
||||
# c, u = self.wallet.get_addr_balance(addr)
|
||||
# out = { "confirmed": str(Decimal(c)/100000000) }
|
||||
# if u: out["unconfirmed"] = str(Decimal(u)/100000000)
|
||||
# return out
|
||||
return self.network.synchronous_get([ ('blockchain.address.get_balance',[addr]) ])[0]
|
||||
|
||||
def getservers(self):
|
||||
return self.network.get_servers()
|
||||
|
@ -350,11 +363,19 @@ class Commands:
|
|||
if cmd.options: print_msg("options:\n" + cmd.options)
|
||||
return None
|
||||
|
||||
|
||||
def getrawtransaction(self, tx_hash):
|
||||
import transaction
|
||||
if self.wallet:
|
||||
tx = self.wallet.transactions.get(tx_hash)
|
||||
if tx:
|
||||
return tx
|
||||
return self.network.retrieve_transaction(tx_hash)
|
||||
|
||||
r = self.network.synchronous_get([ ('blockchain.transaction.get',[tx_hash]) ])[0]
|
||||
if r:
|
||||
return transaction.Transaction(r)
|
||||
else:
|
||||
return "unknown transaction"
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -82,6 +82,14 @@ class Network(threading.Thread):
|
|||
return self.interface and self.interface.is_connected
|
||||
|
||||
|
||||
def is_up_to_date(self):
|
||||
return self.interface.is_up_to_date()
|
||||
|
||||
|
||||
def main_server(self):
|
||||
return self.interface.server
|
||||
|
||||
|
||||
def send_subscriptions(self):
|
||||
for cb, sub in self.subscriptions.items():
|
||||
self.interface.send(sub, cb)
|
||||
|
@ -372,11 +380,11 @@ class Network(threading.Thread):
|
|||
return out
|
||||
|
||||
|
||||
def retrieve_transaction(self, tx_hash, tx_height=0):
|
||||
import transaction
|
||||
r = self.synchronous_get([ ('blockchain.transaction.get',[tx_hash, tx_height]) ])[0]
|
||||
if r:
|
||||
return transaction.Transaction(r)
|
||||
#def retrieve_transaction(self, tx_hash, tx_height=0):
|
||||
# import transaction
|
||||
# r = self.synchronous_get([ ('blockchain.transaction.get',[tx_hash, tx_height]) ])[0]
|
||||
# if r:
|
||||
# return transaction.Transaction(r)
|
||||
|
||||
|
||||
def parse_servers(self, result):
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
ELECTRUM_VERSION = "1.9.7" # version of the client package
|
||||
PROTOCOL_VERSION = '0.6' # protocol version requested
|
||||
ELECTRUM_VERSION = "2.0" # version of the client package
|
||||
PROTOCOL_VERSION = '0.9' # protocol version requested
|
||||
SEED_VERSION = 4 # bump this every time the seed generation is modified
|
||||
SEED_PREFIX = '01' # the hash of the mnemonic seed must begin with this
|
||||
|
||||
|
|
|
@ -1550,7 +1550,7 @@ class Wallet:
|
|||
def start_threads(self, network):
|
||||
from verifier import TxVerifier
|
||||
self.network = network
|
||||
if self.network:
|
||||
if self.network is not None:
|
||||
self.verifier = TxVerifier(self.network, self.storage)
|
||||
self.verifier.start()
|
||||
self.set_verifier(self.verifier)
|
||||
|
@ -1635,12 +1635,12 @@ class WalletSynchronizer(threading.Thread):
|
|||
if not self.network.is_connected():
|
||||
self.network.wait_until_connected()
|
||||
|
||||
self.run_interface(self.network.interface)
|
||||
self.run_interface()
|
||||
|
||||
|
||||
def run_interface(self, interface):
|
||||
def run_interface(self):
|
||||
|
||||
print_error("synchronizer: connected to", interface.server)
|
||||
print_error("synchronizer: connected to", self.network.main_server())
|
||||
|
||||
requested_tx = []
|
||||
missing_tx = []
|
||||
|
@ -1670,12 +1670,12 @@ class WalletSynchronizer(threading.Thread):
|
|||
# request missing transactions
|
||||
for tx_hash, tx_height in missing_tx:
|
||||
if (tx_hash, tx_height) not in requested_tx:
|
||||
interface.send([ ('blockchain.transaction.get',[tx_hash, tx_height]) ], lambda i,r: self.queue.put(r))
|
||||
self.network.send([ ('blockchain.transaction.get',[tx_hash, tx_height]) ], lambda i,r: self.queue.put(r))
|
||||
requested_tx.append( (tx_hash, tx_height) )
|
||||
missing_tx = []
|
||||
|
||||
# detect if situation has changed
|
||||
if interface.is_up_to_date() and self.queue.empty():
|
||||
if self.network.is_up_to_date() and self.queue.empty():
|
||||
if not self.wallet.is_up_to_date():
|
||||
self.wallet.set_up_to_date(True)
|
||||
self.was_updated = True
|
||||
|
@ -1685,7 +1685,7 @@ class WalletSynchronizer(threading.Thread):
|
|||
self.was_updated = True
|
||||
|
||||
if self.was_updated:
|
||||
self.wallet.network.trigger_callback('updated')
|
||||
self.network.trigger_callback('updated')
|
||||
self.was_updated = False
|
||||
|
||||
# 2. get a response
|
||||
|
@ -1694,8 +1694,9 @@ class WalletSynchronizer(threading.Thread):
|
|||
except Queue.Empty:
|
||||
continue
|
||||
|
||||
if interface != self.network.interface:
|
||||
break
|
||||
# see if it changed
|
||||
#if interface != self.network.interface:
|
||||
# break
|
||||
|
||||
if not r:
|
||||
continue
|
||||
|
@ -1713,7 +1714,7 @@ class WalletSynchronizer(threading.Thread):
|
|||
addr = params[0]
|
||||
if self.wallet.get_status(self.wallet.get_history(addr)) != result:
|
||||
if requested_histories.get(addr) is None:
|
||||
interface.send([('blockchain.address.get_history', [addr])], lambda i,r:self.queue.put(r))
|
||||
self.network.send([('blockchain.address.get_history', [addr])], lambda i,r:self.queue.put(r))
|
||||
requested_histories[addr] = result
|
||||
|
||||
elif method == 'blockchain.address.get_history':
|
||||
|
@ -1763,7 +1764,7 @@ class WalletSynchronizer(threading.Thread):
|
|||
print_error("Error: Unknown message:" + method + ", " + repr(params) + ", " + repr(result) )
|
||||
|
||||
if self.was_updated and not requested_tx:
|
||||
self.wallet.network.trigger_callback('updated')
|
||||
self.wallet.network.trigger_callback("new_transaction") # Updated gets called too many times from other places as well; if we use that signal we get the notification three times
|
||||
|
||||
self.network.trigger_callback('updated')
|
||||
# Updated gets called too many times from other places as well; if we use that signal we get the notification three times
|
||||
self.network.trigger_callback("new_transaction")
|
||||
self.was_updated = False
|
||||
|
|
Loading…
Reference in New Issue