From f313cbd5894cb1378d7d0f3ecbba3ac408297305 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andrej=20Buko=C5=A1ek?= Date: Thu, 14 Sep 2023 17:43:58 +0200 Subject: [PATCH] temp --- go/consensus/cometbft/api/genesis.go | 2 +- .../cometbft/apps/scheduler/genesis.go | 4 +-- .../cometbft/apps/scheduler/scheduler.go | 2 +- go/genesis/api/sanity_check.go | 2 +- go/scheduler/api/api.go | 33 +++++++++++++++++-- go/scheduler/api/sanity_check.go | 7 ++-- 6 files changed, 40 insertions(+), 10 deletions(-) diff --git a/go/consensus/cometbft/api/genesis.go b/go/consensus/cometbft/api/genesis.go index 41aa122a972..9c0e92871f4 100644 --- a/go/consensus/cometbft/api/genesis.go +++ b/go/consensus/cometbft/api/genesis.go @@ -174,7 +174,7 @@ func convertValidators(d *genesis.Document) ([]cmttypes.GenesisValidator, error) // have an account in the ledger at all. stake = &quantity.Quantity{} } - power, err = scheduler.VotingPowerFromStake(stake) + power, err = scheduler.VotingPowerFromStake(stake, d.Scheduler.Parameters.VotingPowerDistribution) if err != nil { return nil, fmt.Errorf("cometbft: computing voting power for entity %s with account %s and stake %v: %w", openedNode.EntityID, diff --git a/go/consensus/cometbft/apps/scheduler/genesis.go b/go/consensus/cometbft/apps/scheduler/genesis.go index b0036193ede..0948c3a3f85 100644 --- a/go/consensus/cometbft/apps/scheduler/genesis.go +++ b/go/consensus/cometbft/apps/scheduler/genesis.go @@ -109,7 +109,7 @@ func (app *schedulerApplication) InitChain(ctx *abciAPI.Context, req types.Reque err, ) } - expectedPower, err = scheduler.VotingPowerFromStake(&account.Escrow.Active.Balance) + expectedPower, err = scheduler.VotingPowerFromStake(&account.Escrow.Active.Balance, doc.Scheduler.Parameters.VotingPowerDistribution) if err != nil { ctx.Logger().Error("computing voting power from stake failed", "err", err, @@ -162,7 +162,7 @@ func (app *schedulerApplication) InitChain(ctx *abciAPI.Context, req types.Reque } if !doc.Scheduler.Parameters.DebugBypassStake { - supplyPower, err := scheduler.VotingPowerFromStake(&doc.Staking.TotalSupply) + supplyPower, err := scheduler.VotingPowerFromStake(&doc.Staking.TotalSupply, doc.Scheduler.Parameters.VotingPowerDistribution) if err != nil { return fmt.Errorf("init chain: total supply would break voting power computation: %w", err) } diff --git a/go/consensus/cometbft/apps/scheduler/scheduler.go b/go/consensus/cometbft/apps/scheduler/scheduler.go index 486319b3b30..f3ffa5a20dc 100644 --- a/go/consensus/cometbft/apps/scheduler/scheduler.go +++ b/go/consensus/cometbft/apps/scheduler/scheduler.go @@ -535,7 +535,7 @@ electLoop: if err != nil { return nil, fmt.Errorf("failed to fetch escrow balance for account %s: %w", entAddr, err) } - power, err = scheduler.VotingPowerFromStake(stake) + power, err = scheduler.VotingPowerFromStake(stake, params.VotingPowerDistribution) if err != nil { return nil, fmt.Errorf("computing voting power for account %s with balance %v: %w", entAddr, stake, err, diff --git a/go/genesis/api/sanity_check.go b/go/genesis/api/sanity_check.go index fc87a6ff2b5..1c058edd79a 100644 --- a/go/genesis/api/sanity_check.go +++ b/go/genesis/api/sanity_check.go @@ -42,7 +42,7 @@ func (d *Document) SanityCheck() error { if err := d.KeyManager.SanityCheck(); err != nil { return err } - if err := d.Scheduler.SanityCheck(&d.Staking.TotalSupply); err != nil { + if err := d.Scheduler.SanityCheck(&d.Staking.TotalSupply, d.Scheduler.Parameters.VotingPowerDistribution); err != nil { return err } return d.Governance.SanityCheck(epoch, &d.Staking.GovernanceDeposits) diff --git a/go/scheduler/api/api.go b/go/scheduler/api/api.go index 0891b383561..d7e11603afd 100644 --- a/go/scheduler/api/api.go +++ b/go/scheduler/api/api.go @@ -204,13 +204,25 @@ func (c *Committee) EncodedMembersHash() hash.Hash { // BaseUnitsPerVotingPower is the ratio of base units staked to validator power. var BaseUnitsPerVotingPower quantity.Quantity +// VotingPowerDistribution is the voting power distribution type. +type VotingPowerDistribution uint8 + +const ( + // VotingPowerDistributionLinear is the distribution where power is + // linearly proportional to the stake. + VotingPowerDistributionLinear = 0 + // VotingPowerDistributionSqrt is the distribution where power is + // proportional to the square root of the stake. + VotingPowerDistributionSqrt = 1 +) + // VotingPowerFromStake computes that by dividing by BaseUnitsPerVotingPower. // // NOTE: It's not that we're implementation-hiding the conversion though. // It's just that otherwise if we accidentally skip the `IsInt64`, it would // still appear to work, and that would be a bad thing to have in a routine // that's written multiple times. -func VotingPowerFromStake(t *quantity.Quantity) (int64, error) { +func VotingPowerFromStake(t *quantity.Quantity, distribution VotingPowerDistribution) (int64, error) { powerQ := t.Clone() if err := powerQ.Quo(&BaseUnitsPerVotingPower); err != nil { return 0, fmt.Errorf("quo %v / %v: %w", t, &BaseUnitsPerVotingPower, err) @@ -226,7 +238,15 @@ func VotingPowerFromStake(t *quantity.Quantity) (int64, error) { if !powerBI.IsInt64() { return 0, fmt.Errorf("%v is too many base units to convert to power", powerQ) } - return powerBI.Int64(), nil + + switch distribution { + case VotingPowerDistributionLinear: + return powerBI.Int64(), nil + case VotingPowerDistributionSqrt: + return powerBI.Sqrt(powerBI).Int64(), nil + default: + panic("invalid voting power distribution") + } } // Validator is a consensus validator. @@ -313,6 +333,9 @@ type ConsensusParameters struct { // DebugAllowWeakAlpha allows VRF based elections based on proofs // generated by an alpha value considered weak. DebugAllowWeakAlpha bool `json:"debug_allow_weak_alpha,omitempty"` + + // VotingPowerDistribution is the voting power distribution. + VotingPowerDistribution VotingPowerDistribution `json:"voting_power_distribution,omitempty"` } // ConsensusParameterChanges are allowed scheduler consensus parameter changes. @@ -322,6 +345,9 @@ type ConsensusParameterChanges struct { // MaxValidators is the new maximum number of validators. MaxValidators *int `json:"max_validators"` + + // VotingPowerDistribution is the new voting power distribution. + VotingPowerDistribution *VotingPowerDistribution `json:"voting_power_distribution,omitempty"` } // Apply applies changes to the given consensus parameters. @@ -332,6 +358,9 @@ func (c *ConsensusParameterChanges) Apply(params *ConsensusParameters) error { if c.MaxValidators != nil { params.MaxValidators = *c.MaxValidators } + if c.VotingPowerDistribution != nil { + params.VotingPowerDistribution = *c.VotingPowerDistribution + } return nil } diff --git a/go/scheduler/api/sanity_check.go b/go/scheduler/api/sanity_check.go index 0ab3f06cb74..609b7b19e90 100644 --- a/go/scheduler/api/sanity_check.go +++ b/go/scheduler/api/sanity_check.go @@ -9,13 +9,13 @@ import ( ) // SanityCheck does basic sanity checking on the genesis state. -func (g *Genesis) SanityCheck(stakingTotalSupply *quantity.Quantity) error { +func (g *Genesis) SanityCheck(stakingTotalSupply *quantity.Quantity, votingPowerDistribution VotingPowerDistribution) error { if err := g.Parameters.SanityCheck(); err != nil { return fmt.Errorf("scheduler: sanity check failed: %w", err) } if !g.Parameters.DebugBypassStake { - supplyPower, err := VotingPowerFromStake(stakingTotalSupply) + supplyPower, err := VotingPowerFromStake(stakingTotalSupply, votingPowerDistribution) if err != nil { return fmt.Errorf("scheduler: sanity check failed: total supply would break voting power computation: %w", err) } @@ -42,7 +42,8 @@ func (p *ConsensusParameters) SanityCheck() error { // SanityCheck performs a sanity check on the consensus parameter changes. func (c *ConsensusParameterChanges) SanityCheck() error { if c.MinValidators == nil && - c.MaxValidators == nil { + c.MaxValidators == nil && + c.VotingPowerDistribution == nil { return fmt.Errorf("consensus parameter changes should not be empty") } return nil