From f179c679353cb38636f48cccd83d8e8afc3b36d5 Mon Sep 17 00:00:00 2001 From: TheLazieR Yip Date: Sun, 14 May 2017 14:59:51 +0000 Subject: [PATCH 1/5] Add support for Dash Masternode methods + Add DashDaemon class + Add DashElectrumX class + Update coin configurations for Dash --- lib/coins.py | 4 ++++ server/daemon.py | 9 ++++++++ server/session.py | 56 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 69 insertions(+) diff --git a/lib/coins.py b/lib/coins.py index 4b0551b..f66d148 100644 --- a/lib/coins.py +++ b/lib/coins.py @@ -596,6 +596,10 @@ class Dash(Coin): 'electrum.dash.siampm.com s t', 'wl4sfwq2hwxnodof.onion s t', ] + from server.session import DashElectrumX + SESSIONCLS = DashElectrumX + from server.daemon import DashDaemon + DAEMON = DashDaemon @classmethod def header_hash(cls, header): diff --git a/server/daemon.py b/server/daemon.py index 39109cc..36f6b14 100644 --- a/server/daemon.py +++ b/server/daemon.py @@ -247,3 +247,12 @@ class Daemon(util.LoggedClass): If the daemon has not been queried yet this returns None.''' return self._height + +class DashDaemon(Daemon): + async def masternode_broadcast(self, params): + '''Broadcast a transaction to the network.''' + return await self._send_single('masternodebroadcast', params) + + async def masternode_list(self, params ): + '''Return the masternode status.''' + return await self._send_single('masternodelist', params) diff --git a/server/session.py b/server/session.py index a59c9a8..43cc2a3 100644 --- a/server/session.py +++ b/server/session.py @@ -387,3 +387,59 @@ class LocalRPC(SessionBase): def request_handler(self, method): '''Return the async handler for the given request method.''' return self.controller.rpc_handlers.get(method) + + +class DashElectrumX(ElectrumX): + '''A TCP server that handles incoming Electrum Dash connections.''' + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.electrumx_handlers['masternode.announce.broadcast'] = self.masternode_announce_broadcast + self.electrumx_handlers['masternode.subscribe'] = self.masternode_subscribe + self.subscribe_mns = False + self.mns = set() + + async def notify(self, height, touched): + '''Notify the client about changes in masternode list.''' + + await super().notify(height, touched) + + if self.subscribe_mns: + for masternode in self.mns: + status = await self.daemon.masternode_list(['status', masternode]) + payload = { + 'id': None, + 'method': 'masternode.subscribe', + 'params': [masternode], + 'result': status.get(masternode), + } + self.send_binary(self.encode_payload(payload)) + + # Masternode command handlers + async def masternode_announce_broadcast(self, signmnb): + '''Pass through the parameters to the daemon. + + An ugly API: current Electrum clients only pass the masternode + broadcast message in hex and expect error messages to be returned in + the result field. And the server shouldn't be doing the client's + user interface job here. + ''' + try: + mnb_info = await self.daemon.masternode_broadcast(['relay',signmnb]) + return mnb_info + except DaemonError as e: + error = e.args[0] + message = error['message'] + self.log_info('masternode_broadcast: {}'.format(message)) + return ( + 'The masternode broadcast was rejected. ({})\n[{}]' + .format(message, signmnb) + ) + + async def masternode_subscribe(self, vin): + '''Returns the status of masternode.''' + result = await self.daemon.masternode_list(['status',vin]) + if result is not None: + self.mns.add(vin) + self.subscribe_mns = True + return result.get(vin) From 4da227872986bbec8f7c11e75f73764e2534fd33 Mon Sep 17 00:00:00 2001 From: TheLazieR Yip Date: Sun, 14 May 2017 17:38:55 +0000 Subject: [PATCH 2/5] Force server string response for Electrum-Dash 2.6.4 client --- server/session.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/server/session.py b/server/session.py index 43cc2a3..a302c58 100644 --- a/server/session.py +++ b/server/session.py @@ -415,6 +415,16 @@ class DashElectrumX(ElectrumX): } self.send_binary(self.encode_payload(payload)) + def server_version(self, client_name=None, protocol_version=None): + '''Returns the server version as a string. + ForcE version string response for Electrum-Dash 2.6.4 + ''' + + default_return = super().server_version(client_name, protocol_version) + if self.client == '2.6.4': + return '1.0' + return default_return + # Masternode command handlers async def masternode_announce_broadcast(self, signmnb): '''Pass through the parameters to the daemon. From 8d21eae2bbf3a72388af4d6969831677220d0529 Mon Sep 17 00:00:00 2001 From: TheLazieR Yip Date: Mon, 15 May 2017 04:12:15 +0000 Subject: [PATCH 3/5] Move import lines to top of class --- lib/coins.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/coins.py b/lib/coins.py index f66d148..cff766c 100644 --- a/lib/coins.py +++ b/lib/coins.py @@ -572,6 +572,8 @@ class DogecoinTestnet(Dogecoin): # Source: https://github.com/dashpay/dash class Dash(Coin): + from server.session import DashElectrumX + from server.daemon import DashDaemon NAME = "Dash" SHORTNAME = "DASH" NET = "mainnet" @@ -596,9 +598,7 @@ class Dash(Coin): 'electrum.dash.siampm.com s t', 'wl4sfwq2hwxnodof.onion s t', ] - from server.session import DashElectrumX SESSIONCLS = DashElectrumX - from server.daemon import DashDaemon DAEMON = DashDaemon @classmethod From e99400c225e0246272c4865d5294e5b168736659 Mon Sep 17 00:00:00 2001 From: TheLazieR Yip Date: Mon, 15 May 2017 04:12:33 +0000 Subject: [PATCH 4/5] Update DashElectrumX as commented --- server/session.py | 37 +++++++++++++++---------------------- 1 file changed, 15 insertions(+), 22 deletions(-) diff --git a/server/session.py b/server/session.py index a302c58..4b39098 100644 --- a/server/session.py +++ b/server/session.py @@ -396,7 +396,6 @@ class DashElectrumX(ElectrumX): super().__init__(*args, **kwargs) self.electrumx_handlers['masternode.announce.broadcast'] = self.masternode_announce_broadcast self.electrumx_handlers['masternode.subscribe'] = self.masternode_subscribe - self.subscribe_mns = False self.mns = set() async def notify(self, height, touched): @@ -404,20 +403,19 @@ class DashElectrumX(ElectrumX): await super().notify(height, touched) - if self.subscribe_mns: - for masternode in self.mns: - status = await self.daemon.masternode_list(['status', masternode]) - payload = { - 'id': None, - 'method': 'masternode.subscribe', - 'params': [masternode], - 'result': status.get(masternode), - } - self.send_binary(self.encode_payload(payload)) + for masternode in self.mns: + status = await self.daemon.masternode_list(['status', masternode]) + payload = { + 'id': None, + 'method': 'masternode.subscribe', + 'params': [masternode], + 'result': status.get(masternode), + } + self.send_binary(self.encode_payload(payload)) def server_version(self, client_name=None, protocol_version=None): '''Returns the server version as a string. - ForcE version string response for Electrum-Dash 2.6.4 + Force version string response for Electrum-Dash 2.6.4 ''' default_return = super().server_version(client_name, protocol_version) @@ -427,15 +425,10 @@ class DashElectrumX(ElectrumX): # Masternode command handlers async def masternode_announce_broadcast(self, signmnb): - '''Pass through the parameters to the daemon. + '''Pass through the masternode announce message to be broadcast by the daemon.''' - An ugly API: current Electrum clients only pass the masternode - broadcast message in hex and expect error messages to be returned in - the result field. And the server shouldn't be doing the client's - user interface job here. - ''' try: - mnb_info = await self.daemon.masternode_broadcast(['relay',signmnb]) + mnb_info = await self.daemon.masternode_broadcast(['relay', signmnb]) return mnb_info except DaemonError as e: error = e.args[0] @@ -448,8 +441,8 @@ class DashElectrumX(ElectrumX): async def masternode_subscribe(self, vin): '''Returns the status of masternode.''' - result = await self.daemon.masternode_list(['status',vin]) + result = await self.daemon.masternode_list(['status', vin]) if result is not None: self.mns.add(vin) - self.subscribe_mns = True - return result.get(vin) + return result.get(vin) + return None From 2e87d49e04b060a8e6fd9f69327d363e901e9b8c Mon Sep 17 00:00:00 2001 From: TheLazieR Yip Date: Mon, 15 May 2017 08:10:09 +0000 Subject: [PATCH 5/5] Add more comment on DashElectrumX.server_version --- server/session.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/server/session.py b/server/session.py index 4b39098..72fb8a3 100644 --- a/server/session.py +++ b/server/session.py @@ -415,7 +415,8 @@ class DashElectrumX(ElectrumX): def server_version(self, client_name=None, protocol_version=None): '''Returns the server version as a string. - Force version string response for Electrum-Dash 2.6.4 + Force version string response for Electrum-Dash 2.6.4 client caused by + https://github.com/dashpay/electrum-dash/commit/638cf6c0aeb7be14a85ad98f873791cb7b49ee29 ''' default_return = super().server_version(client_name, protocol_version)