Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add ApproveOracleRegistration tx #527

Merged
merged 24 commits into from
Dec 9, 2022
Merged
Show file tree
Hide file tree
Changes from 14 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
5 changes: 3 additions & 2 deletions proto/panacea/oracle/v2/tx.proto
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,9 @@ message MsgApproveOracleRegistration {
// ApproveOracleRegistration defines for oracle registration approval
message ApproveOracleRegistration {
string unique_id = 1;
string target_oracle_address = 2;
bytes encrypted_oracle_priv_key = 3;
string approver_oracle_address = 2;
string target_oracle_address = 3;
bytes encrypted_oracle_priv_key = 4;
}

// MsgApproveOracleRegistrationResponse defines the Msg/ApproveOracleRegistration
Expand Down
17 changes: 17 additions & 0 deletions types/testsuite/suite.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ import (
aoltypes "github.com/medibloc/panacea-core/v2/x/aol/types"
burnkeeper "github.com/medibloc/panacea-core/v2/x/burn/keeper"
burntypes "github.com/medibloc/panacea-core/v2/x/burn/types"
oraclekeeper "github.com/medibloc/panacea-core/v2/x/oracle/keeper"
oracletypes "github.com/medibloc/panacea-core/v2/x/oracle/types"
"github.com/stretchr/testify/suite"
"github.com/tendermint/tendermint/crypto/secp256k1"
"github.com/tendermint/tendermint/libs/log"
Expand All @@ -52,6 +54,7 @@ type TestSuite struct {
suite.Suite

Ctx sdk.Context
Cdc params.EncodingConfig

AccountKeeper authkeeper.AccountKeeper
StakingKeeper stakingkeeper.Keeper
Expand All @@ -65,6 +68,8 @@ type TestSuite struct {
TransferKeeper ibctransferkeeper.Keeper
DIDMsgServer didtypes.MsgServer
DIDKeeper didkeeper.Keeper
OracleKeeper oraclekeeper.Keeper
OracleMsgServer oracletypes.MsgServer
WasmKeeper wasm.Keeper
UpgradeKeeper upgradekeeper.Keeper
}
Expand All @@ -76,6 +81,7 @@ func (suite *TestSuite) SetupTest() {
banktypes.StoreKey,
paramstypes.StoreKey,
didtypes.StoreKey,
oracletypes.StoreKey,
wasm.StoreKey,
ibchost.StoreKey,
capabilitytypes.StoreKey,
Expand Down Expand Up @@ -127,6 +133,7 @@ func (suite *TestSuite) SetupTest() {
scopedIBCKeeper := suite.CapabilityKeeper.ScopeToModule(ibchost.ModuleName)

suite.Ctx = ctx
suite.Cdc = cdc
suite.AccountKeeper = authkeeper.NewAccountKeeper(
cdc.Marshaler,
keyParams[authtypes.StoreKey],
Expand Down Expand Up @@ -202,6 +209,15 @@ func (suite *TestSuite) SetupTest() {
memKeys[didtypes.MemStoreKey],
)
suite.DIDMsgServer = didkeeper.NewMsgServerImpl(suite.DIDKeeper)

suite.OracleKeeper = *oraclekeeper.NewKeeper(
cdc.Marshaler,
keyParams[oracletypes.StoreKey],
memKeys[oracletypes.MemStoreKey],
paramsKeeper.Subspace(oracletypes.ModuleName),
)

suite.OracleMsgServer = oraclekeeper.NewMsgServerImpl(suite.OracleKeeper)
}

func (suite *TestSuite) BeforeTest(suiteName, testName string) {
Expand All @@ -218,6 +234,7 @@ func newTestCodec() params.EncodingConfig {
authtypes.RegisterInterfaces(interfaceRegistry)
banktypes.RegisterInterfaces(interfaceRegistry)
didtypes.RegisterInterfaces(interfaceRegistry)
oracletypes.RegisterInterfaces(interfaceRegistry)
marshaler := codec.NewProtoCodec(interfaceRegistry)

return params.EncodingConfig{
Expand Down
2 changes: 2 additions & 0 deletions x/oracle/client/cli/tx.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,5 +18,7 @@ func GetTxCmd() *cobra.Command {
RunE: client.ValidateCmd,
}

cmd.AddCommand(CmdApproveOracleRegistration())

return cmd
}
43 changes: 43 additions & 0 deletions x/oracle/client/cli/txApproveOracleRegistration.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package cli

import (
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/flags"
"github.com/cosmos/cosmos-sdk/client/tx"
"github.com/medibloc/panacea-core/v2/x/oracle/types"
"github.com/spf13/cobra"
)

func CmdApproveOracleRegistration() *cobra.Command {
youngjoon-lee marked this conversation as resolved.
Show resolved Hide resolved
cmd := &cobra.Command{
Use: "approve-oracle-registration [unique ID] [target oracle address] [encrypted oracle private key] [signature]",
inchori marked this conversation as resolved.
Show resolved Hide resolved
Short: "approve a new oracle registration",
Args: cobra.ExactArgs(4),
RunE: func(cmd *cobra.Command, args []string) error {
clientCtx, err := client.GetClientTxContext(cmd)
if err != nil {
return err
}

oracleAddress := clientCtx.GetFromAddress().String()

approveOracleRegistration := &types.ApproveOracleRegistration{
UniqueId: args[0],
ApproverOracleAddress: oracleAddress,
TargetOracleAddress: args[1],
EncryptedOraclePrivKey: []byte(args[2]),
}

msg := types.NewMsgApproveOracleRegistration(approveOracleRegistration, []byte(args[3]))
if err := msg.ValidateBasic(); err != nil {
return err
}

return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg)
},
}

flags.AddTxFlagsToCmd(cmd)

return cmd
}
20 changes: 17 additions & 3 deletions x/oracle/keeper/msg_server_oracle.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package keeper
import (
"context"

sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/medibloc/panacea-core/v2/x/oracle/types"
)

Expand All @@ -11,9 +12,22 @@ func (m msgServer) RegisterOracle(ctx context.Context, oracle *types.MsgRegister
panic("implement me")
}

func (m msgServer) ApproveOracleRegistration(ctx context.Context, registration *types.MsgApproveOracleRegistration) (*types.MsgApproveOracleRegistrationResponse, error) {
//TODO implement me
panic("implement me")
func (m msgServer) ApproveOracleRegistration(goCtx context.Context, msg *types.MsgApproveOracleRegistration) (*types.MsgApproveOracleRegistrationResponse, error) {
ctx := sdk.UnwrapSDKContext(goCtx)

if err := m.Keeper.ApproveOracleRegistration(ctx, msg); err != nil {
return nil, err
}

ctx.EventManager().EmitEvent(
sdk.NewEvent(

sdk.EventTypeMessage,
audtlr24 marked this conversation as resolved.
Show resolved Hide resolved
sdk.NewAttribute(sdk.AttributeKeyModule, types.ModuleName),
),
)

return &types.MsgApproveOracleRegistrationResponse{}, nil
}

func (m msgServer) UpdateOracleInfo(ctx context.Context, info *types.MsgUpdateOracleInfo) (*types.MsgUpdateOracleInfoResponse, error) {
Expand Down
199 changes: 199 additions & 0 deletions x/oracle/keeper/oracle.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,199 @@
package keeper

import (
"errors"
"fmt"

sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
"github.com/medibloc/panacea-core/v2/x/oracle/types"
"github.com/tendermint/tendermint/crypto/secp256k1"
)

func (k Keeper) RegisterOracle(ctx sdk.Context, msg *types.MsgRegisterOracle) error {
oracleRegistration := types.NewOracleRegistration(msg)

if err := oracleRegistration.ValidateBasic(); err != nil {
return err
}

params := k.GetParams(ctx)
if params.UniqueId != oracleRegistration.UniqueId {
return sdkerrors.Wrapf(types.ErrOracleRegistration, "is not match the currently active uniqueID")
}

if oracle, err := k.GetOracle(ctx, oracleRegistration.OracleAddress); !errors.Is(types.ErrOracleNotFound, err) {
if oracle != nil {
return sdkerrors.Wrapf(types.ErrOracleRegistration, "already registered oracle. address(%s)", oracleRegistration.OracleAddress)
} else {
return sdkerrors.Wrapf(types.ErrOracleRegistration, err.Error())
}
}

if err := k.SetOracleRegistration(ctx, oracleRegistration); err != nil {
return err
}

ctx.EventManager().EmitEvent(
sdk.NewEvent(
types.EventTypeRegistration,
sdk.NewAttribute(types.AttributeKeyUniqueID, oracleRegistration.UniqueId),
sdk.NewAttribute(types.AttributeKeyOracleAddress, oracleRegistration.OracleAddress),
),
)
return nil
}

func (k Keeper) ApproveOracleRegistration(ctx sdk.Context, msg *types.MsgApproveOracleRegistration) error {

if err := k.validateApproveOracleRegistration(ctx, msg); err != nil {
return err
audtlr24 marked this conversation as resolved.
Show resolved Hide resolved
}

oracleRegistration, err := k.GetOracleRegistration(ctx, msg.ApproveOracleRegistration.UniqueId, msg.ApproveOracleRegistration.TargetOracleAddress)
if err != nil {
return err
}

newOracle := &types.Oracle{
OracleAddress: msg.ApproveOracleRegistration.TargetOracleAddress,
UniqueId: msg.ApproveOracleRegistration.UniqueId,
Endpoint: oracleRegistration.Endpoint,
OracleCommissionRate: oracleRegistration.OracleCommissionRate,
}
audtlr24 marked this conversation as resolved.
Show resolved Hide resolved

// append new oracle info
if err := k.SetOracle(ctx, newOracle); err != nil {
return err
}

ctx.EventManager().EmitEvent(
sdk.NewEvent(
types.EventTypeApproveOracleRegistration,
sdk.NewAttribute(types.AttributeKeyOracleAddress, msg.ApproveOracleRegistration.TargetOracleAddress),
sdk.NewAttribute(types.AttributeKeyEncryptedOraclePrivKey, string(msg.ApproveOracleRegistration.EncryptedOraclePrivKey)),
),
)

return nil

}

// validateApproveOracleRegistration checks signature
func (k Keeper) validateApproveOracleRegistration(ctx sdk.Context, msg *types.MsgApproveOracleRegistration) error {

params := k.GetParams(ctx)
targetOracleAddress := msg.ApproveOracleRegistration.TargetOracleAddress

// check unique id
if msg.ApproveOracleRegistration.UniqueId != params.UniqueId {
return types.ErrInvalidUniqueId
}

// verify signature
ApproveOracleRegistrationBz := k.cdc.MustMarshal(msg.ApproveOracleRegistration)
oraclePubKeyBz := k.GetParams(ctx).MustDecodeOraclePublicKey()

if !secp256k1.PubKey(oraclePubKeyBz).VerifySignature(ApproveOracleRegistrationBz, msg.Signature) {
audtlr24 marked this conversation as resolved.
Show resolved Hide resolved
return fmt.Errorf("failed to signature validation")
}

// check if the oracle has been already registered
hasOracle, err := k.HasOracle(ctx, targetOracleAddress)
gyuguen marked this conversation as resolved.
Show resolved Hide resolved
if err != nil {
return err
}
if hasOracle {
return fmt.Errorf("already registered oracle. address(%s)", targetOracleAddress)
}

return nil
}

func (k Keeper) SetOracleRegistration(ctx sdk.Context, regOracle *types.OracleRegistration) error {
store := ctx.KVStore(k.storeKey)

accAddr, err := sdk.AccAddressFromBech32(regOracle.OracleAddress)
if err != nil {
return err
}
key := types.GetOracleRegistrationKey(regOracle.UniqueId, accAddr)
bz, err := k.cdc.MarshalLengthPrefixed(regOracle)
if err != nil {
return err
}

store.Set(key, bz)

return nil
}

func (k Keeper) GetOracleRegistration(ctx sdk.Context, uniqueID, address string) (*types.OracleRegistration, error) {
store := ctx.KVStore(k.storeKey)
accAddr, err := sdk.AccAddressFromBech32(address)
if err != nil {
return nil, err
}
key := types.GetOracleRegistrationKey(uniqueID, accAddr)
bz := store.Get(key)
if bz == nil {
return nil, sdkerrors.Wrapf(types.ErrGetOracleRegistration, "oracle registration not found")
}

oracleRegistration := &types.OracleRegistration{}

if err := k.cdc.UnmarshalLengthPrefixed(bz, oracleRegistration); err != nil {
return nil, err
}

return oracleRegistration, nil
}

func (k Keeper) SetOracle(ctx sdk.Context, oracle *types.Oracle) error {
store := ctx.KVStore(k.storeKey)
accAddr, err := sdk.AccAddressFromBech32(oracle.OracleAddress)
if err != nil {
return err
}
key := types.GetOracleKey(accAddr)
bz, err := k.cdc.MarshalLengthPrefixed(oracle)
if err != nil {
return err
}

store.Set(key, bz)

return nil
}

func (k Keeper) GetOracle(ctx sdk.Context, address string) (*types.Oracle, error) {
store := ctx.KVStore(k.storeKey)
accAddr, err := sdk.AccAddressFromBech32(address)
if err != nil {
return nil, err
}
key := types.GetOracleKey(accAddr)
bz := store.Get(key)
if bz == nil {
return nil, sdkerrors.Wrapf(types.ErrOracleNotFound, "oracle '%s' does not exist", address)
}

oracle := &types.Oracle{}

err = k.cdc.UnmarshalLengthPrefixed(bz, oracle)
if err != nil {
return nil, sdkerrors.Wrapf(types.ErrGetOracle, err.Error())
}

return oracle, nil
}

func (k Keeper) HasOracle(ctx sdk.Context, address string) (bool, error) {
store := ctx.KVStore(k.storeKey)
accAddr, err := sdk.AccAddressFromBech32(address)
if err != nil {
return false, err
}

return store.Has(types.GetOracleKey(accAddr)), nil
}
Loading