From 81ece1ff3b470cadfb6b003864328deadc038fde Mon Sep 17 00:00:00 2001 From: The MMGen Project Date: Sun, 26 Oct 2025 10:35:54 +0000 Subject: [PATCH] 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. --- mmgen/data/version | 2 +- mmgen/proto/bch/params.py | 1 + mmgen/proto/btc/daemon.py | 2 +- mmgen/proto/btc/params.py | 2 +- mmgen/proto/btc/regtest.py | 4 ++-- mmgen/proto/btc/rpc/local.py | 22 ++++++++++++++++++++-- mmgen/proto/ltc/params.py | 1 + test/cmdtest_d/main.py | 6 ++++-- test/test-release.d/cfg.sh | 2 -- 9 files changed, 31 insertions(+), 11 deletions(-) diff --git a/mmgen/data/version b/mmgen/data/version index cc9f6d03..2ac0ff52 100644 --- a/mmgen/data/version +++ b/mmgen/data/version @@ -1 +1 @@ -16.1.dev5 +16.1.dev6 diff --git a/mmgen/proto/bch/params.py b/mmgen/proto/bch/params.py index d1851903..a28c7c70 100755 --- a/mmgen/proto/bch/params.py +++ b/mmgen/proto/bch/params.py @@ -29,6 +29,7 @@ class mainnet(mainnet): caps = () coin_amt = 'BCHAmt' max_tx_fee = 0.1 + max_op_return_data_len = 80 cashaddr_pfx = 'bitcoincash' cashaddr = True diff --git a/mmgen/proto/btc/daemon.py b/mmgen/proto/btc/daemon.py index 936f2915..107e2de2 100755 --- a/mmgen/proto/btc/daemon.py +++ b/mmgen/proto/btc/daemon.py @@ -19,7 +19,7 @@ from ...util import list_gen from ...daemon import CoinDaemon, _nw, _dd 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' cli_fn = 'bitcoin-cli' testnet_dir = 'testnet3' diff --git a/mmgen/proto/btc/params.py b/mmgen/proto/btc/params.py index 4077a7e6..3433435f 100755 --- a/mmgen/proto/btc/params.py +++ b/mmgen/proto/btc/params.py @@ -52,7 +52,7 @@ class mainnet(CoinProtocol.Secp256k1): # chainparams.cpp max_halvings = 64 start_subsidy = 50 max_int = 0xffffffff - max_op_return_data_len = 80 + max_op_return_data_len = 4096 address_reuse_ok = False coin_cfg_opts = ( diff --git a/mmgen/proto/btc/regtest.py b/mmgen/proto/btc/regtest.py index d4fefd18..daf5a2a6 100755 --- a/mmgen/proto/btc/regtest.py +++ b/mmgen/proto/btc/regtest.py @@ -76,7 +76,7 @@ class MMGenRegtest(MMGenObject): def __init__(self, cfg, coin, *, bdb_wallet=False): self.cfg = cfg 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' @@ -85,7 +85,7 @@ class MMGenRegtest(MMGenObject): cfg, network_id = self.coin + '_rt', 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, # so reinstantiate with every call: diff --git a/mmgen/proto/btc/rpc/local.py b/mmgen/proto/btc/rpc/local.py index a1d3f1d6..2df2f98a 100755 --- a/mmgen/proto/btc/rpc/local.py +++ b/mmgen/proto/btc/rpc/local.py @@ -49,8 +49,9 @@ class CallSigs: class bitcoin_core: - def __init__(self, cfg): + def __init__(self, cfg, rpc): self.cfg = cfg + self.rpc = rpc def createwallet( self, @@ -86,6 +87,10 @@ class CallSigs: # decoderawtransaction) def gettransaction(self, txid, include_watchonly, verbose): return ( + 'gettransaction', + txid, + verbose + ) if 'descriptor_wallet_only' in self.rpc.caps else ( 'gettransaction', txid, include_watchonly, @@ -109,6 +114,11 @@ class CallSigs: include_watchonly = True, include_immature_coinbase = False): return ( + 'listreceivedbylabel', + minconf, + include_empty, + include_immature_coinbase + ) if 'descriptor_wallet_only' in self.rpc.caps else ( 'listreceivedbylabel', minconf, include_empty, @@ -134,6 +144,11 @@ class CallSigs: include_watchonly = True, include_removed = True): return ( + 'listsinceblock', + blockhash, + target_confirmations, + include_removed + ) if 'descriptor_wallet_only' in self.rpc.caps else ( 'listsinceblock', blockhash, target_confirmations, @@ -197,7 +212,7 @@ class BitcoinRPCClient(RPCClient, metaclass=AsyncInit): self.proto = proto 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) super().__init__( @@ -244,6 +259,9 @@ class BitcoinRPCClient(RPCClient, metaclass=AsyncInit): self.daemon_version_str = self.cached['networkinfo']['subversion'] 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) self.cur_date = (await self.call('getblockheader', tip))['time'] if self.chain != 'regtest': diff --git a/mmgen/proto/ltc/params.py b/mmgen/proto/ltc/params.py index 7a9d53c2..d66e8e5e 100755 --- a/mmgen/proto/ltc/params.py +++ b/mmgen/proto/ltc/params.py @@ -21,6 +21,7 @@ class mainnet(mainnet): mmtypes = ('L', 'C', 'S', 'B') coin_amt = 'LTCAmt' max_tx_fee = 0.3 + max_op_return_data_len = 80 base_coin = 'LTC' forks = [] bech32_hrp = 'ltc' diff --git a/test/cmdtest_d/main.py b/test/cmdtest_d/main.py index 1c25ad29..791e6532 100755 --- a/test/cmdtest_d/main.py +++ b/test/cmdtest_d/main.py @@ -379,7 +379,7 @@ class CmdTestMain(CmdTestBase, CmdTestShared): if trunner is None or self.coin not in self.networks: return 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.unspent_data_file = joinpath('test', 'trash', 'unspent.json') @@ -417,6 +417,7 @@ class CmdTestMain(CmdTestBase, CmdTestShared): def txcreate_dfl_wallet(self, addrfile): return self.txcreate_common( sources = ['15'], + add_opts = ['--btc-max-tx-fee=0.005'], add_output_args = ['data:' + 'z' * self.proto.max_op_return_data_len]) def txsign_dfl_wallet(self, txfile, pf='', save=True, has_label=False): @@ -771,7 +772,7 @@ class CmdTestMain(CmdTestBase, CmdTestShared): def txcreate(self, addrfile): return self.txcreate_common( 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]) def txbump(self, txfile, prepend_args=[], seed_args=[]): @@ -780,6 +781,7 @@ class CmdTestMain(CmdTestBase, CmdTestShared): return 'skip' args = prepend_args + [ '--quiet', + '--btc-max-tx-fee=0.006', '--outdir='+self.tmpdir, txfile ] + seed_args diff --git a/test/test-release.d/cfg.sh b/test/test-release.d/cfg.sh index 450e8a6f..0fd37bd6 100755 --- a/test/test-release.d/cfg.sh +++ b/test/test-release.d/cfg.sh @@ -218,10 +218,8 @@ init_tests() { d_btc_rt="overall operations using the regtest network (Bitcoin, multicoin)" t_btc_rt=" - $cmdtest_py regtest - x $cmdtest_py regtest_legacy a $cmdtest_py swap " - [ "$FAST" ] && t_btc_rt_skip='x' [ "$SKIP_ALT_DEP" ] && t_btc_rt_skip+=' a' d_bch="overall operations with emulated RPC data (Bitcoin Cash Node)"