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

Add types & boilerplate for the Downtime detector module #3609

Merged
merged 5 commits into from
Dec 6, 2022
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
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
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 {
ValarDragon marked this conversation as resolved.
Show resolved Hide resolved
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.
ValarDragon marked this conversation as resolved.
Show resolved Hide resolved
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.
ValarDragon marked this conversation as resolved.
Show resolved Hide resolved
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 and add a state entry for the current block time
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are you referring to the delta between the last block timestamp and the previous block?

Why would we iterate over all $DOWNTIME_PERIODS of the difference is, for example, only 35 seconds? Wouldn't we only want to update the 30 seconds downtime period and exit?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ah yeah, right! Should amend this, would iterate over all applicable durations that the downtime is longer than


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