Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
64 changes: 2 additions & 62 deletions app/antedecorators/gasless.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,21 +55,11 @@ func isTxGasless(tx sdk.Tx, ctx sdk.Context, oracleKeeper oraclekeeper.Keeper) b
continue
}
return false
case *oracletypes.MsgAggregateExchangeRatePrevote:
if OraclePrevoteIsGasless(m, ctx, oracleKeeper) {
continue
}
return false
case *oracletypes.MsgAggregateExchangeRateVote:
if OracleVoteIsGasless(m, ctx, oracleKeeper) {
continue
}
return false
case *oracletypes.MsgAggregateExchangeRateCombinedVote:
if OracleCombinedVoteIsGasless(m, ctx, oracleKeeper) {
continue
}
return false
default:
return false
}
Expand Down Expand Up @@ -104,34 +94,6 @@ func allSignersWhitelisted(msg *dextypes.MsgCancelOrders) bool {
return true
}

func OraclePrevoteIsGasless(msg *oracletypes.MsgAggregateExchangeRatePrevote, ctx sdk.Context, keeper oraclekeeper.Keeper) bool {
feederAddr, err := sdk.AccAddressFromBech32(msg.Feeder)
if err != nil {
return false
}

valAddr, err := sdk.ValAddressFromBech32(msg.Validator)
if err != nil {
return false
}

err = keeper.ValidateFeeder(ctx, feederAddr, valAddr)
if err != nil {
return false
}

currHeight := ctx.BlockHeight()
votePeriod := keeper.VotePeriod(ctx)
lastPrevote, err := keeper.GetAggregateExchangeRatePrevote(ctx, valAddr)
if err != nil {
return true
}

lastPrevoteWindow := lastPrevote.SubmitBlock / votePeriod
currPrevoteWindow := uint64(currHeight) / votePeriod
return currPrevoteWindow > lastPrevoteWindow
}

func OracleVoteIsGasless(msg *oracletypes.MsgAggregateExchangeRateVote, ctx sdk.Context, keeper oraclekeeper.Keeper) bool {
feederAddr, err := sdk.AccAddressFromBech32(msg.Feeder)
if err != nil {
Expand All @@ -151,28 +113,6 @@ func OracleVoteIsGasless(msg *oracletypes.MsgAggregateExchangeRateVote, ctx sdk.
// this returns an error IFF there is no vote present
// this also gets cleared out after every vote window, so if there is no vote present, we may want to allow gasless tx
_, err = keeper.GetAggregateExchangeRateVote(ctx, valAddr)
// if there is no error that means there is a vote present, so we dont allow gasless tx
if err == nil {
return false
}

currHeight := ctx.BlockHeight()
votePeriod := keeper.VotePeriod(ctx)
// we expect a prevote from the previous window
lastPrevote, err := keeper.GetAggregateExchangeRatePrevote(ctx, valAddr)
if err != nil {
// if there is no prevote present, there shouldnt be a vote expected so we dont allow gasless
return false
}

lastPrevoteWindow := lastPrevote.SubmitBlock / votePeriod
currPrevoteWindow := uint64(currHeight) / votePeriod

// we allow gasless tx if the difference is exactly 1, since then the prevote is in the valid window
return currPrevoteWindow-lastPrevoteWindow == 1
}

func OracleCombinedVoteIsGasless(msg *oracletypes.MsgAggregateExchangeRateCombinedVote, ctx sdk.Context, keeper oraclekeeper.Keeper) bool {
return (OraclePrevoteIsGasless(msg.GetPrevoteFromCombinedVote(), ctx, keeper) ||
OracleVoteIsGasless(msg.GetVoteFromCombinedVote(), ctx, keeper))
// if there is no error that means there is a vote present, so we dont allow gasless tx otherwise we allow it
return err != nil
}
1 change: 0 additions & 1 deletion proto/oracle/genesis.proto
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ message GenesisState {
repeated ExchangeRateTuple exchange_rates = 3
[(gogoproto.castrepeated) = "ExchangeRateTuples", (gogoproto.nullable) = false];
repeated PenaltyCounter penalty_counters = 4 [(gogoproto.nullable) = false];
repeated AggregateExchangeRatePrevote aggregate_exchange_rate_prevotes = 5 [(gogoproto.nullable) = false];
repeated AggregateExchangeRateVote aggregate_exchange_rate_votes = 6 [(gogoproto.nullable) = false];
}

Expand Down
10 changes: 0 additions & 10 deletions proto/oracle/oracle.proto
Original file line number Diff line number Diff line change
Expand Up @@ -50,16 +50,6 @@ message Denom {
string name = 1 [(gogoproto.moretags) = "yaml:\"name\""];
}

message AggregateExchangeRatePrevote {
option (gogoproto.equal) = false;
option (gogoproto.goproto_getters) = false;
option (gogoproto.goproto_stringer) = false;

string hash = 1 [(gogoproto.moretags) = "yaml:\"hash\""];
string voter = 2 [(gogoproto.moretags) = "yaml:\"voter\""];
uint64 submit_block = 3 [(gogoproto.moretags) = "yaml:\"submit_block\""];
}

message AggregateExchangeRateVote {
option (gogoproto.equal) = false;
option (gogoproto.goproto_getters) = false;
Expand Down
36 changes: 0 additions & 36 deletions proto/oracle/query.proto
Original file line number Diff line number Diff line change
Expand Up @@ -48,16 +48,6 @@ service Query {
option (google.api.http).get = "/sei-protocol/sei-chain/oracle/validators/{validator_addr}/vote_penalty_counter";
}

// AggregatePrevote returns an aggregate prevote of a validator
rpc AggregatePrevote(QueryAggregatePrevoteRequest) returns (QueryAggregatePrevoteResponse) {
option (google.api.http).get = "/sei-protocol/sei-chain/oracle/validators/{validator_addr}/aggregate_prevote";
}

// AggregatePrevotes returns aggregate prevotes of all validators
rpc AggregatePrevotes(QueryAggregatePrevotesRequest) returns (QueryAggregatePrevotesResponse) {
option (google.api.http).get = "/sei-protocol/sei-chain/oracle/validators/aggregate_prevotes";
}

// AggregateVote returns an aggregate vote of a validator
rpc AggregateVote(QueryAggregateVoteRequest) returns (QueryAggregateVoteResponse) {
option (google.api.http).get = "/sei-protocol/sei-chain/oracle/validators/{validator_addr}/aggregate_vote";
Expand Down Expand Up @@ -180,32 +170,6 @@ message QueryVotePenaltyCounterResponse {
VotePenaltyCounter vote_penalty_counter = 1;
}

// QueryAggregatePrevoteRequest is the request type for the Query/AggregatePrevote RPC method.
message QueryAggregatePrevoteRequest {
option (gogoproto.equal) = false;
option (gogoproto.goproto_getters) = false;

// validator defines the validator address to query for.
string validator_addr = 1;
}

// QueryAggregatePrevoteResponse is response type for the
// Query/AggregatePrevote RPC method.
message QueryAggregatePrevoteResponse {
// aggregate_prevote defines oracle aggregate prevote submitted by a validator in the current vote period
AggregateExchangeRatePrevote aggregate_prevote = 1 [(gogoproto.nullable) = false];
}

// QueryAggregatePrevotesRequest is the request type for the Query/AggregatePrevotes RPC method.
message QueryAggregatePrevotesRequest {}

// QueryAggregatePrevotesResponse is response type for the
// Query/AggregatePrevotes RPC method.
message QueryAggregatePrevotesResponse {
// aggregate_prevotes defines all oracle aggregate prevotes submitted in the current vote period
repeated AggregateExchangeRatePrevote aggregate_prevotes = 1 [(gogoproto.nullable) = false];
}

// QueryAggregateVoteRequest is the request type for the Query/AggregateVote RPC method.
message QueryAggregateVoteRequest {
option (gogoproto.equal) = false;
Expand Down
39 changes: 1 addition & 38 deletions proto/oracle/tx.proto
Original file line number Diff line number Diff line change
Expand Up @@ -7,42 +7,21 @@ option go_package = "github.com/sei-protocol/sei-chain/x/oracle/types";

// Msg defines the oracle Msg service.
service Msg {
// AggregateExchangeRatePrevote defines a method for submitting
// aggregate exchange rate prevote
rpc AggregateExchangeRatePrevote(MsgAggregateExchangeRatePrevote) returns (MsgAggregateExchangeRatePrevoteResponse);

// AggregateExchangeRateVote defines a method for submitting
// aggregate exchange rate vote
rpc AggregateExchangeRateVote(MsgAggregateExchangeRateVote) returns (MsgAggregateExchangeRateVoteResponse);

// Aggregate vote and prevote combines the functionality of prevote and vote into one RPC
rpc AggregateExchangeRateCombinedVote(MsgAggregateExchangeRateCombinedVote) returns (MsgAggregateExchangeRateCombinedVoteResponse);

// DelegateFeedConsent defines a method for setting the feeder delegation
rpc DelegateFeedConsent(MsgDelegateFeedConsent) returns (MsgDelegateFeedConsentResponse);
}

// MsgAggregateExchangeRatePrevote represents a message to submit
// aggregate exchange rate prevote.
message MsgAggregateExchangeRatePrevote {
option (gogoproto.equal) = false;
option (gogoproto.goproto_getters) = false;

string hash = 1 [(gogoproto.moretags) = "yaml:\"hash\""];
string feeder = 2 [(gogoproto.moretags) = "yaml:\"feeder\""];
string validator = 3 [(gogoproto.moretags) = "yaml:\"validator\""];
}

// MsgAggregateExchangeRatePrevoteResponse defines the Msg/AggregateExchangeRatePrevote response type.
message MsgAggregateExchangeRatePrevoteResponse {}

// MsgAggregateExchangeRateVote represents a message to submit
// aggregate exchange rate vote.
message MsgAggregateExchangeRateVote {
option (gogoproto.equal) = false;
option (gogoproto.goproto_getters) = false;

string salt = 1 [(gogoproto.moretags) = "yaml:\"salt\""];
// 1 reserved from old field `salt`
string exchange_rates = 2 [(gogoproto.moretags) = "yaml:\"exchange_rates\""];
string feeder = 3 [(gogoproto.moretags) = "yaml:\"feeder\""];
string validator = 4 [(gogoproto.moretags) = "yaml:\"validator\""];
Expand All @@ -51,22 +30,6 @@ message MsgAggregateExchangeRateVote {
// MsgAggregateExchangeRateVoteResponse defines the Msg/AggregateExchangeRateVote response type.
message MsgAggregateExchangeRateVoteResponse {}

// MsgAggregateExchangeRateVote represents a message to submit
// aggregate exchange rate vote.
message MsgAggregateExchangeRateCombinedVote {
option (gogoproto.equal) = false;
option (gogoproto.goproto_getters) = false;

string vote_salt = 1 [(gogoproto.moretags) = "yaml:\"vote_salt\""];
string vote_exchange_rates = 2 [(gogoproto.moretags) = "yaml:\"vote_exchange_rates\""];
string prevote_hash = 3 [(gogoproto.moretags) = "yaml:\"prevote_hash\""];
string feeder = 4 [(gogoproto.moretags) = "yaml:\"feeder\""];
string validator = 5 [(gogoproto.moretags) = "yaml:\"validator\""];
}

// MsgAggregateExchangeRateVoteResponse defines the Msg/AggregateExchangeRateVote response type.
message MsgAggregateExchangeRateCombinedVoteResponse {}

// MsgDelegateFeedConsent represents a message to
// delegate oracle voting rights to another address.
message MsgDelegateFeedConsent {
Expand Down
6 changes: 1 addition & 5 deletions x/oracle/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,7 @@

Sei Network has an `oracle` module to support asset exchange rate pricing for use by other modules and contracts. When validating for the network, participation as an Oracle is expected and required in order to ensure the most reliable and accurate pricing for assets.

For oracle pricing, the voting rounds have several steps to ensure integrity and consensus of pricing data prior to accepting the exchange rates as the source of truth. In each voting period, there are two aggregation steps that oracles must participate in.

The prevote step is a step where a validator provides their oracle pricing submission during voting window X for the next voting window X+1. In this prevote step, the validator hashes their proposed exchange rates to prevent other validators from simply copying that validator's votes.

In the vote step for window X, the validator provides their proposed exchange rates for the current window. These are hashed and compared with the prevotes from window X-1 to ensure that the voted values haven't changed across the voting window. At the end of the voting period, all of the exchange rate votes are accumulated and a weighted median is computed (weighted by validator voting power) to determine the true exchange rate for each asset.
In the vote step for window X, the validator provides their proposed exchange rates for the current window. At the end of the voting period, all of the exchange rate votes are accumulated and a weighted median is computed (weighted by validator voting power) to determine the true exchange rate for each asset.

There are penalties for non-participation and participation with bad data. Validators have a miss count that tracks the number of voting windows in which a validator has either not provided data or provided data that deviated too much from the weighted median. In a given number of voting periods, if a validators miss count is too high, they are slashed as a penalty for misbehaving over an extended period of time.

Expand Down
Loading