Skip to content

Conversation

@agustinmista
Copy link
Contributor

@agustinmista agustinmista commented Dec 8, 2025

This PR comes in preparation to the implementation of the PerasVoteDB, and introduces a couple of new data types related to Peras votes and the certificate forging API:

  • The main PerasVote type, and its corresponding ValidatedPerasVote.
  • The auxiliary types PerasVoteTarget, PerasVoterId, PerasVoteStake, PerasVoteStakeDistr
  • The new Peras parameter PerasQuorumStakeThreshold (corresponding to perasQuorum in the design document, section 2.1)

@agustinmista agustinmista self-assigned this Dec 8, 2025
@agustinmista agustinmista force-pushed the peras/main-pr/votedb-api branch from bf3a52c to 4063507 Compare December 9, 2025 10:39
@agustinmista agustinmista changed the title [Peras 13] Add votes and voting API [Peras 13] Add votes and vote forging API Dec 9, 2025
@agustinmista agustinmista changed the title [Peras 13] Add votes and vote forging API [Peras 13] Add votes and certificate forging API Dec 9, 2025
@agustinmista agustinmista force-pushed the peras/main-pr/votedb-api branch from 4063507 to 06f4e61 Compare December 9, 2025 10:53
@agustinmista agustinmista changed the title [Peras 13] Add votes and certificate forging API [Peras 13] Introduce votes and certificate forging API Dec 9, 2025
Copy link
Contributor

@tbagrel1 tbagrel1 left a comment

Choose a reason for hiding this comment

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

Looks perfect to me! 😃

@agustinmista agustinmista marked this pull request as ready for review December 9, 2025 14:48
@agustinmista agustinmista force-pushed the peras/main-pr/votedb-api branch from 06f4e61 to 42bb662 Compare December 12, 2025 13:42
@agustinmista agustinmista force-pushed the peras/main-pr/new-defs-and-plumbing branch 2 times, most recently from c314f45 to bb97f3f Compare December 16, 2025 09:40
@agustinmista agustinmista force-pushed the peras/main-pr/votedb-api branch from 42bb662 to 4f2f0cc Compare December 16, 2025 10:08
pcCertBoostedBlock <- decode
pure $ PerasCert{pcCertRound, pcCertBoostedBlock}

instance Serialise (HeaderHash blk) => Serialise (PerasVote blk) where
Copy link
Contributor

Choose a reason for hiding this comment

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

Why chose Serialise instead of ToCBOR/FromCBOR?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@tbagrel1 maybe you have a better idea?

Copy link
Contributor

Choose a reason for hiding this comment

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

Ouroboros.Consensus.Network.NodeToNode uses SerialiseNodeToNode class to serialise stuff. For types whose serialisation doesn't depend on a particular NodeToNodeVersion, the instances often fallback to encode/decode from Serialise class. For Peras types we've just followed the same existing pattern :)

Comment on lines +213 to +228
-- Consistent with the 'Serialise' instance for 'PerasVote' defined in Ouroboros.Consensus.Block.SupportsPeras
encodeNodeToNode ccfg version PerasVote{..} =
encodeListLen 3
<> encodeNodeToNode ccfg version pvVoteRound
<> encodeNodeToNode ccfg version pvVoteBlock
<> encodeNodeToNode ccfg version pvVoteVoterId
decodeNodeToNode ccfg version = do
decodeListLenOf 3
pvVoteRound <- decodeNodeToNode ccfg version
pvVoteBlock <- decodeNodeToNode ccfg version
pvVoteVoterId <- decodeNodeToNode ccfg version
pure $ PerasVote pvVoteRound pvVoteBlock pvVoteVoterId

instance SerialiseNodeToNode blk PerasVoterId where
encodeNodeToNode _ccfg _version = KeyHash.toCBOR . unPerasVoterId
decodeNodeToNode _ccfg _version = PerasVoterId <$> KeyHash.fromCBOR
Copy link
Contributor

Choose a reason for hiding this comment

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

I guess the Serialise instance could change as it is used for storing on disk (confirm?), while this one would require a new NTN version etc etc. So if any I would put the comment in the Serialise instance saying that it matches the NTN one.

Also I think I would expose a function

-- Ouroboros.Consensus.Block.SupportsPeras

encodeVoteNodeToNode :: CodecConfig blk -> NodeToNodeVersion -> PerasVote blk -> Encoding
encodeVoteNodeToNode _ccfg _version = encode

maybe? I should check how we do this in other places but I think this is the pattern we usually use.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Bystander comment: I'm not super familiar with how these two type classes interact with each other but, in any case, we should remember to also apply any transformation to the instance for PerasCert defined above.

@agustinmista agustinmista force-pushed the peras/main-pr/new-defs-and-plumbing branch from bb97f3f to 43c1fdc Compare December 16, 2025 10:44
@agustinmista agustinmista force-pushed the peras/main-pr/votedb-api branch from 4f2f0cc to fd401fc Compare December 16, 2025 10:59
@agustinmista agustinmista force-pushed the peras/main-pr/new-defs-and-plumbing branch from 43c1fdc to e7eadb3 Compare December 16, 2025 12:00
agustinmista and others added 2 commits December 16, 2025 13:06
This commit introduces a couple of new types to represent Peras votes
and their corresponding certificate forging API. Notably, this requires
an initial representation of notions like vote targets, vote stakes and stake
distributions over multiple stake pools.

Co-authored-by: Agustin Mista <[email protected]>
Co-authored-by: Alexander Esgen <[email protected]>
Co-authored-by: Georgy Lukyanov <[email protected]>
Co-authored-by: Thomas BAGREL <[email protected]>
Co-authored-by: Nicolas BACQUEY <[email protected]>
Co-authored-by: Agustin Mista <[email protected]>
Co-authored-by: Alexander Esgen <[email protected]>
Co-authored-by: Georgy Lukyanov <[email protected]>
Co-authored-by: Thomas BAGREL <[email protected]>
Co-authored-by: Nicolas BACQUEY <[email protected]>
@agustinmista agustinmista force-pushed the peras/main-pr/votedb-api branch from fd401fc to 0006522 Compare December 16, 2025 12:06
deriving Semigroup via Sum Rational
deriving Monoid via Sum Rational

newtype PerasVoteStakeDistr = PerasVoteStakeDistr
Copy link
Contributor

@fraser-iohk fraser-iohk Dec 17, 2025

Choose a reason for hiding this comment

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

can this be named PerasVoteStakeDistribution?

newtype PerasVoteStake = PerasVoteStake
{ unPerasVoteStake :: Rational
}
deriving newtype (Enum, Eq, Ord, Num, Fractional, NoThunks, Serialise)
Copy link
Contributor

Choose a reason for hiding this comment

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

can we remove the Enum instance? it's strange having this type be both Fractional and Enum, even if Rational underneath is

{ vpvVote :: !(PerasVote blk)
, vpvVoteStake :: !PerasVoteStake
}
deriving stock (Show, Eq, Ord, Generic)
Copy link
Contributor

Choose a reason for hiding this comment

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

do we need this Ord instance for Map/Set at the moment, and can we remove it otherwise? I don't like being able to compare two ValidatedPerasVotes when it's only really a meaningful comparison on the stake when they're both for the same vote

= PerasQuorumStakeThreshold {unPerasQuorumStakeThreshold :: Rational}
deriving Show via Quiet PerasQuorumStakeThreshold
deriving stock Generic
deriving newtype (Enum, Eq, Ord, NoThunks, Condense)
Copy link
Contributor

Choose a reason for hiding this comment

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

if this should presumably always be a value between 0 and 1 (?), this Enum instance doesn't make sense and should be removed

deriving stock (Show, Eq, Ord, Generic)
deriving anyclass NoThunks

-- | Lookup the stake of vote casted by a member of a given stake distribution.
Copy link
Contributor

Choose a reason for hiding this comment

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

"casted" should be "cast"

deriving Show via Quiet PerasVoterId

newtype PerasVoteStake = PerasVoteStake
{ unPerasVoteStake :: Rational
Copy link
Contributor

Choose a reason for hiding this comment

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

I don't understand what exactly this Rational represents w.r.t. the stake amount. Are we just using Rational here to precisely represent a fractional value, or are we using the denominator to indicate the total stake (either across the committee or overall)? Should all of the PerasVoteStake values contained within a PerasVoteStakeDistr sum to exactly 1?

Copy link
Contributor

Choose a reason for hiding this comment

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

At the moment there is no consensus from researchers/engineers on how we go from the absolute stake of a voter in the ledger to the relative stake of their vote in the voting commitee (given that the quorum is expressed as a relative value of the voting commitee total stake). It is still being debated, cf. 2025/12/16 "Peras Acceleration meeting".

So you can consider this Rational as the best approximation we have at the moment of the concrete type for a relative vote stake that can be compared to the quorum value.

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.

4 participants