Basic Ethereum RPC support (Parity)
This commit is contained in:
parent
06af7342cf
commit
7ad2fdf66c
3 changed files with 77 additions and 34 deletions
|
|
@ -294,6 +294,10 @@ class EthereumProtocol(DummyWIF,BitcoinProtocolAddrgen):
|
|||
base_coin = 'ETH'
|
||||
pubkey_type = 'std' # required by DummyWIF
|
||||
|
||||
daemon_name = 'parity'
|
||||
rpc_port = 8545
|
||||
mmcaps = ('key','addr','rpc')
|
||||
|
||||
@classmethod
|
||||
def verify_addr(cls,addr,hex_width,return_dict=False):
|
||||
from mmgen.util import is_hex_str_lc
|
||||
|
|
@ -310,7 +314,8 @@ class EthereumProtocol(DummyWIF,BitcoinProtocolAddrgen):
|
|||
|
||||
class EthereumTestnetProtocol(EthereumProtocol): pass
|
||||
class EthereumClassicProtocol(EthereumProtocol):
|
||||
name = 'ethereum_classic'
|
||||
name = 'ethereum_classic'
|
||||
mmcaps = ('key','addr')
|
||||
class EthereumClassicTestnetProtocol(EthereumClassicProtocol): pass
|
||||
|
||||
class ZcashProtocol(BitcoinProtocolAddrgen):
|
||||
|
|
@ -400,7 +405,7 @@ class CoinProtocol(MMGenObject):
|
|||
'btc': (BitcoinProtocol,BitcoinTestnetProtocol,None),
|
||||
'bch': (BitcoinCashProtocol,BitcoinCashTestnetProtocol,None),
|
||||
'ltc': (LitecoinProtocol,LitecoinTestnetProtocol,None),
|
||||
'eth': (EthereumProtocol,EthereumTestnetProtocol,2),
|
||||
'eth': (EthereumProtocol,EthereumTestnetProtocol,None),
|
||||
'etc': (EthereumClassicProtocol,EthereumClassicTestnetProtocol,2),
|
||||
'zec': (ZcashProtocol,ZcashTestnetProtocol,2),
|
||||
'xmr': (MoneroProtocol,MoneroTestnetProtocol,None)
|
||||
|
|
|
|||
53
mmgen/rpc.py
53
mmgen/rpc.py
|
|
@ -32,9 +32,9 @@ class RPCFailure(Exception): pass
|
|||
|
||||
class CoinDaemonRPCConnection(object):
|
||||
|
||||
def __init__(self,host=None,port=None,user=None,passwd=None,auth_cookie=None):
|
||||
def __init__(self,host=None,port=None,user=None,passwd=None,auth_cookie=None,auth=True):
|
||||
|
||||
dmsg_rpc('=== CoinDaemonRPCConnection.__init__() debug ===')
|
||||
dmsg_rpc('=== {}.__init__() debug ==='.format(type(self).__name__))
|
||||
dmsg_rpc(' host [{}] port [{}] user [{}] passwd [{}] auth_cookie [{}]\n'.format(
|
||||
host,port,user,passwd,auth_cookie))
|
||||
|
||||
|
|
@ -44,7 +44,9 @@ class CoinDaemonRPCConnection(object):
|
|||
except:
|
||||
die(1,'Unable to connect to {}:{}'.format(host,port))
|
||||
|
||||
if user and passwd:
|
||||
if not auth:
|
||||
self.auth_str = ''
|
||||
elif user and passwd:
|
||||
self.auth_str = '{}:{}'.format(user,passwd)
|
||||
elif auth_cookie:
|
||||
self.auth_str = auth_cookie
|
||||
|
|
@ -85,9 +87,9 @@ class CoinDaemonRPCConnection(object):
|
|||
hc = httplib.HTTPConnection(self.host, self.port, False, cf['timeout'])
|
||||
|
||||
if cf['batch']:
|
||||
p = [{'method':cmd,'params':r,'id':n} for n,r in enumerate(args[0],1)]
|
||||
p = [{'method':cmd,'params':r,'id':n,'jsonrpc':'2.0'} for n,r in enumerate(args[0],1)]
|
||||
else:
|
||||
p = {'method':cmd,'params':args,'id':1}
|
||||
p = {'method':cmd,'params':args,'id':1,'jsonrpc':'2.0'}
|
||||
|
||||
def do_fail(*args):
|
||||
if cf['on_fail'] in ('return','silent'):
|
||||
|
|
@ -110,14 +112,16 @@ class CoinDaemonRPCConnection(object):
|
|||
return g.proto.get_rpc_coin_amt_type()(obj)
|
||||
return json.JSONEncoder.default(self, obj)
|
||||
|
||||
dmsg_rpc(' RPC AUTHORIZATION data ==> raw: [{}]\n{}enc: [Basic {}]\n'.format(
|
||||
self.auth_str,' '*31,base64.b64encode(self.auth_str)))
|
||||
http_hdr = { 'Content-Type': 'application/json' }
|
||||
if self.auth_str:
|
||||
dmsg_rpc(' RPC AUTHORIZATION data ==> raw: [{}]\n{}enc: [Basic {}]\n'.format(
|
||||
self.auth_str,' '*31,base64.b64encode(self.auth_str)))
|
||||
http_hdr.update({
|
||||
'Host': self.host,
|
||||
'Authorization': 'Basic {}'.format(base64.b64encode(self.auth_str)) })
|
||||
|
||||
try:
|
||||
hc.request('POST', '/', json.dumps(p,cls=MyJSONEncoder), {
|
||||
'Host': self.host,
|
||||
'Authorization': 'Basic {}'.format(base64.b64encode(self.auth_str))
|
||||
})
|
||||
hc.request('POST','/',json.dumps(p,cls=MyJSONEncoder),http_hdr)
|
||||
except Exception as e:
|
||||
m = '{}\nUnable to connect to {} at {}:{}'
|
||||
return do_fail(None,2,m.format(e,g.proto.daemon_name,self.host,self.port))
|
||||
|
|
@ -197,6 +201,33 @@ class CoinDaemonRPCConnection(object):
|
|||
for name in rpcmethods:
|
||||
exec "def {n}(self,*a,**k):return self.request('{n}',*a,**k)\n".format(n=name)
|
||||
|
||||
class EthereumRPCConnection(CoinDaemonRPCConnection):
|
||||
|
||||
rpcmethods = (
|
||||
'eth_accounts',
|
||||
'eth_blockNumber',
|
||||
'eth_gasPrice',
|
||||
'eth_getBalance',
|
||||
'eth_getBlockByHash',
|
||||
'eth_getBlockByNumber',
|
||||
'eth_getTransactionByHash',
|
||||
'eth_protocolVersion',
|
||||
'eth_sendRawTransaction',
|
||||
'eth_signTransaction',
|
||||
'eth_syncing',
|
||||
'parity_accountsInfo',
|
||||
'parity_chainStatus',
|
||||
'parity_gasCeilTarget',
|
||||
'parity_gasFloorTarget',
|
||||
'parity_minGasPrice',
|
||||
'parity_netPeers',
|
||||
'parity_versionInfo',
|
||||
)
|
||||
|
||||
for name in rpcmethods:
|
||||
exec "def {n}(self,*a,**k):return self.request('{n}',*a,**k)\n".format(n=name)
|
||||
|
||||
|
||||
def rpc_error(ret):
|
||||
return type(ret) is tuple and ret and ret[0] == 'rpcfail'
|
||||
|
||||
|
|
|
|||
|
|
@ -825,8 +825,7 @@ def rpc_init(reinit=False):
|
|||
assert block0 == g.proto.block0,'Incorrect Genesis block for {}'.format(g.proto.__name__)
|
||||
for fork in g.proto.forks:
|
||||
if fork[0] == None or latest < fork[0]: break
|
||||
bhash = conn.getblockhash(fork[0])
|
||||
assert bhash == fork[1], (
|
||||
assert conn.getblockhash(fork[0]) == fork[1], (
|
||||
'Bad block hash at fork block {}. Is this the {} chain?'.format(fork[0],fork[2].upper()))
|
||||
except Exception as e:
|
||||
die(2,"{}\n'{c}' requested, but this is not the {c} chain!".format(e,c=g.coin))
|
||||
|
|
@ -839,26 +838,34 @@ def rpc_init(reinit=False):
|
|||
except Exception as e:
|
||||
die(1,'{}\nChain is {}!'.format(e,g.chain))
|
||||
|
||||
cfg = get_daemon_cfg_options(('rpcuser','rpcpassword'))
|
||||
import mmgen.rpc
|
||||
conn = mmgen.rpc.CoinDaemonRPCConnection(
|
||||
g.rpc_host or 'localhost',
|
||||
g.rpc_port or g.proto.rpc_port,
|
||||
g.rpc_user or cfg['rpcuser'], # MMGen's rpcuser,rpcpassword override coin daemon's
|
||||
g.rpc_password or cfg['rpcpassword'],
|
||||
auth_cookie=get_coin_daemon_auth_cookie())
|
||||
if g.coin == 'ETH':
|
||||
conn = mmgen.rpc.EthereumRPCConnection(
|
||||
g.rpc_host or 'localhost',
|
||||
g.rpc_port or g.proto.rpc_port,
|
||||
auth=False)
|
||||
if not g.daemon_version: # First call
|
||||
g.daemon_version = conn.parity_versionInfo()['version'] # fail immediately if daemon is geth
|
||||
else:
|
||||
cfg = get_daemon_cfg_options(('rpcuser','rpcpassword'))
|
||||
conn = mmgen.rpc.CoinDaemonRPCConnection(
|
||||
g.rpc_host or 'localhost',
|
||||
g.rpc_port or g.proto.rpc_port,
|
||||
g.rpc_user or cfg['rpcuser'], # MMGen's rpcuser,rpcpassword override coin daemon's
|
||||
g.rpc_password or cfg['rpcpassword'],
|
||||
auth_cookie=get_coin_daemon_auth_cookie())
|
||||
|
||||
if not g.daemon_version: # First call
|
||||
if g.bob or g.alice:
|
||||
import regtest as rt
|
||||
rt.user(('alice','bob')[g.bob],quiet=True)
|
||||
g.daemon_version = int(conn.getnetworkinfo()['version'])
|
||||
g.chain = conn.getblockchaininfo()['chain']
|
||||
if g.chain != 'regtest': g.chain += 'net'
|
||||
assert g.chain in g.chains
|
||||
check_chaintype_mismatch()
|
||||
if g.chain == 'mainnet': # skip this for testnet, as Genesis block may change
|
||||
check_chainfork_mismatch(conn)
|
||||
if not g.daemon_version: # First call
|
||||
if g.bob or g.alice:
|
||||
import regtest as rt
|
||||
rt.user(('alice','bob')[g.bob],quiet=True)
|
||||
g.daemon_version = int(conn.getnetworkinfo()['version'])
|
||||
g.chain = conn.getblockchaininfo()['chain']
|
||||
if g.chain != 'regtest': g.chain += 'net'
|
||||
assert g.chain in g.chains
|
||||
check_chaintype_mismatch()
|
||||
if g.chain == 'mainnet': # skip this for testnet, as Genesis block may change
|
||||
check_chainfork_mismatch(conn)
|
||||
|
||||
g.rpch = conn
|
||||
return conn
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue