Skip to content

Commit

Permalink
Add downtime detector module (#3688)
Browse files Browse the repository at this point in the history
* WIP

* Switch to enum

* Remove params query

* Add query

* Add wiring, add import/export test

* Start begin block test

* Finish keeper tests

* Add CLI

* Wire downtime detector CLI + queries

* more module wiring

* add types test

* Fix state alteration test

* Fix superfluid test

* Add stargate whitelist support

* Apply code comment

* Rename folder

* Add requested godoc

* Update x/downtime-detector/genesis.go

Co-authored-by: Adam Tucker <[email protected]>

* Apply adam suggestion for having a `-`

* move genesis test to own file

Co-authored-by: Adam Tucker <[email protected]>
  • Loading branch information
ValarDragon and czarcas7ic authored Dec 14, 2022
1 parent a942009 commit 68bae6b
Show file tree
Hide file tree
Showing 33 changed files with 984 additions and 781 deletions.
2 changes: 1 addition & 1 deletion app/apptesting/test_suite.go
Original file line number Diff line number Diff line change
Expand Up @@ -374,7 +374,7 @@ func (s *KeeperTestHelper) BuildTx(
// StateNotAltered validates that app state is not altered. Fails if it is.
func (s *KeeperTestHelper) StateNotAltered() {
oldState := s.App.ExportState(s.Ctx)
s.Commit()
s.App.Commit()
newState := s.App.ExportState(s.Ctx)
s.Require().Equal(oldState, newState)
}
Expand Down
8 changes: 8 additions & 0 deletions app/keepers/keepers.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ import (
upgradekeeper "github.com/cosmos/cosmos-sdk/x/upgrade/keeper"
upgradetypes "github.com/cosmos/cosmos-sdk/x/upgrade/types"

downtimedetector "github.com/osmosis-labs/osmosis/v13/x/downtime-detector"
downtimetypes "github.com/osmosis-labs/osmosis/v13/x/downtime-detector/types"
ibchooks "github.com/osmosis-labs/osmosis/v13/x/ibc-hooks"
ibcratelimit "github.com/osmosis-labs/osmosis/v13/x/ibc-rate-limit"
ibcratelimittypes "github.com/osmosis-labs/osmosis/v13/x/ibc-rate-limit/types"
Expand Down Expand Up @@ -104,6 +106,7 @@ type AppKeepers struct {
AuthzKeeper *authzkeeper.Keeper
StakingKeeper *stakingkeeper.Keeper
DistrKeeper *distrkeeper.Keeper
DowntimeKeeper *downtimedetector.Keeper
SlashingKeeper *slashingkeeper.Keeper
IBCKeeper *ibckeeper.Keeper
ICAHostKeeper *icahostkeeper.Keeper
Expand Down Expand Up @@ -197,6 +200,10 @@ func (appKeepers *AppKeepers) InitNormalKeepers(
)
appKeepers.DistrKeeper = &distrKeeper

appKeepers.DowntimeKeeper = downtimedetector.NewKeeper(
appKeepers.keys[downtimetypes.StoreKey],
)

slashingKeeper := slashingkeeper.NewKeeper(
appCodec,
appKeepers.keys[slashingtypes.StoreKey],
Expand Down Expand Up @@ -595,6 +602,7 @@ func KVStoreKeys() []string {
stakingtypes.StoreKey,
minttypes.StoreKey,
distrtypes.StoreKey,
downtimetypes.StoreKey,
slashingtypes.StoreKey,
govtypes.StoreKey,
paramstypes.StoreKey,
Expand Down
2 changes: 2 additions & 0 deletions app/keepers/modules.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import (
ica "github.com/cosmos/ibc-go/v3/modules/apps/27-interchain-accounts"

_ "github.com/osmosis-labs/osmosis/v13/client/docs/statik"
downtimemodule "github.com/osmosis-labs/osmosis/v13/x/downtime-detector/module"
"github.com/osmosis-labs/osmosis/v13/x/epochs"
"github.com/osmosis-labs/osmosis/v13/x/gamm"
ibc_hooks "github.com/osmosis-labs/osmosis/v13/x/ibc-hooks"
Expand All @@ -54,6 +55,7 @@ var AppModuleBasics = []module.AppModuleBasic{
capability.AppModuleBasic{},
staking.AppModuleBasic{},
mint.AppModuleBasic{},
downtimemodule.AppModuleBasic{},
distr.AppModuleBasic{},
gov.NewAppModuleBasic(
append(
Expand Down
6 changes: 6 additions & 0 deletions app/modules.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ import (
ica "github.com/cosmos/ibc-go/v3/modules/apps/27-interchain-accounts"
icatypes "github.com/cosmos/ibc-go/v3/modules/apps/27-interchain-accounts/types"

downtimemodule "github.com/osmosis-labs/osmosis/v13/x/downtime-detector/module"
downtimetypes "github.com/osmosis-labs/osmosis/v13/x/downtime-detector/types"

ibc_hooks "github.com/osmosis-labs/osmosis/v13/x/ibc-hooks"

"github.com/cosmos/cosmos-sdk/types/module"
Expand Down Expand Up @@ -125,6 +128,7 @@ func appModules(
mint.NewAppModule(appCodec, *app.MintKeeper, app.AccountKeeper, app.BankKeeper),
slashing.NewAppModule(appCodec, *app.SlashingKeeper, app.AccountKeeper, app.BankKeeper, *app.StakingKeeper),
distr.NewAppModule(appCodec, *app.DistrKeeper, app.AccountKeeper, app.BankKeeper, *app.StakingKeeper),
downtimemodule.NewAppModule(*app.DowntimeKeeper),
staking.NewAppModule(appCodec, *app.StakingKeeper, app.AccountKeeper, app.BankKeeper),
upgrade.NewAppModule(*app.UpgradeKeeper),
wasm.NewAppModule(appCodec, app.WasmKeeper, app.StakingKeeper, app.AccountKeeper, app.BankKeeper),
Expand Down Expand Up @@ -175,6 +179,7 @@ func orderBeginBlockers(allModuleNames []string) []string {
// IBChost came after staking, before superfluid.
// TODO: Come back and delete this line after testing the base change.
ord.Sequence(stakingtypes.ModuleName, ibchost.ModuleName, superfluidtypes.ModuleName)
// We leave downtime-detector un-constrained.
// every remaining module's begin block is a no-op.
return ord.TotalOrdering()
}
Expand Down Expand Up @@ -204,6 +209,7 @@ func OrderInitGenesis(allModuleNames []string) []string {
authtypes.ModuleName,
banktypes.ModuleName,
distrtypes.ModuleName,
downtimetypes.ModuleName,
stakingtypes.ModuleName,
slashingtypes.ModuleName,
govtypes.ModuleName,
Expand Down
3 changes: 2 additions & 1 deletion app/upgrades/v14/constants.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
store "github.com/cosmos/cosmos-sdk/store/types"

"github.com/osmosis-labs/osmosis/v13/app/upgrades"
downtimetypes "github.com/osmosis-labs/osmosis/v13/x/downtime-detector/types"
protorevtypes "github.com/osmosis-labs/osmosis/v13/x/protorev/types"
valsetpreftypes "github.com/osmosis-labs/osmosis/v13/x/valset-pref/types"
)
Expand All @@ -15,7 +16,7 @@ var Upgrade = upgrades.Upgrade{
UpgradeName: UpgradeName,
CreateUpgradeHandler: CreateUpgradeHandler,
StoreUpgrades: store.StoreUpgrades{
Added: []string{valsetpreftypes.StoreKey, protorevtypes.StoreKey},
Added: []string{valsetpreftypes.StoreKey, protorevtypes.StoreKey, downtimetypes.StoreKey},
Deleted: []string{},
},
}
3 changes: 2 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ go 1.18
require (
github.com/CosmWasm/wasmd v0.29.2-osmo-v13
github.com/cosmos/cosmos-proto v1.0.0-alpha8
github.com/cosmos/cosmos-sdk v0.45.11
github.com/cosmos/cosmos-sdk v0.46.6
github.com/cosmos/go-bip39 v1.0.0
github.com/cosmos/iavl v0.19.4
github.com/cosmos/ibc-go/v3 v3.4.0
Expand All @@ -27,6 +27,7 @@ require (
github.com/stretchr/testify v1.8.1
github.com/tendermint/tendermint v0.34.24
github.com/tendermint/tm-db v0.6.8-0.20220506192307-f628bb5dc95b
github.com/tidwall/btree v1.6.0
go.uber.org/multierr v1.8.0
golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e
google.golang.org/genproto v0.0.0-20221024183307-1bc688fe9f3e
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -1091,6 +1091,8 @@ github.com/tenntenn/text/transform v0.0.0-20200319021203-7eef512accb3 h1:f+jULpR
github.com/tenntenn/text/transform v0.0.0-20200319021203-7eef512accb3/go.mod h1:ON8b8w4BN/kE1EOhwT0o+d62W65a6aPw1nouo9LMgyY=
github.com/tetafro/godot v1.4.11 h1:BVoBIqAf/2QdbFmSwAWnaIqDivZdOV0ZRwEm6jivLKw=
github.com/tetafro/godot v1.4.11/go.mod h1:LR3CJpxDVGlYOWn3ZZg1PgNZdTUvzsZWu8xaEohUpn8=
github.com/tidwall/btree v1.6.0 h1:LDZfKfQIBHGHWSwckhXI0RPSXzlo+KYdjK7FWSqOzzg=
github.com/tidwall/btree v1.6.0/go.mod h1:twD9XRA5jj9VUQGELzDO4HPQTNJsoWWfYEL+EUQ2cKY=
github.com/tidwall/gjson v1.6.7/go.mod h1:zeFuBCIqD4sN/gmqBzZ4j7Jd6UcA2Fc56x7QFsv+8fI=
github.com/tidwall/match v1.0.3/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM=
github.com/tidwall/pretty v1.0.2/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk=
Expand Down
38 changes: 38 additions & 0 deletions proto/osmosis/downtime-detector/v1beta1/downtime_duration.proto
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
syntax = "proto3";
package osmosis.downtimedetector.v1beta1;

import "gogoproto/gogo.proto";
import "google/protobuf/any.proto";
import "cosmos_proto/cosmos.proto";
import "google/protobuf/duration.proto";
import "google/protobuf/timestamp.proto";

option go_package = "github.com/osmosis-labs/osmosis/v13/x/downtime-detector/types";

enum Downtime {
DURATION_30S = 0;
DURATION_1M = 1;
DURATION_2M = 2;
DURATION_3M = 3;
DURATION_4M = 4;
DURATION_5M = 5;
DURATION_10M = 6;
DURATION_20M = 7;
DURATION_30M = 8;
DURATION_40M = 9;
DURATION_50M = 10;
DURATION_1H = 11;
DURATION_1_5H = 12;
DURATION_2H = 13;
DURATION_2_5H = 14;
DURATION_3H = 15;
DURATION_4H = 16;
DURATION_5H = 17;
DURATION_6H = 18;
DURATION_9H = 19;
DURATION_12H = 20;
DURATION_18H = 21;
DURATION_24H = 22;
DURATION_36H = 23;
DURATION_48H = 24;
}
13 changes: 2 additions & 11 deletions proto/osmosis/downtime-detector/v1beta1/genesis.proto
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,12 @@ import "google/protobuf/any.proto";
import "cosmos_proto/cosmos.proto";
import "google/protobuf/duration.proto";
import "google/protobuf/timestamp.proto";
import "osmosis/downtime-detector/v1beta1/downtime_duration.proto";

option go_package = "github.com/osmosis-labs/osmosis/v13/x/downtime-detector/types";

// Params holds parameters for the downtime-detector module
message Params {}

message GenesisDowntimeEntry {
google.protobuf.Duration downtime_duration = 1 [
(gogoproto.nullable) = false,
(gogoproto.stdduration) = true,
(gogoproto.moretags) = "yaml:\"downtime_duration\""
];
Downtime duration = 1 [ (gogoproto.moretags) = "yaml:\"duration\"" ];
google.protobuf.Timestamp last_downtime = 2 [
(gogoproto.nullable) = false,
(gogoproto.stdtime) = true,
Expand All @@ -34,7 +28,4 @@ message GenesisState {
(gogoproto.stdtime) = true,
(gogoproto.moretags) = "yaml:\"last_block_time\""
];

// params is the container of twap parameters.
Params params = 3 [ (gogoproto.nullable) = false ];
}
14 changes: 2 additions & 12 deletions proto/osmosis/downtime-detector/v1beta1/query.proto
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package osmosis.downtimedetector.v1beta1;

import "gogoproto/gogo.proto";
import "osmosis/downtime-detector/v1beta1/genesis.proto";
import "osmosis/downtime-detector/v1beta1/downtime_duration.proto";

import "cosmos/base/v1beta1/coin.proto";
import "cosmos/base/query/v1beta1/pagination.proto";
Expand All @@ -15,9 +16,6 @@ import "google/protobuf/timestamp.proto";
option go_package = "github.com/osmosis-labs/osmosis/v13/x/downtime-detector/client/queryproto";

service Query {
rpc Params(ParamsRequest) returns (ParamsResponse) {
option (google.api.http).get = "/osmosis/downtime-detector/v1beta1/Params";
}
rpc RecoveredSinceDowntimeOfLength(RecoveredSinceDowntimeOfLengthRequest)
returns (RecoveredSinceDowntimeOfLengthResponse) {
option (google.api.http).get =
Expand All @@ -27,13 +25,8 @@ service Query {

// Query for has it been at least $RECOVERY_DURATION units of time,
// since the chain has been down for $DOWNTIME_DURATION.
// Note: $DOWNTIME_DURATION must be in set {SPECIFY_SET}
message RecoveredSinceDowntimeOfLengthRequest {
google.protobuf.Duration downtime = 1 [
(gogoproto.nullable) = false,
(gogoproto.stdduration) = true,
(gogoproto.moretags) = "yaml:\"downtime_duration\""
];
Downtime downtime = 1 [ (gogoproto.moretags) = "yaml:\"downtime\"" ];
google.protobuf.Duration recovery = 2 [
(gogoproto.nullable) = false,
(gogoproto.stdduration) = true,
Expand All @@ -44,6 +37,3 @@ message RecoveredSinceDowntimeOfLengthRequest {
message RecoveredSinceDowntimeOfLengthResponse {
bool succesfully_recovered = 1;
}

message ParamsRequest {}
message ParamsResponse { Params params = 1 [ (gogoproto.nullable) = false ]; }
8 changes: 8 additions & 0 deletions proto/osmosis/downtime-detector/v1beta1/query.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
keeper:
path: "github.com/osmosis-labs/osmosis/v13/x/downtime-detector"
struct: "Keeper"
client_path: "github.com/osmosis-labs/osmosis/v13/x/downtime-detector/client"
queries:
RecoveredSinceDowntimeOfLength:
proto_wrapper:
query_func: "k.RecoveredSinceDowntimeOfLength"
4 changes: 4 additions & 0 deletions wasmbinding/stargate_whitelist.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import (
slashingtypes "github.com/cosmos/cosmos-sdk/x/slashing/types"
stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types"

downtimequerytypes "github.com/osmosis-labs/osmosis/v13/x/downtime-detector/client/queryproto"
epochtypes "github.com/osmosis-labs/osmosis/v13/x/epochs/types"
gammtypes "github.com/osmosis-labs/osmosis/v13/x/gamm/types"
gammv2types "github.com/osmosis-labs/osmosis/v13/x/gamm/v2types"
Expand Down Expand Up @@ -125,6 +126,9 @@ func init() {
setWhitelistedQuery("/osmosis.twap.v1beta1.Query/ArithmeticTwap", &twapquerytypes.ArithmeticTwapResponse{})
setWhitelistedQuery("/osmosis.twap.v1beta1.Query/ArithmeticTwapToNow", &twapquerytypes.ArithmeticTwapToNowResponse{})
setWhitelistedQuery("/osmosis.twap.v1beta1.Query/Params", &twapquerytypes.ParamsResponse{})

// downtime-detector
setWhitelistedQuery("/osmosis.downtimedetector.v1beta1.Query/RecoveredSinceDowntimeOfLength", &downtimequerytypes.RecoveredSinceDowntimeOfLengthResponse{})
}

// GetWhitelistedQuery returns the whitelisted query at the provided path.
Expand Down
37 changes: 37 additions & 0 deletions x/downtime-detector/abci.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package downtimedetector

import (
"time"

sdk "github.com/cosmos/cosmos-sdk/types"

"github.com/osmosis-labs/osmosis/v13/x/downtime-detector/types"
)

func (k *Keeper) BeginBlock(ctx sdk.Context) {
curTime := ctx.BlockTime()
lastBlockTime, err := k.GetLastBlockTime(ctx)
if err != nil {
ctx.Logger().Error("Downtime-detector, could not get last block time, did initialization happen correctly. " + err.Error())
}
downtime := curTime.Sub(lastBlockTime)
k.saveDowntimeUpdates(ctx, downtime)
k.StoreLastBlockTime(ctx, curTime)
}

// saveDowntimeUpdates saves the current block time as the
// last time the chain was down for all downtime lengths that are LTE the provided downtime.
func (k *Keeper) saveDowntimeUpdates(ctx sdk.Context, downtime time.Duration) {
// minimum stored downtime is 30S, so if downtime is less than that, don't update anything.
if downtime < 30*time.Second {
return
}
types.DowntimeToDuration.Ascend(0, func(downType types.Downtime, duration time.Duration) bool {
// if downtime < duration of this entry, stop iterating further, don't update this entry.
if downtime < duration {
return false
}
k.StoreLastDowntimeOfLength(ctx, downType, ctx.BlockTime())
return true
})
}
40 changes: 40 additions & 0 deletions x/downtime-detector/client/cli/query.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package cli

import (
"time"

"github.com/spf13/cobra"
"github.com/spf13/pflag"

"github.com/osmosis-labs/osmosis/v13/osmoutils/osmocli"
"github.com/osmosis-labs/osmosis/v13/x/downtime-detector/client/queryproto"
"github.com/osmosis-labs/osmosis/v13/x/downtime-detector/types"
)

func GetQueryCmd() *cobra.Command {
cmd := osmocli.QueryIndexCmd(types.ModuleName)
osmocli.AddQueryCmd(cmd, queryproto.NewQueryClient, RecoveredSinceQueryCmd)

return cmd
}

func RecoveredSinceQueryCmd() (*osmocli.QueryDescriptor, *queryproto.RecoveredSinceDowntimeOfLengthRequest) {
return &osmocli.QueryDescriptor{
Use: "recovered-since downtime-duration recovery-duration",
Short: "Queries if it has been at least <recovery-duration> since the chain was down for <downtime-duration>",
Long: `{{.Short}}
downtime-duration is a duration, but is restricted to a smaller set. Heres a few from the set: 30s, 1m, 5m, 10m, 30m, 1h, 3 h, 6h, 12h, 24h, 36h, 48h]
{{.ExampleHeader}}
{{.CommandPrefix}} recovered-since 24h 30m`,
CustomFieldParsers: map[string]osmocli.CustomFieldParserFn{"Downtime": parseDowntimeDuration},
}, &queryproto.RecoveredSinceDowntimeOfLengthRequest{}
}

func parseDowntimeDuration(arg string, _ *pflag.FlagSet) (any, osmocli.FieldReadLocation, error) {
dur, err := time.ParseDuration(arg)
if err != nil {
return nil, osmocli.UsedArg, err
}
downtime, err := types.DowntimeByDuration(dur)
return downtime, osmocli.UsedArg, err
}
Loading

0 comments on commit 68bae6b

Please sign in to comment.