Browse Source

support Bitcoin Core v30.0

As of Core v30, legacy BDB wallets are no longer supported.  Users with legacy
tracking wallets must convert them to descriptor wallets.  See `bitcoin-cli
migratewallet` for details.

The maximum OP_RETURN data size has been increased to 4096 bytes, while the one
data output per transaction limitation has been retained.  This seems like a
reasonable compromise.  The MMGen Project discourages the use of MMGen Wallet
to spam the blockchain.
The MMGen Project 1 month ago
parent
commit
81ece1ff3b

+ 1 - 1
mmgen/data/version

@@ -1 +1 @@
-16.1.dev5
+16.1.dev6

+ 1 - 0
mmgen/proto/bch/params.py

@@ -29,6 +29,7 @@ class mainnet(mainnet):
 	caps = ()
 	caps = ()
 	coin_amt        = 'BCHAmt'
 	coin_amt        = 'BCHAmt'
 	max_tx_fee      = 0.1
 	max_tx_fee      = 0.1
+	max_op_return_data_len = 80
 	cashaddr_pfx    = 'bitcoincash'
 	cashaddr_pfx    = 'bitcoincash'
 	cashaddr        = True
 	cashaddr        = True
 
 

+ 1 - 1
mmgen/proto/btc/daemon.py

@@ -19,7 +19,7 @@ from ...util import list_gen
 from ...daemon import CoinDaemon, _nw, _dd
 from ...daemon import CoinDaemon, _nw, _dd
 
 
 class bitcoin_core_daemon(CoinDaemon):
 class bitcoin_core_daemon(CoinDaemon):
-	daemon_data = _dd('Bitcoin Core', 290100, '29.1.0')
+	daemon_data = _dd('Bitcoin Core', 300000, '30.0.0')
 	exec_fn = 'bitcoind'
 	exec_fn = 'bitcoind'
 	cli_fn = 'bitcoin-cli'
 	cli_fn = 'bitcoin-cli'
 	testnet_dir = 'testnet3'
 	testnet_dir = 'testnet3'

+ 1 - 1
mmgen/proto/btc/params.py

@@ -52,7 +52,7 @@ class mainnet(CoinProtocol.Secp256k1): # chainparams.cpp
 	max_halvings    = 64
 	max_halvings    = 64
 	start_subsidy   = 50
 	start_subsidy   = 50
 	max_int         = 0xffffffff
 	max_int         = 0xffffffff
-	max_op_return_data_len = 80
+	max_op_return_data_len = 4096
 	address_reuse_ok = False
 	address_reuse_ok = False
 
 
 	coin_cfg_opts = (
 	coin_cfg_opts = (

+ 2 - 2
mmgen/proto/btc/regtest.py

@@ -76,7 +76,7 @@ class MMGenRegtest(MMGenObject):
 	def __init__(self, cfg, coin, *, bdb_wallet=False):
 	def __init__(self, cfg, coin, *, bdb_wallet=False):
 		self.cfg = cfg
 		self.cfg = cfg
 		self.coin = coin.lower()
 		self.coin = coin.lower()
-		self.bdb_wallet = bdb_wallet
+		self.bdb_wallet = bdb_wallet and self.coin != 'btc'
 
 
 		assert self.coin in self.coins, f'{coin!r}: invalid coin for regtest'
 		assert self.coin in self.coins, f'{coin!r}: invalid coin for regtest'
 
 
@@ -85,7 +85,7 @@ class MMGenRegtest(MMGenObject):
 			cfg,
 			cfg,
 			network_id = self.coin + '_rt',
 			network_id = self.coin + '_rt',
 			test_suite = cfg.test_suite,
 			test_suite = cfg.test_suite,
-			opts       = ['bdb_wallet'] if bdb_wallet else None)
+			opts       = ['bdb_wallet'] if self.bdb_wallet else None)
 
 
 	# Caching creates problems (broken pipe) when recreating + loading wallets,
 	# Caching creates problems (broken pipe) when recreating + loading wallets,
 	# so reinstantiate with every call:
 	# so reinstantiate with every call:

+ 20 - 2
mmgen/proto/btc/rpc/local.py

@@ -49,8 +49,9 @@ class CallSigs:
 
 
 	class bitcoin_core:
 	class bitcoin_core:
 
 
-		def __init__(self, cfg):
+		def __init__(self, cfg, rpc):
 			self.cfg = cfg
 			self.cfg = cfg
+			self.rpc = rpc
 
 
 		def createwallet(
 		def createwallet(
 				self,
 				self,
@@ -86,6 +87,10 @@ class CallSigs:
 		#                         decoderawtransaction)
 		#                         decoderawtransaction)
 		def gettransaction(self, txid, include_watchonly, verbose):
 		def gettransaction(self, txid, include_watchonly, verbose):
 			return (
 			return (
+				'gettransaction',
+				txid,
+				verbose
+			) if 'descriptor_wallet_only' in self.rpc.caps else (
 				'gettransaction',
 				'gettransaction',
 				txid,
 				txid,
 				include_watchonly,
 				include_watchonly,
@@ -109,6 +114,11 @@ class CallSigs:
 				include_watchonly = True,
 				include_watchonly = True,
 				include_immature_coinbase = False):
 				include_immature_coinbase = False):
 			return (
 			return (
+				'listreceivedbylabel',
+				minconf,
+				include_empty,
+				include_immature_coinbase
+			) if 'descriptor_wallet_only' in self.rpc.caps else (
 				'listreceivedbylabel',
 				'listreceivedbylabel',
 				minconf,
 				minconf,
 				include_empty,
 				include_empty,
@@ -134,6 +144,11 @@ class CallSigs:
 				include_watchonly = True,
 				include_watchonly = True,
 				include_removed = True):
 				include_removed = True):
 			return (
 			return (
+				'listsinceblock',
+				blockhash,
+				target_confirmations,
+				include_removed
+			) if 'descriptor_wallet_only' in self.rpc.caps else (
 				'listsinceblock',
 				'listsinceblock',
 				blockhash,
 				blockhash,
 				target_confirmations,
 				target_confirmations,
@@ -197,7 +212,7 @@ class BitcoinRPCClient(RPCClient, metaclass=AsyncInit):
 
 
 		self.proto = proto
 		self.proto = proto
 		self.daemon = daemon
 		self.daemon = daemon
-		self.call_sigs = getattr(CallSigs, daemon.id)(cfg)
+		self.call_sigs = getattr(CallSigs, daemon.id)(cfg, self)
 		self.twname = TrackingWalletName(cfg.regtest_user or proto.tw_name or cfg.tw_name or self.dfl_twname)
 		self.twname = TrackingWalletName(cfg.regtest_user or proto.tw_name or cfg.tw_name or self.dfl_twname)
 
 
 		super().__init__(
 		super().__init__(
@@ -244,6 +259,9 @@ class BitcoinRPCClient(RPCClient, metaclass=AsyncInit):
 		self.daemon_version_str = self.cached['networkinfo']['subversion']
 		self.daemon_version_str = self.cached['networkinfo']['subversion']
 		self.chain = self.cached['blockchaininfo']['chain']
 		self.chain = self.cached['blockchaininfo']['chain']
 
 
+		if self.daemon.id == 'bitcoin_core' and self.daemon_version >= 300000:
+			self.caps += ('descriptor_wallet_only',)
+
 		tip = await self.call('getblockhash', self.blockcount)
 		tip = await self.call('getblockhash', self.blockcount)
 		self.cur_date = (await self.call('getblockheader', tip))['time']
 		self.cur_date = (await self.call('getblockheader', tip))['time']
 		if self.chain != 'regtest':
 		if self.chain != 'regtest':

+ 1 - 0
mmgen/proto/ltc/params.py

@@ -21,6 +21,7 @@ class mainnet(mainnet):
 	mmtypes         = ('L', 'C', 'S', 'B')
 	mmtypes         = ('L', 'C', 'S', 'B')
 	coin_amt        = 'LTCAmt'
 	coin_amt        = 'LTCAmt'
 	max_tx_fee      = 0.3
 	max_tx_fee      = 0.3
+	max_op_return_data_len = 80
 	base_coin       = 'LTC'
 	base_coin       = 'LTC'
 	forks           = []
 	forks           = []
 	bech32_hrp      = 'ltc'
 	bech32_hrp      = 'ltc'

+ 4 - 2
test/cmdtest_d/main.py

@@ -379,7 +379,7 @@ class CmdTestMain(CmdTestBase, CmdTestShared):
 		if trunner is None or self.coin not in self.networks:
 		if trunner is None or self.coin not in self.networks:
 			return
 			return
 		if self.coin in ('btc', 'bch', 'ltc'):
 		if self.coin in ('btc', 'bch', 'ltc'):
-			self.tx_fee     = {'btc':'0.0001', 'bch':'0.001', 'ltc':'0.01'}[self.coin]
+			self.tx_fee     = {'btc':'90s', 'bch':'0.001', 'ltc':'0.01'}[self.coin]
 			self.txbump_fee = {'btc':'123s', 'bch':'567s', 'ltc':'12345s'}[self.coin]
 			self.txbump_fee = {'btc':'123s', 'bch':'567s', 'ltc':'12345s'}[self.coin]
 
 
 		self.unspent_data_file = joinpath('test', 'trash', 'unspent.json')
 		self.unspent_data_file = joinpath('test', 'trash', 'unspent.json')
@@ -417,6 +417,7 @@ class CmdTestMain(CmdTestBase, CmdTestShared):
 	def txcreate_dfl_wallet(self, addrfile):
 	def txcreate_dfl_wallet(self, addrfile):
 		return self.txcreate_common(
 		return self.txcreate_common(
 			sources = ['15'],
 			sources = ['15'],
+			add_opts = ['--btc-max-tx-fee=0.005'],
 			add_output_args = ['data:' + 'z' * self.proto.max_op_return_data_len])
 			add_output_args = ['data:' + 'z' * self.proto.max_op_return_data_len])
 
 
 	def txsign_dfl_wallet(self, txfile, pf='', save=True, has_label=False):
 	def txsign_dfl_wallet(self, txfile, pf='', save=True, has_label=False):
@@ -771,7 +772,7 @@ class CmdTestMain(CmdTestBase, CmdTestShared):
 	def txcreate(self, addrfile):
 	def txcreate(self, addrfile):
 		return self.txcreate_common(
 		return self.txcreate_common(
 			sources = ['1'],
 			sources = ['1'],
-			add_opts = ['--vsize-adj=1.01'],
+			add_opts = ['--vsize-adj=1.01', '--btc-max-tx-fee=0.005'],
 			add_output_args = ['hexdata:' + 'ee' * self.proto.max_op_return_data_len])
 			add_output_args = ['hexdata:' + 'ee' * self.proto.max_op_return_data_len])
 
 
 	def txbump(self, txfile, prepend_args=[], seed_args=[]):
 	def txbump(self, txfile, prepend_args=[], seed_args=[]):
@@ -780,6 +781,7 @@ class CmdTestMain(CmdTestBase, CmdTestShared):
 			return 'skip'
 			return 'skip'
 		args = prepend_args + [
 		args = prepend_args + [
 			'--quiet',
 			'--quiet',
+			'--btc-max-tx-fee=0.006',
 			'--outdir='+self.tmpdir,
 			'--outdir='+self.tmpdir,
 			txfile
 			txfile
 			] + seed_args
 			] + seed_args

+ 0 - 2
test/test-release.d/cfg.sh

@@ -218,10 +218,8 @@ init_tests() {
 	d_btc_rt="overall operations using the regtest network (Bitcoin, multicoin)"
 	d_btc_rt="overall operations using the regtest network (Bitcoin, multicoin)"
 	t_btc_rt="
 	t_btc_rt="
 		- $cmdtest_py regtest
 		- $cmdtest_py regtest
-		x $cmdtest_py regtest_legacy
 		a $cmdtest_py swap
 		a $cmdtest_py swap
 	"
 	"
-	[ "$FAST" ] && t_btc_rt_skip='x'
 	[ "$SKIP_ALT_DEP" ] && t_btc_rt_skip+=' a'
 	[ "$SKIP_ALT_DEP" ] && t_btc_rt_skip+=' a'
 
 
 	d_bch="overall operations with emulated RPC data (Bitcoin Cash Node)"
 	d_bch="overall operations with emulated RPC data (Bitcoin Cash Node)"