Browse Source

rpc: add CallSigs classes, indirect RPC call (icall) method

The MMGen Project 4 years ago
parent
commit
4ed86de639
2 changed files with 63 additions and 0 deletions
  1. 7 0
      mmgen/daemon.py
  2. 56 0
      mmgen/rpc.py

+ 7 - 0
mmgen/daemon.py

@@ -297,6 +297,7 @@ class CoinDaemon(Daemon):
 	network_ids = ('btc','btc_tn','btc_rt','bch','bch_tn','bch_rt','ltc','ltc_tn','ltc_rt','xmr','eth','etc')
 
 	cd = namedtuple('daemon_data', [
+		'id',
 		'coin',
 		'cls_pfx',
 		'coind_name',
@@ -311,6 +312,7 @@ class CoinDaemon(Daemon):
 
 	daemon_ids = {
 		'btc': cd(
+			'bitcoin_core',
 			'Bitcoin',
 			'Bitcoin',
 			'Bitcoin Core', 210000, '0.21.0',
@@ -320,6 +322,7 @@ class CoinDaemon(Daemon):
 			'testnet3',
 			8332, 18332, 18444),
 		'bch': cd(
+			'bitcoin_cash_node',
 			'BitcoinCashNode',
 			'Bitcoin',
 			'Bitcoin Cash Node', 22020000, '22.2.0',
@@ -329,6 +332,7 @@ class CoinDaemon(Daemon):
 			'testnet3',
 			8442, 18442, 18553), # for BCH we use non-standard RPC ports
 		'ltc': cd(
+			'litecoin_core',
 			'Litecoin',
 			'Bitcoin',
 			'Litecoin Core', 180100, '0.18.1',
@@ -338,6 +342,7 @@ class CoinDaemon(Daemon):
 			'testnet4',
 			9332, 19332, 19444),
 		'xmr': cd(
+			'monerod',
 			'Monero',
 			'Monero',
 			'Monero', 'N/A', 'N/A',
@@ -347,6 +352,7 @@ class CoinDaemon(Daemon):
 			None,
 			18081, None, None),
 		'eth': cd(
+			'openethereum',
 			'Ethereum',
 			'Ethereum',
 			'OpenEthereum', 3000001, '3.0.1',
@@ -356,6 +362,7 @@ class CoinDaemon(Daemon):
 			None,
 			8545, 8545, 8545),
 		'etc': cd(
+			'openethereum',
 			'Ethereum Classic',
 			'Ethereum',
 			'OpenEthereum', 3000001, '3.0.1',

+ 56 - 0
mmgen/rpc.py

@@ -193,6 +193,47 @@ class RPCBackends:
 from collections import namedtuple
 auth_data = namedtuple('rpc_auth_data',['user','passwd'])
 
+class CallSigs:
+
+	class Bitcoin:
+
+		class bitcoin_core:
+
+			@classmethod
+			def createwallet(cls,wallet_name,no_keys=True,passphrase='',load_on_startup=True):
+				"""
+				Quirk: when --datadir is specified (even if standard), wallet is created directly in
+				datadir, otherwise in datadir/wallets
+				"""
+				return (
+					'createwallet',
+					wallet_name,    # 1. wallet_name
+					no_keys,        # 2. disable_private_keys
+					no_keys,        # 3. blank (no keys or seed)
+					passphrase,     # 4. passphrase (empty string for non-encrypted)
+					False,          # 5. avoid_reuse (track address reuse)
+					False,          # 6. descriptors (native descriptor wallet)
+					load_on_startup # 7. load_on_startup
+				)
+
+		class litecoin_core(bitcoin_core):
+
+			@classmethod
+			def createwallet(cls,wallet_name,no_keys=True,passphrase='',load_on_startup=True):
+				return (
+					'createwallet',
+					wallet_name,    # 1. wallet_name
+					no_keys,        # 2. disable_private_keys
+					no_keys,        # 3. blank (no keys or seed)
+				)
+
+		class bitcoin_cash_node(litecoin_core): pass
+
+	class Ethereum:
+
+		class openethereum: pass
+
+
 class RPCClient(MMGenObject):
 
 	auth_type = None
@@ -307,6 +348,19 @@ class RPCClient(MMGenObject):
 
 		return ret
 
+	# Icall family of methods - indirect RPC call using CallSigs mechanism:
+	# - 'timeout' and 'wallet' kwargs are passed to corresponding Call method
+	# - remaining kwargs are passed to CallSigs method
+	# - CallSigs method returns method and positional params for Call method
+
+	def icall(self,method,**kwargs):
+		timeout = kwargs.pop('timeout',None)
+		wallet = kwargs.pop('wallet',None)
+		return self.call(
+			*getattr(self.call_sigs,method)(**kwargs),
+			timeout = timeout,
+			wallet = wallet )
+
 	async def process_http_resp(self,coro,batch=False):
 		text,status = await coro
 		if status == 200:
@@ -341,6 +395,7 @@ class BitcoinRPCClient(RPCClient,metaclass=aInitMeta):
 
 		self.proto = proto
 		self.daemon = daemon
+		self.call_sigs = getattr(getattr(CallSigs,proto.base_proto),daemon.id)
 
 		super().__init__(
 			host = 'localhost' if g.test_suite else (g.rpc_host or 'localhost'),
@@ -530,6 +585,7 @@ class EthereumRPCClient(RPCClient,metaclass=aInitMeta):
 	async def __ainit__(self,proto,daemon,backend,caller):
 		self.proto = proto
 		self.daemon = daemon
+		self.call_sigs = getattr(getattr(CallSigs,proto.base_proto),daemon.id)
 
 		super().__init__(
 			host = 'localhost' if g.test_suite else (g.rpc_host or 'localhost'),