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

feat(dogfood): implement ExportGenesis #95

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
86bef00
feat(dogfood): re-scaffold genesis
MaxMustermann2 Jun 10, 2024
e8d36f0
fix(dogfood): remove deprecated keys
MaxMustermann2 Jun 10, 2024
50452cf
refactor: use new dogfood genesis
MaxMustermann2 Jun 10, 2024
89591f3
refactor(dogfood): - validatorupdate from gen
MaxMustermann2 Jun 10, 2024
686631a
refactor(dogfood): update ImportGenesis
MaxMustermann2 Jun 10, 2024
9192a9c
refactor(dogfood): simplify gen state names
MaxMustermann2 Jun 10, 2024
0b4957b
feat(dogfood): implement ExportGenesis
MaxMustermann2 Jun 10, 2024
12aa144
chore: lint
MaxMustermann2 Jun 10, 2024
3f28fc2
proto(dogfood): remove unused import
MaxMustermann2 Jun 10, 2024
9a7912e
fix(local): compat with new dogfood genesis
MaxMustermann2 Jun 10, 2024
ddc8e48
chore: lint proto file and gen
MaxMustermann2 Jun 10, 2024
dab2d5e
fix(test): use correct struct member name
MaxMustermann2 Jun 10, 2024
b2ea284
chore: update go version to 1.21.11
MaxMustermann2 Jun 10, 2024
685f68f
fix(ci): disable buggy workflows
MaxMustermann2 Jun 10, 2024
1b4365a
chore: lint
MaxMustermann2 Jun 10, 2024
97723ed
fix(dogfood): don't stop iterating in export
MaxMustermann2 Jun 12, 2024
2a8f1ae
fix(doc): add comment about exported validators
MaxMustermann2 Jun 12, 2024
e8731d0
doc(dogfood): log iteration failure
MaxMustermann2 Jun 12, 2024
e983c46
docs(delegation): validation of record key params
MaxMustermann2 Jun 12, 2024
5f19653
Merge branch 'develop' into fix/dogfood-export-gen
cloud8little Jun 13, 2024
98bfc6b
Merge develop
MaxMustermann2 Jun 16, 2024
e1a9294
fix(app): register operator hooks for dogfood
MaxMustermann2 Jun 16, 2024
e72979a
feat(operator): return `OptingOut` status
MaxMustermann2 Jun 16, 2024
03623e6
refactor(operator): rationalize opt-in/out
MaxMustermann2 Jun 16, 2024
5cd3ac1
refactor(delegation): verbose panic
MaxMustermann2 Jun 16, 2024
b7c4dab
fix(dogfood): query validator by cons addr not hex
MaxMustermann2 Jun 16, 2024
7a2611e
refactor(dogfood): move opt func to correct loc
MaxMustermann2 Jun 16, 2024
d0c2e6e
chore(x/operator): lint go
MaxMustermann2 Jun 16, 2024
add0753
fix(operator): wrap and return error
MaxMustermann2 Jun 16, 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
4 changes: 4 additions & 0 deletions app/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -591,6 +591,10 @@ func NewExocoreApp(
app.AssetsKeeper, // assets for vote power
)

(&app.OperatorKeeper).SetHooks(
app.StakingKeeper.OperatorHooks(),
)

(&app.EpochsKeeper).SetHooks(
app.StakingKeeper.EpochsHooks(),
)
Expand Down
3 changes: 3 additions & 0 deletions app/ethtest_helper.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"encoding/json"
"time"

"cosmossdk.io/math"
"cosmossdk.io/simapp"
"github.com/cosmos/cosmos-sdk/baseapp"
"github.com/cosmos/cosmos-sdk/codec"
Expand Down Expand Up @@ -252,6 +253,8 @@ func genesisStateWithValSet(codec codec.Codec, genesisState simapp.GenesisState,
Power: 1,
},
},
[]dogfoodtypes.EpochToOperatorAddrs{}, []dogfoodtypes.EpochToConsensusAddrs{},
[]dogfoodtypes.EpochToUndelegationRecordKeys{}, math.NewInt(1),
)
genesisState[dogfoodtypes.ModuleName] = codec.MustMarshalJSON(dogfoodGenesis)

Expand Down
9 changes: 4 additions & 5 deletions app/export.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,14 +75,13 @@ func (app *ExocoreApp) ExportAppStateAndValidators(
return servertypes.ExportedApp{}, err
}

validators, err := app.StakingKeeper.WriteValidators(ctx)
if err != nil {
return servertypes.ExportedApp{}, err
}
// the x/dogfood validator set is exported in its `val_set` key, and hence,
// does not need to be part of the app export. in other words, we do not
// duplicate the exported validator set. besides, as far as i can tell, the
// SDK does not use the Validators member of the ExportedApp struct.

return servertypes.ExportedApp{
AppState: appState,
Validators: validators,
Height: height,
ConsensusParams: app.BaseApp.GetConsensusParams(ctx),
}, nil
Expand Down
6 changes: 6 additions & 0 deletions app/test_helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/crypto"

"cosmossdk.io/math"
"cosmossdk.io/simapp"
dbm "github.com/cometbft/cometbft-db"
abci "github.com/cometbft/cometbft/abci/types"
Expand Down Expand Up @@ -267,13 +268,18 @@ func GenesisStateWithValSet(app *ExocoreApp, genesisState simapp.GenesisState,
delegationGenesis := delegationtypes.NewGenesis(delegationsByStaker)
genesisState[delegationtypes.ModuleName] = app.AppCodec().MustMarshalJSON(delegationGenesis)

// create a dogfood genesis with just the validator set, that is, the bare
// minimum valid genesis required to start a chain.
dogfoodGenesis := dogfoodtypes.NewGenesis(
dogfoodtypes.DefaultParams(), []dogfoodtypes.GenesisValidator{
{
PublicKey: consensusKeyRecords[0].Chains[0].ConsensusKey,
Power: 1,
},
},
[]dogfoodtypes.EpochToOperatorAddrs{}, []dogfoodtypes.EpochToConsensusAddrs{},
[]dogfoodtypes.EpochToUndelegationRecordKeys{},
math.NewInt(1), // total vote power
)
genesisState[dogfoodtypes.ModuleName] = app.AppCodec().MustMarshalJSON(dogfoodGenesis)

Expand Down
6 changes: 6 additions & 0 deletions cmd/exocored/testnet.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (
"sort"
"strings"

"cosmossdk.io/math"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"

Expand Down Expand Up @@ -459,6 +460,7 @@ func getTestExocoreGenesis(
Power: power,
})
}
totalPower := math.NewInt(power * int64(len(operatorAddrs)))
return assetstypes.NewGenesis(
assetstypes.DefaultParams(),
clientChains, []assetstypes.StakingAssetInfo{
Expand All @@ -482,6 +484,10 @@ func getTestExocoreGenesis(
[]string{assetID},
),
validators,
[]dogfoodtypes.EpochToOperatorAddrs{},
[]dogfoodtypes.EpochToConsensusAddrs{},
[]dogfoodtypes.EpochToUndelegationRecordKeys{},
totalPower,
)
}

Expand Down
4 changes: 2 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ require (
github.com/smartystreets/goconvey v1.6.4
github.com/spf13/cast v1.5.1
github.com/spf13/cobra v1.7.0
github.com/spf13/pflag v1.0.5
github.com/spf13/viper v1.16.0
github.com/stretchr/testify v1.8.4
go.opencensus.io v0.24.0
Expand All @@ -40,6 +41,7 @@ require (
golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2
google.golang.org/genproto/googleapis/api v0.0.0-20231212172506-995d672761c0
google.golang.org/grpc v1.60.1
google.golang.org/protobuf v1.33.0
gopkg.in/yaml.v2 v2.4.0
sigs.k8s.io/yaml v1.3.0
)
Expand Down Expand Up @@ -201,7 +203,6 @@ require (
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d // indirect
github.com/spf13/afero v1.10.0 // indirect
github.com/spf13/jwalterweatherman v1.1.0 // indirect
github.com/spf13/pflag v1.0.5 // indirect
github.com/status-im/keycard-go v0.2.0 // indirect
github.com/subosito/gotenv v1.4.2 // indirect
github.com/supranational/blst v0.3.11 // indirect
Expand Down Expand Up @@ -232,7 +233,6 @@ require (
google.golang.org/appengine v1.6.8 // indirect
google.golang.org/genproto v0.0.0-20240102182953-50ed04b92917 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20240108191215-35c7eff3a6b1 // indirect
google.golang.org/protobuf v1.33.0 // indirect
gopkg.in/ini.v1 v1.67.0 // indirect
gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
Expand Down
5 changes: 3 additions & 2 deletions local_node.sh
Original file line number Diff line number Diff line change
Expand Up @@ -115,10 +115,11 @@ if [[ $overwrite == "y" || $overwrite == "Y" ]]; then
jq '.app_state["delegation"]["delegations"][0]["delegations"][0]["per_operator_amounts"][0]["value"]["amount"]="5000"' "$GENESIS" >"$TMP_GENESIS" && mv "$TMP_GENESIS" "$GENESIS"

# x/dogfood
jq '.app_state["dogfood"]["initial_val_set"][0]["public_key"]="0xf0f6919e522c5b97db2c8255bff743f9dfddd7ad9fc37cb0c1670b480d0f9914"' "$GENESIS" >"$TMP_GENESIS" && mv "$TMP_GENESIS" "$GENESIS"
jq '.app_state["dogfood"]["initial_val_set"][0]["power"]="5000"' "$GENESIS" >"$TMP_GENESIS" && mv "$TMP_GENESIS" "$GENESIS"
jq '.app_state["dogfood"]["val_set"][0]["public_key"]="0xf0f6919e522c5b97db2c8255bff743f9dfddd7ad9fc37cb0c1670b480d0f9914"' "$GENESIS" >"$TMP_GENESIS" && mv "$TMP_GENESIS" "$GENESIS"
jq '.app_state["dogfood"]["val_set"][0]["power"]="5000"' "$GENESIS" >"$TMP_GENESIS" && mv "$TMP_GENESIS" "$GENESIS"
# change the epoch to an hour when starting a local node, which facilitates the testing.
jq '.app_state["dogfood"]["params"]["epoch_identifier"]="hour"' "$GENESIS" >"$TMP_GENESIS" && mv "$TMP_GENESIS" "$GENESIS"
jq '.app_state["dogfood"]["last_total_power"]="5000"' "$GENESIS" >"$TMP_GENESIS" && mv "$TMP_GENESIS" "$GENESIS"
MaxMustermann2 marked this conversation as resolved.
Show resolved Hide resolved

# x/epochs
HOUR_EPOCH='{
Expand Down
93 changes: 89 additions & 4 deletions proto/exocore/dogfood/v1/genesis.proto
Original file line number Diff line number Diff line change
Expand Up @@ -2,28 +2,113 @@

package exocore.dogfood.v1;

import "amino/amino.proto";
import "gogoproto/gogo.proto";

import "exocore/dogfood/v1/params.proto";

option go_package = "github.com/ExocoreNetwork/exocore/x/dogfood/types";

// GenesisState defines the dogfood module's genesis state.
// GenesisState defines the dogfood module's genesis state. Note that, as always,
// `genesis` is a misnomer. Ideally, this state can be exported at any point in
// time (or height), and reimported elsewhere where it will be the new genesis
// potentially at a non-zero height. In other words, it is the entire, current,
// state of the module.
message GenesisState {
// params refers to the parameters of the module.
Params params = 1 [(gogoproto.nullable) = false];

// initial_val_set is the initial validator set.
repeated GenesisValidator initial_val_set = 2
// val_set is the initial validator set. it onyl represents the active
// validators.
repeated GenesisValidator val_set = 2

Check failure on line 23 in proto/exocore/dogfood/v1/genesis.proto

View workflow job for this annotation

GitHub Actions / break-check

Field "2" with name "val_set" on message "GenesisState" changed option "json_name" from "initialValSet" to "valSet".

Check failure on line 23 in proto/exocore/dogfood/v1/genesis.proto

View workflow job for this annotation

GitHub Actions / break-check

Field "2" on message "GenesisState" changed name from "initial_val_set" to "val_set".
MaxMustermann2 marked this conversation as resolved.
Show resolved Hide resolved
[ (gogoproto.nullable) = false ];

// opt_out_expiries is a list of (future) epochs at the end of which the
// corresponding operators' opt-out will expire. we store this, as well as its reverse
// lookup.
repeated EpochToOperatorAddrs opt_out_expiries = 3
[ (gogoproto.nullable) = false ];

// epochs_consensus_addrs is a list of epochs at the end of which the corresponding
// consensus addresses should be pruned from the operator module.
repeated EpochToConsensusAddrs consensus_addrs_to_prune = 4
[ (gogoproto.nullable) = false ];

// undelegation_maturities is a list of epochs at the end of which the corresponding
// undelegations will mature. we store its reverse lookup as well.
repeated EpochToUndelegationRecordKeys undelegation_maturities = 5
[ (gogoproto.nullable) = false ];

// data against HistoricalInfoBytePrefix is not made available in the module
// state for import / export. this is in line with Cosmos SDK.

// the data indexed by the pending keys is created within the epochs hooks
// which happen in the BeginBlocker. it is applied during the EndBlocker and
// then immediately cleared.
// remember that data can be exported from a node that is stopped.
// a node can be stopped only if it has committed a block. if a full
// block is committed, data that is saved to state during BeginBlock
// and cleared at EndBlock will not be available. hence, we don't need
// to make data for any of the `pending` keys available here.

// last_total_power tracks the total voting power as of the last validator set
// update. such an update is most likely to be at the end of the last epoch (or the
// beginning of this one, to be more precise) and less likely to be at other blocks,
// since the validator set can otherwise only change as a result of slashing events.
bytes last_total_power = 6 [
(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int",
(gogoproto.nullable) = false,
(amino.dont_omitempty) = true
];

// validator_updates is a list of validator updates applied at the end of the previous
// block. it is then cleared at the end of the next block, and hence, is available
// for other modules to access during that block. however, for a new chain, it does
// not make sense for it to exist, since all of the validators should be considered
// as an update. this behaviour is the same as the Cosmos SDK.
}

// GenesisValidator defines a genesis validator. It is a helper struct
// used for serializing the genesis state.
// used for serializing the genesis state. The only reason it is a different
// structure is to support importing hex public keys from Solidity.
// TODO: consider this set up when resolving issue 73 about storage
// optimization between dogfood and operator modules.
// https://github.com/ExocoreNetwork/exocore/issues/73
message GenesisValidator {
// public_key is the consensus public key of the validator. It should
// be exactly 32 bytes, but this is not enforced in protobuf.
string public_key = 1;
// power is the voting power of the validator.
int64 power = 2;
}

// EpochToOperatorAddress is used to store a mapping from epoch to a list of
// operator account addresses.
message EpochToOperatorAddrs {
// epoch is the epoch in question.
int64 epoch = 1;
// operator_acc_addrs is the list of account addresses to expire at this epoch.
// It is of type string for human readability of the genesis file.
repeated string operator_acc_addrs = 2;
}

// EpochToConsensusAddrs is used to store a mapping from the epoch to a list of
// consensus addresses.
message EpochToConsensusAddrs {
// epoch is the epoch in question.
int64 epoch = 1;
// cons_addrs is the list of consensus addresses to prune at this epoch.
// It is of type string for human readability of the genesis file.
repeated string cons_addrs = 2;
}

// EpochToUndelegationRecordKeys is used to store a mapping from an epoch to a list of
// undelegations which mature at that epoch.
message EpochToUndelegationRecordKeys {
// epoch is the epoch in question.
int64 epoch = 1;
// undelegation_record_keys is the list of undelegations (defined by the record key)
// to expire at this epoch.
// It is of type string for human readability of the genesis file.
repeated string undelegation_record_keys = 2;
}
8 changes: 8 additions & 0 deletions proto/exocore/operator/v1/query.proto
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@ message QueryOperatorConsKeyRequest {
message QueryOperatorConsKeyResponse {
// public_key is the consensus public key of the operator.
tendermint.crypto.PublicKey public_key = 1 [ (gogoproto.nullable) = false ];
// opting_out is a flag to indicate if the operator is opting out of consensus.
bool opting_out = 2;
}

// QueryOperatorConsAddressRequest is the request to obtain the consensus address of the operator
Expand All @@ -63,6 +65,8 @@ message QueryOperatorConsAddressResponse {
// cons_addr is the consensus address corresponding to the consensus public key
// currently in use by the operator.
string cons_addr = 1;
// opting_out is a flag to indicate if the operator is opting out of consensus.
bool opting_out = 2;
}

// QueryAllOperatorConsKeysByChainIDRequest is the request to obtain all operator addresses
Expand Down Expand Up @@ -92,6 +96,8 @@ message OperatorConsKeyPair {
string operator_acc_addr = 1;
// public_key is the consensus public key of the operator.
tendermint.crypto.PublicKey public_key = 2;
// opting_out is a flag to indicate if the operator is opting out of consensus.
bool opting_out = 3;
}

// QueryAllOperatorConsAddrsByChainIDRequest is the request to obtain all operator addresses
Expand Down Expand Up @@ -121,6 +127,8 @@ message OperatorConsAddrPair {
// cons_addr is the consensus address corresponding to the consensus public key
// currently in use by the operator.
string cons_addr = 2;
// opting_out is a flag to indicate if the operator is opting out of consensus.
bool opting_out = 3;
}

// Query defines the gRPC querier service.
Expand Down
26 changes: 6 additions & 20 deletions proto/exocore/operator/v1/tx.proto
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
syntax = "proto3";

Check failure on line 1 in proto/exocore/operator/v1/tx.proto

View workflow job for this annotation

GitHub Actions / break-check

Previously present message "InitConsKeyRemovalReq" was deleted from file.

Check failure on line 1 in proto/exocore/operator/v1/tx.proto

View workflow job for this annotation

GitHub Actions / break-check

Previously present message "InitConsKeyRemovalResponse" was deleted from file.
package exocore.operator.v1;

import "amino/amino.proto";
Expand Down Expand Up @@ -145,6 +145,9 @@
[(cosmos_proto.scalar) = "cosmos.AddressString"];
// avs_address is the address of the AVS - either an 0x address or a chainID.
string avs_address = 2;
// optional parameter to provide the consensus key or the BLS key, depending
// on the AVS. we still have to design this fully.
string public_key = 3;
}

// OptIntoAVSResponse is the response to a opt into an AVS request.
Expand Down Expand Up @@ -187,33 +190,16 @@
// SetConsKeyResponse is the response to SetConsKeyReq.
message SetConsKeyResponse {}

// InitConsKeyRemovalReq is the request for an operator to stop validating on a chain. It
// allows the operator to remove their consensus key from the specified chain. It must be
// followed by a separate call to OptOutOfAVS to remove the operator from the AVS.
message InitConsKeyRemovalReq {
option (cosmos.msg.v1.signer) = "address";
option (amino.name) = "cosmos-sdk/InitConsKeyRemovalReq";
option (gogoproto.equal) = false;
option (gogoproto.goproto_getters) = false;
// address is the operator address
string address = 1 [(cosmos_proto.scalar) = "cosmos.AddressString"];
// chain_id is the identifier for the chain that wants to opt out.
string chain_id = 2 [(gogoproto.customname) = "ChainID"];
}

// InitConsKeyRemovalResponse defines the InitConsKeyRemovalReq response.
message InitConsKeyRemovalResponse {}

// Msg defines the operator Msg service.
service Msg {

Check failure on line 194 in proto/exocore/operator/v1/tx.proto

View workflow job for this annotation

GitHub Actions / break-check

Previously present RPC "InitConsKeyRemoval" on service "Msg" was deleted.
option (cosmos.msg.v1.service) = true;
// RegisterOperator registers a new operator.
rpc RegisterOperator(RegisterOperatorReq) returns (RegisterOperatorResponse);

// SetConsKey sets the operator's consensus key for a chain.
// SetConsKey sets the operator's consensus key for a chain. To do this, the operator
// must have previously opted into the chain.
// TODO; rationalize this with non-chain AVSs wherein other keys can be set.
rpc SetConsKey(SetConsKeyReq) returns (SetConsKeyResponse) {};
// InitConsKeyRemoval removes the operator's consensus key for a chain.
rpc InitConsKeyRemoval(InitConsKeyRemovalReq) returns (InitConsKeyRemovalResponse) {};

// OptIntoAVS opts an operator into an AVS.
rpc OptIntoAVS(OptIntoAVSReq) returns (OptIntoAVSResponse);
Expand Down
6 changes: 6 additions & 0 deletions testutil/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -229,6 +229,8 @@ func (suite *BaseTestSuite) SetupWithGenesisValSet(genAccs []authtypes.GenesisAc
delegationGenesis := delegationtypes.NewGenesis(delegationsByStaker)
genesisState[delegationtypes.ModuleName] = app.AppCodec().MustMarshalJSON(delegationGenesis)

// create a dogfood genesis with just the validator set, that is, the bare
// minimum valid genesis required to start a chain.
dogfoodGenesis := dogfoodtypes.NewGenesis(
dogfoodtypes.DefaultParams(), []dogfoodtypes.GenesisValidator{
{
Expand All @@ -240,6 +242,10 @@ func (suite *BaseTestSuite) SetupWithGenesisValSet(genAccs []authtypes.GenesisAc
Power: 1,
},
},
[]dogfoodtypes.EpochToOperatorAddrs{},
[]dogfoodtypes.EpochToConsensusAddrs{},
[]dogfoodtypes.EpochToUndelegationRecordKeys{},
math.NewInt(2), // must match total vote power
)
genesisState[dogfoodtypes.ModuleName] = app.AppCodec().MustMarshalJSON(dogfoodGenesis)

Expand Down
3 changes: 2 additions & 1 deletion x/delegation/keeper/genesis.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package keeper

import (
errorsmod "cosmossdk.io/errors"
assetstype "github.com/ExocoreNetwork/exocore/x/assets/types"
delegationtype "github.com/ExocoreNetwork/exocore/x/delegation/types"
abci "github.com/cometbft/cometbft/abci/types"
Expand Down Expand Up @@ -44,7 +45,7 @@ func (k Keeper) InitGenesis(
// they are the LzNonce and TxHash
}
if err := k.delegateTo(ctx, delegationParams, false); err != nil {
panic(err)
panic(errorsmod.Wrap(err, "failed to delegate to operator"))
MaxMustermann2 marked this conversation as resolved.
Show resolved Hide resolved
}
}
}
Expand Down
Loading
Loading