Merge rust-bitcoin/rust-bitcoin#6789: fuzz: fix p2p commands master and 0.32 divergence
What changed, and why it matters
This is a fuzz-test-only fix. It changes a test harness so it skips comparing two newer Bitcoin P2P network commands ('feature' and 'sendtxrcncl') between the current master code and an older 0.32 release. The older release stores unknown commands as raw data, while the newer code parses and can reject them. The fix prevents the fuzz test from panicking on this expected difference. It does not change any production library code.
No production action needed. Reviewers can verify the skip list matches the documented master-only commands and that the regression tests exercise the skip paths.
Security signals we found
Fuzz harness panic on expected version divergence
Test-only change, no production code modified
Comparison between master and 0.32 behavior for new P2P commands
Evidence from the diff
The commit modifies fuzz/fuzz_targets/bitcoin/compare_consensus_encoding.rs. It adds v1_network_message_should_skip() which detects command strings ‘sendtxrcncl’ and ‘feature’ in a V1 P2P message header and skips the compare_encoding!() round-trip test for V1NetworkMessage when they are present. It also changes the regression test module cfg from all(test, fuzzing) to test, and adds regression tests for the two skipped commands plus a short-input test. No runtime consensus or P2P code is changed.
Changed components
fuzz/fuzz_targets/bitcoin/compare_consensus_encoding.rsInspect captured patch +47 / −3
### fuzz/fuzz_targets/bitcoin/compare_consensus_encoding.rs
@@ -154,6 +154,16 @@ fn addrv2_payload_should_skip(data: &[u8]) -> bool {
.unwrap_or(false)
}
+/// Returns `true` if `V1NetworkMessage` carries a command that only the master decodes.
+fn v1_network_message_should_skip(data: &[u8]) -> bool {
+ const MASTER_ONLY: &[&str] = &["sendtxrcncl", "feature"];
+
+ // A V1 header is `magic(4) || command(12) || ...`
+ data.get(4..16)
+ .and_then(|command| std::str::from_utf8(command).ok())
+ .is_some_and(|command| MASTER_ONLY.contains(&command.trim_end_matches('\0')))
+}
+
#[rustfmt::skip] // rustfmt butchers all of these with inconsistent newlines.
fn do_test(data: &[u8]) {
compare_encoding!(data, Block);
@@ -211,7 +221,11 @@ fn do_test(data: &[u8]) {
compare_encoding!(data, p2p::message::NetworkHeader, (bitcoin_0_32::block::Header, u8));
compare_encoding!(data, p2p::message::Ping, u64);
compare_encoding!(data, p2p::message::Pong, u64);
- compare_encoding!(data, p2p::message::V1NetworkMessage, bitcoin_0_32::p2p::message::RawNetworkMessage);
+ // Skip messages unknown to bitcoin 0.32, which never fails them, while master
+ // decoder parses can recognize and reject them.
+ if !v1_network_message_should_skip(data) {
+ compare_encoding!(data, p2p::message::V1NetworkMessage, bitcoin_0_32::p2p::message::RawNetworkMessage);
+ }
compare_encoding!(data, p2p::message_blockdata::BlockLocator, Vec<bitcoin_0_32::BlockHash>);
compare_encoding!(data, p2p::message_network::Alert, Vec<u8>);
compare_encoding!(data, p2p::message_network::UserAgent, String);
@@ -242,7 +256,7 @@ fuzz_target!(|data| {
do_test(data);
});
-#[cfg(all(test, fuzzing))]
+#[cfg(test)]
mod tests {
fn extend_vec_from_hex(hex: &str, out: &mut Vec<u8>) {
let mut b = 0;
@@ -262,7 +276,37 @@ mod tests {
}
#[test]
- fn duplicate_crash() {
+ fn v1_network_message_feature_is_skipped() {
+ let mut a = Vec::new();
+ extend_vec_from_hex(
+ concat!(
+ "1101fc00", // magic
+ "666561747572650000000000", // command: "feature"
+ "00000000", // payload_len: 0
+ "01000000", // checksum
+ ),
+ &mut a,
+ );
+ super::do_test(&a);
+ }
+
+ #[test]
+ fn v1_network_message_sendtxrcncl_is_skipped() {
+ let mut a = Vec::new();
+ extend_vec_from_hex(
+ concat!(
+ "1101fc00", // magic
+ "73656e64747872636e636c00", // command: "sendtxrcncl"
+ "00000000", // payload_len: 0
+ "01000000", // checksum
+ ),
+ &mut a,
+ );
+ super::do_test(&a);
+ }
+
+ #[test]
+ fn arbitrary_short_input_does_not_panic() {
let mut a = Vec::new();
extend_vec_from_hex("00003cb1133bb113", &mut a);
super::do_test(&a);Why this scored 18/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.