ceremonyclient/node/consensus/global/consensus_voting_provider.go
Cassandra Heart 8dc7e0d526
v2.1.0.14 (#484)
* v2.1.0.14

* release notes
2025-12-03 23:56:34 -06:00

179 lines
5.1 KiB
Go

package global
import (
"context"
"slices"
"sort"
"time"
"github.com/pkg/errors"
"go.uber.org/zap"
"source.quilibrium.com/quilibrium/monorepo/consensus"
"source.quilibrium.com/quilibrium/monorepo/consensus/models"
"source.quilibrium.com/quilibrium/monorepo/consensus/verification"
"source.quilibrium.com/quilibrium/monorepo/protobufs"
)
// GlobalVotingProvider implements VotingProvider
type GlobalVotingProvider struct {
engine *GlobalConsensusEngine
}
// FinalizeQuorumCertificate implements consensus.VotingProvider.
func (p *GlobalVotingProvider) FinalizeQuorumCertificate(
ctx context.Context,
state *models.State[*protobufs.GlobalFrame],
aggregatedSignature models.AggregatedSignature,
) (models.QuorumCertificate, error) {
return &protobufs.QuorumCertificate{
Rank: (*state.State).GetRank(),
FrameNumber: (*state.State).Header.FrameNumber,
Selector: []byte((*state.State).Identity()),
Timestamp: uint64(time.Now().UnixMilli()),
AggregateSignature: &protobufs.BLS48581AggregateSignature{
Signature: aggregatedSignature.GetSignature(),
PublicKey: &protobufs.BLS48581G2PublicKey{
KeyValue: aggregatedSignature.GetPubKey(),
},
Bitmask: aggregatedSignature.GetBitmask(),
},
}, nil
}
// FinalizeTimeout implements consensus.VotingProvider.
func (p *GlobalVotingProvider) FinalizeTimeout(
ctx context.Context,
rank uint64,
latestQuorumCertificate models.QuorumCertificate,
latestQuorumCertificateRanks []consensus.TimeoutSignerInfo,
aggregatedSignature models.AggregatedSignature,
) (models.TimeoutCertificate, error) {
ranksInProverOrder := slices.Clone(latestQuorumCertificateRanks)
provers, err := p.engine.proverRegistry.GetActiveProvers(nil)
if err != nil {
return nil, err
}
proverIndexes := map[models.Identity]int{}
for i, p := range provers {
proverIndexes[models.Identity(p.Address)] = i
}
sort.Slice(ranksInProverOrder, func(i, j int) bool {
return proverIndexes[ranksInProverOrder[i].Signer]-
proverIndexes[ranksInProverOrder[j].Signer] < 0
})
ranks := []uint64{}
for _, r := range ranksInProverOrder {
ranks = append(ranks, r.NewestQCRank)
}
return &protobufs.TimeoutCertificate{
Rank: rank,
LatestRanks: ranks,
LatestQuorumCertificate: latestQuorumCertificate.(*protobufs.QuorumCertificate),
Timestamp: uint64(time.Now().UnixMilli()),
AggregateSignature: &protobufs.BLS48581AggregateSignature{
Signature: aggregatedSignature.GetSignature(),
PublicKey: &protobufs.BLS48581G2PublicKey{
KeyValue: aggregatedSignature.GetPubKey(),
},
Bitmask: aggregatedSignature.GetBitmask(),
},
}, nil
}
// SignTimeoutVote implements consensus.VotingProvider.
func (p *GlobalVotingProvider) SignTimeoutVote(
ctx context.Context,
filter []byte,
currentRank uint64,
newestQuorumCertificateRank uint64,
) (**protobufs.ProposalVote, error) {
// Get signing key
signer, _, publicKey, _ := p.engine.GetProvingKey(p.engine.config.Engine)
if publicKey == nil {
p.engine.logger.Error("no proving key available")
return nil, errors.Wrap(
errors.New("no proving key available for voting"),
"sign vote",
)
}
// Create vote (signature)
signatureData := verification.MakeTimeoutMessage(
nil,
currentRank,
newestQuorumCertificateRank,
)
sig, err := signer.SignWithDomain(signatureData, []byte("globaltimeout"))
if err != nil {
p.engine.logger.Error("could not sign vote", zap.Error(err))
return nil, errors.Wrap(err, "sign vote")
}
voterAddress := p.engine.getAddressFromPublicKey(publicKey)
// Create vote message
vote := &protobufs.ProposalVote{
FrameNumber: 0,
Rank: currentRank,
Selector: nil,
Timestamp: uint64(time.Now().UnixMilli()),
PublicKeySignatureBls48581: &protobufs.BLS48581AddressedSignature{
Address: voterAddress,
Signature: sig,
},
}
return &vote, nil
}
// SignVote implements consensus.VotingProvider.
func (p *GlobalVotingProvider) SignVote(
ctx context.Context,
state *models.State[*protobufs.GlobalFrame],
) (**protobufs.ProposalVote, error) {
// Get signing key
signer, _, publicKey, _ := p.engine.GetProvingKey(p.engine.config.Engine)
if publicKey == nil {
p.engine.logger.Error("no proving key available")
return nil, errors.Wrap(
errors.New("no proving key available for voting"),
"sign vote",
)
}
// Create vote (signature)
signatureData := verification.MakeVoteMessage(
nil,
state.Rank,
state.Identifier,
)
sig, err := signer.SignWithDomain(signatureData, []byte("global"))
if err != nil {
p.engine.logger.Error("could not sign vote", zap.Error(err))
return nil, errors.Wrap(err, "sign vote")
}
voterAddress := p.engine.getAddressFromPublicKey(publicKey)
// Create vote message
vote := &protobufs.ProposalVote{
FrameNumber: (*state.State).Header.FrameNumber,
Rank: (*state.State).Header.Rank,
Selector: []byte((*state.State).Identity()),
Timestamp: uint64(time.Now().UnixMilli()),
PublicKeySignatureBls48581: &protobufs.BLS48581AddressedSignature{
Address: voterAddress,
Signature: sig,
},
}
return &vote, nil
}
var _ consensus.VotingProvider[*protobufs.GlobalFrame, *protobufs.ProposalVote, GlobalPeerID] = (*GlobalVotingProvider)(nil)