(TIP) Oracle optimization - SPEC

Oracle Optimization


Currently, a separate prevote and vote object needs to be formed for all the denoms in the oracle whitelist, which clogs up the message bus.


Decrease msg size as much as possible
Reduce resources required to process oracle msg handler


Compress oracle vote msg by aggregating vote for all denoms


Introduce aggregated prevote&vote. Each aggregated oracle vote contains multiple swap rates as a single string splitted by a comma instead of multiple DecCoin to reduce unnecessary object keys. Each aggregated oracle prevote contains a single hex string representing hash value of aggregated oracle vote.

type MsgAggregateExchangeRateVote struct {
    Salt           string          `json:"salt" yaml:"salt"`
    ExchangeRates  string          `json:"exchange_rates" yaml:"exchange_rates"`
    Feeder         sdk.AccAddress  `json:"feeder" yaml:"feeder"`
    Validator      sdk.ValAddress  `json:"validator" yaml:"validator"`
type MsgAggregateExchangeRatePrevote struct {
    Hash      AggregateVoteHash  `json:"hash" yaml:"hash"`
    Feeder    sdk.AccAddress     `json:"feeder" yaml:"feeder"`
    Validator sdk.ValAddress     `json:"validator" yaml:"validator"`

The hash of aggregate oracle prevote has {salt}:{exchange rate}{denom},...,{exchange rate}{denom}:{voter} format. only difference of hash between old style prevote and aggregate prevote is that it takes comma joined exchange rates string instead of a single exchange rate. We directly use exchange rates string at verifying hash of aggregate oracle vote, so third party application do not need to fill zeros to meet cosmos Dec’s stringify specification.

Msg handler parse the comma joined exchange rates string to exchange rate tuples and store these tuples to reduce redundant parsing cost.

type ExchangeRateTuple struct {
    Denom        string  `json:"denom"`
    ExchangeRate sdk.Dec `json:"exchange_rate"`
type AggregateExchangeRateVote struct {
    ExchangeRateTuples ExchangeRateTuples `json:"exchange_rate_tuples"`
    Voter              sdk.ValAddress     `json:"voter"`

Notable Problems

Redundant vote from both old style vote and aggregate vote

The core checks the aggregate vote first, and then ignores the old style votes of the validator who did the aggregate vote.


It’s probably important to note that full nodes are requiring up to 128GB disk at this point - much of which is lots of unecessary redundancy from prevotes / votes per every denom every 5 blocks. This will allow only 1 of each vote/prevote to be submitted per validator instead of N (= # of whitelisted oracle denoms) so should save a lot of disk space going forward