Skip to content

Leios: vote and certify over the announcing RbHash#2086

Open
geo2a wants to merge 4 commits into
ch1bo/leios-certifyingfrom
geo2a/vote-on-rbhash
Open

Leios: vote and certify over the announcing RbHash#2086
geo2a wants to merge 4 commits into
ch1bo/leios-certifyingfrom
geo2a/vote-on-rbhash

Conversation

@geo2a

@geo2a geo2a commented Jun 19, 2026

Copy link
Copy Markdown
Contributor

Fixes input-output-hk/ouroboros-leios#941

Changes to LeiosDemoTypes

  • Add RbHash --- a newtype over ByteString representing a hash of a Ranking Block.
  • LeiosVote now carries an RbHash instead of LeiosPoint. This is the crux of the PR, all other changes stem from here.
  • LeiosOutstanding gets a new field offeredEbRbHashes :: Map EbHash RbHash. This field records the RbHash for each EB announcement. We cannot write the RbHash directly in the DB, because we don't yet have the EB body to attach to.

Changes to the DB interface

  • add the leiosDbRbOfEb :: EbHash -> m RbHash field to LeiosDbConnection. leiosDbRbOfEb maps an EbHash to the RbHash for the ranking block that announced this EB.
  • Both constructors of LeiosEbNotification now carry an RbHash.
  • leiosDbInsertEbBody and leiosDbInsertTxs now accept RbHash.

Changes to the forge

  • when forgeShelleyBlock forges an RB and produces an EB announcement (as decided by decideLeios), take note of the hash of the forged RB and store it into leiosDbRbOfEb for future reference.
  • when forgeShelleyBlock certifies an EB, fetch the hash of its announcing RB from leiosDbRbOfEb.
  • minor: mkAndStoreEb is split into two separate functions: mkEb and storeEb. This is necessary because storeEb needs to know the RbHash of the newly forged RB when announcing an EB, so it needs to be called after the RB is forged.

Changes to LeiosNotify

  • MsgLeiosBlockOffer now carries the RbHash of the announcing block. This is needed so that we can record the RbHash of the EBs we received from peers into the DB.

Changes to voting

  • In runLeiosVoting, we now forge votes on RbHash instead of LeiosPoint.
  • queryCert now accepts RbHash as the index instead of LeiosPoint.
  • The HasLeiosVoting instance for Dijkstra now needs the ShelleyCompatible constraint in order to convert the previous block's HeaderHash into a raw hash and interpret it as RbHash to stick into validateLeiosCertificate.
  • In the HasLeiosVoting instance for Dijkstra, we don't use the payload of the announcement in validateLeiosBlockCert anymore, as we only need the HeaderHash of the previous block for validateLeiosCertificate. We still pattern-match on the announcement to check if it's not Nothing and refuse to validate the cert if it is.

@geo2a geo2a force-pushed the geo2a/vote-on-rbhash branch from 6aa7446 to 005523e Compare June 19, 2026 11:43
@geo2a geo2a requested a review from ch1bo June 19, 2026 11:44
@geo2a geo2a self-assigned this Jun 19, 2026
@geo2a geo2a linked an issue Jun 19, 2026 that may be closed by this pull request
3 tasks
@geo2a geo2a force-pushed the geo2a/vote-on-rbhash branch 2 times, most recently from 550cc26 to 7e136f2 Compare June 19, 2026 13:49
@ch1bo ch1bo force-pushed the ch1bo/leios-certifying branch 5 times, most recently from 1b8460a to eb18f0b Compare June 22, 2026 06:51
@ch1bo ch1bo force-pushed the geo2a/vote-on-rbhash branch from 7e136f2 to 3cf5afc Compare June 22, 2026 06:55

@ch1bo ch1bo left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Not fully through it, but I'm not convinced that we need that many changes.

The certificate verification and vote signing is correct AFAIS, but it's a big of a too big rats tail on the storage and definitely the N2N mini protocols should not change? Please argue for why if I'm wrong.

Nothing ->
-- A CertRB always has a (non-genesis) announcing parent;
-- the apply path shouldn't have produced one otherwise.
error "applyBlock: cannot determine announcing RB hash for CertRB"

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Should: replace the call to protocolStateLeiosAnnouncement above with this

The RbHash is the new announcement and all what we need to verify the cert. We might be able to drop protocolStateLeiosAnnouncement completely

| TraceLeiosVoted {vote :: LeiosVote, weight :: Weight}
| TraceLeiosVoteAcquired {vote :: LeiosVote}
| TraceLeiosCertified {point :: LeiosPoint}
| TraceLeiosCertified {rbHash :: RbHash}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Could: keep point and give this a more descriptive name like announcingRbHash

pure $ MsgLeiosBlockOffer point ebSize
AcquiredEbTxs point ->
AcquiredEb point announcingRbHash ebSize ->
pure $ MsgLeiosBlockOffer point (Leios.rbHashBytes announcingRbHash) ebSize

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Must: not change the N2N protocol because of this

Why would we need the offer to include the announcement?

instance SignableRepresentation RbHash where
getSignableRepresentation point =
toStrictByteString $
encodeRbHash point

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Should: just use the hash bytes directly instead of CBOR

Not entirely sure what is the more common paradigm in the codebase? In any case, we should keep a note in the CIP / the vote CDDL about this.

data LeiosVote = MkLeiosVote
{ point :: LeiosPoint
{ point :: RbHash
-- ^ Point that gets signed. The slot also identifies the voting round.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Should: rename this field. It's not a point, but just a block header hash.

Also, there is no slot in this.

mconcat
[ "slot" .= point.pointSlotNo
, "ebHash" .= prettyEbHash point.pointEbHash
[ "rbHash" .= prettyRbHash point

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Note to myself: The frontend uses the slot and ebHash to visualize votes

We must update it

, "voterId" .= voterId.voterIndex
]

-- | Create a vote for given 'LeiosPoint' and signing key.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Should: fix Haddocks

= AcquiredEb LeiosPoint BytesSize
| AcquiredEbTxs LeiosPoint
= AcquiredEb LeiosPoint RbHash BytesSize
| AcquiredEbTxs LeiosPoint RbHash

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Do we emit this now for each announcement (RbHash) that was completed when an EbTxs (closure) gets completed?

I'm asking because we would need to vote for each announcement (that is not equivocated).

-- ^ Batch filter: returns the subset of input TxHashes that we do NOT have.
, leiosDbQueryCompletedEbByPoint :: HasCallStack => LeiosPoint -> m (Maybe [(TxHash, ByteString)])
, leiosDbRbOfEb :: HasCallStack => EbHash -> m RbHash
-- ^ For an EB, find the RB that announced it.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Must: store announcements differently

This is not a 1:1 relationship. Instead, we would have a n:m relationship between announcements (RB headers) and EBs.

-- NOTE: This is O(n) and should only be used at startup for initialization.
, -- NOTE: yields a LeiosOfferBlock notification
leiosDbInsertEbBody :: HasCallStack => LeiosPoint -> LeiosEb -> m ()
leiosDbInsertEbBody :: HasCallStack => LeiosPoint -> RbHash -> LeiosEb -> m ()

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Should: not need to change this

An EB body should actually only be indexed by EbHash and having the Slot via LeiosPoint here is already problematic.

@ch1bo ch1bo force-pushed the ch1bo/leios-certifying branch 3 times, most recently from c8f869c to 13e6a58 Compare June 22, 2026 16:05
Vote on the hash of the ranking block that announced the EB instead of the
LeiosPoint, which comprises the slot number and EB hash. This forbids reusing
Leios certificates across Praos forks.
@geo2a geo2a force-pushed the geo2a/vote-on-rbhash branch from 3cf5afc to 4293065 Compare June 23, 2026 09:16
@geo2a geo2a force-pushed the geo2a/vote-on-rbhash branch from 4293065 to 1c2f282 Compare June 23, 2026 10:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Leios Certificates and Votes must be signing RbHash

3 participants