aboutsummaryrefslogtreecommitdiff
path: root/test
diff options
context:
space:
mode:
Diffstat (limited to 'test')
-rw-r--r--test/functional/data/rpc_decodescript.json2
-rwxr-xr-xtest/functional/mining_basic.py46
-rwxr-xr-xtest/functional/rpc_decodescript.py2
-rwxr-xr-xtest/functional/test_framework/test_node.py11
-rwxr-xr-xtest/functional/wallet_bumpfee.py77
-rwxr-xr-xtest/functional/wallet_migration.py50
-rwxr-xr-xtest/functional/wallet_resendwallettransactions.py8
-rwxr-xr-xtest/fuzz/test_runner.py49
8 files changed, 224 insertions, 21 deletions
diff --git a/test/functional/data/rpc_decodescript.json b/test/functional/data/rpc_decodescript.json
index 5f3e725d4c..4a15ae8792 100644
--- a/test/functional/data/rpc_decodescript.json
+++ b/test/functional/data/rpc_decodescript.json
@@ -69,7 +69,7 @@
"p2sh": "2N34iiGoUUkVSPiaaTFpJjB1FR9TXQu3PGM",
"segwit": {
"asm": "0 96c2368fc30514a438a8bd909f93c49a1549d77198ccbdb792043b666cb24f42",
- "desc": "wsh(raw(02eeee))#gtay4y0z",
+ "desc": "addr(bcrt1qjmprdr7rq522gw9ghkgfly7yng25n4m3nrxtmdujqsakvm9jfapqk795l5)#5akkdska",
"hex": "002096c2368fc30514a438a8bd909f93c49a1549d77198ccbdb792043b666cb24f42",
"address": "bcrt1qjmprdr7rq522gw9ghkgfly7yng25n4m3nrxtmdujqsakvm9jfapqk795l5",
"type": "witness_v0_scripthash",
diff --git a/test/functional/mining_basic.py b/test/functional/mining_basic.py
index aabf06ee53..56cd615dac 100755
--- a/test/functional/mining_basic.py
+++ b/test/functional/mining_basic.py
@@ -18,9 +18,10 @@ from test_framework.blocktools import (
TIME_GENESIS_BLOCK,
)
from test_framework.messages import (
+ BLOCK_HEADER_SIZE,
CBlock,
CBlockHeader,
- BLOCK_HEADER_SIZE,
+ COIN,
ser_uint256,
)
from test_framework.p2p import P2PDataStore
@@ -28,12 +29,14 @@ from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import (
assert_equal,
assert_raises_rpc_error,
+ get_fee,
)
from test_framework.wallet import MiniWallet
VERSIONBITS_TOP_BITS = 0x20000000
VERSIONBITS_DEPLOYMENT_TESTDUMMY_BIT = 28
+DEFAULT_BLOCK_MIN_TX_FEE = 1000 # default `-blockmintxfee` setting [sat/kvB]
def assert_template(node, block, expect, rehash=True):
@@ -73,6 +76,45 @@ class MiningTest(BitcoinTestFramework):
self.restart_node(0)
self.connect_nodes(0, 1)
+ def test_blockmintxfee_parameter(self):
+ self.log.info("Test -blockmintxfee setting")
+ self.restart_node(0, extra_args=['-minrelaytxfee=0', '-persistmempool=0'])
+ node = self.nodes[0]
+
+ # test default (no parameter), zero and a bunch of arbitrary blockmintxfee rates [sat/kvB]
+ for blockmintxfee_sat_kvb in (DEFAULT_BLOCK_MIN_TX_FEE, 0, 50, 100, 500, 2500, 5000, 21000, 333333, 2500000):
+ blockmintxfee_btc_kvb = blockmintxfee_sat_kvb / Decimal(COIN)
+ if blockmintxfee_sat_kvb == DEFAULT_BLOCK_MIN_TX_FEE:
+ self.log.info(f"-> Default -blockmintxfee setting ({blockmintxfee_sat_kvb} sat/kvB)...")
+ else:
+ blockmintxfee_parameter = f"-blockmintxfee={blockmintxfee_btc_kvb:.8f}"
+ self.log.info(f"-> Test {blockmintxfee_parameter} ({blockmintxfee_sat_kvb} sat/kvB)...")
+ self.restart_node(0, extra_args=[blockmintxfee_parameter, '-minrelaytxfee=0', '-persistmempool=0'])
+ self.wallet.rescan_utxos() # to avoid spending outputs of txs that are not in mempool anymore after restart
+
+ # submit one tx with exactly the blockmintxfee rate, and one slightly below
+ tx_with_min_feerate = self.wallet.send_self_transfer(from_node=node, fee_rate=blockmintxfee_btc_kvb)
+ assert_equal(tx_with_min_feerate["fee"], get_fee(tx_with_min_feerate["tx"].get_vsize(), blockmintxfee_btc_kvb))
+ if blockmintxfee_btc_kvb > 0:
+ lowerfee_btc_kvb = blockmintxfee_btc_kvb - Decimal(10)/COIN # 0.01 sat/vbyte lower
+ tx_below_min_feerate = self.wallet.send_self_transfer(from_node=node, fee_rate=lowerfee_btc_kvb)
+ assert_equal(tx_below_min_feerate["fee"], get_fee(tx_below_min_feerate["tx"].get_vsize(), lowerfee_btc_kvb))
+ else: # go below zero fee by using modified fees
+ tx_below_min_feerate = self.wallet.send_self_transfer(from_node=node, fee_rate=blockmintxfee_btc_kvb)
+ node.prioritisetransaction(tx_below_min_feerate["txid"], 0, -1)
+
+ # check that tx below specified fee-rate is neither in template nor in the actual block
+ block_template = node.getblocktemplate(NORMAL_GBT_REQUEST_PARAMS)
+ block_template_txids = [tx['txid'] for tx in block_template['transactions']]
+ self.generate(self.wallet, 1, sync_fun=self.no_op)
+ block = node.getblock(node.getbestblockhash(), verbosity=2)
+ block_txids = [tx['txid'] for tx in block['tx']]
+
+ assert tx_with_min_feerate['txid'] in block_template_txids
+ assert tx_with_min_feerate['txid'] in block_txids
+ assert tx_below_min_feerate['txid'] not in block_template_txids
+ assert tx_below_min_feerate['txid'] not in block_txids
+
def run_test(self):
node = self.nodes[0]
self.wallet = MiniWallet(node)
@@ -279,6 +321,8 @@ class MiningTest(BitcoinTestFramework):
node.submitheader(hexdata=CBlockHeader(bad_block_root).serialize().hex())
assert_equal(node.submitblock(hexdata=block.serialize().hex()), 'duplicate') # valid
+ self.test_blockmintxfee_parameter()
+
if __name__ == '__main__':
MiningTest().main()
diff --git a/test/functional/rpc_decodescript.py b/test/functional/rpc_decodescript.py
index 673836bd04..f37e61ab50 100755
--- a/test/functional/rpc_decodescript.py
+++ b/test/functional/rpc_decodescript.py
@@ -271,7 +271,7 @@ class DecodeScriptTest(BitcoinTestFramework):
assert res["segwit"]["desc"] == "wsh(and_v(and_v(v:hash160(ffffffffffffffffffffffffffffffffffffffff),v:pk(0250929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac0)),older(1)))#gm8xz4fl"
# Miniscript-incompatible offered HTLC
res = self.nodes[0].decodescript("82012088a914ffffffffffffffffffffffffffffffffffffffff882102ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffacb2")
- assert res["segwit"]["desc"] == "wsh(raw(82012088a914ffffffffffffffffffffffffffffffffffffffff882102ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffacb2))#ra6w2xa7"
+ assert res["segwit"]["desc"] == "addr(bcrt1q73qyfypp47hvgnkjqnav0j3k2lq3v76wg22dk8tmwuz5sfgv66xsvxg6uu)#9p3q328s"
# Miniscript-compatible multisig bigger than 520 byte P2SH limit.
res = self.nodes[0].decodescript("5b21020e0338c96a8870479f2396c373cc7696ba124e8635d41b0ea581112b678172612102675333a4e4b8fb51d9d4e22fa5a8eaced3fdac8a8cbf9be8c030f75712e6af992102896807d54bc55c24981f24a453c60ad3e8993d693732288068a23df3d9f50d4821029e51a5ef5db3137051de8323b001749932f2ff0d34c82e96a2c2461de96ae56c2102a4e1a9638d46923272c266631d94d36bdb03a64ee0e14c7518e49d2f29bc401021031c41fdbcebe17bec8d49816e00ca1b5ac34766b91c9f2ac37d39c63e5e008afb2103079e252e85abffd3c401a69b087e590a9b86f33f574f08129ccbd3521ecf516b2103111cf405b627e22135b3b3733a4a34aa5723fb0f58379a16d32861bf576b0ec2210318f331b3e5d38156da6633b31929c5b220349859cc9ca3d33fb4e68aa08401742103230dae6b4ac93480aeab26d000841298e3b8f6157028e47b0897c1e025165de121035abff4281ff00660f99ab27bb53e6b33689c2cd8dcd364bc3c90ca5aea0d71a62103bd45cddfacf2083b14310ae4a84e25de61e451637346325222747b157446614c2103cc297026b06c71cbfa52089149157b5ff23de027ac5ab781800a578192d175462103d3bde5d63bdb3a6379b461be64dad45eabff42f758543a9645afd42f6d4248282103ed1e8d5109c9ed66f7941bc53cc71137baa76d50d274bda8d5e8ffbd6e61fe9a5fae736402c00fb269522103aab896d53a8e7d6433137bbba940f9c521e085dd07e60994579b64a6d992cf79210291b7d0b1b692f8f524516ed950872e5da10fb1b808b5a526dedc6fed1cf29807210386aa9372fbab374593466bc5451dc59954e90787f08060964d95c87ef34ca5bb53ae68")
assert_equal(res["segwit"]["desc"], "wsh(or_d(multi(11,020e0338c96a8870479f2396c373cc7696ba124e8635d41b0ea581112b67817261,02675333a4e4b8fb51d9d4e22fa5a8eaced3fdac8a8cbf9be8c030f75712e6af99,02896807d54bc55c24981f24a453c60ad3e8993d693732288068a23df3d9f50d48,029e51a5ef5db3137051de8323b001749932f2ff0d34c82e96a2c2461de96ae56c,02a4e1a9638d46923272c266631d94d36bdb03a64ee0e14c7518e49d2f29bc4010,031c41fdbcebe17bec8d49816e00ca1b5ac34766b91c9f2ac37d39c63e5e008afb,03079e252e85abffd3c401a69b087e590a9b86f33f574f08129ccbd3521ecf516b,03111cf405b627e22135b3b3733a4a34aa5723fb0f58379a16d32861bf576b0ec2,0318f331b3e5d38156da6633b31929c5b220349859cc9ca3d33fb4e68aa0840174,03230dae6b4ac93480aeab26d000841298e3b8f6157028e47b0897c1e025165de1,035abff4281ff00660f99ab27bb53e6b33689c2cd8dcd364bc3c90ca5aea0d71a6,03bd45cddfacf2083b14310ae4a84e25de61e451637346325222747b157446614c,03cc297026b06c71cbfa52089149157b5ff23de027ac5ab781800a578192d17546,03d3bde5d63bdb3a6379b461be64dad45eabff42f758543a9645afd42f6d424828,03ed1e8d5109c9ed66f7941bc53cc71137baa76d50d274bda8d5e8ffbd6e61fe9a),and_v(v:older(4032),multi(2,03aab896d53a8e7d6433137bbba940f9c521e085dd07e60994579b64a6d992cf79,0291b7d0b1b692f8f524516ed950872e5da10fb1b808b5a526dedc6fed1cf29807,0386aa9372fbab374593466bc5451dc59954e90787f08060964d95c87ef34ca5bb))))#7jwwklk4")
diff --git a/test/functional/test_framework/test_node.py b/test/functional/test_framework/test_node.py
index 56087013fb..1fcef6ce1c 100755
--- a/test/functional/test_framework/test_node.py
+++ b/test/functional/test_framework/test_node.py
@@ -644,10 +644,13 @@ class TestNode():
# in comparison to the upside of making tests less fragile and unexpected intermittent errors less likely.
p2p_conn.sync_with_ping()
- # Consistency check that the Bitcoin Core has received our user agent string. This checks the
- # node's newest peer. It could be racy if another Bitcoin Core node has connected since we opened
- # our connection, but we don't expect that to happen.
- assert_equal(self.getpeerinfo()[-1]['subver'], P2P_SUBVERSION)
+ # Consistency check that the node received our user agent string.
+ # Find our connection in getpeerinfo by our address:port, as it is unique.
+ sockname = p2p_conn._transport.get_extra_info("socket").getsockname()
+ our_addr_and_port = f"{sockname[0]}:{sockname[1]}"
+ info = [peer for peer in self.getpeerinfo() if peer["addr"] == our_addr_and_port]
+ assert_equal(len(info), 1)
+ assert_equal(info[0]["subver"], P2P_SUBVERSION)
return p2p_conn
diff --git a/test/functional/wallet_bumpfee.py b/test/functional/wallet_bumpfee.py
index b9ebf64c22..4bc01f3035 100755
--- a/test/functional/wallet_bumpfee.py
+++ b/test/functional/wallet_bumpfee.py
@@ -24,9 +24,11 @@ from test_framework.messages import (
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import (
assert_equal,
+ assert_fee_amount,
assert_greater_than,
assert_raises_rpc_error,
get_fee,
+ find_vout_for_address,
)
from test_framework.wallet import MiniWallet
@@ -109,6 +111,8 @@ class BumpFeeTest(BitcoinTestFramework):
test_small_output_with_feerate_succeeds(self, rbf_node, dest_address)
test_no_more_inputs_fails(self, rbf_node, dest_address)
self.test_bump_back_to_yourself()
+ self.test_provided_change_pos(rbf_node)
+ self.test_single_output()
# Context independent tests
test_feerate_checks_replaced_outputs(self, rbf_node, peer_node)
@@ -174,6 +178,13 @@ class BumpFeeTest(BitcoinTestFramework):
assert_raises_rpc_error(-8, "Invalid parameter, duplicate key: data",
rbf_node.bumpfee, rbfid, {"outputs": [{"data": "deadbeef"}, {"data": "deadbeef"}]})
+ self.log.info("Test reduce_output option")
+ assert_raises_rpc_error(-1, "JSON integer out of range", rbf_node.bumpfee, rbfid, {"reduce_output": -1})
+ assert_raises_rpc_error(-8, "Change position is out of range", rbf_node.bumpfee, rbfid, {"reduce_output": 2})
+
+ self.log.info("Test outputs and reduce_output cannot both be provided")
+ assert_raises_rpc_error(-8, "Cannot specify both new outputs to use and an output index to reduce", rbf_node.bumpfee, rbfid, {"reduce_output": 2, "outputs": [{dest_address: 0.1}]})
+
self.clear_mempool()
def test_bump_back_to_yourself(self):
@@ -225,6 +236,72 @@ class BumpFeeTest(BitcoinTestFramework):
node.unloadwallet("back_to_yourself")
+ def test_provided_change_pos(self, rbf_node):
+ self.log.info("Test the reduce_output option")
+
+ change_addr = rbf_node.getnewaddress()
+ dest_addr = rbf_node.getnewaddress()
+ assert_equal(rbf_node.getaddressinfo(change_addr)["ischange"], False)
+ assert_equal(rbf_node.getaddressinfo(dest_addr)["ischange"], False)
+
+ send_res = rbf_node.send(outputs=[{dest_addr: 1}], options={"change_address": change_addr})
+ assert send_res["complete"]
+ txid = send_res["txid"]
+
+ tx = rbf_node.gettransaction(txid=txid, verbose=True)
+ assert_equal(len(tx["decoded"]["vout"]), 2)
+
+ change_pos = find_vout_for_address(rbf_node, txid, change_addr)
+ change_value = tx["decoded"]["vout"][change_pos]["value"]
+
+ bumped = rbf_node.bumpfee(txid, {"reduce_output": change_pos})
+ new_txid = bumped["txid"]
+
+ new_tx = rbf_node.gettransaction(txid=new_txid, verbose=True)
+ assert_equal(len(new_tx["decoded"]["vout"]), 2)
+ new_change_pos = find_vout_for_address(rbf_node, new_txid, change_addr)
+ new_change_value = new_tx["decoded"]["vout"][new_change_pos]["value"]
+
+ assert_greater_than(change_value, new_change_value)
+
+
+ def test_single_output(self):
+ self.log.info("Test that single output txs can be bumped")
+ node = self.nodes[1]
+
+ node.createwallet("single_out_rbf")
+ wallet = node.get_wallet_rpc("single_out_rbf")
+
+ addr = wallet.getnewaddress()
+ amount = Decimal("0.001")
+ # Make 2 UTXOs
+ self.nodes[0].sendtoaddress(addr, amount)
+ self.nodes[0].sendtoaddress(addr, amount)
+ self.generate(self.nodes[0], 1)
+ utxos = wallet.listunspent()
+
+ tx = wallet.sendall(recipients=[wallet.getnewaddress()], fee_rate=2, options={"inputs": [utxos[0]]})
+
+ # Reduce the only output with a crazy high feerate, should fail as the output would be dust
+ assert_raises_rpc_error(-4, "The transaction amount is too small to pay the fee", wallet.bumpfee, txid=tx["txid"], options={"fee_rate": 1100, "reduce_output": 0})
+
+ # Reduce the only output successfully
+ bumped = wallet.bumpfee(txid=tx["txid"], options={"fee_rate": 10, "reduce_output": 0})
+ bumped_tx = wallet.gettransaction(txid=bumped["txid"], verbose=True)
+ assert_equal(len(bumped_tx["decoded"]["vout"]), 1)
+ assert_equal(len(bumped_tx["decoded"]["vin"]), 1)
+ assert_equal(bumped_tx["decoded"]["vout"][0]["value"] + bumped["fee"], amount)
+ assert_fee_amount(bumped["fee"], bumped_tx["decoded"]["vsize"], Decimal(10) / Decimal(1e8) * 1000)
+
+ # Bumping without reducing adds a new input and output
+ bumped = wallet.bumpfee(txid=bumped["txid"], options={"fee_rate": 20})
+ bumped_tx = wallet.gettransaction(txid=bumped["txid"], verbose=True)
+ assert_equal(len(bumped_tx["decoded"]["vout"]), 2)
+ assert_equal(len(bumped_tx["decoded"]["vin"]), 2)
+ assert_fee_amount(bumped["fee"], bumped_tx["decoded"]["vsize"], Decimal(20) / Decimal(1e8) * 1000)
+
+ wallet.unloadwallet()
+
def test_simple_bumpfee_succeeds(self, mode, rbf_node, peer_node, dest_address):
self.log.info('Test simple bumpfee: {}'.format(mode))
rbfid = spend_one_input(rbf_node, dest_address)
diff --git a/test/functional/wallet_migration.py b/test/functional/wallet_migration.py
index 278ef1ec87..925376e8cd 100755
--- a/test/functional/wallet_migration.py
+++ b/test/functional/wallet_migration.py
@@ -8,6 +8,8 @@ import random
import shutil
from test_framework.descriptors import descsum_create
from test_framework.test_framework import BitcoinTestFramework
+from test_framework.messages import COIN, CTransaction, CTxOut
+from test_framework.script_util import key_to_p2pkh_script, script_to_p2sh_script, script_to_p2wsh_script
from test_framework.util import (
assert_equal,
assert_raises_rpc_error,
@@ -639,6 +641,53 @@ class WalletMigrationTest(BitcoinTestFramework):
for addr_info in [addr_external, addr_external_with_label]:
check(addr_info, wallet_solvables)
+ def test_migrate_raw_p2sh(self):
+ self.log.info("Test migration of watch-only raw p2sh script")
+ df_wallet = self.nodes[0].get_wallet_rpc(self.default_wallet_name)
+ wallet = self.create_legacy_wallet("raw_p2sh")
+
+ def send_to_script(script, amount):
+ tx = CTransaction()
+ tx.vout.append(CTxOut(nValue=amount*COIN, scriptPubKey=script))
+
+ hex_tx = df_wallet.fundrawtransaction(tx.serialize().hex())['hex']
+ signed_tx = df_wallet.signrawtransactionwithwallet(hex_tx)
+ df_wallet.sendrawtransaction(signed_tx['hex'])
+ self.generate(self.nodes[0], 1)
+
+ # Craft sh(pkh(key)) script and send coins to it
+ pubkey = df_wallet.getaddressinfo(df_wallet.getnewaddress())["pubkey"]
+ script_pkh = key_to_p2pkh_script(pubkey)
+ script_sh_pkh = script_to_p2sh_script(script_pkh)
+ send_to_script(script=script_sh_pkh, amount=2)
+
+ # Import script and check balance
+ wallet.rpc.importaddress(address=script_pkh.hex(), label="raw_spk", rescan=True, p2sh=True)
+ assert_equal(wallet.getbalances()['watchonly']['trusted'], 2)
+
+ # Craft wsh(pkh(key)) and send coins to it
+ pubkey = df_wallet.getaddressinfo(df_wallet.getnewaddress())["pubkey"]
+ script_wsh_pkh = script_to_p2wsh_script(key_to_p2pkh_script(pubkey))
+ send_to_script(script=script_wsh_pkh, amount=3)
+
+ # Import script and check balance
+ wallet.rpc.importaddress(address=script_wsh_pkh.hex(), label="raw_spk2", rescan=True, p2sh=False)
+ assert_equal(wallet.getbalances()['watchonly']['trusted'], 5)
+
+ # Migrate wallet and re-check balance
+ info_migration = wallet.migratewallet()
+ wallet_wo = self.nodes[0].get_wallet_rpc(info_migration["watchonly_name"])
+
+ # Watch-only balance is under "mine".
+ assert_equal(wallet_wo.getbalances()['mine']['trusted'], 5)
+ # The watch-only scripts are no longer part of the main wallet
+ assert_equal(wallet.getbalances()['mine']['trusted'], 0)
+
+ # Just in case, also verify wallet restart
+ self.nodes[0].unloadwallet(info_migration["watchonly_name"])
+ self.nodes[0].loadwallet(info_migration["watchonly_name"])
+ assert_equal(wallet_wo.getbalances()['mine']['trusted'], 5)
+
def run_test(self):
self.generate(self.nodes[0], 101)
@@ -654,6 +703,7 @@ class WalletMigrationTest(BitcoinTestFramework):
self.test_default_wallet()
self.test_direct_file()
self.test_addressbook()
+ self.test_migrate_raw_p2sh()
if __name__ == '__main__':
WalletMigrationTest().main()
diff --git a/test/functional/wallet_resendwallettransactions.py b/test/functional/wallet_resendwallettransactions.py
index 7bdb6f5e3a..f36d8efda7 100755
--- a/test/functional/wallet_resendwallettransactions.py
+++ b/test/functional/wallet_resendwallettransactions.py
@@ -108,9 +108,13 @@ class ResendWalletTransactionsTest(BitcoinTestFramework):
# Set correct m_best_block_time, which is used in ResubmitWalletTransactions
node.syncwithvalidationinterfacequeue()
- # Evict these txs from the mempool
evict_time = block_time + 60 * 60 * DEFAULT_MEMPOOL_EXPIRY_HOURS + 5
- node.setmocktime(evict_time)
+ # Flush out currently scheduled resubmit attempt now so that there can't be one right between eviction and check.
+ with node.assert_debug_log(['resubmit 2 unconfirmed transactions']):
+ node.setmocktime(evict_time)
+ node.mockscheduler(60)
+
+ # Evict these txs from the mempool
indep_send = node.send(outputs=[{node.getnewaddress(): 1}], inputs=[indep_utxo])
node.getmempoolentry(indep_send["txid"])
assert_raises_rpc_error(-5, "Transaction not in mempool", node.getmempoolentry, txid)
diff --git a/test/fuzz/test_runner.py b/test/fuzz/test_runner.py
index ef1583d446..1ce7c71360 100755
--- a/test/fuzz/test_runner.py
+++ b/test/fuzz/test_runner.py
@@ -193,27 +193,52 @@ def main():
)
-def generate_corpus(*, fuzz_pool, src_dir, build_dir, corpus_dir, targets):
- """Generates new corpus.
+def transform_process_message_target(targets, src_dir):
+ """Add a target per process message, and also keep ("process_message", {}) to allow for
+ cross-pollination, or unlimited search"""
+
+ p2p_msg_target = "process_message"
+ if (p2p_msg_target, {}) in targets:
+ lines = subprocess.run(
+ ["git", "grep", "--function-context", "g_all_net_message_types{", src_dir / "src" / "protocol.cpp"],
+ check=True,
+ stdout=subprocess.PIPE,
+ text=True,
+ ).stdout.splitlines()
+ lines = [l.split("::", 1)[1].split(",")[0].lower() for l in lines if l.startswith("src/protocol.cpp- NetMsgType::")]
+ assert len(lines)
+ targets += [(p2p_msg_target, {"LIMIT_TO_MESSAGE_TYPE": m}) for m in lines]
+ return targets
+
+
+def transform_rpc_target(targets, src_dir):
+ """Add a target per RPC command, and also keep ("rpc", {}) to allow for cross-pollination,
+ or unlimited search"""
- Run {targets} without input, and outputs the generated corpus to
- {corpus_dir}.
- """
- logging.info("Generating corpus to {}".format(corpus_dir))
rpc_target = "rpc"
- has_rpc = rpc_target in targets
- if has_rpc:
- targets.remove(rpc_target)
- targets = [(t, {}) for t in targets]
- if has_rpc:
+ if (rpc_target, {}) in targets:
lines = subprocess.run(
- ["git", "grep", "--function-context", "RPC_COMMANDS_SAFE_FOR_FUZZING{", os.path.join(src_dir, "src", "test", "fuzz", "rpc.cpp")],
+ ["git", "grep", "--function-context", "RPC_COMMANDS_SAFE_FOR_FUZZING{", src_dir / "src" / "test" / "fuzz" / "rpc.cpp"],
check=True,
stdout=subprocess.PIPE,
text=True,
).stdout.splitlines()
lines = [l.split("\"", 1)[1].split("\"")[0] for l in lines if l.startswith("src/test/fuzz/rpc.cpp- \"")]
+ assert len(lines)
targets += [(rpc_target, {"LIMIT_TO_RPC_COMMAND": r}) for r in lines]
+ return targets
+
+
+def generate_corpus(*, fuzz_pool, src_dir, build_dir, corpus_dir, targets):
+ """Generates new corpus.
+
+ Run {targets} without input, and outputs the generated corpus to
+ {corpus_dir}.
+ """
+ logging.info("Generating corpus to {}".format(corpus_dir))
+ targets = [(t, {}) for t in targets] # expand to add dictionary for target-specific env variables
+ targets = transform_process_message_target(targets, Path(src_dir))
+ targets = transform_rpc_target(targets, Path(src_dir))
def job(command, t, t_env):
logging.debug(f"Running '{command}'")