@@ -192,30 +192,67 @@ func (b *DijkstraBlock) CalculatedBlockBodyHash() common.Blake2b256 {
192192 return b .BlockBody .Hash ()
193193}
194194
195- // DijkstraLeiosCertificate matches the generated Dijkstra CDDL in
196- // IntersectMBO/cardano-ledger at c47305fcf47bd77437b837d0dfb9cb4181bfbc77 :
195+ // DijkstraLeiosCertificate is the in-body Leios certificate added in the
196+ // ouroboros-leios prototype-2026w27 release ( IntersectMBO/cardano-ledger #5872) :
197197//
198- // block = [..., leios_cert : leios_cert / nil, peras_cert : peras_cert / nil]
199- // leios_cert = []
200- // peras_cert = []
198+ // block_body = [..., leios_certificate : leios_certificate / nil, peras_certificate : peras_certificate / nil]
199+ // leios_certificate = [ signers : bytes ; committee signer bitfield
200+ // , aggregated_signature : leios_signature ]
201+ // leios_signature = bytes .size 48
201202//
202- // The Leios and Peras slots are always present and nullable. When non-null,
203- // the current Dijkstra CDDL placeholder is an empty CBOR list, not the CIP-0164
204- // stake-committee EB certificate payload.
203+ // It certifies the endorser block announced by an earlier ranking block; the
204+ // ranking block whose header sets leios_certified carries it in its body. Per
205+ // CIP-0164 a block that carries a Leios certificate carries no Dijkstra-era
206+ // transactions.
205207type DijkstraLeiosCertificate struct {
206208 cbor.DecodeStoreCbor
209+ Signers []byte
210+ AggregatedSignature []byte
207211}
208212
209213func (c * DijkstraLeiosCertificate ) UnmarshalCBOR (cborData []byte ) error {
210- return decodeDijkstraEmptyCertificate (
211- cborData ,
212- "Dijkstra Leios certificate" ,
213- & c .DecodeStoreCbor ,
214- )
214+ var items []cbor.RawMessage
215+ if _ , err := cbor .Decode (cborData , & items ); err != nil {
216+ return fmt .Errorf ("decode Dijkstra Leios certificate: %w" , err )
217+ }
218+ if len (items ) != 2 {
219+ return fmt .Errorf (
220+ "dijkstra Leios certificate must have 2 fields, got %d" ,
221+ len (items ),
222+ )
223+ }
224+ var signers []byte
225+ if _ , err := cbor .Decode (items [0 ], & signers ); err != nil {
226+ return fmt .Errorf (
227+ "decode Dijkstra Leios certificate signers: %w" ,
228+ err ,
229+ )
230+ }
231+ var aggSig []byte
232+ if _ , err := cbor .Decode (items [1 ], & aggSig ); err != nil {
233+ return fmt .Errorf (
234+ "decode Dijkstra Leios certificate aggregated signature: %w" ,
235+ err ,
236+ )
237+ }
238+ if len (aggSig ) != common .LeiosBlsSignatureSize {
239+ return fmt .Errorf (
240+ "invalid Dijkstra Leios certificate aggregated signature length: expected %d, got %d" ,
241+ common .LeiosBlsSignatureSize ,
242+ len (aggSig ),
243+ )
244+ }
245+ c .Signers = signers
246+ c .AggregatedSignature = aggSig
247+ c .SetCbor (cborData )
248+ return nil
215249}
216250
217251func (c DijkstraLeiosCertificate ) MarshalCBOR () ([]byte , error ) {
218- return marshalDijkstraEmptyCertificate (c .DecodeStoreCbor )
252+ if raw := c .Cbor (); len (raw ) > 0 {
253+ return raw , nil
254+ }
255+ return cbor .Encode ([]any {c .Signers , c .AggregatedSignature })
219256}
220257
221258type DijkstraPerasCertificate struct {
@@ -622,12 +659,14 @@ const babbageHeaderBodyFieldCount = 10
622659type DijkstraBlockHeader struct {
623660 babbage.BabbageBlockHeader
624661 // LeiosHeaderExtension holds the Dijkstra/Leios block-header fields that
625- // follow Babbage's protocol_version field. The leios-prototype testnet
626- // began emitting an extra trailing element (a [hash, uint] pair) once the
627- // Leios header extension activated mid-Dijkstra; earlier Dijkstra blocks
628- // carry the plain 10-field Babbage header body, for which this is nil. The
629- // elements are retained verbatim so the header round-trips and hashes
630- // identically to the bytes received on the wire.
662+ // follow Babbage's protocol_version field. As of the ouroboros-leios
663+ // prototype-2026w27 release (IntersectMBO/cardano-ledger #5889) these are
664+ // two fields: leios_certified (bool) and leios_announcement
665+ // ([announced_eb : hash32, announced_eb_size : uint .size 4] / nil). Earlier
666+ // Dijkstra blocks carry the plain 10-field Babbage header body, for which
667+ // this is nil. The elements are retained verbatim so the header round-trips
668+ // and hashes identically to the bytes received on the wire; use
669+ // LeiosCertified and LeiosAnnouncement for typed access.
631670 LeiosHeaderExtension []cbor.RawMessage
632671}
633672
@@ -709,22 +748,42 @@ func (h *DijkstraBlockHeader) Era() common.Era {
709748 return EraDijkstra
710749}
711750
712- // LeiosEndorserBlockRef returns the endorser block referenced by this ranking
713- // block via its Leios header extension. The extension's first element is the
714- // endorser-block announcement [eb_hash, eb_size] (the same shape leios-notify
715- // uses), identifying the endorser block whose transactions this ranking block
716- // endorses. ok is false for pre-Leios-extension Dijkstra headers (which carry
717- // no extension) or if the extension is not the expected [hash32, uint] shape.
718- func (h * DijkstraBlockHeader ) LeiosEndorserBlockRef () (
751+ // LeiosCertified reports whether this ranking block certifies the endorser
752+ // block announced by an earlier ranking block. It is the leios_certified header
753+ // field added in the ouroboros-leios prototype-2026w27 release
754+ // (IntersectMBO/cardano-ledger #5889); when true, the block body carries the
755+ // leios_certificate. present is false for pre-Leios-extension Dijkstra headers,
756+ // which carry no extension.
757+ func (h * DijkstraBlockHeader ) LeiosCertified () (certified bool , present bool ) {
758+ if len (h .LeiosHeaderExtension ) == 0 {
759+ return false , false
760+ }
761+ if _ , err := cbor .Decode (h .LeiosHeaderExtension [0 ], & certified ); err != nil {
762+ return false , false
763+ }
764+ return certified , true
765+ }
766+
767+ // LeiosAnnouncement returns the endorser block this ranking block announces via
768+ // its Leios header extension. It is the leios_announcement header field added in
769+ // the ouroboros-leios prototype-2026w27 release (IntersectMBO/cardano-ledger
770+ // #5889):
771+ //
772+ // leios_announcement = [announced_eb : hash32, announced_eb_size : uint .size 4]
773+ //
774+ // ok is false when the block announces no endorser block (leios_announcement is
775+ // nil), for pre-Leios-extension Dijkstra headers, or if the field is not the
776+ // expected [hash32, uint] shape.
777+ func (h * DijkstraBlockHeader ) LeiosAnnouncement () (
719778 hash common.Blake2b256 ,
720779 size uint64 ,
721780 ok bool ,
722781) {
723- if len (h .LeiosHeaderExtension ) == 0 {
782+ if len (h .LeiosHeaderExtension ) < 2 {
724783 return common.Blake2b256 {}, 0 , false
725784 }
726785 var pair []cbor.RawMessage
727- if _ , err := cbor .Decode (h .LeiosHeaderExtension [0 ], & pair ); err != nil ||
786+ if _ , err := cbor .Decode (h .LeiosHeaderExtension [1 ], & pair ); err != nil ||
728787 len (pair ) != 2 {
729788 return common.Blake2b256 {}, 0 , false
730789 }
0 commit comments