ETH: add experimental support for Erigon

https://github.com/ledgerwatch/erigon

- Support is for testing/development only
- Enable with MMGEN_ENABLE_ERIGON environmental var
- Specify with --daemon-id=erigon
This commit is contained in:
The MMGen Project 2021-08-04 10:47:20 +00:00
commit b88c4bbd48
Signed by: mmgen
GPG key ID: 3F8B1861E32B7DA2
5 changed files with 114 additions and 2 deletions

View file

@ -396,6 +396,10 @@ class EthereumMMGenTX:
return False
if self.rpc.daemon.id in ('parity','openethereum'):
pool = [x['hash'] for x in await self.rpc.call('parity_pendingTransactions')]
elif self.rpc.daemon.id == 'erigon':
res = await self.rpc.call('txpool_content')
pmsg('txpool_content:',res) # DEBUG
pool = list(res['pending']) + list(res['queued'])
return '0x'+self.coin_txid in pool
async def is_in_wallet():

View file

@ -342,7 +342,7 @@ class CoinDaemon(Daemon):
'BCH': _cd('Bitcoin Cash Node', ['bitcoin_cash_node']),
'LTC': _cd('Litecoin', ['litecoin_core']),
'XMR': _cd('Monero', ['monero']),
'ETH': _cd('Ethereum', ['openethereum']),
'ETH': _cd('Ethereum', ['openethereum'] + (['erigon'] if g.enable_erigon else []) ),
'ETC': _cd('Ethereum Classic', ['parity']),
}
@ -656,3 +656,84 @@ class parity_daemon(openethereum_daemon):
exec_fn = 'parity'
ports_shift = _nw(100,110,120)
rpc_ports = _nw(*[8545 + n for n in ports_shift]) # non-standard
# https://github.com/ledgerwatch/erigon
class erigon_daemon(CoinDaemon):
avail_opts = ('online',)
daemon_data = _dd('Erigon', 2021007005, '2021.07.5')
version_pat = r'erigon/(\d+)\.(\d+)\.(\d+)'
exec_fn = 'erigon'
cfg_file = 'erigon.conf'
private_ports = _nw(9090,9091,9092) # testnet and regtest are non-standard
ports_shift = _nw(200,210,220)
rpc_ports = _nw(*[8545 + n for n in ports_shift]) # non-standard
use_pidfile = False
use_threads = True
datadirs = {
'linux': [g.home_dir,'.local','share','erigon'],
'win': [os.getenv('LOCALAPPDATA'),'Erigon'] # FIXME
}
datadir_is_subdir = True
testnet_dir = 'erigon_testnet'
def subclass_init(self):
self.private_port = getattr(self.private_ports,self.network)
if self.network == 'regtest':
self.datadir = None
self.coind_args = list_gen(
['--verbosity=0'],
[f'--private.api.addr=127.0.0.1:{self.private_port}'],
[f'--datadir={self.datadir}', self.network!='regtest'],
['--chain=dev', self.network=='regtest'],
['--chain=goerli', self.network=='testnet'],
['--miner.etherbase=00a329c0648769a73afac7f9381e08fb43dbea72', self.network=='regtest'],
)
self.rpc_d = erigon_rpcdaemon(
proto = self.proto,
rpc_port = self.rpc_port,
private_port = self.private_port,
test_suite = self.test_suite,
datadir = self.datadir )
def start(self,quiet=False,silent=False):
super().start(quiet=quiet,silent=silent)
self.rpc_d.debug = self.debug
return self.rpc_d.start(quiet=quiet,silent=silent)
def stop(self,quiet=False,silent=False):
self.rpc_d.debug = self.debug
self.rpc_d.stop(quiet=quiet,silent=silent)
return super().stop(quiet=quiet,silent=silent)
@property
def start_cmds(self):
return [self.start_cmd,self.rpc_d.start_cmd]
class erigon_rpcdaemon(RPCDaemon):
master_daemon = 'erigon_daemon'
rpc_type = 'Erigon'
exec_fn = 'rpcdaemon'
use_pidfile = False
use_threads = True
def __init__(self,proto,rpc_port,private_port,test_suite,datadir):
self.proto = proto
self.test_suite = test_suite
super().__init__()
self.network = proto.network
self.rpc_port = rpc_port
self.datadir = datadir
self.daemon_args = list_gen(
['--verbosity=0'],
[f'--private.api.addr=127.0.0.1:{private_port}'],
[f'--datadir={self.datadir}', self.network != 'regtest'],
['--http.api=eth,erigon,web3,net,txpool'],
[f'--http.port={self.rpc_port}'],
)
self.lock()

View file

@ -112,6 +112,7 @@ class GlobalContext(Lockable):
# miscellaneous features:
use_internal_keccak_module = False
enable_erigon = False
# test suite:
bogus_wallet_data = ''
@ -227,6 +228,7 @@ class GlobalContext(Lockable):
'MMGEN_RPC_BACKEND',
'MMGEN_IGNORE_DAEMON_VERSION',
'MMGEN_USE_STANDALONE_SCRYPT_MODULE',
'MMGEN_ENABLE_ERIGON',
'MMGEN_DISABLE_COLOR',
'MMGEN_DISABLE_MSWIN_PW_WARNING',

View file

@ -397,6 +397,19 @@ class CoinProtocol(MMGenObject):
avg_bdi = 15
ignore_daemon_version = False
chain_ids = {
1: 'ethereum', # ethereum mainnet
2: 'morden', # morden testnet (deprecated)
3: 'ropsten', # ropsten testnet
4: 'rinkeby', # rinkeby testnet
5: 'goerli', # goerli testnet
42: 'kovan', # kovan testnet
61: 'classic', # ethereum classic mainnet
62: 'morden', # ethereum classic testnet
17: 'developmentchain', # parity dev chain
1337: 'developmentchain', # erigon dev chain
}
@property
def dcoin(self):
return self.tokensym or self.coin
@ -415,7 +428,7 @@ class CoinProtocol(MMGenObject):
return pubkey_hash
class EthereumTestnet(Ethereum):
chain_names = ['kovan']
chain_names = ['kovan','goerli','rinkeby']
class EthereumRegtest(EthereumTestnet):
chain_names = ['developmentchain']

View file

@ -624,12 +624,18 @@ class EthereumRPCClient(RPCClient,metaclass=aInitMeta):
self.caps += ('full_node',)
self.chainID = None if ci == None else Int(ci,16) # parity/oe return chainID only for dev chain
self.chain = (await self.call('parity_chain')).replace(' ','_').replace('_testnet','')
elif self.daemon.id == 'erigon':
do_erigon_warning()
self.caps += ('full_node',)
self.chainID = Int(ci,16)
self.chain = self.proto.chain_ids[self.chainID]
rpcmethods = (
'eth_blockNumber',
'eth_call',
# Returns the EIP155 chain ID used for transaction signing at the current best block.
# Parity: Null is returned if not available, ID not required in transactions
# Erigon: always returns ID, requires ID in transactions
'eth_chainId',
'eth_gasPrice',
'eth_getBalance',
@ -640,6 +646,7 @@ class EthereumRPCClient(RPCClient,metaclass=aInitMeta):
'parity_chain',
'parity_nodeKind',
'parity_pendingTransactions',
'txpool_content',
)
class MoneroRPCClient(RPCClient):
@ -709,6 +716,11 @@ class MoneroWalletRPCClient(MoneroRPCClient):
'refresh', # start_height
)
def do_erigon_warning(erigon_warning_shown=[]):
if not erigon_warning_shown:
rmsg(f'WARNING: Erigon support is EXPERIMENTAL. Use at your own risk!!!')
erigon_warning_shown.append(1)
def handle_unsupported_daemon_version(rpc,proto,ignore_daemon_version,unsupported_daemon_warning_shown=[]):
if ignore_daemon_version or proto.ignore_daemon_version or g.ignore_daemon_version:
if not type(proto) in unsupported_daemon_warning_shown: