package oracle import ( "bytes" sdk "github.com/cosmos/cosmos-sdk/types" ) // Handler handles payload after it passes voting process type Handler func(ctx sdk.Context, p Payload) sdk.Error func (keeper Keeper) update(ctx sdk.Context, val sdk.Validator, valset sdk.ValidatorSet, p Payload, info Info) Info { info.Power = info.Power.Add(val.GetPower()) // Return if the voted power is not bigger than required power totalPower := valset.TotalPower(ctx) requiredPower := totalPower.Mul(keeper.supermaj) if !info.Power.GT(requiredPower) { return info } // Check if the validators hash has been changed during the vote process // and recalculate voted power hash := ctx.BlockHeader().ValidatorsHash if !bytes.Equal(hash, info.Hash) { info.Power = sdk.ZeroRat() info.Hash = hash prefix := GetSignPrefix(p, keeper.cdc) store := keeper.key.KVStore(ctx) iter := sdk.KVStorePrefixIterator(store, prefix) for ; iter.Valid(); iter.Next() { if valset.Validator(ctx, iter.Value()) != nil { store.Delete(iter.Key()) continue } info.Power = info.Power.Add(val.GetPower()) } if !info.Power.GT(totalPower.Mul(keeper.supermaj)) { return info } } info.Status = Processed return info } // Handle is used by other modules to handle Msg func (keeper Keeper) Handle(h Handler, ctx sdk.Context, o Msg, codespace sdk.CodespaceType) sdk.Result { valset := keeper.valset signer := o.Signer payload := o.Payload // Check the oracle is not in process info := keeper.Info(ctx, payload) if info.Status != Pending { return ErrAlreadyProcessed(codespace).Result() } // Check if it is reporting timeout now := ctx.BlockHeight() if now > info.LastSigned+keeper.timeout { info = Info{Status: Timeout} keeper.setInfo(ctx, payload, info) keeper.clearSigns(ctx, payload) return sdk.Result{} } info.LastSigned = ctx.BlockHeight() // Check the signer is a validater val := valset.Validator(ctx, signer) if val == nil { return ErrNotValidator(codespace, signer).Result() } // Check double signing if keeper.signed(ctx, payload, signer) { return ErrAlreadySigned(codespace).Result() } keeper.sign(ctx, payload, signer) info = keeper.update(ctx, val, valset, payload, info) if info.Status == Processed { info = Info{Status: Processed} } keeper.setInfo(ctx, payload, info) if info.Status == Processed { keeper.clearSigns(ctx, payload) cctx, write := ctx.CacheContext() err := h(cctx, payload) if err != nil { return sdk.Result{ Code: sdk.ABCICodeOK, Log: err.ABCILog(), } } write() } return sdk.Result{} }