In order to use the data provided by the Oracle module, we must make sure all validators come to a consensus about what is commeted to the blockchain state.
While the Oracle module provides some helper methods, the app developer is ultimately responsible for doing this.
Copy
func(k Keeper)UpdateAtomUsd(ctx sdk.Context){
claimType := types.AtomClaim
pending := k.oracleKeeper.GetPendingRounds(ctx, claimType)// sort pending rounds in ascending order
sort.SliceStable(pending,func(i, j int)bool{return pending[i]< pending[j]})for_, roundID :=range pending {
result := k.oracleKeeper.TallyVotes(ctx, claimType, roundID)if result ==nil|| result.Claims[0]==nil{continue}// take an average of all claims and commit to chain
avgAtomUsd := sdk.NewDec(0)var blockHeight int64var totalVotePower int64for_, claimResult :=range result.Claims {
claimHash := claimResult.ClaimHash
atomClaim, ok := k.oracleKeeper.GetClaim(ctx, claimHash).(*types.AtomUsd)if ok ==false{
fmt.Printf("Error retrieving claim")continue}
weightedAvg := avgAtomUsd.Mul(sdk.NewDec(totalVotePower))
weightedVote := atomClaim.Price.Mul(sdk.NewDec(result.VotePower))
totalVotePower += result.VotePower
avgAtomUsd = weightedAvg.Add(weightedVote).Quo(sdk.NewDec(totalVotePower))
blockHeight = atomClaim.BlockHeight
}
atomUsd :=&types.AtomUsd{
Price: avgAtomUsd,
BlockHeight: blockHeight,}
k.SetAtomUsd(ctx,*atomUsd)// TODO delete the any earlier pending rounds
k.oracleKeeper.FinalizeRound(ctx, claimType, roundID)}}
Here is what happens in the code above:
We get all 'PendingRounds' from the oracleKeeper and sort them in ascending order so we can process the early claims first
For each pending round, we tally the votes using the oracleKeeper's TallyVotes method. If consensus threshold we specified in the params is reached, TallyVotes returns a RoundResult struct.
Copy
type ClaimVoteResult struct{
ClaimHash tmbytes.HexBytes
VotePower int64}// RoundResult is is a record of vote tallies for a given roundtype RoundResult struct{
VotePower int64
TotalPower int64
ClaimType string
Claims []*ClaimVoteResult
}
We iterate through the round result's Claims field, fetch the Claim and weigh the price by the validators power. This gives us an average submission price weighted by validator power.
Write the final result on-chain along with the Claim's BlockHeight
Note in reality you may want to use weighted median value rather than a weighted average.
As a final step we add the querier and cli methods to fetch the on-chain price. You consult the starport examples on how to do this, or simply view the final result here: https://github.com/relevant-community/oracle/tree/main/x/atom