diff --git a/proto/block_marker.options b/proto/block_marker.options new file mode 100644 index 0000000..297501a --- /dev/null +++ b/proto/block_marker.options @@ -0,0 +1,26 @@ +block_marker.proto package:"fd_exec_test" +block_marker.proto include:"../../../../ballet/nanopb/pb_firedancer.h" + +fd_exec_test.BlockMarkerContext.data type:FT_POINTER + +fd_exec_test.BlockMarkerBitmap.signers type:FT_POINTER + +fd_exec_test.BlockMarkerVotesAggregate.signature max_size:96 fixed_length:true + +fd_exec_test.BlockMarkerFinalizationCert.block_id max_size:32 fixed_length:true + +fd_exec_test.BlockMarkerSkipRewardCert.signature max_size:96 fixed_length:true + +fd_exec_test.BlockMarkerNotarRewardCert.block_id max_size:32 fixed_length:true +fd_exec_test.BlockMarkerNotarRewardCert.signature max_size:96 fixed_length:true + +fd_exec_test.BlockMarkerHeader.parent_block_id max_size:32 fixed_length:true + +fd_exec_test.BlockMarkerUpdateParent.new_parent_block_id max_size:32 fixed_length:true + +fd_exec_test.BlockMarkerFooter.bank_hash max_size:32 fixed_length:true +fd_exec_test.BlockMarkerFooter.block_user_agent max_size:255 + +fd_exec_test.BlockMarkerGenesisCert.block_id max_size:32 fixed_length:true +fd_exec_test.BlockMarkerGenesisCert.signature max_size:192 fixed_length:true +fd_exec_test.BlockMarkerGenesisCert.bitmap type:FT_POINTER diff --git a/proto/block_marker.proto b/proto/block_marker.proto new file mode 100644 index 0000000..af2d07d --- /dev/null +++ b/proto/block_marker.proto @@ -0,0 +1,126 @@ +syntax = "proto3"; +package org.solana.sealevel.v1; + +import "metadata.proto"; + +/* Protobuf definitions for the Alpenglow block marker differential + fuzzer. The testing scope is deserialization of a single block + component that carries a BlockMarker (BlockComponent with a zero + entry count followed by a VersionedBlockMarker), i.e.: + + * BlockComponent / VersionedBlockMarker / BlockMarkerV1 framing and + LengthPrefixed length checks + * BlockHeaderV1, UpdateParentV1, BlockFooterV1 and + GenesisCertBlockMarker field decoding + * Base2 signer bitmap decoding for every certificate in the footer + + Checks that need bank state (parent slot, clock bounds, reward slot + ranges, stake / rank maps, BLS signature verification) are out of + scope. Signatures are reported as raw bytes and never verified. + + Bitmaps are decoded against a fixed validator cap of 2000 (the VAT + cap), not the epoch's rank map size. */ + +message BlockMarkerContext { + // Raw bytes of one data batch + bytes data = 1; +} + +enum BlockMarkerParseResult { + BLOCK_MARKER_PARSE_RESULT_ACCEPTED = 0; + // The component is a marker but failed to deserialize. + BLOCK_MARKER_PARSE_RESULT_REJECTED = 1; + // The component's entry count is nonzero (or data is shorter than the + // entry count), so it is an entry batch, not a marker. + BLOCK_MARKER_PARSE_RESULT_NOT_A_MARKER = 2; +} + +message BlockMarkerBitmap { + // Number of validator ranks the bitmap covers. + uint32 bit_cnt = 1; + // Ranks whose bit is set, ascending. + repeated uint32 signers = 2; +} + +message BlockMarkerVotesAggregate { + // Compressed BLS signature. Exactly 96 bytes. + bytes signature = 1; + BlockMarkerBitmap bitmap = 2; +} + +message BlockMarkerFinalizationCert { + uint64 slot = 1; + // Exactly 32 bytes. + bytes block_id = 2; + BlockMarkerVotesAggregate final_aggregate = 3; + // Unset for fast finalization. + BlockMarkerVotesAggregate notar_aggregate = 4; +} + +message BlockMarkerSkipRewardCert { + uint64 slot = 1; + // Compressed BLS signature. Exactly 96 bytes. + bytes signature = 2; + BlockMarkerBitmap bitmap = 3; +} + +message BlockMarkerNotarRewardCert { + uint64 slot = 1; + // Exactly 32 bytes. + bytes block_id = 2; + // Compressed BLS signature. Exactly 96 bytes. + bytes signature = 3; + BlockMarkerBitmap bitmap = 4; +} + +message BlockMarkerHeader { + uint64 parent_slot = 1; + // Exactly 32 bytes. + bytes parent_block_id = 2; +} + +message BlockMarkerUpdateParent { + uint64 new_parent_slot = 1; + // Exactly 32 bytes. + bytes new_parent_block_id = 2; +} + +message BlockMarkerFooter { + // Exactly 32 bytes. + bytes bank_hash = 1; + uint64 block_producer_time_nanos = 2; + // At most 255 bytes. + bytes block_user_agent = 3; + // Each is unset when the footer does not carry it. + BlockMarkerFinalizationCert block_final_cert = 4; + BlockMarkerSkipRewardCert skip_reward_cert = 5; + BlockMarkerNotarRewardCert notar_reward_cert = 6; +} + +message BlockMarkerGenesisCert { + uint64 slot = 1; + // Exactly 32 bytes. + bytes block_id = 2; + // Uncompressed BLS signature. Exactly 192 bytes. + bytes signature = 3; + // Raw bitmap bytes, not decoded. + bytes bitmap = 4; +} + +message BlockMarkerEffects { + BlockMarkerParseResult result = 1; + + // Set iff result is ACCEPTED. + oneof marker { + BlockMarkerFooter footer = 2; + BlockMarkerHeader header = 3; + BlockMarkerUpdateParent update_parent = 4; + BlockMarkerGenesisCert genesis_cert = 5; + } +} + +message BlockMarkerFixture { + FixtureMetadata metadata = 1; + BlockMarkerContext input = 2; + BlockMarkerEffects output = 3; +} diff --git a/src/generated/file_descriptor_set.bin b/src/generated/file_descriptor_set.bin index 4aa17bb..c5ada2d 100644 Binary files a/src/generated/file_descriptor_set.bin and b/src/generated/file_descriptor_set.bin differ diff --git a/src/generated/org.solana.sealevel.v1.rs b/src/generated/org.solana.sealevel.v1.rs index 81a83bf..ba541cf 100644 --- a/src/generated/org.solana.sealevel.v1.rs +++ b/src/generated/org.solana.sealevel.v1.rs @@ -514,6 +514,177 @@ impl WarmupCooldownRate { } } #[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)] +pub struct BlockMarkerContext { + /// Raw bytes of one data batch + #[prost(bytes = "vec", tag = "1")] + pub data: ::prost::alloc::vec::Vec, +} +#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)] +pub struct BlockMarkerBitmap { + /// Number of validator ranks the bitmap covers. + #[prost(uint32, tag = "1")] + pub bit_cnt: u32, + /// Ranks whose bit is set, ascending. + #[prost(uint32, repeated, tag = "2")] + pub signers: ::prost::alloc::vec::Vec, +} +#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)] +pub struct BlockMarkerVotesAggregate { + /// Compressed BLS signature. Exactly 96 bytes. + #[prost(bytes = "vec", tag = "1")] + pub signature: ::prost::alloc::vec::Vec, + #[prost(message, optional, tag = "2")] + pub bitmap: ::core::option::Option, +} +#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)] +pub struct BlockMarkerFinalizationCert { + #[prost(uint64, tag = "1")] + pub slot: u64, + /// Exactly 32 bytes. + #[prost(bytes = "vec", tag = "2")] + pub block_id: ::prost::alloc::vec::Vec, + #[prost(message, optional, tag = "3")] + pub final_aggregate: ::core::option::Option, + /// Unset for fast finalization. + #[prost(message, optional, tag = "4")] + pub notar_aggregate: ::core::option::Option, +} +#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)] +pub struct BlockMarkerSkipRewardCert { + #[prost(uint64, tag = "1")] + pub slot: u64, + /// Compressed BLS signature. Exactly 96 bytes. + #[prost(bytes = "vec", tag = "2")] + pub signature: ::prost::alloc::vec::Vec, + #[prost(message, optional, tag = "3")] + pub bitmap: ::core::option::Option, +} +#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)] +pub struct BlockMarkerNotarRewardCert { + #[prost(uint64, tag = "1")] + pub slot: u64, + /// Exactly 32 bytes. + #[prost(bytes = "vec", tag = "2")] + pub block_id: ::prost::alloc::vec::Vec, + /// Compressed BLS signature. Exactly 96 bytes. + #[prost(bytes = "vec", tag = "3")] + pub signature: ::prost::alloc::vec::Vec, + #[prost(message, optional, tag = "4")] + pub bitmap: ::core::option::Option, +} +#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)] +pub struct BlockMarkerHeader { + #[prost(uint64, tag = "1")] + pub parent_slot: u64, + /// Exactly 32 bytes. + #[prost(bytes = "vec", tag = "2")] + pub parent_block_id: ::prost::alloc::vec::Vec, +} +#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)] +pub struct BlockMarkerUpdateParent { + #[prost(uint64, tag = "1")] + pub new_parent_slot: u64, + /// Exactly 32 bytes. + #[prost(bytes = "vec", tag = "2")] + pub new_parent_block_id: ::prost::alloc::vec::Vec, +} +#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)] +pub struct BlockMarkerFooter { + /// Exactly 32 bytes. + #[prost(bytes = "vec", tag = "1")] + pub bank_hash: ::prost::alloc::vec::Vec, + #[prost(uint64, tag = "2")] + pub block_producer_time_nanos: u64, + /// At most 255 bytes. + #[prost(bytes = "vec", tag = "3")] + pub block_user_agent: ::prost::alloc::vec::Vec, + /// Each is unset when the footer does not carry it. + #[prost(message, optional, tag = "4")] + pub block_final_cert: ::core::option::Option, + #[prost(message, optional, tag = "5")] + pub skip_reward_cert: ::core::option::Option, + #[prost(message, optional, tag = "6")] + pub notar_reward_cert: ::core::option::Option, +} +#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)] +pub struct BlockMarkerGenesisCert { + #[prost(uint64, tag = "1")] + pub slot: u64, + /// Exactly 32 bytes. + #[prost(bytes = "vec", tag = "2")] + pub block_id: ::prost::alloc::vec::Vec, + /// Uncompressed BLS signature. Exactly 192 bytes. + #[prost(bytes = "vec", tag = "3")] + pub signature: ::prost::alloc::vec::Vec, + /// Raw bitmap bytes, not decoded. + #[prost(bytes = "vec", tag = "4")] + pub bitmap: ::prost::alloc::vec::Vec, +} +#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)] +pub struct BlockMarkerEffects { + #[prost(enumeration = "BlockMarkerParseResult", tag = "1")] + pub result: i32, + /// Set iff result is ACCEPTED. + #[prost(oneof = "block_marker_effects::Marker", tags = "2, 3, 4, 5")] + pub marker: ::core::option::Option, +} +/// Nested message and enum types in `BlockMarkerEffects`. +pub mod block_marker_effects { + /// Set iff result is ACCEPTED. + #[derive(Clone, PartialEq, Eq, Hash, ::prost::Oneof)] + pub enum Marker { + #[prost(message, tag = "2")] + Footer(super::BlockMarkerFooter), + #[prost(message, tag = "3")] + Header(super::BlockMarkerHeader), + #[prost(message, tag = "4")] + UpdateParent(super::BlockMarkerUpdateParent), + #[prost(message, tag = "5")] + GenesisCert(super::BlockMarkerGenesisCert), + } +} +#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)] +pub struct BlockMarkerFixture { + #[prost(message, optional, tag = "1")] + pub metadata: ::core::option::Option, + #[prost(message, optional, tag = "2")] + pub input: ::core::option::Option, + #[prost(message, optional, tag = "3")] + pub output: ::core::option::Option, +} +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)] +#[repr(i32)] +pub enum BlockMarkerParseResult { + Accepted = 0, + /// The component is a marker but failed to deserialize. + Rejected = 1, + /// The component's entry count is nonzero (or data is shorter than the + /// entry count), so it is an entry batch, not a marker. + NotAMarker = 2, +} +impl BlockMarkerParseResult { + /// String value of the enum field names used in the ProtoBuf definition. + /// + /// The values are not transformed in any way and thus are considered stable + /// (if the ProtoBuf definition does not change) and safe for programmatic use. + pub fn as_str_name(&self) -> &'static str { + match self { + Self::Accepted => "BLOCK_MARKER_PARSE_RESULT_ACCEPTED", + Self::Rejected => "BLOCK_MARKER_PARSE_RESULT_REJECTED", + Self::NotAMarker => "BLOCK_MARKER_PARSE_RESULT_NOT_A_MARKER", + } + } + /// Creates an enum from field names used in the ProtoBuf definition. + pub fn from_str_name(value: &str) -> ::core::option::Option { + match value { + "BLOCK_MARKER_PARSE_RESULT_ACCEPTED" => Some(Self::Accepted), + "BLOCK_MARKER_PARSE_RESULT_REJECTED" => Some(Self::Rejected), + "BLOCK_MARKER_PARSE_RESULT_NOT_A_MARKER" => Some(Self::NotAMarker), + _ => None, + } + } +} +#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)] pub struct StakeDelta { #[prost(bytes = "vec", tag = "1")] pub address: ::prost::alloc::vec::Vec,