Browse Source

support Rust Ethereum client (Reth)

Tested on Linux only

Testing:

    $ test/cmdtest.py --coin=eth --daemon-id=reth ethdev
The MMGen Project 2 days ago
parent
commit
1e422b2c2b

+ 1 - 0
MANIFEST.in

@@ -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

+ 1 - 1
mmgen/daemon.py

@@ -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']),
 	}
 

+ 1 - 1
mmgen/data/version

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

+ 12 - 2
mmgen/proto/eth/daemon.py

@@ -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')

+ 2 - 0
mmgen/proto/eth/params.py

@@ -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 = (

+ 5 - 1
mmgen/proto/eth/rpc.py

@@ -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',)

+ 1 - 1
mmgen/proto/eth/tx/status.py

@@ -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

+ 41 - 6
test/cmdtest_d/ct_ethdev.py

@@ -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
 

+ 1 - 1
test/daemontest_d/ut_rpc.py

@@ -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):

+ 0 - 0
test/ref/ethereum/bin/mm1/ERC20Interface.bin → test/ref/ethereum/bin/geth/mm1/ERC20Interface.bin


+ 0 - 0
test/ref/ethereum/bin/mm1/Owned.bin → test/ref/ethereum/bin/geth/mm1/Owned.bin


+ 0 - 0
test/ref/ethereum/bin/mm1/SafeMath.bin → test/ref/ethereum/bin/geth/mm1/SafeMath.bin


+ 0 - 0
test/ref/ethereum/bin/mm1/Token.bin → test/ref/ethereum/bin/geth/mm1/Token.bin


+ 0 - 0
test/ref/ethereum/bin/mm2/ERC20Interface.bin → test/ref/ethereum/bin/geth/mm2/ERC20Interface.bin


+ 0 - 0
test/ref/ethereum/bin/mm2/Owned.bin → test/ref/ethereum/bin/geth/mm2/Owned.bin


+ 0 - 0
test/ref/ethereum/bin/mm2/SafeMath.bin → test/ref/ethereum/bin/geth/mm2/SafeMath.bin


+ 0 - 0
test/ref/ethereum/bin/mm2/Token.bin → test/ref/ethereum/bin/geth/mm2/Token.bin


+ 0 - 0
test/ref/ethereum/bin/reth/mm1/ERC20Interface.bin


+ 1 - 0
test/ref/ethereum/bin/reth/mm1/Owned.bin

@@ -0,0 +1 @@
+6080604052348015600f57600080fd5b50600080546001600160a01b031916331790556101ca806100316000396000f3fe608060405234801561001057600080fd5b506004361061004c5760003560e01c806379ba5097146100515780638da5cb5b1461005b578063d4ee1d901461008a578063f2fde38b1461009d575b600080fd5b6100596100b0565b005b60005461006e906001600160a01b031681565b6040516001600160a01b03909116815260200160405180910390f35b60015461006e906001600160a01b031681565b6100596100ab366004610164565b61012b565b6001546001600160a01b031633146100c757600080fd5b600154600080546040516001600160a01b0393841693909116917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a360018054600080546001600160a01b03199081166001600160a01b03841617909155169055565b6000546001600160a01b0316331461014257600080fd5b600180546001600160a01b0319166001600160a01b0392909216919091179055565b60006020828403121561017657600080fd5b81356001600160a01b038116811461018d57600080fd5b939250505056fea2646970667358221220bcd3e32a06d3bc97ce1339e72449373355373643c31c80385ca5f89938aca39c64736f6c634300081a0033

+ 1 - 0
test/ref/ethereum/bin/reth/mm1/SafeMath.bin

@@ -0,0 +1 @@
+6080604052348015600f57600080fd5b506102018061001f6000396000f3fe608060405234801561001057600080fd5b506004361061004c5760003560e01c8063a293d1e814610051578063b5931f7c14610076578063d05c78da14610089578063e6cb90131461009c575b600080fd5b61006461005f366004610134565b6100af565b60405190815260200160405180910390f35b610064610084366004610134565b6100cf565b610064610097366004610134565b6100e7565b6100646100aa366004610134565b610119565b6000828211156100be57600080fd5b6100c8828461016c565b9392505050565b60008082116100dd57600080fd5b6100c8828461017f565b60006100f382846101a1565b905082158061010a575081610108848361017f565b145b61011357600080fd5b92915050565b600061012582846101b8565b90508281101561011357600080fd5b6000806040838503121561014757600080fd5b50508035926020909101359150565b634e487b7160e01b600052601160045260246000fd5b8181038181111561011357610113610156565b60008261019c57634e487b7160e01b600052601260045260246000fd5b500490565b808202811582820484141761011357610113610156565b808201808211156101135761011361015656fea264697066735822122081e009254874ff32aa4fa09f9d8a315bf6a4e9e870bfb5d8b4e6611f659ed84964736f6c634300081a0033

File diff suppressed because it is too large
+ 0 - 0
test/ref/ethereum/bin/reth/mm1/Token.bin


+ 0 - 0
test/ref/ethereum/bin/reth/mm2/ERC20Interface.bin


+ 1 - 0
test/ref/ethereum/bin/reth/mm2/Owned.bin

@@ -0,0 +1 @@
+6080604052348015600f57600080fd5b50600080546001600160a01b031916331790556101ca806100316000396000f3fe608060405234801561001057600080fd5b506004361061004c5760003560e01c806379ba5097146100515780638da5cb5b1461005b578063d4ee1d901461008a578063f2fde38b1461009d575b600080fd5b6100596100b0565b005b60005461006e906001600160a01b031681565b6040516001600160a01b03909116815260200160405180910390f35b60015461006e906001600160a01b031681565b6100596100ab366004610164565b61012b565b6001546001600160a01b031633146100c757600080fd5b600154600080546040516001600160a01b0393841693909116917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a360018054600080546001600160a01b03199081166001600160a01b03841617909155169055565b6000546001600160a01b0316331461014257600080fd5b600180546001600160a01b0319166001600160a01b0392909216919091179055565b60006020828403121561017657600080fd5b81356001600160a01b038116811461018d57600080fd5b939250505056fea2646970667358221220099e0ef07629964c2926acd072d60ab552ff4e436a34052b97f44c2afb36e84664736f6c634300081a0033

+ 1 - 0
test/ref/ethereum/bin/reth/mm2/SafeMath.bin

@@ -0,0 +1 @@
+6080604052348015600f57600080fd5b506102018061001f6000396000f3fe608060405234801561001057600080fd5b506004361061004c5760003560e01c8063a293d1e814610051578063b5931f7c14610076578063d05c78da14610089578063e6cb90131461009c575b600080fd5b61006461005f366004610134565b6100af565b60405190815260200160405180910390f35b610064610084366004610134565b6100cf565b610064610097366004610134565b6100e7565b6100646100aa366004610134565b610119565b6000828211156100be57600080fd5b6100c8828461016c565b9392505050565b60008082116100dd57600080fd5b6100c8828461017f565b60006100f382846101a1565b905082158061010a575081610108848361017f565b145b61011357600080fd5b92915050565b600061012582846101b8565b90508281101561011357600080fd5b6000806040838503121561014757600080fd5b50508035926020909101359150565b634e487b7160e01b600052601160045260246000fd5b8181038181111561011357610113610156565b60008261019c57634e487b7160e01b600052601260045260246000fd5b500490565b808202811582820484141761011357610113610156565b808201808211156101135761011361015656fea264697066735822122045f0003b01e5d932310b9838629204723acd115b8e8d8a25145a9d08e21cce6164736f6c634300081a0033

File diff suppressed because it is too large
+ 0 - 0
test/ref/ethereum/bin/reth/mm2/Token.bin


Some files were not shown because too many files changed in this diff