ceremonyclient/node/consensus/global/consensus_dynamic_committee.go
Cassandra Heart bc10bd497c
v2.1.0.7
2025-11-13 23:37:09 -06:00

185 lines
4.6 KiB
Go

package global
import (
"bytes"
"encoding/binary"
"math/big"
"slices"
"github.com/iden3/go-iden3-crypto/poseidon"
"github.com/pkg/errors"
"source.quilibrium.com/quilibrium/monorepo/consensus/models"
tconsensus "source.quilibrium.com/quilibrium/monorepo/types/consensus"
)
type ConsensusWeightedIdentity struct {
prover *tconsensus.ProverInfo
}
// Identity implements models.WeightedIdentity.
func (c *ConsensusWeightedIdentity) Identity() models.Identity {
return models.Identity(c.prover.Address)
}
// PublicKey implements models.WeightedIdentity.
func (c *ConsensusWeightedIdentity) PublicKey() []byte {
return c.prover.PublicKey
}
// Weight implements models.WeightedIdentity.
func (c *ConsensusWeightedIdentity) Weight() uint64 {
return c.prover.Seniority
}
// IdentitiesByRank implements consensus.DynamicCommittee.
func (e *GlobalConsensusEngine) IdentitiesByRank(
rank uint64,
) ([]models.WeightedIdentity, error) {
proverInfo, err := e.proverRegistry.GetActiveProvers(nil)
if err != nil {
return nil, errors.Wrap(err, "identities by rank")
}
return internalProversToWeightedIdentity(proverInfo), nil
}
// IdentitiesByState implements consensus.DynamicCommittee.
func (e *GlobalConsensusEngine) IdentitiesByState(
stateID models.Identity,
) ([]models.WeightedIdentity, error) {
proverInfo, err := e.proverRegistry.GetActiveProvers(nil)
if err != nil {
return nil, errors.Wrap(err, "identities by state")
}
return internalProversToWeightedIdentity(proverInfo), nil
}
// IdentityByRank implements consensus.DynamicCommittee.
func (e *GlobalConsensusEngine) IdentityByRank(
rank uint64,
participantID models.Identity,
) (models.WeightedIdentity, error) {
proverInfo, err := e.proverRegistry.GetActiveProvers(nil)
if err != nil {
return nil, errors.Wrap(err, "identity by rank")
}
var found *tconsensus.ProverInfo
for _, p := range proverInfo {
if bytes.Equal(p.Address, []byte(participantID)) {
found = p
break
}
}
if found == nil {
return nil, errors.Wrap(errors.New("prover not found"), "identity by rank")
}
return internalProverToWeightedIdentity(found), nil
}
// IdentityByState implements consensus.DynamicCommittee.
func (e *GlobalConsensusEngine) IdentityByState(
stateID models.Identity,
participantID models.Identity,
) (models.WeightedIdentity, error) {
proverInfo, err := e.proverRegistry.GetActiveProvers(nil)
if err != nil {
return nil, errors.Wrap(err, "identity by state")
}
var found *tconsensus.ProverInfo
for _, p := range proverInfo {
if bytes.Equal(p.Address, []byte(participantID)) {
found = p
break
}
}
if found == nil {
return nil, errors.Wrap(errors.New("prover not found"), "identity by state")
}
return internalProverToWeightedIdentity(found), nil
}
// LeaderForRank implements consensus.DynamicCommittee.
func (e *GlobalConsensusEngine) LeaderForRank(
rank uint64,
) (models.Identity, error) {
// TODO(2.2): revisit this
inputBI, err := poseidon.HashBytes(slices.Concat(
binary.BigEndian.AppendUint64(nil, rank),
))
if err != nil {
return "", errors.Wrap(err, "leader for rank")
}
proverSet, err := e.proverRegistry.GetActiveProvers(nil)
if err != nil {
return "", errors.Wrap(err, "leader for rank")
}
inputBI.Mod(inputBI, big.NewInt(int64(len(proverSet))))
index := inputBI.Int64()
return models.Identity(proverSet[int(index)].Address), nil
}
// QuorumThresholdForRank implements consensus.DynamicCommittee.
func (e *GlobalConsensusEngine) QuorumThresholdForRank(
rank uint64,
) (uint64, error) {
proverInfo, err := e.proverRegistry.GetActiveProvers(nil)
if err != nil {
return 0, errors.Wrap(err, "quorum threshold for rank")
}
total := uint64(0)
for _, p := range proverInfo {
total += p.Seniority
}
return (total * 2) / 3, nil
}
// Self implements consensus.DynamicCommittee.
func (e *GlobalConsensusEngine) Self() models.Identity {
return e.getPeerID().Identity()
}
// TimeoutThresholdForRank implements consensus.DynamicCommittee.
func (e *GlobalConsensusEngine) TimeoutThresholdForRank(
rank uint64,
) (uint64, error) {
proverInfo, err := e.proverRegistry.GetActiveProvers(nil)
if err != nil {
return 0, errors.Wrap(err, "quorum threshold for rank")
}
total := uint64(0)
for _, p := range proverInfo {
total += p.Seniority
}
return (total * 2) / 3, nil
}
func internalProversToWeightedIdentity(
provers []*tconsensus.ProverInfo,
) []models.WeightedIdentity {
wis := []models.WeightedIdentity{}
for _, p := range provers {
wis = append(wis, internalProverToWeightedIdentity(p))
}
return wis
}
func internalProverToWeightedIdentity(
prover *tconsensus.ProverInfo,
) models.WeightedIdentity {
return &ConsensusWeightedIdentity{prover}
}