feat(core): encode/decode UnsignedDataSet proto for all duty types#508
Conversation
Add the all-duty-type proto codec covering attester, proposer, aggregator, and sync-contribution unsigned data. The encoder/decoder is wire-compatible with Charon's SSZ-first UnsignedDataSet format (with legacy JSON fallback on decode), unblocking non-attester duties through consensus.
f5013ec to
5e0331f
Compare
…allback The aggregator JSON fallback re-implemented the per-fork dispatch and validator-index parsing already provided by signeddata::VersionedAttestation's Deserialize impl. Since VersionedAggregatedAttestation is a newtype over the same inner type, deserialize directly into VersionedAttestation and rewrap, dropping the redundant VersionedAggregatedAttestationJson wrapper. This also gains the version/payload validation from VersionedAttestation::new.
… JSON The proposer JSON fallback re-implemented the per-fork (version, blinded) dispatch that VersionedSignedProposal's Deserialize already does. Add a Deserialize impl for the unsigned VersionedProposal in signeddata next to its signed sibling, sharing the VersionedRawBlockJson wrapper, and have the codec just call serde_json::from_slice. Drops the one-off VersionedProposalJson wrapper and its parse_json/block_field/field/parse_default helpers.
looks_like_json was defined three times (a nested fn in parsigex_codec and two copies in unsigneddata, one of them inline). Promote the parsigex_codec copy to a pub(crate) fn and reuse it everywhere.
charon writes a two-slot offset table for AttestationData even though both fields are fixed-size; ssz_derive would omit it, so the manual layout is required for wire compatibility. Document this to prevent a future regression.
|
Claude finished @emlautarom1's task in 3m 44s —— View job Code Review:
|
emlautarom1
left a comment
There was a problem hiding this comment.
Manually checked, LGTM. The serialization/deserialization code is just messy by nature due to this JSON/SSZ split.
Summary
Implements the all-duty-type
UnsignedDataSetprotobuf codec inpluto-core, so unsigned duty data for every duty type can be carried over the consensus wire and decoded by peers.What it implements
unsigned_data_set_to_proto(&UnsignedDataSet) -> Result<pbcore::UnsignedDataSet, ParSigExCodecError>— encodes attester, proposer, aggregator, and sync-contribution unsigned data.unsigned_data_set_from_protodecoding for proposer, aggregator, and sync-contribution duty data (attester was already supported).ssz_codecfor the unsignedVersionedProposal,VersionedAggregatedAttestation, andSyncContribution.The encoding is SSZ-first with a JSON fallback on decode, matching Charon's
UnsignedDataSetwire format so a Pluto node interoperates with Charon nodes in a mixed-client cluster.The JSON-fallback path reuses the existing versioned deserializers in
signeddatainstead of duplicating the per-fork dispatch:VersionedAggregatedAttestationdecodes throughVersionedAttestation'sDeserialize, and a newDeserialize for VersionedProposalis added beside its signed sibling (sharing theVersionedRawBlockJsonwrapper). Thelooks_like_jsonprefix check is shared withparsigex_codec. As a result the diff also touchessigneddata.rsandparsigex_codec.rs.Ports
charon/core/proto.go+core/unsigneddata.go. Part of #402.Testing
Round-trip (encode → decode) unit tests for all four duty types, plus the non-versioned aggregator and JSON-fallback decode paths.