Skip to content

tests: make Event::Encode match the JIP-3 wire format - #43

Merged
michalkucharczyk merged 7 commits into
mainfrom
mku-tests-events-encoding
Sep 2, 2026
Merged

michalkucharczyk merged 7 commits into
mainfrom
mku-tests-events-encoding

Conversation

@michalkucharczyk

Copy link
Copy Markdown
Contributor

The test harness pretends to be a JAM node, but its event encoder didn't match the real JIP-3 wire format (wrong bitfield and length encodings, and 10 event types just panicked). This fixes the encoder so tests send real protocol bytes, and adds tests that check the byte layout against the spec.

@s0me0ne-unkn0wn s0me0ne-unkn0wn left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good, left some minor comments.

Comment thread src/events.rs
Comment on lines +2166 to +2175
Event::WorkPackageSubmission { .. } => 32 + 1, // builder + bundle
Event::WorkPackageBeingShared { .. } => 32, // primary
Event::DuplicateWorkPackage { .. } => 8 + 2 + 32, // submission_or_share_id + core + hash
Event::ExtrinsicDataReceived { .. } => 8, // submission_or_share_id
Event::ImportsReceived { .. } => 8, // submission_or_share_id
Event::SharingWorkPackage { .. } => 8 + 32, // submission_id + secondary
Event::WorkPackageSharingFailed { reason, .. } => 8 + 32 + reason.encoded_size(),
Event::BundleSent { .. } => 8 + 32, // submission_id + secondary
Event::WorkReportSignatureSent { .. } => 8, // share_id
Event::WorkReportSignatureReceived { .. } => 8 + 32, // submission_id + secondary

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We're just... Hardcoding them all? For real? That looks brittle 🤔

I'd discuss a refactoring of this entire module (out of the scope of this PR, obviously)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

follow up sounds good.

Comment thread src/types.rs
self.anchor.encode(buf)?;
self.bitfield.encode(buf)?; // Encoded with variable-length prefix
// JIP-3: bitfield is [u8; ceil(core_count/8)] — fixed size, no length prefix
buf.extend_from_slice(&self.bitfield);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The fact that the encoding is a transparent pass-through does not generally mean we can omit the encoding call itself. Properly implemented, bitfield.encode() should be an identity call, and it should be performed here.

Comment thread tests/encoding_tests.rs
Comment on lines +365 to +425
#[test]
fn test_distributing_assurance_bitfield_fixed_no_prefix() {
// JIP-3: AvailabilityStatement bitfield is [u8; ceil(core_count/8)], fixed-size with NO
// length prefix. The decoder reads exactly ceil(core_count/8) bytes after the anchor.
use tart_backend::events::Event;
use tart_backend::types::AvailabilityStatement;

let core_count = 16u16; // ceil(16/8) = 2 bytes
let anchor = [0xABu8; 32];
let bitfield = vec![0xFFu8; 2];
let event = Event::DistributingAssurance {
timestamp: 1_700_000_000_000_000,
statement: AvailabilityStatement { anchor, bitfield },
};

let mut buf = BytesMut::new();
event.encode(&mut buf).unwrap();

// content = timestamp(8) + discriminator(1) + anchor(32) + bitfield(2) = 43
assert_eq!(buf.len(), 43, "no length prefix expected for fixed bitfield");
assert_eq!(buf[41], 0xFF);
assert_eq!(buf[42], 0xFF);

// Decoder must consume the bitfield without a prefix and round-trip.
let mut cursor = Cursor::new(&buf[..]);
let decoded = Event::decode_event(&mut cursor, core_count).unwrap();
match decoded {
Event::DistributingAssurance { statement, .. } => {
assert_eq!(statement.anchor, anchor);
assert_eq!(statement.bitfield, vec![0xFFu8; 2]);
}
_ => panic!("wrong variant decoded"),
}
assert_eq!(cursor.position() as usize, buf.len(), "whole event consumed");
}

#[test]
fn test_sending_segment_shard_request_varlen_prefix() {
// BoundedVec<(u16,u16)> shards use a variable-length count prefix.
use tart_backend::events::Event;

let event = Event::SendingSegmentShardRequest {
timestamp: 1_700_000_000_000_000,
submission_id: 42,
assurer: [0x11u8; 32],
proofs: true, // bool — 1 byte, no prefix
shards: vec![(1u16, 2u16)], // BoundedVec<(u16,u16)> — varlen count 1 byte + 4 bytes
};

let mut buf = BytesMut::new();
event.encode(&mut buf).unwrap();
assert_eq!(buf.len(), event.encoded_size());

// Round-trip through the decoder.
let mut cursor = Cursor::new(&buf[..]);
let decoded = Event::decode_event(&mut cursor, 16).unwrap();
assert_eq!(decoded.event_type() as u8, 162); // SendingSegmentShardRequest
let mut reencoded = BytesMut::new();
decoded.encode(&mut reencoded).unwrap();
assert_eq!(reencoded, buf);
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need tests for those narrow cases? I mean, we don't have a separate test for every event type, how are these ones different? (I'm not opposed to adding them, just thinking aloud).

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The truth is that whole this testsuit needs more love one day. I am in progress of reviewing it, sadly delayed by work in parachain-service, so improvements will come piece by piece.

@michalkucharczyk
michalkucharczyk merged commit 09495d5 into main Sep 2, 2026
6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants