Skip to content

Commit

Permalink
feat: finish the todos in the oracle module and add test cases (#174)
Browse files Browse the repository at this point in the history
  • Loading branch information
yutianwu authored Apr 12, 2023
1 parent 0a01b4e commit e801e09
Show file tree
Hide file tree
Showing 13 changed files with 1,010 additions and 12 deletions.
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ require (
github.com/tendermint/go-amino v0.16.0
github.com/tendermint/tendermint v0.35.9
github.com/wealdtech/go-eth2-util v1.6.3
github.com/willf/bitset v1.1.3
golang.org/x/crypto v0.7.0
golang.org/x/exp v0.0.0-20230321023759-10a507213a29
golang.org/x/sync v0.1.0
Expand Down
1 change: 1 addition & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -1940,6 +1940,7 @@ github.com/whyrusleeping/go-logging v0.0.0-20170515211332-0457bb6b88fc/go.mod h1
github.com/whyrusleeping/mdns v0.0.0-20190826153040-b9b60ed33aa9/go.mod h1:j4l84WPFclQPj320J9gp0XwNKBb3U0zt5CBqjPp22G4=
github.com/whyrusleeping/multiaddr-filter v0.0.0-20160516205228-e903e4adabd7/go.mod h1:X2c0RVCI1eSUFI8eLcY3c0423ykwiUdxLJtkDvruhjI=
github.com/whyrusleeping/timecache v0.0.0-20160911033111-cfcb2f1abfee/go.mod h1:m2aV4LZI4Aez7dP5PMyVKEHhUyEJ/RjmPEDOpDvudHg=
github.com/willf/bitset v1.1.3 h1:ekJIKh6+YbUIVt9DfNbkR5d6aFcFTLDRyJNAACURBg8=
github.com/willf/bitset v1.1.3/go.mod h1:RjeCKbqT1RxIR/KWY6phxZiaY1IyutSBfGjNPySAYV4=
github.com/x-cray/logrus-prefixed-formatter v0.5.2/go.mod h1:2duySbKsL6M18s5GU7VPsoEPHyzalCE06qoARUCeBBE=
github.com/xdg/scram v0.0.0-20180814205039-7eeb5667e42c/go.mod h1:lB8K/P019DLNhemzwFU4jHLhdvlE6uDZjXFejJXr49I=
Expand Down
1 change: 1 addition & 0 deletions simapp/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,7 @@ require (
github.com/wealdtech/go-bytesutil v1.1.1 // indirect
github.com/wealdtech/go-eth2-types/v2 v2.5.2 // indirect
github.com/wealdtech/go-eth2-util v1.6.3 // indirect
github.com/willf/bitset v1.1.3 // indirect
github.com/zondax/hid v0.9.1 // indirect
github.com/zondax/ledger-go v0.14.1 // indirect
go.etcd.io/bbolt v1.3.6 // indirect
Expand Down
1 change: 1 addition & 0 deletions simapp/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -1694,6 +1694,7 @@ github.com/whyrusleeping/go-logging v0.0.0-20170515211332-0457bb6b88fc/go.mod h1
github.com/whyrusleeping/mdns v0.0.0-20190826153040-b9b60ed33aa9/go.mod h1:j4l84WPFclQPj320J9gp0XwNKBb3U0zt5CBqjPp22G4=
github.com/whyrusleeping/multiaddr-filter v0.0.0-20160516205228-e903e4adabd7/go.mod h1:X2c0RVCI1eSUFI8eLcY3c0423ykwiUdxLJtkDvruhjI=
github.com/whyrusleeping/timecache v0.0.0-20160911033111-cfcb2f1abfee/go.mod h1:m2aV4LZI4Aez7dP5PMyVKEHhUyEJ/RjmPEDOpDvudHg=
github.com/willf/bitset v1.1.3 h1:ekJIKh6+YbUIVt9DfNbkR5d6aFcFTLDRyJNAACURBg8=
github.com/willf/bitset v1.1.3/go.mod h1:RjeCKbqT1RxIR/KWY6phxZiaY1IyutSBfGjNPySAYV4=
github.com/x-cray/logrus-prefixed-formatter v0.5.2/go.mod h1:2duySbKsL6M18s5GU7VPsoEPHyzalCE06qoARUCeBBE=
github.com/xdg/scram v0.0.0-20180814205039-7eeb5667e42c/go.mod h1:lB8K/P019DLNhemzwFU4jHLhdvlE6uDZjXFejJXr49I=
Expand Down
1 change: 1 addition & 0 deletions tests/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ require (
github.com/prysmaticlabs/prysm v0.0.0-20220124113610-e26cde5e091b
github.com/spf13/cobra v1.6.1
github.com/stretchr/testify v1.8.2
github.com/willf/bitset v1.1.3 // indirect
google.golang.org/protobuf v1.30.0
gotest.tools/v3 v3.4.0
pgregory.net/rapid v0.5.5
Expand Down
1 change: 1 addition & 0 deletions tests/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -1696,6 +1696,7 @@ github.com/whyrusleeping/go-logging v0.0.0-20170515211332-0457bb6b88fc/go.mod h1
github.com/whyrusleeping/mdns v0.0.0-20190826153040-b9b60ed33aa9/go.mod h1:j4l84WPFclQPj320J9gp0XwNKBb3U0zt5CBqjPp22G4=
github.com/whyrusleeping/multiaddr-filter v0.0.0-20160516205228-e903e4adabd7/go.mod h1:X2c0RVCI1eSUFI8eLcY3c0423ykwiUdxLJtkDvruhjI=
github.com/whyrusleeping/timecache v0.0.0-20160911033111-cfcb2f1abfee/go.mod h1:m2aV4LZI4Aez7dP5PMyVKEHhUyEJ/RjmPEDOpDvudHg=
github.com/willf/bitset v1.1.3 h1:ekJIKh6+YbUIVt9DfNbkR5d6aFcFTLDRyJNAACURBg8=
github.com/willf/bitset v1.1.3/go.mod h1:RjeCKbqT1RxIR/KWY6phxZiaY1IyutSBfGjNPySAYV4=
github.com/x-cray/logrus-prefixed-formatter v0.5.2/go.mod h1:2duySbKsL6M18s5GU7VPsoEPHyzalCE06qoARUCeBBE=
github.com/xdg/scram v0.0.0-20180814205039-7eeb5667e42c/go.mod h1:lB8K/P019DLNhemzwFU4jHLhdvlE6uDZjXFejJXr49I=
Expand Down
14 changes: 14 additions & 0 deletions x/oracle/keeper/grpc_query_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package keeper_test

import (
gocontext "context"

"github.com/cosmos/cosmos-sdk/x/oracle/types"
)

func (s *TestSuite) TestQueryParams() {
res, err := s.queryClient.Params(gocontext.Background(), &types.QueryParamsRequest{})
s.Require().NoError(err)
s.Require().NotNil(res)
s.Require().Equal(s.oracleKeeper.GetParams(s.ctx), res.GetParams())
}
127 changes: 121 additions & 6 deletions x/oracle/keeper/keeper.go
Original file line number Diff line number Diff line change
@@ -1,10 +1,15 @@
package keeper

import (
"bytes"
"encoding/hex"

sdkerrors "cosmossdk.io/errors"
"cosmossdk.io/log"
storetypes "cosmossdk.io/store/types"
"github.com/prysmaticlabs/prysm/crypto/bls"
"github.com/willf/bitset"

"github.com/cosmos/cosmos-sdk/codec"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/oracle/types"
Expand Down Expand Up @@ -76,15 +81,101 @@ func (k Keeper) GetRelayerRewardShare(ctx sdk.Context) uint32 {

// IsRelayerValid returns true if the relayer is valid and allowed to send the claim message
func (k Keeper) IsRelayerValid(ctx sdk.Context, relayer sdk.AccAddress, validators []stakingtypes.Validator, claimTimestamp uint64) (bool, error) {
// todo: implement this
return true, nil
var validatorIndex int64 = -1
var vldr stakingtypes.Validator
for index, validator := range validators {
if validator.RelayerAddress == relayer.String() {
validatorIndex = int64(index)
vldr = validator
break
}
}

if validatorIndex < 0 {
return false, sdkerrors.Wrapf(types.ErrNotRelayer, "sender(%s) is not a relayer", relayer.String())
}

inturnRelayerTimeout, relayerInterval := k.GetRelayerParams(ctx)

// check whether submitter of msgClaim is an in-turn relayer
inturnRelayerBlsKey, _, err := k.getInturnRelayer(ctx, relayerInterval)
if err != nil {
return false, err
}

if bytes.Equal(inturnRelayerBlsKey, vldr.RelayerBlsKey) {
return true, nil
}

// It is possible that claim comes from out-turn relayers when exceeding the inturnRelayerTimeout, all other
// relayers can relay within the in-turn relayer's current interval
curTime := ctx.BlockTime().Unix()
if uint64(curTime) < claimTimestamp {
return false, nil
}

return uint64(curTime)-claimTimestamp >= inturnRelayerTimeout, nil
}

// CheckClaim checks the bls signature
func (k Keeper) CheckClaim(ctx sdk.Context, claim *types.MsgClaim) (sdk.AccAddress, []sdk.AccAddress, error) {
// todo: implement this
relayer, err := sdk.AccAddressFromHexUnsafe(claim.FromAddress)
if err != nil {
return sdk.AccAddress{}, nil, sdkerrors.Wrapf(types.ErrInvalidAddress, "from address (%s) is invalid", claim.FromAddress)
}

historicalInfo, ok := k.StakingKeeper.GetHistoricalInfo(ctx, ctx.BlockHeight())
if !ok {
return sdk.AccAddress{}, nil, sdkerrors.Wrapf(types.ErrValidatorSet, "get historical validators failed")
}
validators := historicalInfo.Valset

isValid, err := k.IsRelayerValid(ctx, relayer, validators, claim.Timestamp)
if err != nil {
return sdk.AccAddress{}, nil, err
}

if !isValid {
return sdk.AccAddress{}, nil, sdkerrors.Wrapf(types.ErrRelayerNotInTurn, "relayer(%s) is not in turn", claim.FromAddress)
}

return sdk.AccAddress{}, []sdk.AccAddress{}, nil
validatorsBitSet := bitset.From(claim.VoteAddressSet)
if validatorsBitSet.Count() > uint(len(validators)) {
return sdk.AccAddress{}, nil, sdkerrors.Wrapf(types.ErrValidatorSet, "number of validator set is larger than validators")
}

signedRelayers := make([]sdk.AccAddress, 0, validatorsBitSet.Count())
votedPubKeys := make([]bls.PublicKey, 0, validatorsBitSet.Count())
for index, val := range validators {
if !validatorsBitSet.Test(uint(index)) {
continue
}

signedRelayers = append(signedRelayers, sdk.MustAccAddressFromHex(val.RelayerAddress))

votePubKey, err := bls.PublicKeyFromBytes(val.RelayerBlsKey)
if err != nil {
return sdk.AccAddress{}, nil, sdkerrors.Wrapf(types.ErrBlsPubKey, "BLS public key converts failed: %v", err)
}
votedPubKeys = append(votedPubKeys, votePubKey)
}

// The valid voted validators should be no less than 2/3 validators.
if len(votedPubKeys) <= len(validators)*2/3 {
return sdk.AccAddress{}, nil, sdkerrors.Wrapf(types.ErrBlsVotesNotEnough, "not enough validators voted, need: %d, voted: %d", len(validators)*2/3, len(votedPubKeys))
}

// Verify the aggregated signature.
aggSig, err := bls.SignatureFromBytes(claim.AggSignature)
if err != nil {
return sdk.AccAddress{}, nil, sdkerrors.Wrapf(types.ErrInvalidBlsSignature, "BLS signature converts failed: %v", err)
}

if !aggSig.FastAggregateVerify(votedPubKeys, claim.GetBlsSignBytes()) {
return sdk.AccAddress{}, nil, sdkerrors.Wrapf(types.ErrInvalidBlsSignature, "signature verify failed")
}

return relayer, signedRelayers, nil
}

// GetParams returns the current params
Expand All @@ -100,8 +191,32 @@ func (k Keeper) GetParams(ctx sdk.Context) (params types.Params) {
}

func (k Keeper) getInturnRelayer(ctx sdk.Context, relayerInterval uint64) ([]byte, *types.RelayInterval, error) {
// todo: implement this
return nil, nil, nil
historicalInfo, ok := k.StakingKeeper.GetHistoricalInfo(ctx, ctx.BlockHeight())
if !ok {
return nil, nil, sdkerrors.Wrapf(types.ErrValidatorSet, "get historical validators failed")
}
validators := historicalInfo.Valset

validatorsSize := len(validators)

// totalIntervals is sum of intervals from all relayers
totalIntervals := relayerInterval * uint64(validatorsSize)

curTimeStamp := uint64(ctx.BlockTime().Unix())

// remainder is used to locate inturn relayer.
remainder := curTimeStamp % totalIntervals
inTurnRelayerIndex := remainder / relayerInterval

start := curTimeStamp - (remainder - inTurnRelayerIndex*relayerInterval)
end := start + relayerInterval

inturnRelayer := validators[inTurnRelayerIndex]

return inturnRelayer.RelayerBlsKey, &types.RelayInterval{
Start: start,
End: end,
}, nil
}

func (k Keeper) GetInturnRelayer(ctx sdk.Context, relayerInterval uint64) (*types.QueryInturnRelayerResponse, error) {
Expand Down
Loading

0 comments on commit e801e09

Please sign in to comment.