Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[DON'T MERGE] feat(x/gov): add governors #16

Draft
wants to merge 47 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from 32 commits
Commits
Show all changes
47 commits
Select commit Hold shift + click to select a range
b301574
tally prototype with governors
giunatale Sep 13, 2024
8cb99c2
add protos
giunatale Sep 13, 2024
41b042f
governor object started (copy from Validator)
giunatale Sep 13, 2024
d4a8c03
wip
giunatale Sep 13, 2024
96abd4c
wip
giunatale Sep 14, 2024
f9ad9d8
...
giunatale Sep 14, 2024
700703d
...
giunatale Sep 14, 2024
f6c3392
missing governor election
giunatale Sep 14, 2024
6951d84
not right, cannot iterate on all governors
giunatale Sep 14, 2024
1a8495c
remove percentage and try sorting governors by VP
giunatale Sep 14, 2024
a769118
add msgs
giunatale Sep 14, 2024
ca19aaf
update test mock keepers
giunatale Sep 14, 2024
be1db00
...
giunatale Sep 14, 2024
e1a2bbb
compiles
giunatale Sep 15, 2024
851c005
add query and cli
giunatale Sep 15, 2024
372bca2
allow governor status updates only once a month
giunatale Sep 15, 2024
4ea0dad
genesis
giunatale Sep 15, 2024
fedba97
fix e2e
giunatale Sep 15, 2024
68645f2
add governors vp invariant
giunatale Sep 15, 2024
201b112
iterate over correct values
giunatale Sep 16, 2024
e5c1284
format pass
giunatale Sep 18, 2024
6f37870
fix missing return
giunatale Sep 18, 2024
c0cdec9
cleanup protos
giunatale Sep 19, 2024
80f44c7
Merge branch 'main' into governors
giunatale Sep 24, 2024
afa8d07
fix merge mistake
giunatale Sep 24, 2024
58d6a83
fix merge mistakes
giunatale Sep 24, 2024
44d71e6
approx VP computation for quorum with governors
giunatale Sep 24, 2024
5767cca
fix error in keeper.GetGovernor
giunatale Sep 24, 2024
25d017a
protogen
giunatale Sep 24, 2024
671755c
add min bonding requirements for governors
giunatale Sep 24, 2024
86031e6
governance delegations invariant
giunatale Sep 24, 2024
3a9f71f
fmt pass
giunatale Sep 24, 2024
b8eac36
use math
giunatale Sep 25, 2024
9bcbd0f
remove iteration over map
giunatale Sep 25, 2024
8daaffb
more efficient
giunatale Sep 25, 2024
26ff811
fix
giunatale Sep 25, 2024
ec48fe5
remove ambiguity
giunatale Sep 25, 2024
180e1c1
...
giunatale Sep 25, 2024
e147827
various fixes
giunatale Sep 25, 2024
e0d3865
Merge remote-tracking branch 'origin/main' into governors
giunatale Sep 25, 2024
48f45be
fix error codes
giunatale Sep 25, 2024
0659b9d
add alternative for tallying governors VP
giunatale Sep 25, 2024
8b79c43
tally results updated only once only per voter
giunatale Sep 25, 2024
1f8e5a9
...
giunatale Sep 25, 2024
374c315
Merge remote-tracking branch 'origin/main' into governors
giunatale Sep 27, 2024
90f540c
Merge branch 'main' into governors
giunatale Oct 2, 2024
c5e5ce4
fmt
giunatale Oct 2, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 10 additions & 9 deletions app/keepers/keepers.go
Original file line number Diff line number Diff line change
Expand Up @@ -207,15 +207,6 @@ func NewAppKeeper(
authtypes.NewModuleAddress(govtypes.ModuleName).String(),
)

// register the staking hooks
// NOTE: stakingKeeper above is passed by reference, so that it will contain these hooks
appKeepers.StakingKeeper.SetHooks(
stakingtypes.NewMultiStakingHooks(
appKeepers.DistrKeeper.Hooks(),
appKeepers.SlashingKeeper.Hooks(),
),
)

// UpgradeKeeper must be created before IBCKeeper
appKeepers.UpgradeKeeper = upgradekeeper.NewKeeper(
skipUpgradeHeights,
Expand Down Expand Up @@ -266,6 +257,16 @@ func NewAppKeeper(
// If evidence needs to be handled for the app, set routes in router here and seal
appKeepers.EvidenceKeeper = *evidenceKeeper

// register the staking hooks
// NOTE: stakingKeeper above is passed by reference, so that it will contain these hooks
appKeepers.StakingKeeper.SetHooks(
stakingtypes.NewMultiStakingHooks(
appKeepers.DistrKeeper.Hooks(),
appKeepers.SlashingKeeper.Hooks(),
appKeepers.GovKeeper.StakingHooks(),
),
)

return appKeepers
}

Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ require (
golang.org/x/sync v0.4.0
google.golang.org/genproto/googleapis/api v0.0.0-20231212172506-995d672761c0
google.golang.org/protobuf v1.32.0
gopkg.in/yaml.v2 v2.4.0
gotest.tools/v3 v3.5.1
sigs.k8s.io/yaml v1.4.0
)
Expand Down Expand Up @@ -203,7 +204,6 @@ require (
google.golang.org/appengine v1.6.8 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20240108191215-35c7eff3a6b1 // indirect
gopkg.in/ini.v1 v1.67.0 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
nhooyr.io/websocket v1.8.6 // indirect
pgregory.net/rapid v1.1.0 // indirect
Expand Down
4 changes: 4 additions & 0 deletions proto/atomone/gov/v1/genesis.proto
Original file line number Diff line number Diff line change
Expand Up @@ -34,4 +34,8 @@ message GenesisState {
//
// Since: cosmos-sdk 0.48
string constitution = 9;
// governors defines all the governors present at genesis.
repeated Governor governors = 10;
// governance_delegations defines all the governance delegations present at genesis.
repeated GovernanceDelegation governance_delegations = 11;
}
90 changes: 90 additions & 0 deletions proto/atomone/gov/v1/gov.proto
Original file line number Diff line number Diff line change
Expand Up @@ -272,4 +272,94 @@ message Params {
// Number of times a proposal should be checked for quorum after the quorum timeout
// has elapsed. Used to compute the amount of time in between quorum checks.
uint64 quorum_check_count = 22;

// defines the maximum number of governors that can be active at any given time.
uint64 max_governors = 23;
// defines the duration of time that need to elapse between governor status changes.
google.protobuf.Duration governor_status_change_period = 24 [(gogoproto.stdduration) = true];
// defines the minimum amound of bonded tokens, aka the "self-delegation" (because active governors
// must have the governance VP from the base account automatically delegated to them), that a governor
// must have to be considered active.
string min_governor_self_delegation = 25 [(cosmos_proto.scalar) = "cosmos.Int" ];
}


// Governor defines a governor, together with the total amount of delegated
// validator's bond shares for a set amount of validators. When a delegator
// delegates a percentage of its x/gov power to a governor, the resulting
// shares from each delegators delegations in x/staking are added to the
// governor's total shares.
message Governor {
option (gogoproto.equal) = false;
option (gogoproto.goproto_getters) = false;

// governor_address defines the address of the governor; bech32-encoded.
string governor_address = 1;
// status is the status of the governor (active/inactive).
GovernorStatus status = 2;
// description defines the description terms for the governor.
GovernorDescription description = 3 [(gogoproto.nullable) = false, (amino.dont_omitempty) = true];
// voting_power defines the (estimated) voting power of the governor.
string voting_power = 4 [
(cosmos_proto.scalar) = "cosmos.Dec",
(gogoproto.customtype) = "cosmossdk.io/math.LegacyDec",
(gogoproto.nullable) = false
];

// last_status_change_time is the time when the governor's status was last changed.
google.protobuf.Timestamp last_status_change_time = 5 [(gogoproto.stdtime) = true];
}

// GovernorStatus is the status of a governor.
enum GovernorStatus {
option (gogoproto.goproto_enum_prefix) = false;

// UNSPECIFIED defines an invalid governor status.
GOVERNOR_STATUS_UNSPECIFIED = 0 [(gogoproto.enumvalue_customname) = "Unspecified"];
// ACTIVE defines a governor that is active.
GOVERNOR_STATUS_ACTIVE = 1 [(gogoproto.enumvalue_customname) = "Active"];
// INACTIVE defines a governor that is inactive.
GOVERNOR_STATUS_INACTIVE = 2 [(gogoproto.enumvalue_customname) = "Inactive"];
}

// Description defines a governor description.
message GovernorDescription {
option (gogoproto.equal) = true;

// moniker defines a human-readable name for the governor.
string moniker = 1;
// identity defines an optional identity signature (ex. UPort or Keybase).
string identity = 2;
// website defines an optional website link.
string website = 3;
// security_contact defines an optional email for security contact.
string security_contact = 4;
// details define other optional details.
string details = 5;
}

// GovernorValShares holds the number of virtual shares from the
// specific validator that a governor can use to vote on proposals.
message GovernorValShares {
option (gogoproto.equal) = false;
option (gogoproto.goproto_getters) = false;

string governor_address = 1;
string validator_address = 2 [(cosmos_proto.scalar) = "cosmos.ValidatorAddressString"];
// shares define the delegation shares available from this validator.
string shares = 3 [
(cosmos_proto.scalar) = "cosmos.Dec",
(gogoproto.customtype) = "cosmossdk.io/math.LegacyDec",
(gogoproto.nullable) = false
];
}

// GovernanceDelegation defines a delegation of governance voting power from a
// delegator to a governor.
message GovernanceDelegation {
option (gogoproto.equal) = false;
option (gogoproto.goproto_getters) = false;

string delegator_address = 1 [(cosmos_proto.scalar) = "cosmos.AddressString"];
string governor_address = 2;
}
100 changes: 100 additions & 0 deletions proto/atomone/gov/v1/query.proto
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,31 @@ service Query {
option (google.api.http).get =
"/atomone/gov/v1/proposals/{proposal_id}/tally";
}

// Governor queries governor information based on governor address.
rpc Governor(QueryGovernorRequest) returns (QueryGovernorResponse) {
option (google.api.http).get = "/atomone/gov/v1/governor/{governor_address}";
}

// Governors queries all governors.
rpc Governors(QueryGovernorsRequest) returns (QueryGovernorsResponse) {
option (google.api.http).get = "/atomone/gov/v1/governors";
}

// GovernanceDelegations queries all delegations of a governor.
rpc GovernanceDelegations(QueryGovernanceDelegationsRequest) returns (QueryGovernanceDelegationsResponse) {
option (google.api.http).get = "/atomone/gov/v1/governors/{governor_address}/delegations";
}

// GovernanceDelegation queries a delegation
rpc GovernanceDelegation(QueryGovernanceDelegationRequest) returns (QueryGovernanceDelegationResponse) {
option (google.api.http).get = "/atomone/gov/v1/delegations/{delegator_address}";
}

// GovernorValShares queries all governor virtual validator shares resulting from all governance delegations.
rpc GovernorValShares(QueryGovernorValSharesRequest) returns (QueryGovernorValSharesResponse) {
option (google.api.http).get = "/atomone/gov/v1/vshares/{governor_address}";
}
}

// QueryConstitutionRequest is the request type for the Query/Constitution RPC method
Expand Down Expand Up @@ -209,3 +234,78 @@ message QueryTallyResultResponse {
// tally defines the requested tally.
TallyResult tally = 1;
}

// QueryGovernorRequest is the request type for the Query/Governor RPC method.
message QueryGovernorRequest {
// gvernor_address defines the address of the governor.
string governor_address = 1 [(cosmos_proto.scalar) = "atomone.GovernorAddressString"];
}

// QueryGovernorResponse is the response type for the Query/Governor RPC method.
message QueryGovernorResponse {
// governor defines the requested governor.
Governor governor = 1;
}

// QueryGovernorsRequest is the request type for the Query/Governors RPC method.
message QueryGovernorsRequest {
// pagination defines an optional pagination for the request.
cosmos.base.query.v1beta1.PageRequest pagination = 1;
}

// QueryGovernorsResponse is the response type for the Query/Governors RPC method.
message QueryGovernorsResponse {
// governors defines the requested governors.
repeated Governor governors = 1;

// pagination defines the pagination in the response.
cosmos.base.query.v1beta1.PageResponse pagination = 2;
}

// QueryGovernanceDelegationsRequest is the request type for the Query/GovernanceDelegations RPC method.
message QueryGovernanceDelegationsRequest {
// governor_address defines the address of the governor.
string governor_address = 1 [(cosmos_proto.scalar) = "atomone.GovernorAddressString"];

// pagination defines an optional pagination for the request.
cosmos.base.query.v1beta1.PageRequest pagination = 2;
}

// QueryGovernanceDelegationsResponse is the response type for the Query/GovernanceDelegations RPC method.
message QueryGovernanceDelegationsResponse {
// delegations defines the requested delegations.
repeated GovernanceDelegation delegations = 1;

// pagination defines the pagination in the response.
cosmos.base.query.v1beta1.PageResponse pagination = 2;
}

// QueryGovernanceDelegationRequest is the request type for the Query/GovernanceDelegation RPC method.
message QueryGovernanceDelegationRequest {
// delegator_address defines the address of the delegator.
string delegator_address = 1 [(cosmos_proto.scalar) = "cosmos.AddressString"];
}

// QueryGovernanceDelegationResponse is the response type for the Query/GovernanceDelegation RPC method.
message QueryGovernanceDelegationResponse {
// governor_address defines the address of the governor.
string governor_address = 1;
}

// QueryGovernorValSharesRequest is the request type for the Query/GovernorValShares RPC method.
message QueryGovernorValSharesRequest {
// governor_address defines the address of the governor.
string governor_address = 1 [(cosmos_proto.scalar) = "atomone.GovernorAddressString"];

// pagination defines the pagination in the request.
cosmos.base.query.v1beta1.PageRequest pagination = 2;
}

// QueryGovernorValSharesResponse is the response type for the Query/GovernorValShares RPC method.
message QueryGovernorValSharesResponse {
// val_shares defines the requested validator shares.
repeated GovernorValShares val_shares = 1;

// pagination defines the pagination in the response.
cosmos.base.query.v1beta1.PageResponse pagination = 2;
}
97 changes: 96 additions & 1 deletion proto/atomone/gov/v1/tx.proto
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,23 @@ service Msg {
// new constitution amendment. The authority is defined in the keeper.
rpc ProposeConstitutionAmendment(MsgProposeConstitutionAmendment)
returns (MsgProposeConstitutionAmendmentResponse);

// CreateGovernor defines a method to create a new governor.
rpc CreateGovernor(MsgCreateGovernor) returns (MsgCreateGovernorResponse);

// EditGovernor defines a method to edit an existing governor.
// It also sets its status.
rpc EditGovernor(MsgEditGovernor) returns (MsgEditGovernorResponse);

// UpdateGovernorStatus defines a method to update the status of a governor.
rpc UpdateGovernorStatus(MsgUpdateGovernorStatus) returns (MsgUpdateGovernorStatusResponse);

// DelegateGovernor defines a method to delegate a non-zero percentange of
// governance voting power from a delegator to a governor.
rpc DelegateGovernor(MsgDelegateGovernor) returns (MsgDelegateGovernorResponse);

// UndelegateGovernor defines a method to undelegate governance voting power
rpc UndelegateGovernor(MsgUndelegateGovernor) returns (MsgUndelegateGovernorResponse);
}

// MsgSubmitProposal defines an sdk.Msg type that supports submitting arbitrary
Expand Down Expand Up @@ -217,4 +234,82 @@ message MsgProposeConstitutionAmendment {

// MsgProposeConstitutionAmendmentResponse defines the response structure for executing a
// MsgProposeConstitutionAmendment message.
message MsgProposeConstitutionAmendmentResponse {}
message MsgProposeConstitutionAmendmentResponse {}

// MsgCreateGovernor defines a SDK message for creating a new governor.
message MsgCreateGovernor {
option (cosmos.msg.v1.signer) = "address";
option (amino.name) = "atomone/MsgCreateGovernor";

option (gogoproto.equal) = false;
option (gogoproto.goproto_getters) = false;

// address is the base account address that is creating the governor.
string address = 1 [(cosmos_proto.scalar) = "cosmos.AddressString"];
GovernorDescription description = 2 [(gogoproto.nullable) = false, (amino.dont_omitempty) = true];
}

// MsgCreateGovernorrResponse defines the Msg/CreateGovernor response type.
message MsgCreateGovernorResponse {}

// MsgEditGovernor defines a SDK message for editing an existing governor.
message MsgEditGovernor {
option (cosmos.msg.v1.signer) = "address";
option (amino.name) = "cosmos-sdk/MsgEditGovernor";

option (gogoproto.equal) = false;
option (gogoproto.goproto_getters) = false;

// address is the base account address that is editing the corresponding governor.
string address = 1 [(cosmos_proto.scalar) = "cosmos.AddressString"];
GovernorDescription description = 2 [(gogoproto.nullable) = false, (amino.dont_omitempty) = true];
}

// MsgEditGovernorResponse defines the Msg/EditGovernor response type.
message MsgEditGovernorResponse {}

// MsgUpdateGovernorStatus defines a SDK message for updating the status of a governor.
message MsgUpdateGovernorStatus {
option (cosmos.msg.v1.signer) = "address";
option (amino.name) = "cosmos-sdk/MsgUpdateGovernorStatus";

option (gogoproto.equal) = false;
option (gogoproto.goproto_getters) = false;

// address is the base account address that is editing the corresponding governor.
string address = 1 [(cosmos_proto.scalar) = "cosmos.AddressString"];
GovernorStatus status = 2;
}

// MsgUpdateGovernorStatusResponse defines the Msg/UpdateGovernorStatus response type.
message MsgUpdateGovernorStatusResponse {}

// MsgDelegateGovernor defines a SDK message for performing a delegation of governance voting power
// from a delegator to a governor.
message MsgDelegateGovernor {
option (cosmos.msg.v1.signer) = "delegator_address";
option (amino.name) = "atomone/MsgDelegateGovernor";

option (gogoproto.equal) = false;
option (gogoproto.goproto_getters) = false;

string delegator_address = 1 [(cosmos_proto.scalar) = "cosmos.AddressString"];
string governor_address = 2;
}

// MsgDelegateGovernorResponse defines the Msg/Delegate response type.
message MsgDelegateGovernorResponse {}

// MsgUndelegateGovernor defines a SDK message for undelegating governance voting power
message MsgUndelegateGovernor {
option (cosmos.msg.v1.signer) = "delegator_address";
option (amino.name) = "cosmos-sdk/MsgUndelegateGovernor";

option (gogoproto.equal) = false;
option (gogoproto.goproto_getters) = false;

string delegator_address = 1 [(cosmos_proto.scalar) = "cosmos.AddressString"];
}

// MsgUndelegateGovernorResponse defines the Msg/UndelegateGovernor response type.
message MsgUndelegateGovernorResponse {}
4 changes: 4 additions & 0 deletions tests/e2e/genesis.go
Original file line number Diff line number Diff line change
Expand Up @@ -128,9 +128,12 @@ func modifyGenesis(path, moniker, amountStr string, addrAll []sdk.AccAddress, de
lawThreshold, _ := sdk.NewDecFromStr("0.000000000000000001")
amendmentsQuorum, _ := sdk.NewDecFromStr("0.000000000000000001")
amendmentsThreshold, _ := sdk.NewDecFromStr("0.000000000000000001")
minGovernorSelfDelegation, _ := sdk.NewIntFromString("10000000")

maxDepositPeriod := 10 * time.Minute
votingPeriod := 15 * time.Second
maxGovernors := uint64(100)
governorStatusChangePeriod := 30 * time.Second

govGenState := govv1.NewGenesisState(1,
govv1.NewParams(
Expand All @@ -141,6 +144,7 @@ func modifyGenesis(path, moniker, amountStr string, addrAll []sdk.AccAddress, de
sdk.ZeroDec().String(),
false, false, govv1.DefaultMinDepositRatio.String(),
govv1.DefaultQuorumTimeout, govv1.DefaultMaxVotingPeriodExtension, govv1.DefaultQuorumCheckCount,
maxGovernors, governorStatusChangePeriod, minGovernorSelfDelegation.String(),
),
)
govGenStateBz, err := cdc.MarshalJSON(govGenState)
Expand Down
Loading
Loading