support Rust Ethereum client (Reth)

Tested on Linux only

Testing:

    $ test/cmdtest.py --coin=eth --daemon-id=reth ethdev
This commit is contained in:
The MMGen Project 2025-03-10 14:28:55 +00:00
commit 1e422b2c2b
Signed by: mmgen
GPG key ID: 3F8B1861E32B7DA2
25 changed files with 71 additions and 13 deletions

View file

@ -16,6 +16,7 @@ include test/*/*.py
include test/ref/*
include test/ref/*/*
include test/ref/*/*/*/*
include test/ref/*/*/*/*/*
include test/overlay/fakemods/mmgen/*.py
include test/overlay/fakemods/mmgen/*/*.py
include test/overlay/fakemods/mmgen/*/*/*/*.py

View file

@ -287,7 +287,7 @@ class CoinDaemon(Daemon):
'BCH': _cd(['bitcoin_cash_node']),
'LTC': _cd(['litecoin_core']),
'XMR': _cd(['monero']),
'ETH': _cd(['geth', 'erigon', 'openethereum']),
'ETH': _cd(['geth', 'reth', 'erigon', 'openethereum']),
'ETC': _cd(['parity']),
}

View file

@ -1 +1 @@
15.1.dev18
15.1.dev19

View file

@ -113,19 +113,29 @@ class geth_daemon(ethereum_daemon):
def init_subclass(self):
self.coind_args = list_gen(
['--verbosity=0'],
['node', self.id == 'reth'],
['--quiet', self.id == 'reth'],
['--verbosity=0', self.id == 'geth'],
['--ipcdisable'], # IPC-RPC: if path to socket is longer than 108 chars, geth fails to start
['--http'],
['--http.api=eth,web3,txpool'],
[f'--http.port={self.rpc_port}'],
[f'--authrpc.port={self.authrpc_port}'],
[f'--port={self.p2p_port}', self.p2p_port], # geth binds p2p port even with --maxpeers=0
['--maxpeers=0', not self.opt.online],
['--maxpeers=0', self.id == 'geth' and not self.opt.online],
[f'--datadir={self.datadir}', self.non_dfl_datadir],
['--holesky', self.network=='testnet'],
['--dev', self.network=='regtest'],
)
class reth_daemon(geth_daemon):
daemon_data = _dd('Reth', 1002002, '1.2.2')
version_pat = r'reth/v(\d+)\.(\d+)\.(\d+)'
exec_fn = 'reth'
datadirs = {
'linux': [gc.home_dir, '.local', 'share', 'reth'],
}
# https://github.com/ledgerwatch/erigon
class erigon_daemon(geth_daemon):
daemon_data = _dd('Erigon', 2022099099, '2022.99.99')

View file

@ -38,6 +38,7 @@ class mainnet(CoinProtocol.DummyWIF, CoinProtocol.Secp256k1):
avg_bdi = 15
decimal_prec = 36
# https://www.chainid.dev
chain_ids = {
1: 'ethereum', # ethereum mainnet
2: 'morden', # morden testnet (deprecated)
@ -50,6 +51,7 @@ class mainnet(CoinProtocol.DummyWIF, CoinProtocol.Secp256k1):
17: 'developmentchain', # parity dev chain
1337: 'developmentchain', # geth dev chain
711: 'ethereum', # geth mainnet (empty chain)
17000: 'holesky', # proof-of-stake testnet
}
coin_cfg_opts = (

View file

@ -25,6 +25,10 @@ class daemon_warning(oneshot_warning_group):
color = 'yellow'
message = 'Geth has not been tested on mainnet. You may experience problems.'
class reth:
color = 'yellow'
message = 'Reth has not been tested on mainnet. You may experience problems.'
class erigon:
color = 'red'
message = 'Erigon support is EXPERIMENTAL. Use at your own risk!!!'
@ -80,7 +84,7 @@ class EthereumRPCClient(RPCClient, metaclass=AsyncInit):
self.caps += ('full_node',)
self.chainID = None if ci is 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 in ('geth', 'erigon'):
elif self.daemon.id in ('geth', 'reth', 'erigon'):
if self.daemon.network == 'mainnet':
daemon_warning(self.daemon.id)
self.caps += ('full_node',)

View file

@ -33,7 +33,7 @@ class Status(TxBase.Status):
return False
if tx.rpc.daemon.id in ('parity', 'openethereum'):
pool = [x['hash'] for x in await tx.rpc.call('parity_pendingTransactions')]
elif tx.rpc.daemon.id in ('geth', 'erigon'):
elif tx.rpc.daemon.id in ('geth', 'reth', 'erigon'):
res = await tx.rpc.call('txpool_content')
pool = list(res['pending']) + list(res['queued'])
return '0x'+tx.coin_txid in pool

View file

@ -20,7 +20,7 @@
test.cmdtest_d.ct_ethdev: Ethdev tests for the cmdtest.py test suite
"""
import sys, os, re, shutil, asyncio, json
import sys, time, os, re, shutil, asyncio, json
from decimal import Decimal
from collections import namedtuple
from subprocess import run, PIPE, DEVNULL
@ -66,6 +66,15 @@ dfl_sid = '98831F3A'
dfl_devaddr = '00a329c0648769a73afac7f9381e08fb43dbea72'
dfl_devkey = '4d5db4107d237df6a3d58ee5f70ae63d73d7658d4026f2eefd2f204c81682cb7'
def get_reth_dev_keypair():
from mmgen.bip39 import bip39
from mmgen.bip_hd import MasterNode
mn = 'test test test test test test test test test test test junk' # See ‘reth node --help’
seed = bip39().generate_seed(mn.split())
m = MasterNode(cfg, seed)
node = m.to_chain(idx=0, coin='eth').derive_private(0)
return (node.key.hex(), node.address)
burn_addr = 'deadbeef'*5
burn_addr2 = 'beadcafe'*5
@ -85,6 +94,16 @@ def set_vbals(daemon_id):
vbal6 = '999904.14880104212345678'
vbal7 = '999902.91891764212345678'
vbal9 = '1.2262504'
elif daemon_id == 'reth':
vbal1 = '1.2288334'
vbal2 = '99.996560752'
vbal3 = '1.23142525'
vbal3 = '1.2314176'
vbal4 = '127.0287834'
vbal5 = '999904.14775104212345678'
vbal6 = '999904.14880104212345678'
vbal7 = '999902.91891764212345678'
vbal9 = '1.2262504'
else:
vbal1 = '1.2288396'
vbal2 = '99.997088092'
@ -409,6 +428,10 @@ class CmdTestEthdev(CmdTestBase, CmdTestShared):
from mmgen.daemon import CoinDaemon
self.daemon = CoinDaemon( cfg, self.proto.coin+'_rt', test_suite=True)
if self.daemon.id == 'reth':
global dfl_devkey, dfl_devaddr
dfl_devkey, dfl_devaddr = get_reth_dev_keypair()
set_vbals(self.daemon.id)
self.using_solc = check_solc_ver()
@ -432,16 +455,21 @@ class CmdTestEthdev(CmdTestBase, CmdTestShared):
from mmgen.rpc import rpc_init
return await rpc_init(cfg, self.proto)
def mining_delay(self): # workaround for mining race condition in dev mode
if self.daemon.id == 'reth':
time.sleep(0.5)
async def setup(self):
self.spawn('', msg_only=True)
d = self.daemon
if not self.using_solc:
srcdir = os.path.join(self.tr.repo_root, 'test', 'ref', 'ethereum', 'bin')
subdir = 'reth' if d.id == 'reth' else 'geth'
srcdir = os.path.join(self.tr.repo_root, 'test', 'ref', 'ethereum', 'bin', subdir)
from shutil import copytree
for d in ('mm1', 'mm2'):
copytree(os.path.join(srcdir, d), os.path.join(self.tmpdir, d))
for _ in ('mm1', 'mm2'):
copytree(os.path.join(srcdir, _), os.path.join(self.tmpdir, _))
if d.id in ('geth', 'erigon'):
self.genesis_setup(d)
@ -575,6 +603,8 @@ class CmdTestEthdev(CmdTestBase, CmdTestShared):
[f'--coin={self.proto.coin}', '--regtest=1', 'eth_getBalance', '0x'+dfl_devaddr, 'latest'])
if self.daemon.id == 'geth':
t.expect('0x33b2e3c91ec0e9113986000')
elif self.daemon.id == 'reth':
t.expect('0xd3c21bcecceda1000000')
return t
async def _wallet_upgrade(self, src_fn, expect1, expect2=None):
@ -763,6 +793,7 @@ class CmdTestEthdev(CmdTestBase, CmdTestShared):
return self.bal(n='3')
def tx_status(self, ext, expect_str, expect_str2='', add_args=[], exit_val=0):
self.mining_delay()
ext = ext.format('' if cfg.debug_utf8 else '')
txfile = self.get_file_with_ext(ext, no_dot=True)
t = self.spawn(
@ -893,6 +924,7 @@ class CmdTestEthdev(CmdTestBase, CmdTestShared):
return self.bal(n='5')
def bal(self, n):
self.mining_delay()
t = self.spawn('mmgen-tool', self.eth_args + ['twview', 'wide=1'])
text = t.read(strip_color=True)
for addr, amt in bals(n):
@ -903,6 +935,7 @@ class CmdTestEthdev(CmdTestBase, CmdTestShared):
return t
def token_bal(self, n=None):
self.mining_delay()
t = self.spawn('mmgen-tool', self.eth_args + ['--token=mm1', 'twview', 'wide=1'])
text = t.read(strip_color=True)
for addr, _amt1, _amt2 in token_bals(n):
@ -982,8 +1015,8 @@ class CmdTestEthdev(CmdTestBase, CmdTestShared):
return self.token_compile(token_data)
async def get_tx_receipt(self, txid):
if self.daemon.id == 'geth': # yet another Geth bug
await asyncio.sleep(0.5)
if self.daemon.id in ('geth', 'reth'): # workaround for mining race condition in dev mode
await asyncio.sleep(1 if self.daemon.id == 'reth' else 0.5)
from mmgen.tx import NewTX
tx = await NewTX(cfg=cfg, proto=self.proto, target='tx')
tx.rpc = await self.rpc
@ -1313,6 +1346,8 @@ class CmdTestEthdev(CmdTestBase, CmdTestShared):
def _txcreate_refresh_balances(self, bals, args, total, adj_total, total_coin):
self.mining_delay()
if total_coin is None:
total_coin = self.proto.coin

View file

@ -201,7 +201,7 @@ class unit_tests:
'rpc_port': 32323, # ignored
'btc_tw_name': 'ignored',
'tw_name': 'also-ignored',
'eth_testnet_chain_names': ['goerli', 'foo', 'bar', 'baz'],
'eth_testnet_chain_names': ['goerli', 'holesky', 'foo', 'bar', 'baz'],
})
async def erigon(self, name, ut):

View file

@ -0,0 +1 @@
6080604052348015600f57600080fd5b50600080546001600160a01b031916331790556101ca806100316000396000f3fe608060405234801561001057600080fd5b506004361061004c5760003560e01c806379ba5097146100515780638da5cb5b1461005b578063d4ee1d901461008a578063f2fde38b1461009d575b600080fd5b6100596100b0565b005b60005461006e906001600160a01b031681565b6040516001600160a01b03909116815260200160405180910390f35b60015461006e906001600160a01b031681565b6100596100ab366004610164565b61012b565b6001546001600160a01b031633146100c757600080fd5b600154600080546040516001600160a01b0393841693909116917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a360018054600080546001600160a01b03199081166001600160a01b03841617909155169055565b6000546001600160a01b0316331461014257600080fd5b600180546001600160a01b0319166001600160a01b0392909216919091179055565b60006020828403121561017657600080fd5b81356001600160a01b038116811461018d57600080fd5b939250505056fea2646970667358221220bcd3e32a06d3bc97ce1339e72449373355373643c31c80385ca5f89938aca39c64736f6c634300081a0033

View file

@ -0,0 +1 @@
6080604052348015600f57600080fd5b506102018061001f6000396000f3fe608060405234801561001057600080fd5b506004361061004c5760003560e01c8063a293d1e814610051578063b5931f7c14610076578063d05c78da14610089578063e6cb90131461009c575b600080fd5b61006461005f366004610134565b6100af565b60405190815260200160405180910390f35b610064610084366004610134565b6100cf565b610064610097366004610134565b6100e7565b6100646100aa366004610134565b610119565b6000828211156100be57600080fd5b6100c8828461016c565b9392505050565b60008082116100dd57600080fd5b6100c8828461017f565b60006100f382846101a1565b905082158061010a575081610108848361017f565b145b61011357600080fd5b92915050565b600061012582846101b8565b90508281101561011357600080fd5b6000806040838503121561014757600080fd5b50508035926020909101359150565b634e487b7160e01b600052601160045260246000fd5b8181038181111561011357610113610156565b60008261019c57634e487b7160e01b600052601260045260246000fd5b500490565b808202811582820484141761011357610113610156565b808201808211156101135761011361015656fea264697066735822122081e009254874ff32aa4fa09f9d8a315bf6a4e9e870bfb5d8b4e6611f659ed84964736f6c634300081a0033

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1 @@
6080604052348015600f57600080fd5b50600080546001600160a01b031916331790556101ca806100316000396000f3fe608060405234801561001057600080fd5b506004361061004c5760003560e01c806379ba5097146100515780638da5cb5b1461005b578063d4ee1d901461008a578063f2fde38b1461009d575b600080fd5b6100596100b0565b005b60005461006e906001600160a01b031681565b6040516001600160a01b03909116815260200160405180910390f35b60015461006e906001600160a01b031681565b6100596100ab366004610164565b61012b565b6001546001600160a01b031633146100c757600080fd5b600154600080546040516001600160a01b0393841693909116917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a360018054600080546001600160a01b03199081166001600160a01b03841617909155169055565b6000546001600160a01b0316331461014257600080fd5b600180546001600160a01b0319166001600160a01b0392909216919091179055565b60006020828403121561017657600080fd5b81356001600160a01b038116811461018d57600080fd5b939250505056fea2646970667358221220099e0ef07629964c2926acd072d60ab552ff4e436a34052b97f44c2afb36e84664736f6c634300081a0033

View file

@ -0,0 +1 @@
6080604052348015600f57600080fd5b506102018061001f6000396000f3fe608060405234801561001057600080fd5b506004361061004c5760003560e01c8063a293d1e814610051578063b5931f7c14610076578063d05c78da14610089578063e6cb90131461009c575b600080fd5b61006461005f366004610134565b6100af565b60405190815260200160405180910390f35b610064610084366004610134565b6100cf565b610064610097366004610134565b6100e7565b6100646100aa366004610134565b610119565b6000828211156100be57600080fd5b6100c8828461016c565b9392505050565b60008082116100dd57600080fd5b6100c8828461017f565b60006100f382846101a1565b905082158061010a575081610108848361017f565b145b61011357600080fd5b92915050565b600061012582846101b8565b90508281101561011357600080fd5b6000806040838503121561014757600080fd5b50508035926020909101359150565b634e487b7160e01b600052601160045260246000fd5b8181038181111561011357610113610156565b60008261019c57634e487b7160e01b600052601260045260246000fd5b500490565b808202811582820484141761011357610113610156565b808201808211156101135761011361015656fea264697066735822122045f0003b01e5d932310b9838629204723acd115b8e8d8a25145a9d08e21cce6164736f6c634300081a0033

File diff suppressed because one or more lines are too long