Skip to content

Commit

Permalink
Add types & boilerplate for the Downtime detector module (#3609)
Browse files Browse the repository at this point in the history
Sub-component of #3603 

## What is the purpose of the change

Adds types for the thin module intended for downtime detection

## Brief Changelog

- Add downtime detection module types

## Testing and Verifying

No tests added

## Documentation and Release Note

  - Does this pull request introduce a new feature or user-facing behavior changes? somewhat
  - Is a relevant changelog entry added to the `Unreleased` section in `CHANGELOG.md`? yes
  - How is the feature or change documented? In its spec
  • Loading branch information
ValarDragon authored Dec 6, 2022
1 parent 08a9aa1 commit 014239f
Show file tree
Hide file tree
Showing 12 changed files with 2,325 additions and 3 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Features

* [#3609](https://github.com/osmosis-labs/osmosis/pull/3609) Add Downtime-detection module.
* [#2788](https://github.com/osmosis-labs/osmosis/pull/2788) Add logarithm base 2 implementation.

### Bug fixes
Expand Down
40 changes: 40 additions & 0 deletions proto/osmosis/downtime-detector/v1beta1/genesis.proto
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
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";

// 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\""
];
google.protobuf.Timestamp last_downtime = 2 [
(gogoproto.nullable) = false,
(gogoproto.stdtime) = true,
(gogoproto.moretags) = "yaml:\"last_downtime\""
];
}

// GenesisState defines the twap module's genesis state.
message GenesisState {
repeated GenesisDowntimeEntry downtimes = 1 [ (gogoproto.nullable) = false ];

google.protobuf.Timestamp last_block_time = 2 [
(gogoproto.nullable) = false,
(gogoproto.stdtime) = true,
(gogoproto.moretags) = "yaml:\"last_block_time\""
];

// params is the container of twap parameters.
Params params = 3 [ (gogoproto.nullable) = false ];
}
49 changes: 49 additions & 0 deletions proto/osmosis/downtime-detector/v1beta1/query.proto
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
syntax = "proto3";
package osmosis.downtimedetector.v1beta1;

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

import "cosmos/base/v1beta1/coin.proto";
import "cosmos/base/query/v1beta1/pagination.proto";
import "google/api/annotations.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/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 =
"/osmosis/downtime-detector/v1beta1/RecoveredSinceDowntimeOfLength";
}
}

// 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\""
];
google.protobuf.Duration recovery = 2 [
(gogoproto.nullable) = false,
(gogoproto.stdduration) = true,
(gogoproto.moretags) = "yaml:\"recovery_duration\""
];
}

message RecoveredSinceDowntimeOfLengthResponse {
bool succesfully_recovered = 1;
}

message ParamsRequest {}
message ParamsResponse { Params params = 1 [ (gogoproto.nullable) = false ]; }
30 changes: 30 additions & 0 deletions x/downtime-detector/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# Downtime-detector

For several use cases, we need a module that can detect when the chain is recovering from downtime. We want to be able to efficiently know "Has it been $RECOVERY_PERIOD minutes since the chain has been down for $DOWNTIME_PERIOD", and expose this as a query to contracts.

So for instance, you'd want to know if it has been at least 10 minutes, since the chain was down for > 30 minutes. Since you assume in such an event that it may take ~10 minutes for price oracles to be arb'd to correct.
Suggested Design

Theres a couple designs, such as:

* Iterating over block times from the last N blocks (with a heuristic filter based on average block time)
* Implies bounds on recovery time
* Linear iteration if heuristic is met
* Requires encoding expected block time
* Restricting downtime period, and storing a state entry for last time a downtime of length $D occurred

Because this will be in important txs for contracts, we need to go with the approach that has minimal query compute, which is the latter. So we explain that in more depth.

We restrict the $DOWNTIME_PERIOD options that you can query, to be: 30seconds, 1 min, 2 min, 3 min, 4 min, 5 min, 10 min, 20 min, 30 min, 40 min, 50 min, 1 hr, 1.5hr, 2 hr, 2.5 hr, 3 hr, 4 hr, 5 hr, 6 hr, 9hr, 12hr, 18hr, 24hr, 36hr, 48hr.

In the downtime detector module, we store state entries for:

* Last blocks timestamp
* For each period, last time there was downtime

Then in every begin block:

* Store last blocks timestamp
* if time since last block timestamp >= 30 seconds, iterate through all $DOWNTIME_PERIODS less than the downtime, and in each add a state entry for the current block time

Then our query for has it been $RECOVERY_PERIOD since $DOWNTIME_PERIOD, simply reads the state entry for that $DOWNTIME_PERIOD, and then checks if time difference between now and that block is > RECOVERY_PERIOD.
Loading

0 comments on commit 014239f

Please sign in to comment.