From 34d058ba6643351d7374aeccea205594c48dc375 Mon Sep 17 00:00:00 2001 From: InChul <49394875+inchori@users.noreply.github.com> Date: Tue, 6 Dec 2022 15:15:08 +0900 Subject: [PATCH 01/20] feat: add skeleton code for datadeal module --- x/datadeal/client/cli/query.go | 22 ++++ x/datadeal/client/cli/tx.go | 22 ++++ x/datadeal/genesis.go | 20 ++++ x/datadeal/handler.go | 34 ++++++ x/datadeal/keeper/grpc_query.go | 5 + x/datadeal/keeper/grpc_query_deal.go | 27 +++++ x/datadeal/keeper/keeper.go | 32 ++++++ x/datadeal/keeper/msg_server.go | 15 +++ x/datadeal/keeper/msg_server_deal.go | 22 ++++ x/datadeal/module.go | 166 +++++++++++++++++++++++++++ x/datadeal/types/codec.go | 28 +++++ x/datadeal/types/genesis.go | 17 +++ x/datadeal/types/keys.go | 18 +++ x/datadeal/types/message_deal.go | 31 +++++ 14 files changed, 459 insertions(+) create mode 100644 x/datadeal/client/cli/query.go create mode 100644 x/datadeal/client/cli/tx.go create mode 100644 x/datadeal/genesis.go create mode 100644 x/datadeal/handler.go create mode 100644 x/datadeal/keeper/grpc_query.go create mode 100644 x/datadeal/keeper/grpc_query_deal.go create mode 100644 x/datadeal/keeper/keeper.go create mode 100644 x/datadeal/keeper/msg_server.go create mode 100644 x/datadeal/keeper/msg_server_deal.go create mode 100644 x/datadeal/module.go create mode 100644 x/datadeal/types/codec.go create mode 100644 x/datadeal/types/genesis.go create mode 100644 x/datadeal/types/keys.go create mode 100644 x/datadeal/types/message_deal.go diff --git a/x/datadeal/client/cli/query.go b/x/datadeal/client/cli/query.go new file mode 100644 index 00000000..59459254 --- /dev/null +++ b/x/datadeal/client/cli/query.go @@ -0,0 +1,22 @@ +package cli + +import ( + "fmt" + + "github.com/cosmos/cosmos-sdk/client" + "github.com/medibloc/panacea-core/v2/x/datadeal/types" + "github.com/spf13/cobra" +) + +// GetQueryCmd returns the cli query commands for this module +func GetQueryCmd(queryRoute string) *cobra.Command { + // Group oracle queries under a subcommand + cmd := &cobra.Command{ + Use: types.ModuleName, + Short: fmt.Sprintf("Querying commands for the %s module", types.ModuleName), + DisableFlagParsing: true, + SuggestionsMinimumDistance: 2, + RunE: client.ValidateCmd, + } + return cmd +} diff --git a/x/datadeal/client/cli/tx.go b/x/datadeal/client/cli/tx.go new file mode 100644 index 00000000..c32ed113 --- /dev/null +++ b/x/datadeal/client/cli/tx.go @@ -0,0 +1,22 @@ +package cli + +import ( + "fmt" + + "github.com/cosmos/cosmos-sdk/client" + "github.com/medibloc/panacea-core/v2/x/datadeal/types" + "github.com/spf13/cobra" +) + +// GetTxCmd returns the transaction commands for this module +func GetTxCmd() *cobra.Command { + cmd := &cobra.Command{ + Use: types.ModuleName, + Short: fmt.Sprintf("%s transactions subcommands", types.ModuleName), + DisableFlagParsing: true, + SuggestionsMinimumDistance: 2, + RunE: client.ValidateCmd, + } + + return cmd +} diff --git a/x/datadeal/genesis.go b/x/datadeal/genesis.go new file mode 100644 index 00000000..4243ad88 --- /dev/null +++ b/x/datadeal/genesis.go @@ -0,0 +1,20 @@ +package datadeal + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/medibloc/panacea-core/v2/x/datadeal/keeper" + "github.com/medibloc/panacea-core/v2/x/datadeal/types" +) + +// InitGenesis initializes the capability module's state from a provided genesis +// state. +func InitGenesis(ctx sdk.Context, k keeper.Keeper, genState types.GenesisState) { + //TODO implement me + panic("implement me") +} + +// ExportGenesis returns the capability module's exported genesis. +func ExportGenesis(ctx sdk.Context, k keeper.Keeper) *types.GenesisState { + //TODO implement me + panic("implement me") +} diff --git a/x/datadeal/handler.go b/x/datadeal/handler.go new file mode 100644 index 00000000..17711548 --- /dev/null +++ b/x/datadeal/handler.go @@ -0,0 +1,34 @@ +package datadeal + +import ( + "fmt" + + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + "github.com/medibloc/panacea-core/v2/x/datadeal/keeper" + "github.com/medibloc/panacea-core/v2/x/datadeal/types" +) + +// NewHandler ... +func NewHandler(k keeper.Keeper) sdk.Handler { + msgServer := keeper.NewMsgServerImpl(k) + + return func(ctx sdk.Context, msg sdk.Msg) (*sdk.Result, error) { + ctx = ctx.WithEventManager(sdk.NewEventManager()) + + switch msg := msg.(type) { + case *types.MsgCreateDeal: + res, err := msgServer.CreateDeal(sdk.WrapSDKContext(ctx), msg) + return sdk.WrapServiceResult(ctx, res, err) + //case *types.MsgDeactivateDeal: + // res, err := msgServer.DeactivateDeal(sdk.WrapSDKContext(ctx), msg) + // return sdk.WrapServiceResult(ctx, res, err) + //case *types.MsgSubmitConsent: + // res, err := msgServer.SubmitConsent(sdk.WrapSDKContext(ctx), msg) + // return sdk.WrapServiceResult(ctx, res, err) + default: + errMsg := fmt.Sprintf("unrecognized %s message type: %T", types.ModuleName, msg) + return nil, sdkerrors.Wrap(sdkerrors.ErrUnknownRequest, errMsg) + } + } +} diff --git a/x/datadeal/keeper/grpc_query.go b/x/datadeal/keeper/grpc_query.go new file mode 100644 index 00000000..d60def50 --- /dev/null +++ b/x/datadeal/keeper/grpc_query.go @@ -0,0 +1,5 @@ +package keeper + +import "github.com/medibloc/panacea-core/v2/x/datadeal/types" + +var _ types.QueryServer = Keeper{} diff --git a/x/datadeal/keeper/grpc_query_deal.go b/x/datadeal/keeper/grpc_query_deal.go new file mode 100644 index 00000000..96d7c316 --- /dev/null +++ b/x/datadeal/keeper/grpc_query_deal.go @@ -0,0 +1,27 @@ +package keeper + +import ( + "context" + + "github.com/medibloc/panacea-core/v2/x/datadeal/types" +) + +func (k Keeper) Deals(ctx context.Context, request *types.QueryDealsRequest) (*types.QueryDealsResponse, error) { + //TODO implement me + panic("implement me") +} + +func (k Keeper) Deal(ctx context.Context, request *types.QueryDealRequest) (*types.QueryDealResponse, error) { + //TODO implement me + panic("implement me") +} + +func (k Keeper) Certificates(ctx context.Context, certificates *types.QueryCertificates) (*types.QueryCertificatesResponse, error) { + //TODO implement me + panic("implement me") +} + +func (k Keeper) Certificate(ctx context.Context, certificate *types.QueryCertificate) (*types.QueryCertificateResponse, error) { + //TODO implement me + panic("implement me") +} diff --git a/x/datadeal/keeper/keeper.go b/x/datadeal/keeper/keeper.go new file mode 100644 index 00000000..9fd0ea15 --- /dev/null +++ b/x/datadeal/keeper/keeper.go @@ -0,0 +1,32 @@ +package keeper + +import ( + "github.com/cosmos/cosmos-sdk/codec" + sdk "github.com/cosmos/cosmos-sdk/types" + paramtypes "github.com/cosmos/cosmos-sdk/x/params/types" +) + +type ( + Keeper struct { + cdc codec.Codec + storeKey sdk.StoreKey + memKey sdk.StoreKey + + paramSpace paramtypes.Subspace + } +) + +func NewKeeper( + cdc codec.Codec, + storeKey, + memKey sdk.StoreKey, + paramSpace paramtypes.Subspace, +) *Keeper { + + return &Keeper{ + cdc: cdc, + storeKey: storeKey, + memKey: memKey, + paramSpace: paramSpace, + } +} diff --git a/x/datadeal/keeper/msg_server.go b/x/datadeal/keeper/msg_server.go new file mode 100644 index 00000000..54229d56 --- /dev/null +++ b/x/datadeal/keeper/msg_server.go @@ -0,0 +1,15 @@ +package keeper + +import "github.com/medibloc/panacea-core/v2/x/datadeal/types" + +type msgServer struct { + Keeper +} + +// NewMsgServerImpl returns an implementation of the MsgServer interface +// for the provided Keeper. +func NewMsgServerImpl(keeper Keeper) types.MsgServer { + return &msgServer{Keeper: keeper} +} + +var _ types.MsgServer = msgServer{} diff --git a/x/datadeal/keeper/msg_server_deal.go b/x/datadeal/keeper/msg_server_deal.go new file mode 100644 index 00000000..9bf9523e --- /dev/null +++ b/x/datadeal/keeper/msg_server_deal.go @@ -0,0 +1,22 @@ +package keeper + +import ( + "context" + + "github.com/medibloc/panacea-core/v2/x/datadeal/types" +) + +func (m msgServer) CreateDeal(ctx context.Context, deal *types.MsgCreateDeal) (*types.MsgCreateDealResponse, error) { + //TODO implement me + panic("implement me") +} + +func (m msgServer) DeactivateDeal(ctx context.Context, deal *types.MsgDeactivateDeal) (*types.MsgDeactivateDealResponse, error) { + //TODO implement me + panic("implement me") +} + +func (m msgServer) SubmitConsent(ctx context.Context, consent *types.MsgSubmitConsent) (*types.MsgSubmitConsentResponse, error) { + //TODO implement me + panic("implement me") +} diff --git a/x/datadeal/module.go b/x/datadeal/module.go new file mode 100644 index 00000000..27ccfe9b --- /dev/null +++ b/x/datadeal/module.go @@ -0,0 +1,166 @@ +package datadeal + +import ( + "context" + "encoding/json" + "fmt" + + "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/codec" + cdctypes "github.com/cosmos/cosmos-sdk/codec/types" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/module" + "github.com/gorilla/mux" + "github.com/grpc-ecosystem/grpc-gateway/runtime" + "github.com/medibloc/panacea-core/v2/x/datadeal/client/cli" + "github.com/medibloc/panacea-core/v2/x/datadeal/keeper" + "github.com/medibloc/panacea-core/v2/x/datadeal/types" + "github.com/spf13/cobra" + abci "github.com/tendermint/tendermint/abci/types" +) + +var ( + _ module.AppModule = AppModule{} + _ module.AppModuleBasic = AppModuleBasic{} +) + +// ---------------------------------------------------------------------------- +// AppModuleBasic +// ---------------------------------------------------------------------------- + +// AppModuleBasic implements the AppModuleBasic interface for the capability module. +type AppModuleBasic struct { + cdc codec.Codec +} + +func NewAppModuleBasic(cdc codec.Codec) AppModuleBasic { + return AppModuleBasic{cdc: cdc} +} + +// Name returns the capability module's name. +func (AppModuleBasic) Name() string { + return types.ModuleName +} + +func (AppModuleBasic) RegisterCodec(cdc *codec.LegacyAmino) { + types.RegisterCodec(cdc) +} + +func (AppModuleBasic) RegisterLegacyAminoCodec(cdc *codec.LegacyAmino) { + types.RegisterCodec(cdc) +} + +// RegisterInterfaces registers the module's interface types +func (a AppModuleBasic) RegisterInterfaces(reg cdctypes.InterfaceRegistry) { + types.RegisterInterfaces(reg) +} + +// DefaultGenesis returns the capability module's default genesis state. +func (AppModuleBasic) DefaultGenesis(cdc codec.JSONCodec) json.RawMessage { + return cdc.MustMarshalJSON(types.DefaultGenesis()) +} + +// ValidateGenesis performs genesis state validation for the capability module. +func (AppModuleBasic) ValidateGenesis(cdc codec.JSONCodec, config client.TxEncodingConfig, bz json.RawMessage) error { + var genState types.GenesisState + if err := cdc.UnmarshalJSON(bz, &genState); err != nil { + return fmt.Errorf("failed to unmarshal %s genesis state: %w", types.ModuleName, err) + } + return genState.Validate() +} + +// RegisterRESTRoutes registers the capability module's REST service handlers. +func (AppModuleBasic) RegisterRESTRoutes(clientCtx client.Context, rtr *mux.Router) { +} + +// RegisterGRPCGatewayRoutes registers the gRPC Gateway routes for the module. +func (AppModuleBasic) RegisterGRPCGatewayRoutes(clientCtx client.Context, mux *runtime.ServeMux) { + err := types.RegisterQueryHandlerClient(context.Background(), mux, types.NewQueryClient(clientCtx)) + if err != nil { + panic("Error RegisterGRPCGatewayRoutes") + } +} + +// GetTxCmd returns the capability module's root tx command. +func (a AppModuleBasic) GetTxCmd() *cobra.Command { + return cli.GetTxCmd() +} + +// GetQueryCmd returns the capability module's root query command. +func (AppModuleBasic) GetQueryCmd() *cobra.Command { + return cli.GetQueryCmd(types.StoreKey) +} + +// ---------------------------------------------------------------------------- +// AppModule +// ---------------------------------------------------------------------------- + +// AppModule implements the AppModule interface for the capability module. +type AppModule struct { + AppModuleBasic + keeper keeper.Keeper +} + +func NewAppModule(cdc codec.Codec, keeper keeper.Keeper) AppModule { + return AppModule{ + AppModuleBasic: NewAppModuleBasic(cdc), + keeper: keeper, + } +} + +// Name returns the capability module's name. +func (am AppModule) Name() string { + return am.AppModuleBasic.Name() +} + +// Route returns the capability module's message routing key. +func (am AppModule) Route() sdk.Route { + return sdk.NewRoute(types.RouterKey, NewHandler(am.keeper)) +} + +// QuerierRoute returns the capability module's query routing key. +func (AppModule) QuerierRoute() string { return types.QuerierRoute } + +// LegacyQuerierHandler returns the capability module's Querier. +func (am AppModule) LegacyQuerierHandler(legacyQuerierCdc *codec.LegacyAmino) sdk.Querier { + return nil +} + +// RegisterServices registers a GRPC query service to respond to the +// module-specific GRPC queries. +func (am AppModule) RegisterServices(cfg module.Configurator) { + types.RegisterQueryServer(cfg.QueryServer(), am.keeper) +} + +// RegisterInvariants registers the capability module's invariants. +func (am AppModule) RegisterInvariants(_ sdk.InvariantRegistry) {} + +// InitGenesis performs the capability module's genesis initialization It returns +// no validator updates. +func (am AppModule) InitGenesis(ctx sdk.Context, cdc codec.JSONCodec, gs json.RawMessage) []abci.ValidatorUpdate { + var genState types.GenesisState + // Initialize global index to index in genesis state + cdc.MustUnmarshalJSON(gs, &genState) + + InitGenesis(ctx, am.keeper, genState) + + return []abci.ValidatorUpdate{} +} + +// ExportGenesis returns the capability module's exported genesis state as raw JSON bytes. +func (am AppModule) ExportGenesis(ctx sdk.Context, cdc codec.JSONCodec) json.RawMessage { + genState := ExportGenesis(ctx, am.keeper) + return cdc.MustMarshalJSON(genState) +} + +// BeginBlock executes all ABCI BeginBlock logic respective to the capability module. +func (am AppModule) BeginBlock(_ sdk.Context, _ abci.RequestBeginBlock) {} + +// EndBlock executes all ABCI EndBlock logic respective to the capability module. It +// returns no validator updates. +func (am AppModule) EndBlock(ctx sdk.Context, _ abci.RequestEndBlock) []abci.ValidatorUpdate { + return []abci.ValidatorUpdate{} +} + +// ConsensusVersion implements AppModule/ConsensusVersion. +func (AppModule) ConsensusVersion() uint64 { return 1 } diff --git a/x/datadeal/types/codec.go b/x/datadeal/types/codec.go new file mode 100644 index 00000000..3fa5b79e --- /dev/null +++ b/x/datadeal/types/codec.go @@ -0,0 +1,28 @@ +package types + +import ( + "github.com/cosmos/cosmos-sdk/codec" + cdctypes "github.com/cosmos/cosmos-sdk/codec/types" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/msgservice" +) + +func RegisterCodec(cdc *codec.LegacyAmino) { + cdc.RegisterConcrete(&MsgCreateDeal{}, "datadeal/CreateDeal", nil) + cdc.RegisterConcrete(&MsgDeactivateDeal{}, "datadeal/MsgDeactivateDeal", nil) + cdc.RegisterConcrete(&MsgSubmitConsent{}, "datadeal/SubmitConsent", nil) +} + +func RegisterInterfaces(registry cdctypes.InterfaceRegistry) { + registry.RegisterImplementations((*sdk.Msg)(nil), + &MsgCreateDeal{}, + &MsgDeactivateDeal{}, + &MsgSubmitConsent{}, + ) + msgservice.RegisterMsgServiceDesc(registry, &_Msg_serviceDesc) +} + +var ( + amino = codec.NewLegacyAmino() + ModuleCdc = codec.NewAminoCodec(amino) +) diff --git a/x/datadeal/types/genesis.go b/x/datadeal/types/genesis.go new file mode 100644 index 00000000..c7192636 --- /dev/null +++ b/x/datadeal/types/genesis.go @@ -0,0 +1,17 @@ +package types + +// DefaultGenesis returns the default Capability genesis state +func DefaultGenesis() *GenesisState { + return &GenesisState{ + NextDealNumber: uint64(1), + Deals: []Deal{}, + Certificates: []Certificate{}, + } +} + +// Validate performs basic genesis state validation returning an error upon any +// failure. +func (m GenesisState) Validate() error { + + return nil +} diff --git a/x/datadeal/types/keys.go b/x/datadeal/types/keys.go new file mode 100644 index 00000000..a65310db --- /dev/null +++ b/x/datadeal/types/keys.go @@ -0,0 +1,18 @@ +package types + +const ( + // ModuleName defines the module name + ModuleName = "datadeal" + + // StoreKey defines the primary module store key + StoreKey = ModuleName + + // RouterKey is the message route for slashing + RouterKey = ModuleName + + // QuerierRoute defines the module's query routing key + QuerierRoute = ModuleName + + // MemStoreKey defines the in-memory store key + MemStoreKey = "mem_datadeal" +) diff --git a/x/datadeal/types/message_deal.go b/x/datadeal/types/message_deal.go new file mode 100644 index 00000000..47b4de74 --- /dev/null +++ b/x/datadeal/types/message_deal.go @@ -0,0 +1,31 @@ +package types + +import sdk "github.com/cosmos/cosmos-sdk/types" + +var _ sdk.Msg = &MsgCreateDeal{} + +func (m *MsgCreateDeal) Route() string { + return RouterKey +} + +func (m *MsgCreateDeal) Type() string { + return "RegisterOracle" +} + +func (m *MsgCreateDeal) ValidateBasic() error { + + return nil +} + +func (m *MsgCreateDeal) GetSignBytes() []byte { + bz := ModuleCdc.MustMarshalJSON(m) + return sdk.MustSortJSON(bz) +} + +func (m *MsgCreateDeal) GetSigners() []sdk.AccAddress { + buyerAddress, err := sdk.AccAddressFromBech32(m.BuyerAddress) + if err != nil { + panic(err) + } + return []sdk.AccAddress{buyerAddress} +} From 6b176892cfef5253f4cc986ef2bc11c04ba70033 Mon Sep 17 00:00:00 2001 From: InChul <49394875+inchori@users.noreply.github.com> Date: Tue, 6 Dec 2022 15:16:50 +0900 Subject: [PATCH 02/20] fix --- x/datadeal/client/cli/query.go | 2 +- x/datadeal/types/message_deal.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/x/datadeal/client/cli/query.go b/x/datadeal/client/cli/query.go index 59459254..3f45c0a2 100644 --- a/x/datadeal/client/cli/query.go +++ b/x/datadeal/client/cli/query.go @@ -10,7 +10,7 @@ import ( // GetQueryCmd returns the cli query commands for this module func GetQueryCmd(queryRoute string) *cobra.Command { - // Group oracle queries under a subcommand + // Group datadeal queries under a subcommand cmd := &cobra.Command{ Use: types.ModuleName, Short: fmt.Sprintf("Querying commands for the %s module", types.ModuleName), diff --git a/x/datadeal/types/message_deal.go b/x/datadeal/types/message_deal.go index 47b4de74..5c7fdb87 100644 --- a/x/datadeal/types/message_deal.go +++ b/x/datadeal/types/message_deal.go @@ -9,7 +9,7 @@ func (m *MsgCreateDeal) Route() string { } func (m *MsgCreateDeal) Type() string { - return "RegisterOracle" + return "CreateDeal" } func (m *MsgCreateDeal) ValidateBasic() error { From 351464b7b2ff484dd8d194b99a6ec565dba8e3ce Mon Sep 17 00:00:00 2001 From: InChul <49394875+inchori@users.noreply.github.com> Date: Wed, 7 Dec 2022 09:40:41 +0900 Subject: [PATCH 03/20] fix --- x/datadeal/genesis.go | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/x/datadeal/genesis.go b/x/datadeal/genesis.go index 4243ad88..1b495b94 100644 --- a/x/datadeal/genesis.go +++ b/x/datadeal/genesis.go @@ -9,12 +9,10 @@ import ( // InitGenesis initializes the capability module's state from a provided genesis // state. func InitGenesis(ctx sdk.Context, k keeper.Keeper, genState types.GenesisState) { - //TODO implement me - panic("implement me") + //TODO } // ExportGenesis returns the capability module's exported genesis. func ExportGenesis(ctx sdk.Context, k keeper.Keeper) *types.GenesisState { - //TODO implement me - panic("implement me") + return nil } From 22b7b59895abd7cce4fa313a1491199663c6ec5f Mon Sep 17 00:00:00 2001 From: InChul <49394875+inchori@users.noreply.github.com> Date: Wed, 7 Dec 2022 11:13:41 +0900 Subject: [PATCH 04/20] feat: add create a Deal and query a Deal keeper function --- app/app.go | 28 +++- types/testsuite/suite.go | 12 ++ x/datadeal/keeper/deal.go | 148 ++++++++++++++++++++++ x/datadeal/keeper/deal_test.go | 102 +++++++++++++++ x/datadeal/keeper/grpc_query_deal.go | 21 ++- x/datadeal/keeper/grpc_query_deal_test.go | 36 ++++++ x/datadeal/keeper/keeper.go | 24 ++-- x/datadeal/keeper/msg_server_deal.go | 17 ++- x/datadeal/testutil/suite.go | 25 ++++ x/datadeal/types/deal.go | 58 +++++++++ x/datadeal/types/error.go | 13 ++ x/datadeal/types/expected_keeper.go | 17 +++ x/datadeal/types/keys.go | 16 +++ 13 files changed, 495 insertions(+), 22 deletions(-) create mode 100644 x/datadeal/keeper/deal.go create mode 100644 x/datadeal/keeper/deal_test.go create mode 100644 x/datadeal/keeper/grpc_query_deal_test.go create mode 100644 x/datadeal/testutil/suite.go create mode 100644 x/datadeal/types/deal.go create mode 100644 x/datadeal/types/error.go create mode 100644 x/datadeal/types/expected_keeper.go diff --git a/app/app.go b/app/app.go index 68016a95..abe7abf1 100644 --- a/app/app.go +++ b/app/app.go @@ -113,6 +113,10 @@ import ( "github.com/medibloc/panacea-core/v2/x/did" didkeeper "github.com/medibloc/panacea-core/v2/x/did/keeper" didtypes "github.com/medibloc/panacea-core/v2/x/did/types" + + "github.com/medibloc/panacea-core/v2/x/datadeal" + datadealkeeper "github.com/medibloc/panacea-core/v2/x/datadeal/keeper" + datadealtypes "github.com/medibloc/panacea-core/v2/x/datadeal/types" ) const Name = "panacea" @@ -191,6 +195,7 @@ var ( wasm.AppModuleBasic{}, feegrantmodule.AppModuleBasic{}, authzmodule.AppModuleBasic{}, + datadeal.AppModuleBasic{}, ) // module account permissions @@ -261,10 +266,11 @@ type App struct { ScopedTransferKeeper capabilitykeeper.ScopedKeeper ScopedWasmKeeper capabilitykeeper.ScopedKeeper - aolKeeper aolkeeper.Keeper - didKeeper didkeeper.Keeper - burnKeeper burnkeeper.Keeper - wasmKeeper wasm.Keeper + aolKeeper aolkeeper.Keeper + didKeeper didkeeper.Keeper + burnKeeper burnkeeper.Keeper + wasmKeeper wasm.Keeper + datadealKeeper datadealkeeper.Keeper // the module manager mm *module.Manager @@ -309,6 +315,7 @@ func New( burntypes.StoreKey, wasm.StoreKey, feegrant.StoreKey, + datadealtypes.StoreKey, ) tkeys := sdk.NewTransientStoreKeys(paramstypes.TStoreKey) memKeys := sdk.NewMemoryStoreKeys(capabilitytypes.MemStoreKey) @@ -421,6 +428,14 @@ func New( app.BankKeeper, ) + app.datadealKeeper = *datadealkeeper.NewKeeper( + appCodec, + keys[datadealtypes.StoreKey], + keys[datadealtypes.MemStoreKey], + app.AccountKeeper, + app.BankKeeper, + ) + wasmDir := filepath.Join(homePath, wasm.ModuleName) wasmConfig, err := wasm.ReadWasmConfig(appOpts) if err != nil { @@ -500,6 +515,7 @@ func New( did.NewAppModule(appCodec, app.didKeeper), burn.NewAppModule(appCodec, app.burnKeeper), wasm.NewAppModule(appCodec, &app.wasmKeeper, app.StakingKeeper), + datadeal.NewAppModule(appCodec, app.datadealKeeper), ) // During begin block slashing happens after distr.BeginBlocker so that @@ -529,6 +545,7 @@ func New( burntypes.ModuleName, genutiltypes.ModuleName, authz.ModuleName, + datadealtypes.ModuleName, ) app.mm.SetOrderEndBlockers( @@ -554,6 +571,7 @@ func New( wasm.ModuleName, paramstypes.ModuleName, authz.ModuleName, + datadealtypes.ModuleName, ) // NOTE: The genutils module must occur after staking so that pools are @@ -584,6 +602,7 @@ func New( upgradetypes.ModuleName, vestingtypes.ModuleName, authz.ModuleName, + datadealtypes.ModuleName, ) app.mm.RegisterInvariants(&app.CrisisKeeper) @@ -808,6 +827,7 @@ func initParamsKeeper(appCodec codec.Codec, legacyAmino *codec.LegacyAmino, key, paramsKeeper.Subspace(didtypes.ModuleName) paramsKeeper.Subspace(burntypes.ModuleName) paramsKeeper.Subspace(wasm.ModuleName) + paramsKeeper.Subspace(datadealtypes.ModuleName) return paramsKeeper } diff --git a/types/testsuite/suite.go b/types/testsuite/suite.go index 5dff6c73..3f6f2dfd 100644 --- a/types/testsuite/suite.go +++ b/types/testsuite/suite.go @@ -42,6 +42,8 @@ import ( dbm "github.com/tendermint/tm-db" "github.com/medibloc/panacea-core/v2/app/params" + datadealkeeper "github.com/medibloc/panacea-core/v2/x/datadeal/keeper" + datadealtypes "github.com/medibloc/panacea-core/v2/x/datadeal/types" didkeeper "github.com/medibloc/panacea-core/v2/x/did/keeper" didtypes "github.com/medibloc/panacea-core/v2/x/did/types" ) @@ -65,6 +67,7 @@ type TestSuite struct { TransferKeeper ibctransferkeeper.Keeper DIDMsgServer didtypes.MsgServer DIDKeeper didkeeper.Keeper + DataDealKeeper datadealkeeper.Keeper WasmKeeper wasm.Keeper UpgradeKeeper upgradekeeper.Keeper } @@ -76,6 +79,7 @@ func (suite *TestSuite) SetupTest() { banktypes.StoreKey, paramstypes.StoreKey, didtypes.StoreKey, + datadealtypes.StoreKey, wasm.StoreKey, ibchost.StoreKey, capabilitytypes.StoreKey, @@ -202,6 +206,14 @@ func (suite *TestSuite) SetupTest() { memKeys[didtypes.MemStoreKey], ) suite.DIDMsgServer = didkeeper.NewMsgServerImpl(suite.DIDKeeper) + + suite.DataDealKeeper = *datadealkeeper.NewKeeper( + cdc.Marshaler, + keyParams[datadealtypes.StoreKey], + memKeys[datadealtypes.MemStoreKey], + suite.AccountKeeper, + suite.BankKeeper, + ) } func (suite *TestSuite) BeforeTest(suiteName, testName string) { diff --git a/x/datadeal/keeper/deal.go b/x/datadeal/keeper/deal.go new file mode 100644 index 00000000..f42562cc --- /dev/null +++ b/x/datadeal/keeper/deal.go @@ -0,0 +1,148 @@ +package keeper + +import ( + "strconv" + + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + gogotypes "github.com/gogo/protobuf/types" + "github.com/medibloc/panacea-core/v2/x/datadeal/types" +) + +func (k Keeper) CreateDeal(ctx sdk.Context, buyerAddress sdk.AccAddress, msg *types.MsgCreateDeal) (uint64, error) { + dealID, err := k.GetNextDealNumberAndIncrement(ctx) + if err != nil { + return 0, sdkerrors.Wrapf(err, "failed to get next deal num") + } + + newDeal := types.NewDeal(dealID, msg) + + coins := sdk.NewCoins(*msg.Budget) + + dealAddress, err := sdk.AccAddressFromBech32(newDeal.Address) + if err != nil { + return 0, err + } + + acc := k.accountKeeper.GetAccount(ctx, dealAddress) + if acc != nil { + return 0, sdkerrors.Wrapf(types.ErrDealAlreadyExist, "deal %d already exist", dealID) + } + + acc = k.accountKeeper.NewAccount(ctx, authtypes.NewModuleAccount( + authtypes.NewBaseAccountWithAddress( + dealAddress, + ), + "deal"+strconv.FormatUint(newDeal.Id, 10)), + ) + k.accountKeeper.SetAccount(ctx, acc) + + if err = k.bankKeeper.SendCoins(ctx, buyerAddress, dealAddress, coins); err != nil { + return 0, sdkerrors.Wrapf(err, "Failed to send coins to deal account") + } + + if err = k.SetDeal(ctx, newDeal); err != nil { + return 0, err + } + + return newDeal.Id, nil +} + +func (k Keeper) SetNextDealNumber(ctx sdk.Context, dealNumber uint64) error { + store := ctx.KVStore(k.storeKey) + bz, err := k.cdc.MarshalLengthPrefixed(&gogotypes.UInt64Value{Value: dealNumber}) + if err != nil { + return sdkerrors.Wrapf(err, "Failed to set next deal number") + } + store.Set(types.DealNextNumberKey, bz) + return nil +} + +func (k Keeper) GetNextDealNumber(ctx sdk.Context) (uint64, error) { + var dealNumber uint64 + store := ctx.KVStore(k.storeKey) + + if !store.Has(types.DealNextNumberKey) { + return 0, types.ErrDealNotInitialized + } + + bz := store.Get(types.DealNextNumberKey) + + val := gogotypes.UInt64Value{} + + if err := k.cdc.UnmarshalLengthPrefixed(bz, &val); err != nil { + return 0, sdkerrors.Wrapf(err, "Failed to get next deal number") + } + + dealNumber = val.GetValue() + + return dealNumber, nil +} + +func (k Keeper) GetNextDealNumberAndIncrement(ctx sdk.Context) (uint64, error) { + dealNumber, err := k.GetNextDealNumber(ctx) + if err != nil { + return 0, err + } + + if err = k.SetNextDealNumber(ctx, dealNumber+1); err != nil { + return 0, err + } + + return dealNumber, nil +} + +func (k Keeper) GetDeal(ctx sdk.Context, dealID uint64) (*types.Deal, error) { + store := ctx.KVStore(k.storeKey) + dealKey := types.GetDealKey(dealID) + + bz := store.Get(dealKey) + if bz == nil { + return nil, sdkerrors.Wrapf(types.ErrDealNotFound, "deal with ID %d does not exist", dealID) + } + + deal := &types.Deal{} + if err := k.cdc.UnmarshalLengthPrefixed(bz, deal); err != nil { + return nil, err + } + return deal, nil +} + +func (k Keeper) SetDeal(ctx sdk.Context, deal *types.Deal) error { + store := ctx.KVStore(k.storeKey) + dealKey := types.GetDealKey(deal.GetId()) + bz, err := k.cdc.MarshalLengthPrefixed(deal) + if err != nil { + return sdkerrors.Wrapf(err, "Failed to set deal") + } + store.Set(dealKey, bz) + return nil +} + +func (k Keeper) IsDealCompleted(ctx sdk.Context, dealID uint64) (bool, error) { + deal, err := k.GetDeal(ctx, dealID) + if err != nil { + return false, err + } + if deal.Status == types.DEAL_STATUS_COMPLETED { + return true, nil + } else { + return false, nil + } +} + +func (k Keeper) IncrementCurNumDataAtDeal(ctx sdk.Context, dealID uint64) error { + deal, err := k.GetDeal(ctx, dealID) + if err != nil { + return err + } + deal.CurNumData = deal.CurNumData + 1 + if deal.CurNumData == deal.MaxNumData { + deal.Status = types.DEAL_STATUS_COMPLETED + } + if err = k.SetDeal(ctx, deal); err != nil { + return err + } + return nil +} diff --git a/x/datadeal/keeper/deal_test.go b/x/datadeal/keeper/deal_test.go new file mode 100644 index 00000000..c8470793 --- /dev/null +++ b/x/datadeal/keeper/deal_test.go @@ -0,0 +1,102 @@ +package keeper_test + +import ( + "testing" + + "github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/medibloc/panacea-core/v2/types/assets" + "github.com/medibloc/panacea-core/v2/x/datadeal/testutil" + "github.com/medibloc/panacea-core/v2/x/datadeal/types" + "github.com/stretchr/testify/suite" +) + +type dealTestSuite struct { + testutil.DataDealBaseTestSuite + + defaultFunds sdk.Coins + buyerAccAddr sdk.AccAddress +} + +func TestDealTestSuite(t *testing.T) { + suite.Run(t, new(dealTestSuite)) +} + +func (suite *dealTestSuite) BeforeTest(_, _ string) { + suite.buyerAccAddr = sdk.AccAddress(secp256k1.GenPrivKey().PubKey().Address()) + suite.defaultFunds = sdk.NewCoins(sdk.NewCoin(assets.MicroMedDenom, sdk.NewInt(10000000000))) + + testDeal := suite.MakeTestDeal(1, suite.buyerAccAddr, 100) + err := suite.DataDealKeeper.SetNextDealNumber(suite.Ctx, 2) + suite.Require().NoError(err) + err = suite.DataDealKeeper.SetDeal(suite.Ctx, testDeal) + suite.Require().NoError(err) +} + +func (suite *dealTestSuite) TestCreateNewDeal() { + + err := suite.FundAccount(suite.Ctx, suite.buyerAccAddr, suite.defaultFunds) + suite.Require().NoError(err) + + budget := &sdk.Coin{Denom: assets.MicroMedDenom, Amount: sdk.NewInt(10000000)} + + msgCreateDeal := &types.MsgCreateDeal{ + DataSchema: []string{"http://jsonld.com"}, + Budget: budget, + MaxNumData: 10000, + BuyerAddress: suite.buyerAccAddr.String(), + } + + buyer, err := sdk.AccAddressFromBech32(msgCreateDeal.BuyerAddress) + suite.Require().NoError(err) + + dealID, err := suite.DataDealKeeper.CreateDeal(suite.Ctx, buyer, msgCreateDeal) + suite.Require().NoError(err) + + expectedId, err := suite.DataDealKeeper.GetNextDealNumberAndIncrement(suite.Ctx) + suite.Require().NoError(err) + suite.Require().Equal(dealID, expectedId-uint64(1)) + + deal, err := suite.DataDealKeeper.GetDeal(suite.Ctx, dealID) + suite.Require().NoError(err) + suite.Require().Equal(deal.GetDataSchema(), msgCreateDeal.GetDataSchema()) + suite.Require().Equal(deal.GetBudget(), msgCreateDeal.GetBudget()) + suite.Require().Equal(deal.GetMaxNumData(), msgCreateDeal.GetMaxNumData()) + suite.Require().Equal(deal.GetConsumerAddress(), msgCreateDeal.GetBuyerAddress()) + suite.Require().Equal(deal.GetStatus(), types.DEAL_STATUS_ACTIVE) +} + +func (suite *dealTestSuite) TestCheckDealCurNumDataAndIncrement() { + err := suite.FundAccount(suite.Ctx, suite.buyerAccAddr, suite.defaultFunds) + suite.Require().NoError(err) + + budget := &sdk.Coin{Denom: assets.MicroMedDenom, Amount: sdk.NewInt(10000000)} + + msgCreateDeal := &types.MsgCreateDeal{ + DataSchema: []string{"http://jsonld.com"}, + Budget: budget, + MaxNumData: 1, + BuyerAddress: suite.buyerAccAddr.String(), + } + + buyer, err := sdk.AccAddressFromBech32(msgCreateDeal.BuyerAddress) + suite.Require().NoError(err) + + dealID, err := suite.DataDealKeeper.CreateDeal(suite.Ctx, buyer, msgCreateDeal) + suite.Require().NoError(err) + + check, err := suite.DataDealKeeper.IsDealCompleted(suite.Ctx, dealID) + suite.Require().NoError(err) + suite.Equal(false, check) + + err = suite.DataDealKeeper.IncrementCurNumDataAtDeal(suite.Ctx, dealID) + suite.Require().NoError(err) + updatedDeal, err := suite.DataDealKeeper.GetDeal(suite.Ctx, dealID) + suite.Require().NoError(err) + suite.Require().Equal(uint64(1), updatedDeal.CurNumData) + + check, err = suite.DataDealKeeper.IsDealCompleted(suite.Ctx, dealID) + suite.Require().NoError(err) + suite.Require().Equal(true, check) + +} diff --git a/x/datadeal/keeper/grpc_query_deal.go b/x/datadeal/keeper/grpc_query_deal.go index 96d7c316..6bd26ae6 100644 --- a/x/datadeal/keeper/grpc_query_deal.go +++ b/x/datadeal/keeper/grpc_query_deal.go @@ -3,15 +3,28 @@ package keeper import ( "context" + sdk "github.com/cosmos/cosmos-sdk/types" "github.com/medibloc/panacea-core/v2/x/datadeal/types" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" ) -func (k Keeper) Deals(ctx context.Context, request *types.QueryDealsRequest) (*types.QueryDealsResponse, error) { - //TODO implement me - panic("implement me") +func (k Keeper) Deal(goCtx context.Context, req *types.QueryDealRequest) (*types.QueryDealResponse, error) { + if req == nil { + return nil, status.Error(codes.InvalidArgument, "invalid request") + } + + deal, err := k.GetDeal(sdk.UnwrapSDKContext(goCtx), req.DealId) + if err != nil { + return nil, err + } + + return &types.QueryDealResponse{ + Deal: deal, + }, nil } -func (k Keeper) Deal(ctx context.Context, request *types.QueryDealRequest) (*types.QueryDealResponse, error) { +func (k Keeper) Deals(ctx context.Context, request *types.QueryDealsRequest) (*types.QueryDealsResponse, error) { //TODO implement me panic("implement me") } diff --git a/x/datadeal/keeper/grpc_query_deal_test.go b/x/datadeal/keeper/grpc_query_deal_test.go new file mode 100644 index 00000000..96c40f3c --- /dev/null +++ b/x/datadeal/keeper/grpc_query_deal_test.go @@ -0,0 +1,36 @@ +package keeper_test + +import ( + "testing" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/medibloc/panacea-core/v2/x/datadeal/testutil" + "github.com/medibloc/panacea-core/v2/x/datadeal/types" + "github.com/stretchr/testify/suite" +) + +type queryDealTestSuite struct { + testutil.DataDealBaseTestSuite + + buyerAccAddr sdk.AccAddress +} + +func TestQueryDealTest(t *testing.T) { + suite.Run(t, new(queryDealTestSuite)) +} + +func (suite *queryDealTestSuite) TestQueryDeal() { + deal := suite.MakeTestDeal(1, suite.buyerAccAddr, 100) + err := suite.DataDealKeeper.SetDeal(suite.Ctx, deal) + suite.Require().NoError(err) + err = suite.DataDealKeeper.SetNextDealNumber(suite.Ctx, 2) + suite.Require().NoError(err) + + req := types.QueryDealRequest{ + DealId: deal.Id, + } + res, err := suite.DataDealKeeper.Deal(sdk.WrapSDKContext(suite.Ctx), &req) + suite.Require().NoError(err) + suite.Require().NotNil(res) + suite.Require().Equal(deal, res.Deal) +} diff --git a/x/datadeal/keeper/keeper.go b/x/datadeal/keeper/keeper.go index 9fd0ea15..d81124b8 100644 --- a/x/datadeal/keeper/keeper.go +++ b/x/datadeal/keeper/keeper.go @@ -3,16 +3,16 @@ package keeper import ( "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" - paramtypes "github.com/cosmos/cosmos-sdk/x/params/types" + "github.com/medibloc/panacea-core/v2/x/datadeal/types" ) type ( Keeper struct { - cdc codec.Codec - storeKey sdk.StoreKey - memKey sdk.StoreKey - - paramSpace paramtypes.Subspace + cdc codec.Codec + storeKey sdk.StoreKey + memKey sdk.StoreKey + accountKeeper types.AccountKeeper + bankKeeper types.BankKeeper } ) @@ -20,13 +20,15 @@ func NewKeeper( cdc codec.Codec, storeKey, memKey sdk.StoreKey, - paramSpace paramtypes.Subspace, + accountKeeper types.AccountKeeper, + bankKeeper types.BankKeeper, ) *Keeper { return &Keeper{ - cdc: cdc, - storeKey: storeKey, - memKey: memKey, - paramSpace: paramSpace, + cdc: cdc, + storeKey: storeKey, + memKey: memKey, + accountKeeper: accountKeeper, + bankKeeper: bankKeeper, } } diff --git a/x/datadeal/keeper/msg_server_deal.go b/x/datadeal/keeper/msg_server_deal.go index 9bf9523e..d75a8766 100644 --- a/x/datadeal/keeper/msg_server_deal.go +++ b/x/datadeal/keeper/msg_server_deal.go @@ -3,12 +3,23 @@ package keeper import ( "context" + sdk "github.com/cosmos/cosmos-sdk/types" "github.com/medibloc/panacea-core/v2/x/datadeal/types" ) -func (m msgServer) CreateDeal(ctx context.Context, deal *types.MsgCreateDeal) (*types.MsgCreateDealResponse, error) { - //TODO implement me - panic("implement me") +func (m msgServer) CreateDeal(goCtx context.Context, msg *types.MsgCreateDeal) (*types.MsgCreateDealResponse, error) { + ctx := sdk.UnwrapSDKContext(goCtx) + + buyer, err := sdk.AccAddressFromBech32(msg.BuyerAddress) + if err != nil { + return nil, err + } + newDealID, err := m.Keeper.CreateDeal(ctx, buyer, msg) + if err != nil { + return nil, err + } + + return &types.MsgCreateDealResponse{DealId: newDealID}, nil } func (m msgServer) DeactivateDeal(ctx context.Context, deal *types.MsgDeactivateDeal) (*types.MsgDeactivateDealResponse, error) { diff --git a/x/datadeal/testutil/suite.go b/x/datadeal/testutil/suite.go new file mode 100644 index 00000000..22d8781d --- /dev/null +++ b/x/datadeal/testutil/suite.go @@ -0,0 +1,25 @@ +package testutil + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/medibloc/panacea-core/v2/types/assets" + "github.com/medibloc/panacea-core/v2/types/testsuite" + "github.com/medibloc/panacea-core/v2/x/datadeal/types" +) + +type DataDealBaseTestSuite struct { + testsuite.TestSuite +} + +func (suite *DataDealBaseTestSuite) MakeTestDeal(dealID uint64, consumerAddress sdk.AccAddress, maxNumData uint64) *types.Deal { + return &types.Deal{ + Id: dealID, + Address: types.NewDealAddress(dealID).String(), + DataSchema: []string{"http://jsonld.com"}, + Budget: &sdk.Coin{Denom: assets.MicroMedDenom, Amount: sdk.NewInt(1000000000)}, + MaxNumData: maxNumData, + CurNumData: 0, + ConsumerAddress: consumerAddress.String(), + Status: types.DEAL_STATUS_ACTIVE, + } +} diff --git a/x/datadeal/types/deal.go b/x/datadeal/types/deal.go new file mode 100644 index 00000000..8fa5d7a2 --- /dev/null +++ b/x/datadeal/types/deal.go @@ -0,0 +1,58 @@ +package types + +import ( + "strconv" + + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" +) + +func NewDeal(dealID uint64, msg *MsgCreateDeal) *Deal { + dealAddress := NewDealAddress(dealID) + + return &Deal{ + Id: dealID, + Address: dealAddress.String(), + DataSchema: msg.DataSchema, + Budget: msg.Budget, + MaxNumData: msg.MaxNumData, + CurNumData: 0, + ConsumerAddress: msg.BuyerAddress, + Status: DEAL_STATUS_ACTIVE, + } +} + +func NewDealAddress(dealID uint64) sdk.AccAddress { + dealKey := "deal" + strconv.FormatUint(dealID, 10) + return authtypes.NewModuleAddress(dealKey) +} + +func (m Deal) ValidateBasic() error { + if _, err := sdk.AccAddressFromBech32(m.ConsumerAddress); err != nil { + return sdkerrors.Wrapf(err, "consumer address is invalid. address: %s", m.ConsumerAddress) + } + if len(m.DataSchema) == 0 { + return sdkerrors.Wrapf(sdkerrors.ErrInvalidRequest, "there is no data schema") + } + if m.Id <= 0 { + return sdkerrors.Wrapf(sdkerrors.ErrInvalidRequest, "ID should be bigger than 0") + } + if m.MaxNumData <= 0 { + return sdkerrors.Wrapf(sdkerrors.ErrInvalidRequest, "MaxNumData should be bigger than 0") + } + + if m.Budget == nil { + return sdkerrors.Wrapf(sdkerrors.ErrInvalidRequest, "budget is empty") + } + + if !m.Budget.IsValid() { + return sdkerrors.Wrapf(sdkerrors.ErrInvalidRequest, "budget is not a valid Coin object") + } + + if m.CurNumData > m.MaxNumData { + return sdkerrors.Wrapf(sdkerrors.ErrInvalidRequest, "CurNumData can not be bigger than MaxNumData") + } + + return nil +} diff --git a/x/datadeal/types/error.go b/x/datadeal/types/error.go new file mode 100644 index 00000000..d7dbabfa --- /dev/null +++ b/x/datadeal/types/error.go @@ -0,0 +1,13 @@ +package types + +import sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + +// DONTCOVER + +// x/datadeal module sentinel errors + +var ( + ErrDealNotInitialized = sdkerrors.Register(ModuleName, 1, "deal has not been initialized") + ErrDealAlreadyExist = sdkerrors.Register(ModuleName, 2, "deal already exist") + ErrDealNotFound = sdkerrors.Register(ModuleName, 3, "deal is not found") +) diff --git a/x/datadeal/types/expected_keeper.go b/x/datadeal/types/expected_keeper.go new file mode 100644 index 00000000..e249a2d4 --- /dev/null +++ b/x/datadeal/types/expected_keeper.go @@ -0,0 +1,17 @@ +package types + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" +) + +type AccountKeeper interface { + NewAccount(sdk.Context, authtypes.AccountI) authtypes.AccountI + + SetAccount(sdk.Context, authtypes.AccountI) + GetAccount(sdk.Context, sdk.AccAddress) authtypes.AccountI +} + +type BankKeeper interface { + SendCoins(sdk.Context, sdk.AccAddress, sdk.AccAddress, sdk.Coins) error +} diff --git a/x/datadeal/types/keys.go b/x/datadeal/types/keys.go index a65310db..0c12c239 100644 --- a/x/datadeal/types/keys.go +++ b/x/datadeal/types/keys.go @@ -1,5 +1,7 @@ package types +import sdk "github.com/cosmos/cosmos-sdk/types" + const ( // ModuleName defines the module name ModuleName = "datadeal" @@ -16,3 +18,17 @@ const ( // MemStoreKey defines the in-memory store key MemStoreKey = "mem_datadeal" ) + +var ( + // KeyDealNextNumber defines key to store the next Deal ID to be used + DealNextNumberKey = []byte{0x01} + + // KeyPrefixDeals defines key to store deals + DealKey = []byte{0x02} + + KeyIndexSeparator = []byte{0xFF} +) + +func GetDealKey(dealID uint64) []byte { + return append(DealKey, sdk.Uint64ToBigEndian(dealID)...) +} From ff0562657616517a4979f42ca4d46ed0441d1ac9 Mon Sep 17 00:00:00 2001 From: InChul <49394875+inchori@users.noreply.github.com> Date: Wed, 7 Dec 2022 11:14:58 +0900 Subject: [PATCH 05/20] rename --- proto/panacea/datadeal/v2/tx.proto | 2 +- x/datadeal/types/tx.pb.go | 92 +++++++++++++++--------------- 2 files changed, 47 insertions(+), 47 deletions(-) diff --git a/proto/panacea/datadeal/v2/tx.proto b/proto/panacea/datadeal/v2/tx.proto index ca627eff..88a4b5d8 100644 --- a/proto/panacea/datadeal/v2/tx.proto +++ b/proto/panacea/datadeal/v2/tx.proto @@ -25,7 +25,7 @@ message MsgCreateDeal { repeated string data_schema = 1; cosmos.base.v1beta1.Coin budget = 2; uint64 max_num_data = 3; - string buyer_address = 4; + string consumer_address = 4; } // MsgCreateDealResponse defines the Msg/CreateDeal response type. diff --git a/x/datadeal/types/tx.pb.go b/x/datadeal/types/tx.pb.go index 9ff8999a..f882c488 100644 --- a/x/datadeal/types/tx.pb.go +++ b/x/datadeal/types/tx.pb.go @@ -31,10 +31,10 @@ const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package // MsgCreateDeal defines the Msg/CreateDeal request type. type MsgCreateDeal struct { - DataSchema []string `protobuf:"bytes,1,rep,name=data_schema,json=dataSchema,proto3" json:"data_schema,omitempty"` - Budget *types.Coin `protobuf:"bytes,2,opt,name=budget,proto3" json:"budget,omitempty"` - MaxNumData uint64 `protobuf:"varint,3,opt,name=max_num_data,json=maxNumData,proto3" json:"max_num_data,omitempty"` - BuyerAddress string `protobuf:"bytes,4,opt,name=buyer_address,json=buyerAddress,proto3" json:"buyer_address,omitempty"` + DataSchema []string `protobuf:"bytes,1,rep,name=data_schema,json=dataSchema,proto3" json:"data_schema,omitempty"` + Budget *types.Coin `protobuf:"bytes,2,opt,name=budget,proto3" json:"budget,omitempty"` + MaxNumData uint64 `protobuf:"varint,3,opt,name=max_num_data,json=maxNumData,proto3" json:"max_num_data,omitempty"` + ConsumerAddress string `protobuf:"bytes,4,opt,name=consumer_address,json=consumerAddress,proto3" json:"consumer_address,omitempty"` } func (m *MsgCreateDeal) Reset() { *m = MsgCreateDeal{} } @@ -91,9 +91,9 @@ func (m *MsgCreateDeal) GetMaxNumData() uint64 { return 0 } -func (m *MsgCreateDeal) GetBuyerAddress() string { +func (m *MsgCreateDeal) GetConsumerAddress() string { if m != nil { - return m.BuyerAddress + return m.ConsumerAddress } return "" } @@ -327,39 +327,39 @@ func init() { func init() { proto.RegisterFile("panacea/datadeal/v2/tx.proto", fileDescriptor_9f03db1b9a7fe946) } var fileDescriptor_9f03db1b9a7fe946 = []byte{ - // 498 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x53, 0xc1, 0x6e, 0xd3, 0x40, - 0x14, 0x8c, 0x93, 0x2a, 0xa8, 0x2f, 0x0d, 0x6a, 0x0d, 0x08, 0xd7, 0x20, 0x63, 0x19, 0x15, 0x45, - 0xa0, 0xee, 0x92, 0xf0, 0x05, 0x34, 0xb9, 0x20, 0x14, 0x0e, 0xae, 0x84, 0x04, 0x42, 0xb2, 0xd6, - 0xeb, 0x87, 0x63, 0x29, 0xf6, 0x06, 0xef, 0x3a, 0x4a, 0xff, 0x82, 0xef, 0xe0, 0xcc, 0x47, 0x70, - 0xec, 0x91, 0x23, 0x4a, 0x7e, 0x04, 0xd9, 0x8e, 0xd3, 0xb8, 0x24, 0xa2, 0x37, 0xfb, 0xcd, 0xbc, - 0x99, 0xd9, 0xb1, 0x17, 0x9e, 0xce, 0x58, 0xc2, 0x38, 0x32, 0x1a, 0x30, 0xc5, 0x02, 0x64, 0x53, - 0x3a, 0x1f, 0x50, 0xb5, 0x20, 0xb3, 0x54, 0x28, 0xa1, 0x3f, 0x58, 0xa3, 0xa4, 0x42, 0xc9, 0x7c, - 0x60, 0x3e, 0x0c, 0x45, 0x28, 0x0a, 0x9c, 0xe6, 0x4f, 0x25, 0xd5, 0xb4, 0xb8, 0x90, 0xb1, 0x90, - 0xd4, 0x67, 0x12, 0xe9, 0xbc, 0xef, 0xa3, 0x62, 0x7d, 0xca, 0x45, 0x94, 0x54, 0xf8, 0x2e, 0xa3, - 0x42, 0xb2, 0xc4, 0xcf, 0x76, 0xe1, 0x1c, 0x53, 0x15, 0x7d, 0x8d, 0x38, 0x53, 0x58, 0xd2, 0x9c, - 0x1f, 0x1a, 0x74, 0xc7, 0x32, 0x1c, 0xa6, 0xc8, 0x14, 0x8e, 0x90, 0x4d, 0xf5, 0x67, 0xd0, 0xc9, - 0x57, 0x3c, 0xc9, 0x27, 0x18, 0x33, 0x43, 0xb3, 0x5b, 0xbd, 0x43, 0x17, 0xf2, 0xd1, 0x65, 0x31, - 0xd1, 0xfb, 0xd0, 0xf6, 0xb3, 0x20, 0x44, 0x65, 0x34, 0x6d, 0xad, 0xd7, 0x19, 0x9c, 0x92, 0x32, - 0x2a, 0xc9, 0xa3, 0x92, 0x75, 0x54, 0x32, 0x14, 0x51, 0xe2, 0xae, 0x89, 0xba, 0x0d, 0x47, 0x31, - 0x5b, 0x78, 0x49, 0x16, 0x7b, 0xb9, 0x90, 0xd1, 0xb2, 0xb5, 0xde, 0x81, 0x0b, 0x31, 0x5b, 0x7c, - 0xc8, 0xe2, 0x11, 0x53, 0x4c, 0x7f, 0x0e, 0x5d, 0x3f, 0xbb, 0xc2, 0xd4, 0x63, 0x41, 0x90, 0xa2, - 0x94, 0xc6, 0x81, 0xad, 0xf5, 0x0e, 0xdd, 0xa3, 0x62, 0xf8, 0xb6, 0x9c, 0x39, 0xaf, 0xe1, 0x51, - 0x2d, 0xab, 0x8b, 0x72, 0x26, 0x12, 0x89, 0xfa, 0x63, 0xb8, 0x97, 0x1f, 0xd1, 0x8b, 0x02, 0x43, - 0x2b, 0xa4, 0xdb, 0xf9, 0xeb, 0xbb, 0xc0, 0xf9, 0x04, 0x27, 0x63, 0x19, 0x8e, 0x90, 0x71, 0x15, - 0xcd, 0xab, 0x13, 0xee, 0x63, 0xeb, 0xaf, 0xe0, 0x24, 0xc5, 0x6f, 0x19, 0x4a, 0xb5, 0x15, 0xa4, - 0x59, 0x04, 0x39, 0xde, 0x00, 0x55, 0x98, 0x27, 0x70, 0xfa, 0x8f, 0x74, 0x15, 0xc8, 0xf9, 0x08, - 0xc7, 0x63, 0x19, 0x5e, 0x66, 0x7e, 0x1c, 0xa9, 0x61, 0x3e, 0x49, 0x94, 0x7e, 0x01, 0x9d, 0xad, - 0xfe, 0x0b, 0xeb, 0xce, 0xc0, 0x26, 0x3b, 0x7e, 0x09, 0x32, 0xbc, 0xe1, 0xb9, 0xdb, 0x4b, 0x8e, - 0x09, 0xc6, 0x6d, 0xdd, 0xca, 0x73, 0xf0, 0xb3, 0x09, 0xad, 0xb1, 0x0c, 0xf5, 0x2f, 0x00, 0x5b, - 0x9f, 0xd3, 0xd9, 0x69, 0x50, 0xab, 0xd1, 0x7c, 0xf9, 0x7f, 0xce, 0xa6, 0xea, 0x09, 0xdc, 0xbf, - 0x55, 0xe7, 0x8b, 0x7d, 0xdb, 0x75, 0x9e, 0x49, 0xee, 0xc6, 0xdb, 0x38, 0x21, 0x74, 0xeb, 0x05, - 0x9e, 0xed, 0x13, 0xa8, 0xd1, 0xcc, 0xf3, 0x3b, 0xd1, 0x2a, 0x9b, 0x8b, 0xf7, 0xbf, 0x96, 0x96, - 0x76, 0xbd, 0xb4, 0xb4, 0x3f, 0x4b, 0x4b, 0xfb, 0xbe, 0xb2, 0x1a, 0xd7, 0x2b, 0xab, 0xf1, 0x7b, - 0x65, 0x35, 0x3e, 0xf7, 0xc3, 0x48, 0x4d, 0x32, 0x9f, 0x70, 0x11, 0xd3, 0x18, 0x83, 0xc8, 0x9f, - 0x0a, 0x4e, 0xd7, 0xda, 0xe7, 0x5c, 0xa4, 0x48, 0x17, 0x37, 0xb7, 0x4b, 0x5d, 0xcd, 0x50, 0xfa, - 0xed, 0xe2, 0x56, 0xbd, 0xf9, 0x1b, 0x00, 0x00, 0xff, 0xff, 0x0c, 0xb3, 0x09, 0x27, 0x07, 0x04, - 0x00, 0x00, + // 500 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x53, 0xd1, 0x8e, 0xd2, 0x40, + 0x14, 0xa5, 0xb0, 0xc1, 0xec, 0xc5, 0x55, 0xb6, 0x6a, 0xec, 0x56, 0x53, 0x9b, 0x26, 0x6b, 0x50, + 0xb3, 0x33, 0x82, 0x5f, 0xe0, 0xc2, 0x8b, 0x31, 0xf8, 0xd0, 0x4d, 0x4c, 0x34, 0x26, 0x64, 0x3a, + 0xbd, 0x96, 0x26, 0x4c, 0x07, 0x3b, 0x53, 0x82, 0x7f, 0xe1, 0xa7, 0xf8, 0xe0, 0x47, 0xf8, 0xb8, + 0x8f, 0x3e, 0x1a, 0xf8, 0x11, 0xd3, 0x42, 0x59, 0xba, 0x42, 0x76, 0xdf, 0xe0, 0x9c, 0x73, 0xcf, + 0x39, 0x73, 0xa7, 0x03, 0x4f, 0xa7, 0x2c, 0x61, 0x1c, 0x19, 0x0d, 0x99, 0x66, 0x21, 0xb2, 0x09, + 0x9d, 0xf5, 0xa8, 0x9e, 0x93, 0x69, 0x2a, 0xb5, 0x34, 0x1f, 0xac, 0x59, 0x52, 0xb2, 0x64, 0xd6, + 0xb3, 0x1f, 0x46, 0x32, 0x92, 0x05, 0x4f, 0xf3, 0x5f, 0x2b, 0xa9, 0xed, 0x70, 0xa9, 0x84, 0x54, + 0x34, 0x60, 0x0a, 0xe9, 0xac, 0x1b, 0xa0, 0x66, 0x5d, 0xca, 0x65, 0x9c, 0x94, 0xfc, 0xae, 0xa0, + 0xc2, 0x72, 0xc5, 0x9f, 0xee, 0xe2, 0x39, 0xa6, 0x3a, 0xfe, 0x1a, 0x73, 0xa6, 0x71, 0x25, 0xf3, + 0x7e, 0x1a, 0x70, 0x34, 0x54, 0x51, 0x3f, 0x45, 0xa6, 0x71, 0x80, 0x6c, 0x62, 0x3e, 0x83, 0x56, + 0x3e, 0x32, 0x52, 0x7c, 0x8c, 0x82, 0x59, 0x86, 0xdb, 0xe8, 0x1c, 0xfa, 0x90, 0x43, 0x17, 0x05, + 0x62, 0x76, 0xa1, 0x19, 0x64, 0x61, 0x84, 0xda, 0xaa, 0xbb, 0x46, 0xa7, 0xd5, 0x3b, 0x21, 0xab, + 0xaa, 0x24, 0xaf, 0x4a, 0xd6, 0x55, 0x49, 0x5f, 0xc6, 0x89, 0xbf, 0x16, 0x9a, 0x2e, 0xdc, 0x15, + 0x6c, 0x3e, 0x4a, 0x32, 0x31, 0xca, 0x8d, 0xac, 0x86, 0x6b, 0x74, 0x0e, 0x7c, 0x10, 0x6c, 0xfe, + 0x21, 0x13, 0x03, 0xa6, 0x99, 0xf9, 0x02, 0xda, 0x5c, 0x26, 0x2a, 0x13, 0x98, 0x8e, 0x58, 0x18, + 0xa6, 0xa8, 0x94, 0x75, 0xe0, 0x1a, 0x9d, 0x43, 0xff, 0x7e, 0x89, 0xbf, 0x5d, 0xc1, 0xde, 0x6b, + 0x78, 0x54, 0x69, 0xec, 0xa3, 0x9a, 0xca, 0x44, 0xa1, 0xf9, 0x18, 0xee, 0xe4, 0x07, 0x1d, 0xc5, + 0xa1, 0x65, 0x14, 0x01, 0xcd, 0xfc, 0xef, 0xbb, 0xd0, 0xfb, 0x04, 0xc7, 0x43, 0x15, 0x0d, 0x90, + 0x71, 0x1d, 0xcf, 0xca, 0x73, 0xee, 0x53, 0x9b, 0xaf, 0xe0, 0x38, 0xc5, 0x6f, 0x19, 0x2a, 0xbd, + 0xd5, 0xa5, 0x5e, 0x74, 0x69, 0x6f, 0x88, 0xb2, 0xcc, 0x13, 0x38, 0xf9, 0xcf, 0xba, 0x2c, 0xe4, + 0x7d, 0x84, 0xf6, 0x50, 0x45, 0x17, 0x59, 0x20, 0x62, 0xdd, 0xcf, 0x91, 0x44, 0x9b, 0xe7, 0xd0, + 0xda, 0xba, 0x85, 0x22, 0xba, 0xd5, 0x73, 0xc9, 0x8e, 0x0f, 0x83, 0xf4, 0xaf, 0x74, 0xfe, 0xf6, + 0x90, 0x67, 0x83, 0x75, 0xdd, 0xb7, 0xcc, 0xec, 0xfd, 0xaa, 0x43, 0x63, 0xa8, 0x22, 0xf3, 0x0b, + 0xc0, 0xd6, 0xa5, 0x7a, 0x3b, 0x03, 0x2a, 0x6b, 0xb4, 0x5f, 0xde, 0xac, 0xd9, 0xac, 0x7a, 0x0c, + 0xf7, 0xae, 0xad, 0xf3, 0xf9, 0xbe, 0xe9, 0xaa, 0xce, 0x26, 0xb7, 0xd3, 0x6d, 0x92, 0x10, 0x8e, + 0xaa, 0x0b, 0x3c, 0xdd, 0x67, 0x50, 0x91, 0xd9, 0x67, 0xb7, 0x92, 0x95, 0x31, 0xe7, 0xef, 0x7f, + 0x2f, 0x1c, 0xe3, 0x72, 0xe1, 0x18, 0x7f, 0x17, 0x8e, 0xf1, 0x63, 0xe9, 0xd4, 0x2e, 0x97, 0x4e, + 0xed, 0xcf, 0xd2, 0xa9, 0x7d, 0xee, 0x46, 0xb1, 0x1e, 0x67, 0x01, 0xe1, 0x52, 0x50, 0x81, 0x61, + 0x1c, 0x4c, 0x24, 0xa7, 0x6b, 0xef, 0x33, 0x2e, 0x53, 0xa4, 0xf3, 0xab, 0x37, 0xa6, 0xbf, 0x4f, + 0x51, 0x05, 0xcd, 0xe2, 0x6d, 0xbd, 0xf9, 0x17, 0x00, 0x00, 0xff, 0xff, 0xf5, 0x3d, 0x75, 0x2b, + 0x0d, 0x04, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -540,10 +540,10 @@ func (m *MsgCreateDeal) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l - if len(m.BuyerAddress) > 0 { - i -= len(m.BuyerAddress) - copy(dAtA[i:], m.BuyerAddress) - i = encodeVarintTx(dAtA, i, uint64(len(m.BuyerAddress))) + if len(m.ConsumerAddress) > 0 { + i -= len(m.ConsumerAddress) + copy(dAtA[i:], m.ConsumerAddress) + i = encodeVarintTx(dAtA, i, uint64(len(m.ConsumerAddress))) i-- dAtA[i] = 0x22 } @@ -750,7 +750,7 @@ func (m *MsgCreateDeal) Size() (n int) { if m.MaxNumData != 0 { n += 1 + sovTx(uint64(m.MaxNumData)) } - l = len(m.BuyerAddress) + l = len(m.ConsumerAddress) if l > 0 { n += 1 + l + sovTx(uint64(l)) } @@ -940,7 +940,7 @@ func (m *MsgCreateDeal) Unmarshal(dAtA []byte) error { } case 4: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field BuyerAddress", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field ConsumerAddress", wireType) } var stringLen uint64 for shift := uint(0); ; shift += 7 { @@ -968,7 +968,7 @@ func (m *MsgCreateDeal) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.BuyerAddress = string(dAtA[iNdEx:postIndex]) + m.ConsumerAddress = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex default: iNdEx = preIndex From a5397f1775d41cd884aaf0d7aab9dd9348b1c0cf Mon Sep 17 00:00:00 2001 From: InChul <49394875+inchori@users.noreply.github.com> Date: Wed, 7 Dec 2022 11:16:59 +0900 Subject: [PATCH 06/20] fix --- x/datadeal/types/message_deal.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x/datadeal/types/message_deal.go b/x/datadeal/types/message_deal.go index 5c7fdb87..49c11b67 100644 --- a/x/datadeal/types/message_deal.go +++ b/x/datadeal/types/message_deal.go @@ -23,7 +23,7 @@ func (m *MsgCreateDeal) GetSignBytes() []byte { } func (m *MsgCreateDeal) GetSigners() []sdk.AccAddress { - buyerAddress, err := sdk.AccAddressFromBech32(m.BuyerAddress) + buyerAddress, err := sdk.AccAddressFromBech32(m.ConsumerAddress) if err != nil { panic(err) } From 2c2b906ef107eecabdaf966cf76935c6c57ee9e5 Mon Sep 17 00:00:00 2001 From: InChul <49394875+inchori@users.noreply.github.com> Date: Wed, 7 Dec 2022 11:21:26 +0900 Subject: [PATCH 07/20] fix --- x/datadeal/keeper/deal.go | 4 +-- x/datadeal/keeper/deal_test.go | 36 +++++++++++------------ x/datadeal/keeper/grpc_query_deal_test.go | 4 +-- x/datadeal/keeper/msg_server_deal.go | 4 +-- x/datadeal/types/deal.go | 2 +- x/datadeal/types/message_deal.go | 4 +-- 6 files changed, 27 insertions(+), 27 deletions(-) diff --git a/x/datadeal/keeper/deal.go b/x/datadeal/keeper/deal.go index f42562cc..1593bff5 100644 --- a/x/datadeal/keeper/deal.go +++ b/x/datadeal/keeper/deal.go @@ -10,7 +10,7 @@ import ( "github.com/medibloc/panacea-core/v2/x/datadeal/types" ) -func (k Keeper) CreateDeal(ctx sdk.Context, buyerAddress sdk.AccAddress, msg *types.MsgCreateDeal) (uint64, error) { +func (k Keeper) CreateDeal(ctx sdk.Context, consumerAddress sdk.AccAddress, msg *types.MsgCreateDeal) (uint64, error) { dealID, err := k.GetNextDealNumberAndIncrement(ctx) if err != nil { return 0, sdkerrors.Wrapf(err, "failed to get next deal num") @@ -38,7 +38,7 @@ func (k Keeper) CreateDeal(ctx sdk.Context, buyerAddress sdk.AccAddress, msg *ty ) k.accountKeeper.SetAccount(ctx, acc) - if err = k.bankKeeper.SendCoins(ctx, buyerAddress, dealAddress, coins); err != nil { + if err = k.bankKeeper.SendCoins(ctx, consumerAddress, dealAddress, coins); err != nil { return 0, sdkerrors.Wrapf(err, "Failed to send coins to deal account") } diff --git a/x/datadeal/keeper/deal_test.go b/x/datadeal/keeper/deal_test.go index c8470793..2dfb5c20 100644 --- a/x/datadeal/keeper/deal_test.go +++ b/x/datadeal/keeper/deal_test.go @@ -14,8 +14,8 @@ import ( type dealTestSuite struct { testutil.DataDealBaseTestSuite - defaultFunds sdk.Coins - buyerAccAddr sdk.AccAddress + defaultFunds sdk.Coins + consumerAccAddr sdk.AccAddress } func TestDealTestSuite(t *testing.T) { @@ -23,10 +23,10 @@ func TestDealTestSuite(t *testing.T) { } func (suite *dealTestSuite) BeforeTest(_, _ string) { - suite.buyerAccAddr = sdk.AccAddress(secp256k1.GenPrivKey().PubKey().Address()) + suite.consumerAccAddr = sdk.AccAddress(secp256k1.GenPrivKey().PubKey().Address()) suite.defaultFunds = sdk.NewCoins(sdk.NewCoin(assets.MicroMedDenom, sdk.NewInt(10000000000))) - testDeal := suite.MakeTestDeal(1, suite.buyerAccAddr, 100) + testDeal := suite.MakeTestDeal(1, suite.consumerAccAddr, 100) err := suite.DataDealKeeper.SetNextDealNumber(suite.Ctx, 2) suite.Require().NoError(err) err = suite.DataDealKeeper.SetDeal(suite.Ctx, testDeal) @@ -35,22 +35,22 @@ func (suite *dealTestSuite) BeforeTest(_, _ string) { func (suite *dealTestSuite) TestCreateNewDeal() { - err := suite.FundAccount(suite.Ctx, suite.buyerAccAddr, suite.defaultFunds) + err := suite.FundAccount(suite.Ctx, suite.consumerAccAddr, suite.defaultFunds) suite.Require().NoError(err) budget := &sdk.Coin{Denom: assets.MicroMedDenom, Amount: sdk.NewInt(10000000)} msgCreateDeal := &types.MsgCreateDeal{ - DataSchema: []string{"http://jsonld.com"}, - Budget: budget, - MaxNumData: 10000, - BuyerAddress: suite.buyerAccAddr.String(), + DataSchema: []string{"http://jsonld.com"}, + Budget: budget, + MaxNumData: 10000, + ConsumerAddress: suite.consumerAccAddr.String(), } - buyer, err := sdk.AccAddressFromBech32(msgCreateDeal.BuyerAddress) + consumer, err := sdk.AccAddressFromBech32(msgCreateDeal.ConsumerAddress) suite.Require().NoError(err) - dealID, err := suite.DataDealKeeper.CreateDeal(suite.Ctx, buyer, msgCreateDeal) + dealID, err := suite.DataDealKeeper.CreateDeal(suite.Ctx, consumer, msgCreateDeal) suite.Require().NoError(err) expectedId, err := suite.DataDealKeeper.GetNextDealNumberAndIncrement(suite.Ctx) @@ -62,24 +62,24 @@ func (suite *dealTestSuite) TestCreateNewDeal() { suite.Require().Equal(deal.GetDataSchema(), msgCreateDeal.GetDataSchema()) suite.Require().Equal(deal.GetBudget(), msgCreateDeal.GetBudget()) suite.Require().Equal(deal.GetMaxNumData(), msgCreateDeal.GetMaxNumData()) - suite.Require().Equal(deal.GetConsumerAddress(), msgCreateDeal.GetBuyerAddress()) + suite.Require().Equal(deal.GetConsumerAddress(), msgCreateDeal.GetConsumerAddress()) suite.Require().Equal(deal.GetStatus(), types.DEAL_STATUS_ACTIVE) } func (suite *dealTestSuite) TestCheckDealCurNumDataAndIncrement() { - err := suite.FundAccount(suite.Ctx, suite.buyerAccAddr, suite.defaultFunds) + err := suite.FundAccount(suite.Ctx, suite.consumerAccAddr, suite.defaultFunds) suite.Require().NoError(err) budget := &sdk.Coin{Denom: assets.MicroMedDenom, Amount: sdk.NewInt(10000000)} msgCreateDeal := &types.MsgCreateDeal{ - DataSchema: []string{"http://jsonld.com"}, - Budget: budget, - MaxNumData: 1, - BuyerAddress: suite.buyerAccAddr.String(), + DataSchema: []string{"http://jsonld.com"}, + Budget: budget, + MaxNumData: 1, + ConsumerAddress: suite.consumerAccAddr.String(), } - buyer, err := sdk.AccAddressFromBech32(msgCreateDeal.BuyerAddress) + buyer, err := sdk.AccAddressFromBech32(msgCreateDeal.ConsumerAddress) suite.Require().NoError(err) dealID, err := suite.DataDealKeeper.CreateDeal(suite.Ctx, buyer, msgCreateDeal) diff --git a/x/datadeal/keeper/grpc_query_deal_test.go b/x/datadeal/keeper/grpc_query_deal_test.go index 96c40f3c..19cf9ac3 100644 --- a/x/datadeal/keeper/grpc_query_deal_test.go +++ b/x/datadeal/keeper/grpc_query_deal_test.go @@ -12,7 +12,7 @@ import ( type queryDealTestSuite struct { testutil.DataDealBaseTestSuite - buyerAccAddr sdk.AccAddress + consumerAccAddr sdk.AccAddress } func TestQueryDealTest(t *testing.T) { @@ -20,7 +20,7 @@ func TestQueryDealTest(t *testing.T) { } func (suite *queryDealTestSuite) TestQueryDeal() { - deal := suite.MakeTestDeal(1, suite.buyerAccAddr, 100) + deal := suite.MakeTestDeal(1, suite.consumerAccAddr, 100) err := suite.DataDealKeeper.SetDeal(suite.Ctx, deal) suite.Require().NoError(err) err = suite.DataDealKeeper.SetNextDealNumber(suite.Ctx, 2) diff --git a/x/datadeal/keeper/msg_server_deal.go b/x/datadeal/keeper/msg_server_deal.go index d75a8766..528efd6d 100644 --- a/x/datadeal/keeper/msg_server_deal.go +++ b/x/datadeal/keeper/msg_server_deal.go @@ -10,11 +10,11 @@ import ( func (m msgServer) CreateDeal(goCtx context.Context, msg *types.MsgCreateDeal) (*types.MsgCreateDealResponse, error) { ctx := sdk.UnwrapSDKContext(goCtx) - buyer, err := sdk.AccAddressFromBech32(msg.BuyerAddress) + consumer, err := sdk.AccAddressFromBech32(msg.ConsumerAddress) if err != nil { return nil, err } - newDealID, err := m.Keeper.CreateDeal(ctx, buyer, msg) + newDealID, err := m.Keeper.CreateDeal(ctx, consumer, msg) if err != nil { return nil, err } diff --git a/x/datadeal/types/deal.go b/x/datadeal/types/deal.go index 8fa5d7a2..8d627e58 100644 --- a/x/datadeal/types/deal.go +++ b/x/datadeal/types/deal.go @@ -18,7 +18,7 @@ func NewDeal(dealID uint64, msg *MsgCreateDeal) *Deal { Budget: msg.Budget, MaxNumData: msg.MaxNumData, CurNumData: 0, - ConsumerAddress: msg.BuyerAddress, + ConsumerAddress: msg.ConsumerAddress, Status: DEAL_STATUS_ACTIVE, } } diff --git a/x/datadeal/types/message_deal.go b/x/datadeal/types/message_deal.go index 49c11b67..8935beeb 100644 --- a/x/datadeal/types/message_deal.go +++ b/x/datadeal/types/message_deal.go @@ -23,9 +23,9 @@ func (m *MsgCreateDeal) GetSignBytes() []byte { } func (m *MsgCreateDeal) GetSigners() []sdk.AccAddress { - buyerAddress, err := sdk.AccAddressFromBech32(m.ConsumerAddress) + consumerAddress, err := sdk.AccAddressFromBech32(m.ConsumerAddress) if err != nil { panic(err) } - return []sdk.AccAddress{buyerAddress} + return []sdk.AccAddress{consumerAddress} } From b075d850fcc8d9a410297fc07cb0e9f544e5a77b Mon Sep 17 00:00:00 2001 From: InChul <49394875+inchori@users.noreply.github.com> Date: Wed, 7 Dec 2022 14:13:09 +0900 Subject: [PATCH 08/20] rename --- x/datadeal/types/{error.go => errors.go} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename x/datadeal/types/{error.go => errors.go} (100%) diff --git a/x/datadeal/types/error.go b/x/datadeal/types/errors.go similarity index 100% rename from x/datadeal/types/error.go rename to x/datadeal/types/errors.go From e2fad75bc4eabbca52e9e94880e108ea51ed5a1b Mon Sep 17 00:00:00 2001 From: gyuguen Date: Wed, 7 Dec 2022 18:07:31 +0900 Subject: [PATCH 09/20] feat: implement submit consent --- proto/panacea/datadeal/v2/certificate.proto | 2 +- proto/panacea/datadeal/v2/query.proto | 2 +- types/testsuite/suite.go | 11 + x/datadeal/handler.go | 6 +- x/datadeal/keeper/certificate.go | 132 +++++++++ x/datadeal/keeper/certificate_test.go | 297 ++++++++++++++++++++ x/datadeal/keeper/deal.go | 1 + x/datadeal/keeper/deal_test.go | 2 - x/datadeal/keeper/keeper.go | 4 + x/datadeal/keeper/msg_server_deal.go | 18 +- x/datadeal/types/certificate.pb.go | 52 ++-- x/datadeal/types/deal.go | 12 +- x/datadeal/types/errors.go | 9 +- x/datadeal/types/expected_keeper.go | 1 + x/datadeal/types/keys.go | 22 +- x/datadeal/types/message_deal.go | 80 +++++- x/datadeal/types/query.pb.go | 82 +++--- x/datadeal/types/query.pb.gw.go | 4 +- x/oracle/keeper/keeper.go | 40 +++ x/oracle/types/params.go | 14 +- 20 files changed, 703 insertions(+), 88 deletions(-) create mode 100644 x/datadeal/keeper/certificate.go create mode 100644 x/datadeal/keeper/certificate_test.go diff --git a/proto/panacea/datadeal/v2/certificate.proto b/proto/panacea/datadeal/v2/certificate.proto index 22650913..d1e857bc 100644 --- a/proto/panacea/datadeal/v2/certificate.proto +++ b/proto/panacea/datadeal/v2/certificate.proto @@ -16,7 +16,7 @@ message Certificate { message UnsignedCertificate { string cid = 1; string oracle_address = 2; - int64 deal_id = 3; + uint64 deal_id = 3; string provider_address = 4; string data_hash = 5; } \ No newline at end of file diff --git a/proto/panacea/datadeal/v2/query.proto b/proto/panacea/datadeal/v2/query.proto index 1776eef1..c25e681e 100644 --- a/proto/panacea/datadeal/v2/query.proto +++ b/proto/panacea/datadeal/v2/query.proto @@ -57,7 +57,7 @@ message QueryDealResponse { // QueryDealsRequest defines the request type for the Query/Deals RPC method. message QueryCertificates { - int64 deal_id = 1; + uint64 deal_id = 1; cosmos.base.query.v1beta1.PageRequest pagination = 2; } diff --git a/types/testsuite/suite.go b/types/testsuite/suite.go index 3f6f2dfd..f42fed0d 100644 --- a/types/testsuite/suite.go +++ b/types/testsuite/suite.go @@ -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" @@ -68,6 +70,7 @@ type TestSuite struct { DIDMsgServer didtypes.MsgServer DIDKeeper didkeeper.Keeper DataDealKeeper datadealkeeper.Keeper + OracleKeeper oraclekeeper.Keeper WasmKeeper wasm.Keeper UpgradeKeeper upgradekeeper.Keeper } @@ -207,12 +210,20 @@ func (suite *TestSuite) SetupTest() { ) suite.DIDMsgServer = didkeeper.NewMsgServerImpl(suite.DIDKeeper) + suite.OracleKeeper = *oraclekeeper.NewKeeper( + cdc.Marshaler, + keyParams[oracletypes.StoreKey], + memKeys[oracletypes.MemStoreKey], + paramsKeeper.Subspace(oracletypes.ModuleName), + ) + suite.DataDealKeeper = *datadealkeeper.NewKeeper( cdc.Marshaler, keyParams[datadealtypes.StoreKey], memKeys[datadealtypes.MemStoreKey], suite.AccountKeeper, suite.BankKeeper, + suite.OracleKeeper, ) } diff --git a/x/datadeal/handler.go b/x/datadeal/handler.go index 17711548..b4653db0 100644 --- a/x/datadeal/handler.go +++ b/x/datadeal/handler.go @@ -23,9 +23,9 @@ func NewHandler(k keeper.Keeper) sdk.Handler { //case *types.MsgDeactivateDeal: // res, err := msgServer.DeactivateDeal(sdk.WrapSDKContext(ctx), msg) // return sdk.WrapServiceResult(ctx, res, err) - //case *types.MsgSubmitConsent: - // res, err := msgServer.SubmitConsent(sdk.WrapSDKContext(ctx), msg) - // return sdk.WrapServiceResult(ctx, res, err) + case *types.MsgSubmitConsent: + res, err := msgServer.SubmitConsent(sdk.WrapSDKContext(ctx), msg) + return sdk.WrapServiceResult(ctx, res, err) default: errMsg := fmt.Sprintf("unrecognized %s message type: %T", types.ModuleName, msg) return nil, sdkerrors.Wrap(sdkerrors.ErrUnknownRequest, errMsg) diff --git a/x/datadeal/keeper/certificate.go b/x/datadeal/keeper/certificate.go new file mode 100644 index 00000000..4146775b --- /dev/null +++ b/x/datadeal/keeper/certificate.go @@ -0,0 +1,132 @@ +package keeper + +import ( + "fmt" + + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + "github.com/medibloc/panacea-core/v2/types/assets" + "github.com/medibloc/panacea-core/v2/x/datadeal/types" +) + +func (k Keeper) SubmitConsent(ctx sdk.Context, cert *types.Certificate) error { + unsignedCert := cert.UnsignedCertificate + if err := k.oracleKeeper.VerifySignature(ctx, unsignedCert, cert.Signature); err != nil { + return sdkerrors.Wrapf(types.ErrSubmitConsent, err.Error()) + } + + if err := k.oracleKeeper.VerifyOracle(ctx, unsignedCert.OracleAddress); err != nil { + return sdkerrors.Wrapf(types.ErrSubmitConsent, err.Error()) + } + + deal, err := k.GetDeal(ctx, unsignedCert.DealId) + if err != nil { + return sdkerrors.Wrapf(types.ErrSubmitConsent, "failed to get deal. %v", err) + } else if deal.Status != types.DEAL_STATUS_ACTIVE { + return sdkerrors.Wrapf(types.ErrSubmitConsent, "deal status is not ACTIVE") + } + + if err := k.verifyExistCertificate(ctx, unsignedCert.DealId, unsignedCert.DataHash); err != nil { + return sdkerrors.Wrapf(types.ErrSubmitConsent, err.Error()) + } + + if err := k.SetCertificate(ctx, unsignedCert); err != nil { + return sdkerrors.Wrapf(types.ErrSubmitConsent, err.Error()) + } + + if err := k.sendReward(ctx, deal, unsignedCert); err != nil { + return sdkerrors.Wrapf(types.ErrSubmitConsent, err.Error()) + } + + if err := k.postProcessingOfDeal(ctx, deal); err != nil { + return sdkerrors.Wrapf(types.ErrSubmitConsent, err.Error()) + } + + return nil +} + +func (k Keeper) verifyExistCertificate(ctx sdk.Context, dealID uint64, dataHash string) error { + existUnsignedCert, err := k.GetCertificate(ctx, dealID, dataHash) + if err != types.ErrCertificateNotFound { + if existUnsignedCert != nil { + return fmt.Errorf("already exist certificate. dataHash: %s", dataHash) + } else { + return err + } + } + return nil +} + +func (k Keeper) sendReward(ctx sdk.Context, deal *types.Deal, unsignedCert *types.UnsignedCertificate) error { + dealAccAddr, err := sdk.AccAddressFromBech32(deal.GetAddress()) + if err != nil { + return err + } + + providerAccAddr, err := sdk.AccAddressFromBech32(unsignedCert.ProviderAddress) + if err := k.SetCertificate(ctx, unsignedCert); err != nil { + return err + } + + pricePerData := deal.GetPricePerData() + + dealBalance := k.bankKeeper.GetBalance(ctx, dealAccAddr, assets.MicroMedDenom) + if dealBalance.IsLT(sdk.NewCoin(assets.MicroMedDenom, pricePerData.TruncateInt())) { + return fmt.Errorf("not enough balance in deal") + } + + // TODO calculate oracle commission + + providerReward := sdk.NewCoin(assets.MicroMedDenom, pricePerData.TruncateInt()) + if err := k.bankKeeper.SendCoins(ctx, dealAccAddr, providerAccAddr, sdk.NewCoins(providerReward)); err != nil { + return fmt.Errorf("failed to send reward to provider. %w", err) + } + return nil +} + +func (k Keeper) postProcessingOfDeal(ctx sdk.Context, deal *types.Deal) error { + deal.IncrementCurNumData() + + if deal.CurNumData == deal.MaxNumData { + deal.Status = types.DEAL_STATUS_COMPLETED + } + + if err := k.SetDeal(ctx, deal); err != nil { + return fmt.Errorf("failed to set deal. %w", err) + } + return nil +} + +func (k Keeper) SetCertificate(ctx sdk.Context, unsignedCert *types.UnsignedCertificate) error { + store := ctx.KVStore(k.storeKey) + key := types.GetCertificateKey(unsignedCert.DealId, unsignedCert.DataHash) + + bz, err := k.cdc.MarshalLengthPrefixed(unsignedCert) + + if err != nil { + return err + } + + store.Set(key, bz) + + return nil +} + +func (k Keeper) GetCertificate(ctx sdk.Context, dealID uint64, dataHash string) (*types.UnsignedCertificate, error) { + store := ctx.KVStore(k.storeKey) + key := types.GetCertificateKey(dealID, dataHash) + + bz := store.Get(key) + if bz == nil { + return nil, types.ErrCertificateNotFound + } + + certificate := &types.UnsignedCertificate{} + + err := k.cdc.UnmarshalLengthPrefixed(bz, certificate) + if err != nil { + return nil, sdkerrors.Wrapf(types.ErrGetCertificate, err.Error()) + } + + return certificate, nil +} diff --git a/x/datadeal/keeper/certificate_test.go b/x/datadeal/keeper/certificate_test.go new file mode 100644 index 00000000..081b52bb --- /dev/null +++ b/x/datadeal/keeper/certificate_test.go @@ -0,0 +1,297 @@ +package keeper_test + +import ( + "encoding/base64" + "fmt" + "testing" + + "github.com/btcsuite/btcd/btcec" + "github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1" + cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/medibloc/panacea-core/v2/types/assets" + "github.com/medibloc/panacea-core/v2/x/datadeal/types" + oracletypes "github.com/medibloc/panacea-core/v2/x/oracle/types" + "github.com/stretchr/testify/suite" +) + +type certificateTestSuite struct { + dealTestSuite + + oracleAccPrivKey cryptotypes.PrivKey + oracleAccPubKey cryptotypes.PubKey + oracleAccAddr sdk.AccAddress + + providerAccPrivKey cryptotypes.PrivKey + providerAccPubKey cryptotypes.PubKey + providerAccAddr sdk.AccAddress + + oraclePrivKey *btcec.PrivateKey + oraclePubKey *btcec.PublicKey + invalidOraclePrivKey *btcec.PrivateKey + invalidOraclePubKey *btcec.PublicKey + + dataHash string +} + +func TestCertificateTestSuite(t *testing.T) { + suite.Run(t, new(certificateTestSuite)) +} + +func (suite *certificateTestSuite) BeforeTest(_, _ string) { + suite.consumerAccAddr = sdk.AccAddress(secp256k1.GenPrivKey().PubKey().Address()) + suite.defaultFunds = sdk.NewCoins(sdk.NewCoin(assets.MicroMedDenom, sdk.NewInt(10000000000))) + + suite.oracleAccPrivKey = secp256k1.GenPrivKey() + suite.oracleAccPubKey = suite.oracleAccPrivKey.PubKey() + suite.oracleAccAddr = sdk.AccAddress(suite.oracleAccPubKey.Address()) + + suite.providerAccPrivKey = secp256k1.GenPrivKey() + suite.providerAccPubKey = suite.providerAccPrivKey.PubKey() + suite.providerAccAddr = sdk.AccAddress(suite.providerAccPubKey.Address()) + + suite.oraclePrivKey, _ = btcec.NewPrivateKey(btcec.S256()) + suite.oraclePubKey = suite.oraclePrivKey.PubKey() + suite.invalidOraclePrivKey, _ = btcec.NewPrivateKey(btcec.S256()) + suite.invalidOraclePubKey = suite.invalidOraclePrivKey.PubKey() + + suite.dataHash = "dataHash" + + suite.OracleKeeper.SetParams(suite.Ctx, oracletypes.Params{ + OraclePublicKey: base64.StdEncoding.EncodeToString(suite.oraclePubKey.SerializeCompressed()), + OraclePubKeyRemoteReport: "", + UniqueId: "", + }) + + err := suite.DataDealKeeper.SetNextDealNumber(suite.Ctx, 1) + suite.Require().NoError(err) +} + +func (suite *certificateTestSuite) createSampleDeal(budgetAmount, maxNumData uint64) uint64 { + err := suite.FundAccount(suite.Ctx, suite.consumerAccAddr, suite.defaultFunds) + suite.Require().NoError(err) + + budget := &sdk.Coin{Denom: assets.MicroMedDenom, Amount: sdk.NewIntFromUint64(budgetAmount)} + + msgCreateDeal := &types.MsgCreateDeal{ + DataSchema: []string{"http://jsonld.com"}, + Budget: budget, + MaxNumData: maxNumData, + ConsumerAddress: suite.consumerAccAddr.String(), + } + + consumer, err := sdk.AccAddressFromBech32(msgCreateDeal.ConsumerAddress) + suite.Require().NoError(err) + + dealID, err := suite.DataDealKeeper.CreateDeal(suite.Ctx, consumer, msgCreateDeal) + suite.Require().NoError(err) + + return dealID +} + +func (suite *certificateTestSuite) TestSubmitConsentSuccess() { + budgetAmount := uint64(10000) + dealID := suite.createSampleDeal(budgetAmount, 10) + deal, err := suite.DataDealKeeper.GetDeal(suite.Ctx, dealID) + suite.Require().NoError(err) + + unsignedCert := &types.UnsignedCertificate{ + Cid: "cid", + OracleAddress: suite.oracleAccAddr.String(), + DealId: dealID, + ProviderAddress: suite.providerAccAddr.String(), + DataHash: suite.dataHash, + } + + unsignedCertBz, err := unsignedCert.Marshal() + suite.Require().NoError(err) + + sign, err := suite.oraclePrivKey.Sign(unsignedCertBz) + + suite.Require().NoError(err) + + certificate := &types.Certificate{ + UnsignedCertificate: unsignedCert, + Signature: sign.Serialize(), + } + + providerBalance := suite.BankKeeper.GetBalance(suite.Ctx, suite.providerAccAddr, assets.MicroMedDenom) + suite.Require().Equal(sdk.ZeroInt(), providerBalance.Amount) + + dealAccAddr, err := sdk.AccAddressFromBech32(deal.Address) + suite.Require().NoError(err) + dealBalance := suite.BankKeeper.GetBalance(suite.Ctx, dealAccAddr, assets.MicroMedDenom) + suite.Require().Equal(sdk.NewIntFromUint64(budgetAmount), dealBalance.Amount) + + err = suite.DataDealKeeper.SubmitConsent(suite.Ctx, certificate) + suite.Require().NoError(err) + + providerBalance = suite.BankKeeper.GetBalance(suite.Ctx, suite.providerAccAddr, assets.MicroMedDenom) + suite.Require().Equal(sdk.NewInt(1000), providerBalance.Amount) + + dealAccAddr, err = sdk.AccAddressFromBech32(deal.Address) + suite.Require().NoError(err) + dealBalance = suite.BankKeeper.GetBalance(suite.Ctx, dealAccAddr, assets.MicroMedDenom) + suite.Require().Equal(sdk.NewInt(9000), dealBalance.Amount) + + deal, err = suite.DataDealKeeper.GetDeal(suite.Ctx, dealID) + suite.Require().NoError(err) + suite.Require().Equal(uint64(1), deal.CurNumData) + suite.Require().Equal(types.DEAL_STATUS_ACTIVE, deal.Status) +} + +func (suite *certificateTestSuite) TestSubmitConsentChangeStatusComplete() { + budgetAmount := uint64(10000) + dealID := suite.createSampleDeal(budgetAmount, 1) + deal, err := suite.DataDealKeeper.GetDeal(suite.Ctx, dealID) + suite.Require().NoError(err) + + unsignedCert := &types.UnsignedCertificate{ + Cid: "cid", + OracleAddress: suite.oracleAccAddr.String(), + DealId: dealID, + ProviderAddress: suite.providerAccAddr.String(), + DataHash: suite.dataHash, + } + + unsignedCertBz, err := unsignedCert.Marshal() + suite.Require().NoError(err) + + sign, err := suite.oraclePrivKey.Sign(unsignedCertBz) + suite.Require().NoError(err) + + certificate := &types.Certificate{ + UnsignedCertificate: unsignedCert, + Signature: sign.Serialize(), + } + + providerBalance := suite.BankKeeper.GetBalance(suite.Ctx, suite.providerAccAddr, assets.MicroMedDenom) + suite.Require().Equal(sdk.ZeroInt(), providerBalance.Amount) + + dealAccAddr, err := sdk.AccAddressFromBech32(deal.Address) + suite.Require().NoError(err) + dealBalance := suite.BankKeeper.GetBalance(suite.Ctx, dealAccAddr, assets.MicroMedDenom) + suite.Require().Equal(sdk.NewIntFromUint64(budgetAmount), dealBalance.Amount) + + err = suite.DataDealKeeper.SubmitConsent(suite.Ctx, certificate) + suite.Require().NoError(err) + + providerBalance = suite.BankKeeper.GetBalance(suite.Ctx, suite.providerAccAddr, assets.MicroMedDenom) + suite.Require().Equal(sdk.NewInt(10000), providerBalance.Amount) + + dealAccAddr, err = sdk.AccAddressFromBech32(deal.Address) + suite.Require().NoError(err) + dealBalance = suite.BankKeeper.GetBalance(suite.Ctx, dealAccAddr, assets.MicroMedDenom) + suite.Require().Equal(sdk.ZeroInt(), dealBalance.Amount) + + deal, err = suite.DataDealKeeper.GetDeal(suite.Ctx, dealID) + suite.Require().NoError(err) + suite.Require().Equal(uint64(1), deal.CurNumData) + suite.Require().Equal(types.DEAL_STATUS_COMPLETED, deal.Status) +} + +func (suite *certificateTestSuite) TestSubmitConsentInvalidSignature() { + budgetAmount := uint64(10000) + dealID := suite.createSampleDeal(budgetAmount, 1) + + unsignedCert := &types.UnsignedCertificate{ + Cid: "cid", + OracleAddress: suite.oracleAccAddr.String(), + DealId: dealID, + ProviderAddress: suite.providerAccAddr.String(), + DataHash: suite.dataHash, + } + + unsignedCertBz, err := unsignedCert.Marshal() + suite.Require().NoError(err) + + sign, err := suite.invalidOraclePrivKey.Sign(unsignedCertBz) + suite.Require().NoError(err) + + certificate := &types.Certificate{ + UnsignedCertificate: unsignedCert, + Signature: sign.Serialize(), + } + + err = suite.DataDealKeeper.SubmitConsent(suite.Ctx, certificate) + suite.Require().ErrorIs(err, types.ErrSubmitConsent) + suite.Require().ErrorContains(err, "failed to signature validation") +} + +func (suite *certificateTestSuite) TestSubmitConsentNotExistDeal() { + unsignedCert := &types.UnsignedCertificate{ + Cid: "cid", + OracleAddress: suite.oracleAccAddr.String(), + DealId: 1, + ProviderAddress: suite.providerAccAddr.String(), + DataHash: suite.dataHash, + } + + unsignedCertBz, err := unsignedCert.Marshal() + suite.Require().NoError(err) + + sign, err := suite.oraclePrivKey.Sign(unsignedCertBz) + suite.Require().NoError(err) + + certificate := &types.Certificate{ + UnsignedCertificate: unsignedCert, + Signature: sign.Serialize(), + } + + err = suite.DataDealKeeper.SubmitConsent(suite.Ctx, certificate) + suite.Require().ErrorIs(err, types.ErrSubmitConsent) + suite.Require().ErrorContains(err, "failed to get deal.") +} + +func (suite *certificateTestSuite) TestSubmitConsentAlreadyDealStatusComplete() { + suite.TestSubmitConsentChangeStatusComplete() + + unsignedCert := &types.UnsignedCertificate{ + Cid: "cid", + OracleAddress: suite.oracleAccAddr.String(), + DealId: 1, + ProviderAddress: suite.providerAccAddr.String(), + DataHash: "dataHash2", + } + + unsignedCertBz, err := unsignedCert.Marshal() + suite.Require().NoError(err) + + sign, err := suite.oraclePrivKey.Sign(unsignedCertBz) + + suite.Require().NoError(err) + + certificate := &types.Certificate{ + UnsignedCertificate: unsignedCert, + Signature: sign.Serialize(), + } + err = suite.DataDealKeeper.SubmitConsent(suite.Ctx, certificate) + suite.Require().ErrorIs(err, types.ErrSubmitConsent) + suite.Require().ErrorContains(err, "deal status is not ACTIVE") +} + +func (suite *certificateTestSuite) TestSubmitConsentExistSameCertificate() { + suite.TestSubmitConsentSuccess() + + unsignedCert := &types.UnsignedCertificate{ + Cid: "cid", + OracleAddress: suite.oracleAccAddr.String(), + DealId: 1, + ProviderAddress: suite.providerAccAddr.String(), + DataHash: suite.dataHash, + } + + unsignedCertBz, err := unsignedCert.Marshal() + suite.Require().NoError(err) + + sign, err := suite.oraclePrivKey.Sign(unsignedCertBz) + suite.Require().NoError(err) + + certificate := &types.Certificate{ + UnsignedCertificate: unsignedCert, + Signature: sign.Serialize(), + } + err = suite.DataDealKeeper.SubmitConsent(suite.Ctx, certificate) + suite.Require().ErrorIs(err, types.ErrSubmitConsent) + suite.Require().ErrorContains(err, fmt.Sprintf("already exist certificate. dataHash: %s", suite.dataHash)) +} diff --git a/x/datadeal/keeper/deal.go b/x/datadeal/keeper/deal.go index 1593bff5..f1b734e8 100644 --- a/x/datadeal/keeper/deal.go +++ b/x/datadeal/keeper/deal.go @@ -144,5 +144,6 @@ func (k Keeper) IncrementCurNumDataAtDeal(ctx sdk.Context, dealID uint64) error if err = k.SetDeal(ctx, deal); err != nil { return err } + return nil } diff --git a/x/datadeal/keeper/deal_test.go b/x/datadeal/keeper/deal_test.go index 2dfb5c20..d2b9385e 100644 --- a/x/datadeal/keeper/deal_test.go +++ b/x/datadeal/keeper/deal_test.go @@ -34,7 +34,6 @@ func (suite *dealTestSuite) BeforeTest(_, _ string) { } func (suite *dealTestSuite) TestCreateNewDeal() { - err := suite.FundAccount(suite.Ctx, suite.consumerAccAddr, suite.defaultFunds) suite.Require().NoError(err) @@ -98,5 +97,4 @@ func (suite *dealTestSuite) TestCheckDealCurNumDataAndIncrement() { check, err = suite.DataDealKeeper.IsDealCompleted(suite.Ctx, dealID) suite.Require().NoError(err) suite.Require().Equal(true, check) - } diff --git a/x/datadeal/keeper/keeper.go b/x/datadeal/keeper/keeper.go index d81124b8..e868c4b5 100644 --- a/x/datadeal/keeper/keeper.go +++ b/x/datadeal/keeper/keeper.go @@ -4,6 +4,7 @@ import ( "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/medibloc/panacea-core/v2/x/datadeal/types" + oraclekeeper "github.com/medibloc/panacea-core/v2/x/oracle/keeper" ) type ( @@ -13,6 +14,7 @@ type ( memKey sdk.StoreKey accountKeeper types.AccountKeeper bankKeeper types.BankKeeper + oracleKeeper oraclekeeper.Keeper } ) @@ -22,6 +24,7 @@ func NewKeeper( memKey sdk.StoreKey, accountKeeper types.AccountKeeper, bankKeeper types.BankKeeper, + oracleKeeper oraclekeeper.Keeper, ) *Keeper { return &Keeper{ @@ -30,5 +33,6 @@ func NewKeeper( memKey: memKey, accountKeeper: accountKeeper, bankKeeper: bankKeeper, + oracleKeeper: oracleKeeper, } } diff --git a/x/datadeal/keeper/msg_server_deal.go b/x/datadeal/keeper/msg_server_deal.go index 528efd6d..77b6128c 100644 --- a/x/datadeal/keeper/msg_server_deal.go +++ b/x/datadeal/keeper/msg_server_deal.go @@ -27,7 +27,19 @@ func (m msgServer) DeactivateDeal(ctx context.Context, deal *types.MsgDeactivate panic("implement me") } -func (m msgServer) SubmitConsent(ctx context.Context, consent *types.MsgSubmitConsent) (*types.MsgSubmitConsentResponse, error) { - //TODO implement me - panic("implement me") +func (m msgServer) SubmitConsent(goCtx context.Context, msg *types.MsgSubmitConsent) (*types.MsgSubmitConsentResponse, error) { + ctx := sdk.UnwrapSDKContext(goCtx) + + if err := m.Keeper.SubmitConsent(ctx, msg.Certificate); err != nil { + return nil, err + } + + ctx.EventManager().EmitEvent( + sdk.NewEvent( + sdk.EventTypeMessage, + sdk.NewAttribute(sdk.AttributeKeyModule, types.ModuleName), + ), + ) + + return &types.MsgSubmitConsentResponse{}, nil } diff --git a/x/datadeal/types/certificate.pb.go b/x/datadeal/types/certificate.pb.go index fef568c1..912fdbc0 100644 --- a/x/datadeal/types/certificate.pb.go +++ b/x/datadeal/types/certificate.pb.go @@ -80,7 +80,7 @@ func (m *Certificate) GetSignature() []byte { type UnsignedCertificate struct { Cid string `protobuf:"bytes,1,opt,name=cid,proto3" json:"cid,omitempty"` OracleAddress string `protobuf:"bytes,2,opt,name=oracle_address,json=oracleAddress,proto3" json:"oracle_address,omitempty"` - DealId int64 `protobuf:"varint,3,opt,name=deal_id,json=dealId,proto3" json:"deal_id,omitempty"` + DealId uint64 `protobuf:"varint,3,opt,name=deal_id,json=dealId,proto3" json:"deal_id,omitempty"` ProviderAddress string `protobuf:"bytes,4,opt,name=provider_address,json=providerAddress,proto3" json:"provider_address,omitempty"` DataHash string `protobuf:"bytes,5,opt,name=data_hash,json=dataHash,proto3" json:"data_hash,omitempty"` } @@ -132,7 +132,7 @@ func (m *UnsignedCertificate) GetOracleAddress() string { return "" } -func (m *UnsignedCertificate) GetDealId() int64 { +func (m *UnsignedCertificate) GetDealId() uint64 { if m != nil { return m.DealId } @@ -163,29 +163,29 @@ func init() { } var fileDescriptor_e90678e908dbabdd = []byte{ - // 338 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x6c, 0x91, 0xcf, 0x4e, 0x2a, 0x31, - 0x14, 0x87, 0xe9, 0xe5, 0x8a, 0x4e, 0xf1, 0x0f, 0x29, 0x24, 0x4e, 0xd0, 0x34, 0x84, 0x84, 0x64, - 0x5c, 0x38, 0x8d, 0xf8, 0x04, 0xea, 0x46, 0xe3, 0x6e, 0x12, 0x37, 0xba, 0x98, 0x94, 0xb6, 0xce, - 0x34, 0x01, 0x3a, 0x69, 0x3b, 0x44, 0xdf, 0xc0, 0xa5, 0x6f, 0xe2, 0x6b, 0xb8, 0x64, 0xe9, 0xd2, - 0xc0, 0x8b, 0x98, 0x16, 0x10, 0x12, 0xd9, 0x75, 0xbe, 0xfe, 0xce, 0x77, 0xce, 0xf4, 0xc0, 0x5e, - 0x41, 0xc7, 0x94, 0x09, 0x4a, 0x38, 0xb5, 0x94, 0x0b, 0x3a, 0x24, 0x93, 0x3e, 0x61, 0x42, 0x5b, - 0xf9, 0x2c, 0x19, 0xb5, 0x22, 0x2e, 0xb4, 0xb2, 0x0a, 0x35, 0x97, 0xb1, 0x78, 0x15, 0x8b, 0x27, - 0xfd, 0x76, 0x2b, 0x53, 0x99, 0xf2, 0xf7, 0xc4, 0x9d, 0x16, 0xd1, 0x36, 0xde, 0x66, 0xf4, 0x25, - 0xfe, 0xbe, 0xfb, 0x06, 0x60, 0xfd, 0x66, 0xdd, 0x00, 0x3d, 0xc1, 0x56, 0x39, 0x36, 0x32, 0x1b, - 0x0b, 0x9e, 0x6e, 0x34, 0x0e, 0x41, 0x07, 0x44, 0xf5, 0x7e, 0x14, 0x6f, 0xe9, 0x1c, 0x3f, 0x2c, - 0x0b, 0x36, 0x3c, 0x49, 0xb3, 0xfc, 0x0b, 0xd1, 0x29, 0x0c, 0x1c, 0xa4, 0xb6, 0xd4, 0x22, 0xfc, - 0xd7, 0x01, 0xd1, 0x7e, 0xb2, 0x06, 0xdd, 0x0f, 0x00, 0x9b, 0x5b, 0x54, 0xa8, 0x01, 0xab, 0x4c, - 0x72, 0x3f, 0x41, 0x90, 0xb8, 0x23, 0xea, 0xc1, 0x43, 0xa5, 0x29, 0x1b, 0x8a, 0x94, 0x72, 0xae, - 0x85, 0x31, 0x5e, 0x16, 0x24, 0x07, 0x0b, 0x7a, 0xb5, 0x80, 0xe8, 0x18, 0xee, 0xba, 0x11, 0x53, - 0xc9, 0xc3, 0x6a, 0x07, 0x44, 0xd5, 0xa4, 0xe6, 0x3e, 0xef, 0x38, 0x3a, 0x83, 0x8d, 0x42, 0xab, - 0x89, 0xe4, 0x42, 0xff, 0x1a, 0xfe, 0x7b, 0xc3, 0xd1, 0x8a, 0xaf, 0x1c, 0x27, 0x30, 0x70, 0xbf, - 0x9a, 0xe6, 0xd4, 0xe4, 0xe1, 0x8e, 0xcf, 0xec, 0x39, 0x70, 0x4b, 0x4d, 0x7e, 0x7d, 0xff, 0x39, - 0xc3, 0x60, 0x3a, 0xc3, 0xe0, 0x7b, 0x86, 0xc1, 0xfb, 0x1c, 0x57, 0xa6, 0x73, 0x5c, 0xf9, 0x9a, - 0xe3, 0xca, 0xe3, 0x45, 0x26, 0x6d, 0x5e, 0x0e, 0x62, 0xa6, 0x46, 0x64, 0x24, 0xb8, 0x1c, 0x0c, - 0x15, 0x23, 0xcb, 0xb7, 0x3b, 0x67, 0x4a, 0x0b, 0xf2, 0xb2, 0xde, 0x88, 0x7d, 0x2d, 0x84, 0x19, - 0xd4, 0xfc, 0x42, 0x2e, 0x7f, 0x02, 0x00, 0x00, 0xff, 0xff, 0x8b, 0x25, 0x3c, 0x63, 0x04, 0x02, - 0x00, 0x00, + // 337 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x6c, 0x91, 0x4f, 0x4f, 0xc2, 0x30, + 0x18, 0x87, 0xa9, 0x20, 0xba, 0xe2, 0x1f, 0x52, 0x48, 0x5c, 0xd0, 0x34, 0x84, 0x84, 0x64, 0x1e, + 0x5c, 0x23, 0x7e, 0x02, 0xf5, 0xa2, 0xf1, 0xb6, 0xc4, 0x8b, 0x1e, 0x96, 0xd2, 0xd6, 0xad, 0x09, + 0xd0, 0xa5, 0xeb, 0x88, 0x7e, 0x03, 0x8f, 0x7e, 0x13, 0xbf, 0x86, 0x47, 0x8e, 0x1e, 0x0d, 0x7c, + 0x11, 0xd3, 0x02, 0x42, 0xe2, 0x6e, 0xdd, 0xd3, 0xdf, 0xfb, 0xbc, 0xef, 0xfa, 0xc2, 0x7e, 0x46, + 0x27, 0x94, 0x09, 0x4a, 0x38, 0x35, 0x94, 0x0b, 0x3a, 0x22, 0xd3, 0x01, 0x61, 0x42, 0x1b, 0xf9, + 0x22, 0x19, 0x35, 0x22, 0xcc, 0xb4, 0x32, 0x0a, 0xb5, 0x56, 0xb1, 0x70, 0x1d, 0x0b, 0xa7, 0x83, + 0x4e, 0x3b, 0x51, 0x89, 0x72, 0xf7, 0xc4, 0x9e, 0x96, 0xd1, 0x0e, 0x2e, 0x33, 0xba, 0x12, 0x77, + 0xdf, 0x7b, 0x07, 0xb0, 0x71, 0xbb, 0x69, 0x80, 0x9e, 0x61, 0xbb, 0x98, 0xe4, 0x32, 0x99, 0x08, + 0x1e, 0x6f, 0x35, 0xf6, 0x41, 0x17, 0x04, 0x8d, 0x41, 0x10, 0x96, 0x74, 0x0e, 0x1f, 0x57, 0x05, + 0x5b, 0x9e, 0xa8, 0x55, 0xfc, 0x87, 0xe8, 0x0c, 0x7a, 0x16, 0x52, 0x53, 0x68, 0xe1, 0xef, 0x74, + 0x41, 0x70, 0x10, 0x6d, 0x40, 0xef, 0x13, 0xc0, 0x56, 0x89, 0x0a, 0x35, 0x61, 0x95, 0x49, 0xee, + 0x26, 0xf0, 0x22, 0x7b, 0x44, 0x7d, 0x78, 0xa4, 0x34, 0x65, 0x23, 0x11, 0x53, 0xce, 0xb5, 0xc8, + 0x73, 0x27, 0xf3, 0xa2, 0xc3, 0x25, 0xbd, 0x5e, 0x42, 0x74, 0x02, 0xf7, 0xec, 0x88, 0xb1, 0xe4, + 0x7e, 0xb5, 0x0b, 0x82, 0x5a, 0x54, 0xb7, 0x9f, 0xf7, 0x1c, 0x9d, 0xc3, 0x66, 0xa6, 0xd5, 0x54, + 0x72, 0xa1, 0xff, 0x0c, 0x35, 0x67, 0x38, 0x5e, 0xf3, 0xb5, 0xe3, 0x14, 0x7a, 0xf6, 0x57, 0xe3, + 0x94, 0xe6, 0xa9, 0xbf, 0xeb, 0x32, 0xfb, 0x16, 0xdc, 0xd1, 0x3c, 0xbd, 0x79, 0xf8, 0x9a, 0x63, + 0x30, 0x9b, 0x63, 0xf0, 0x33, 0xc7, 0xe0, 0x63, 0x81, 0x2b, 0xb3, 0x05, 0xae, 0x7c, 0x2f, 0x70, + 0xe5, 0xe9, 0x32, 0x91, 0x26, 0x2d, 0x86, 0x21, 0x53, 0x63, 0x32, 0x16, 0x5c, 0x0e, 0x47, 0x8a, + 0x91, 0xd5, 0xdb, 0x5d, 0x30, 0xa5, 0x05, 0x79, 0xdd, 0x6c, 0xc4, 0xbc, 0x65, 0x22, 0x1f, 0xd6, + 0xdd, 0x42, 0xae, 0x7e, 0x03, 0x00, 0x00, 0xff, 0xff, 0xc4, 0x19, 0x47, 0xaf, 0x04, 0x02, 0x00, + 0x00, } func (m *Certificate) Marshal() (dAtA []byte, err error) { @@ -575,7 +575,7 @@ func (m *UnsignedCertificate) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - m.DealId |= int64(b&0x7F) << shift + m.DealId |= uint64(b&0x7F) << shift if b < 0x80 { break } diff --git a/x/datadeal/types/deal.go b/x/datadeal/types/deal.go index 8d627e58..be174a45 100644 --- a/x/datadeal/types/deal.go +++ b/x/datadeal/types/deal.go @@ -28,7 +28,7 @@ func NewDealAddress(dealID uint64) sdk.AccAddress { return authtypes.NewModuleAddress(dealKey) } -func (m Deal) ValidateBasic() error { +func (m *Deal) ValidateBasic() error { if _, err := sdk.AccAddressFromBech32(m.ConsumerAddress); err != nil { return sdkerrors.Wrapf(err, "consumer address is invalid. address: %s", m.ConsumerAddress) } @@ -56,3 +56,13 @@ func (m Deal) ValidateBasic() error { return nil } + +func (m *Deal) GetPricePerData() sdk.Dec { + totalBudget := m.Budget.Amount.ToDec() + maxNumData := sdk.NewIntFromUint64(m.MaxNumData).ToDec() + return totalBudget.Quo(maxNumData).TruncateDec() +} + +func (m *Deal) IncrementCurNumData() { + m.CurNumData += 1 +} diff --git a/x/datadeal/types/errors.go b/x/datadeal/types/errors.go index d7dbabfa..9cc10a8e 100644 --- a/x/datadeal/types/errors.go +++ b/x/datadeal/types/errors.go @@ -7,7 +7,10 @@ import sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" // x/datadeal module sentinel errors var ( - ErrDealNotInitialized = sdkerrors.Register(ModuleName, 1, "deal has not been initialized") - ErrDealAlreadyExist = sdkerrors.Register(ModuleName, 2, "deal already exist") - ErrDealNotFound = sdkerrors.Register(ModuleName, 3, "deal is not found") + ErrDealNotInitialized = sdkerrors.Register(ModuleName, 1, "deal has not been initialized") + ErrDealAlreadyExist = sdkerrors.Register(ModuleName, 2, "deal already exist") + ErrDealNotFound = sdkerrors.Register(ModuleName, 3, "deal is not found") + ErrCertificateNotFound = sdkerrors.Register(ModuleName, 4, "certificate is not found") + ErrGetCertificate = sdkerrors.Register(ModuleName, 5, "certificate is not found") + ErrSubmitConsent = sdkerrors.Register(ModuleName, 6, "error while submit consent") ) diff --git a/x/datadeal/types/expected_keeper.go b/x/datadeal/types/expected_keeper.go index e249a2d4..41356f5f 100644 --- a/x/datadeal/types/expected_keeper.go +++ b/x/datadeal/types/expected_keeper.go @@ -14,4 +14,5 @@ type AccountKeeper interface { type BankKeeper interface { SendCoins(sdk.Context, sdk.AccAddress, sdk.AccAddress, sdk.Coins) error + GetBalance(sdk.Context, sdk.AccAddress, string) sdk.Coin } diff --git a/x/datadeal/types/keys.go b/x/datadeal/types/keys.go index 0c12c239..f9eda9fc 100644 --- a/x/datadeal/types/keys.go +++ b/x/datadeal/types/keys.go @@ -1,6 +1,10 @@ package types -import sdk "github.com/cosmos/cosmos-sdk/types" +import ( + "bytes" + + sdk "github.com/cosmos/cosmos-sdk/types" +) const ( // ModuleName defines the module name @@ -20,15 +24,27 @@ const ( ) var ( - // KeyDealNextNumber defines key to store the next Deal ID to be used + // DealNextNumberKey defines key to store the next Deal ID to be used DealNextNumberKey = []byte{0x01} - // KeyPrefixDeals defines key to store deals + // DealKey defines key to store deals DealKey = []byte{0x02} + // CertificateKey defines key to store certificate + CertificateKey = []byte{0x03} + KeyIndexSeparator = []byte{0xFF} ) func GetDealKey(dealID uint64) []byte { return append(DealKey, sdk.Uint64ToBigEndian(dealID)...) } + +func GetCertificateKey(dealID uint64, dataHash string) []byte { + return append(CertificateKey, CombineKeys(sdk.Uint64ToBigEndian(dealID), []byte(dataHash))...) +} + +// CombineKeys function defines combines deal_id with data_hash. +func CombineKeys(keys ...[]byte) []byte { + return bytes.Join(keys, KeyIndexSeparator) +} diff --git a/x/datadeal/types/message_deal.go b/x/datadeal/types/message_deal.go index 8935beeb..c84bbc0b 100644 --- a/x/datadeal/types/message_deal.go +++ b/x/datadeal/types/message_deal.go @@ -1,6 +1,9 @@ package types -import sdk "github.com/cosmos/cosmos-sdk/types" +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" +) var _ sdk.Msg = &MsgCreateDeal{} @@ -29,3 +32,78 @@ func (m *MsgCreateDeal) GetSigners() []sdk.AccAddress { } return []sdk.AccAddress{consumerAddress} } + +var _ sdk.Msg = &MsgSubmitConsent{} + +func (m *MsgSubmitConsent) Route() string { + return RouterKey +} + +func (m *MsgSubmitConsent) Type() string { + return "SubmitConsent" +} + +func (m *MsgSubmitConsent) ValidateBasic() error { + if m.Certificate == nil { + return sdkerrors.Wrapf(sdkerrors.ErrInvalidRequest, "certificate is empty") + } + + if err := m.Certificate.ValidateBasic(); err != nil { + return sdkerrors.Wrapf(err, "failed to validation certificate") + } + + return nil +} + +func (m *MsgSubmitConsent) GetSignBytes() []byte { + bz := ModuleCdc.MustMarshalJSON(m) + return sdk.MustSortJSON(bz) +} + +func (m *MsgSubmitConsent) GetSigners() []sdk.AccAddress { + oracleAddress, err := sdk.AccAddressFromBech32(m.Certificate.UnsignedCertificate.OracleAddress) + if err != nil { + panic(err) + } + return []sdk.AccAddress{oracleAddress} +} + +func (m *Certificate) ValidateBasic() error { + if m.UnsignedCertificate == nil { + return sdkerrors.Wrapf(sdkerrors.ErrInvalidRequest, "unsignedCertificate is empty") + } + + if err := m.UnsignedCertificate.ValidateBasic(); err != nil { + return sdkerrors.Wrapf(err, "failed to validation unsignedCertificate") + } + + if m.Signature == nil { + return sdkerrors.Wrapf(sdkerrors.ErrInvalidRequest, "signature is empty") + } + + return nil +} + +func (m *UnsignedCertificate) ValidateBasic() error { + if len(m.Cid) == 0 { + return sdkerrors.Wrapf(sdkerrors.ErrInvalidRequest, "cid is empty") + } + + if _, err := sdk.AccAddressFromBech32(m.OracleAddress); err != nil { + return sdkerrors.Wrapf(sdkerrors.ErrInvalidRequest, "oracleAddress is invalid. address: %s, error: %s", m.OracleAddress, err.Error()) + } + + if m.DealId <= 0 { + return sdkerrors.Wrapf(sdkerrors.ErrInvalidRequest, "dealId is greater than 0") + } + + if _, err := sdk.AccAddressFromBech32(m.ProviderAddress); err != nil { + return sdkerrors.Wrapf(sdkerrors.ErrInvalidRequest, "providerAddress is invalid. address: %s, error: %s", m.OracleAddress, err.Error()) + } + + if len(m.DataHash) == 0 { + return sdkerrors.Wrapf(sdkerrors.ErrInvalidRequest, "dataHash is empty") + } + + return nil +} diff --git a/x/datadeal/types/query.pb.go b/x/datadeal/types/query.pb.go index 5383ae05..b708a0d3 100644 --- a/x/datadeal/types/query.pb.go +++ b/x/datadeal/types/query.pb.go @@ -220,7 +220,7 @@ func (m *QueryDealResponse) GetDeal() *Deal { // QueryDealsRequest defines the request type for the Query/Deals RPC method. type QueryCertificates struct { - DealId int64 `protobuf:"varint,1,opt,name=deal_id,json=dealId,proto3" json:"deal_id,omitempty"` + DealId uint64 `protobuf:"varint,1,opt,name=deal_id,json=dealId,proto3" json:"deal_id,omitempty"` Pagination *query.PageRequest `protobuf:"bytes,2,opt,name=pagination,proto3" json:"pagination,omitempty"` } @@ -257,7 +257,7 @@ func (m *QueryCertificates) XXX_DiscardUnknown() { var xxx_messageInfo_QueryCertificates proto.InternalMessageInfo -func (m *QueryCertificates) GetDealId() int64 { +func (m *QueryCertificates) GetDealId() uint64 { if m != nil { return m.DealId } @@ -436,44 +436,44 @@ func init() { func init() { proto.RegisterFile("panacea/datadeal/v2/query.proto", fileDescriptor_4c7a445ecc4b9161) } var fileDescriptor_4c7a445ecc4b9161 = []byte{ - // 590 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x94, 0x4f, 0x6f, 0x12, 0x41, - 0x18, 0xc6, 0x19, 0x4a, 0xab, 0x1d, 0x7a, 0xd0, 0xd1, 0x44, 0xba, 0x36, 0x2b, 0xd9, 0x08, 0x6d, - 0x54, 0x66, 0x02, 0x3d, 0x79, 0x30, 0x26, 0x58, 0xb5, 0xc6, 0x8b, 0xee, 0x51, 0x13, 0x9b, 0x61, - 0x19, 0x97, 0x4d, 0x60, 0x67, 0xcb, 0x0c, 0xc4, 0xa6, 0xf6, 0xa2, 0x57, 0x0f, 0x26, 0x7e, 0x02, - 0xaf, 0xfd, 0x24, 0x1e, 0x9b, 0x78, 0xf1, 0xe0, 0xc1, 0x80, 0x1f, 0xc4, 0xec, 0xec, 0xb0, 0x2c, - 0x74, 0x29, 0xab, 0xf1, 0x06, 0xbc, 0xcf, 0xfb, 0x3e, 0xbf, 0xf7, 0xcf, 0x00, 0x6f, 0x05, 0xd4, - 0xa7, 0x0e, 0xa3, 0xa4, 0x4d, 0x25, 0x6d, 0x33, 0xda, 0x25, 0xc3, 0x06, 0x39, 0x1c, 0xb0, 0xfe, - 0x11, 0x0e, 0xfa, 0x5c, 0x72, 0x74, 0x4d, 0x0b, 0xf0, 0x44, 0x80, 0x87, 0x0d, 0xe3, 0xba, 0xcb, - 0x5d, 0xae, 0xe2, 0x24, 0xfc, 0x14, 0x49, 0x8d, 0x3b, 0x0e, 0x17, 0x3d, 0x2e, 0x48, 0x8b, 0x0a, - 0x16, 0xd5, 0x20, 0xc3, 0x7a, 0x8b, 0x49, 0x5a, 0x27, 0x01, 0x75, 0x3d, 0x9f, 0x4a, 0x8f, 0xfb, - 0x5a, 0xbb, 0xe5, 0x72, 0xee, 0x76, 0x19, 0xa1, 0x81, 0x47, 0xa8, 0xef, 0x73, 0xa9, 0x82, 0x42, - 0x47, 0xcd, 0x34, 0x2a, 0x65, 0x1e, 0xc5, 0x2b, 0x69, 0x71, 0x87, 0xf5, 0xa5, 0xf7, 0xd6, 0x73, - 0xa8, 0x64, 0x91, 0xcc, 0x7a, 0x0d, 0xaf, 0xbe, 0x0c, 0x31, 0xf6, 0x18, 0xed, 0x0a, 0x9b, 0x1d, - 0x0e, 0x98, 0x90, 0xe8, 0x09, 0x84, 0x53, 0x9a, 0x12, 0x28, 0x83, 0x9d, 0x62, 0xa3, 0x8a, 0x23, - 0x74, 0x1c, 0xa2, 0xe3, 0xa8, 0x7d, 0x8d, 0x8e, 0x5f, 0x50, 0x97, 0xe9, 0x5c, 0x3b, 0x91, 0x69, - 0x7d, 0x02, 0x10, 0x25, 0xab, 0x8b, 0x80, 0xfb, 0x82, 0xa1, 0x1a, 0x2c, 0x84, 0x40, 0x25, 0x50, - 0x5e, 0xd9, 0x29, 0x36, 0x36, 0x71, 0xca, 0xf8, 0x70, 0x98, 0x61, 0x2b, 0x19, 0x7a, 0x3a, 0x43, - 0x93, 0x57, 0x34, 0xdb, 0x4b, 0x69, 0x22, 0xaf, 0x19, 0x9c, 0xbb, 0xf0, 0x4a, 0x4c, 0x33, 0x69, - 0xf5, 0x06, 0xbc, 0x14, 0x9a, 0x1c, 0x78, 0x6d, 0xd5, 0x67, 0xc1, 0x5e, 0x0b, 0xbf, 0x3e, 0x6b, - 0x5b, 0xcd, 0xc4, 0x60, 0x52, 0xc8, 0x41, 0x06, 0x72, 0x4b, 0xea, 0x1a, 0x8f, 0xa6, 0x63, 0x17, - 0xf3, 0x8e, 0x2b, 0x13, 0xc7, 0xb9, 0xa9, 0xe7, 0xff, 0x79, 0xea, 0xa7, 0x00, 0x6e, 0x9e, 0xb3, - 0x8d, 0x5b, 0xd8, 0x83, 0x1b, 0x89, 0x2b, 0x10, 0x7a, 0x09, 0xe5, 0xd4, 0x56, 0x12, 0x05, 0xec, - 0x99, 0xac, 0xff, 0xb7, 0x93, 0x7d, 0xbd, 0x93, 0x84, 0xd5, 0xc2, 0x9d, 0xa0, 0x9b, 0x70, 0x3d, - 0xc4, 0x3b, 0xe8, 0x50, 0xd1, 0x51, 0xa6, 0xeb, 0xf6, 0xe5, 0xf0, 0x87, 0x7d, 0x2a, 0x3a, 0xd6, - 0x1b, 0x58, 0x9a, 0xaf, 0x14, 0x37, 0xdd, 0x84, 0xc5, 0x04, 0xbe, 0x5e, 0xdf, 0xf2, 0x9e, 0x93, - 0x49, 0x8d, 0x9f, 0x05, 0xb8, 0xaa, 0x0c, 0xd0, 0x7b, 0xb8, 0xaa, 0x0e, 0x1a, 0x55, 0x53, 0x2b, - 0x9c, 0x7b, 0x4f, 0xc6, 0xf6, 0x52, 0x5d, 0xc4, 0x69, 0x59, 0x1f, 0xbe, 0xff, 0xfe, 0x92, 0xdf, - 0x42, 0x06, 0x59, 0xf4, 0xba, 0x05, 0xfa, 0x08, 0x60, 0x21, 0xcc, 0x42, 0x95, 0x8b, 0xab, 0x4e, - 0xcc, 0xab, 0xcb, 0x64, 0xda, 0xfb, 0x9e, 0xf2, 0xae, 0xa2, 0xdb, 0x8b, 0xbd, 0xc9, 0xb1, 0xde, - 0xcb, 0x09, 0xfa, 0x0a, 0xe0, 0xc6, 0xcc, 0x59, 0x5f, 0x60, 0x93, 0xd4, 0x19, 0x38, 0x9b, 0x2e, - 0xc6, 0xba, 0xaf, 0xb0, 0x76, 0x51, 0x3d, 0x0b, 0x16, 0x99, 0x39, 0xd2, 0x53, 0x00, 0x8b, 0xc9, - 0xbb, 0xaa, 0x64, 0xb2, 0x36, 0x6a, 0x99, 0x64, 0x31, 0xe0, 0x63, 0x05, 0xf8, 0x10, 0x3d, 0xf8, - 0x6b, 0x40, 0x72, 0x1c, 0x5f, 0xf3, 0x49, 0xf3, 0xf9, 0xb7, 0x91, 0x09, 0xce, 0x46, 0x26, 0xf8, - 0x35, 0x32, 0xc1, 0xe7, 0xb1, 0x99, 0x3b, 0x1b, 0x9b, 0xb9, 0x1f, 0x63, 0x33, 0xf7, 0xaa, 0xee, - 0x7a, 0xb2, 0x33, 0x68, 0x61, 0x87, 0xf7, 0x48, 0x8f, 0xb5, 0xbd, 0x56, 0x97, 0x3b, 0x13, 0xaf, - 0x9a, 0xc3, 0xfb, 0x8c, 0xbc, 0x9b, 0x5a, 0xca, 0xa3, 0x80, 0x89, 0xd6, 0x9a, 0xfa, 0x73, 0xdf, - 0xfd, 0x13, 0x00, 0x00, 0xff, 0xff, 0xbb, 0xda, 0x99, 0xf8, 0xbb, 0x06, 0x00, 0x00, + // 588 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x94, 0x4f, 0x6f, 0x12, 0x4f, + 0x18, 0xc7, 0x19, 0x7e, 0xb4, 0x3f, 0x3b, 0xf4, 0xa0, 0xa3, 0x89, 0x74, 0x6d, 0x56, 0xb2, 0x11, + 0xda, 0xa8, 0xcc, 0x04, 0x7a, 0xf2, 0x60, 0x4c, 0xb0, 0x6a, 0x8d, 0x17, 0xdd, 0xa3, 0x26, 0x36, + 0xc3, 0x32, 0x2e, 0x9b, 0xc0, 0xce, 0x96, 0x19, 0x88, 0x4d, 0xed, 0x45, 0xaf, 0x1e, 0x4c, 0x7c, + 0x05, 0x5e, 0xfb, 0x4a, 0x3c, 0x36, 0xf1, 0xe2, 0xc1, 0x83, 0x01, 0x5f, 0x88, 0xd9, 0xd9, 0x61, + 0x19, 0xda, 0xa5, 0xa0, 0xf1, 0x06, 0x3c, 0xdf, 0xe7, 0xf9, 0x7e, 0x9e, 0x3f, 0x03, 0xbc, 0x19, + 0xd1, 0x90, 0x7a, 0x8c, 0x92, 0x36, 0x95, 0xb4, 0xcd, 0x68, 0x97, 0x0c, 0x1b, 0xe4, 0x60, 0xc0, + 0xfa, 0x87, 0x38, 0xea, 0x73, 0xc9, 0xd1, 0x55, 0x2d, 0xc0, 0x13, 0x01, 0x1e, 0x36, 0xac, 0x6b, + 0x3e, 0xf7, 0xb9, 0x8a, 0x93, 0xf8, 0x53, 0x22, 0xb5, 0x6e, 0x7b, 0x5c, 0xf4, 0xb8, 0x20, 0x2d, + 0x2a, 0x58, 0x52, 0x83, 0x0c, 0xeb, 0x2d, 0x26, 0x69, 0x9d, 0x44, 0xd4, 0x0f, 0x42, 0x2a, 0x03, + 0x1e, 0x6a, 0xed, 0xa6, 0xcf, 0xb9, 0xdf, 0x65, 0x84, 0x46, 0x01, 0xa1, 0x61, 0xc8, 0xa5, 0x0a, + 0x0a, 0x1d, 0xb5, 0xb3, 0xa8, 0x94, 0x79, 0x12, 0xaf, 0x64, 0xc5, 0x3d, 0xd6, 0x97, 0xc1, 0x9b, + 0xc0, 0xa3, 0x92, 0x25, 0x32, 0xe7, 0x15, 0xbc, 0xf2, 0x22, 0xc6, 0xd8, 0x65, 0xb4, 0x2b, 0x5c, + 0x76, 0x30, 0x60, 0x42, 0xa2, 0xc7, 0x10, 0x4e, 0x69, 0x4a, 0xa0, 0x0c, 0xb6, 0x8b, 0x8d, 0x2a, + 0x4e, 0xd0, 0x71, 0x8c, 0x8e, 0x93, 0xf6, 0x35, 0x3a, 0x7e, 0x4e, 0x7d, 0xa6, 0x73, 0x5d, 0x23, + 0xd3, 0xf9, 0x08, 0x20, 0x32, 0xab, 0x8b, 0x88, 0x87, 0x82, 0xa1, 0x1a, 0x2c, 0xc4, 0x40, 0x25, + 0x50, 0xfe, 0x6f, 0xbb, 0xd8, 0xd8, 0xc0, 0x19, 0xe3, 0xc3, 0x71, 0x86, 0xab, 0x64, 0xe8, 0xc9, + 0x0c, 0x4d, 0x5e, 0xd1, 0x6c, 0x2d, 0xa4, 0x49, 0xbc, 0x66, 0x70, 0xee, 0xc0, 0xcb, 0x29, 0xcd, + 0xa4, 0xd5, 0xeb, 0xf0, 0xff, 0xd8, 0x64, 0x3f, 0x68, 0xab, 0x3e, 0x0b, 0xee, 0x6a, 0xfc, 0xf5, + 0x69, 0xdb, 0x69, 0x1a, 0x83, 0xc9, 0x20, 0x07, 0x4b, 0x90, 0x3b, 0x52, 0xd7, 0x78, 0x38, 0x1d, + 0xbb, 0x98, 0xeb, 0x78, 0x66, 0xea, 0xf9, 0xbf, 0x9e, 0xfa, 0x09, 0x80, 0x1b, 0xe7, 0x6c, 0xd3, + 0x16, 0x76, 0xe1, 0xba, 0x71, 0x05, 0x42, 0x2f, 0xa1, 0x9c, 0xd9, 0x8a, 0x51, 0xc0, 0x9d, 0xc9, + 0xfa, 0x77, 0x3b, 0xd9, 0xd3, 0x3b, 0x31, 0xac, 0xe6, 0x4f, 0xe8, 0x06, 0x5c, 0x8b, 0xf1, 0xf6, + 0x3b, 0x54, 0x74, 0x94, 0xe9, 0x9a, 0x7b, 0x29, 0xfe, 0x61, 0x8f, 0x8a, 0x8e, 0xf3, 0x1a, 0x96, + 0xce, 0x56, 0x4a, 0x9b, 0x6e, 0xc2, 0xa2, 0x81, 0xaf, 0xd7, 0xb7, 0xb8, 0x67, 0x33, 0xa9, 0xf1, + 0xa3, 0x00, 0x57, 0x94, 0x01, 0x7a, 0x07, 0x57, 0xd4, 0x41, 0xa3, 0x6a, 0x66, 0x85, 0x73, 0xef, + 0xc9, 0xda, 0x5a, 0xa8, 0x4b, 0x38, 0x1d, 0xe7, 0xfd, 0xb7, 0x5f, 0x9f, 0xf3, 0x9b, 0xc8, 0x22, + 0xf3, 0x5e, 0xb7, 0x40, 0x1f, 0x00, 0x2c, 0xc4, 0x59, 0xa8, 0x72, 0x71, 0xd5, 0x89, 0x79, 0x75, + 0x91, 0x4c, 0x7b, 0xdf, 0x55, 0xde, 0x55, 0x74, 0x6b, 0xbe, 0x37, 0x39, 0xd2, 0x7b, 0x39, 0x46, + 0x5f, 0x00, 0x5c, 0x9f, 0x39, 0xeb, 0x0b, 0x6c, 0x4c, 0x9d, 0x85, 0x97, 0xd3, 0xa5, 0x58, 0xf7, + 0x14, 0xd6, 0x0e, 0xaa, 0x2f, 0x83, 0x45, 0x66, 0x8e, 0xf4, 0x04, 0xc0, 0xa2, 0x79, 0x57, 0x95, + 0xa5, 0xac, 0xad, 0xda, 0x52, 0xb2, 0x14, 0xf0, 0x91, 0x02, 0x7c, 0x80, 0xee, 0xff, 0x31, 0x20, + 0x39, 0x4a, 0xaf, 0xf9, 0xb8, 0xf9, 0xec, 0xeb, 0xc8, 0x06, 0xa7, 0x23, 0x1b, 0xfc, 0x1c, 0xd9, + 0xe0, 0xd3, 0xd8, 0xce, 0x9d, 0x8e, 0xed, 0xdc, 0xf7, 0xb1, 0x9d, 0x7b, 0x59, 0xf7, 0x03, 0xd9, + 0x19, 0xb4, 0xb0, 0xc7, 0x7b, 0xa4, 0xc7, 0xda, 0x41, 0xab, 0xcb, 0xbd, 0x89, 0x57, 0xcd, 0xe3, + 0x7d, 0x46, 0xde, 0x4e, 0x2d, 0xe5, 0x61, 0xc4, 0x44, 0x6b, 0x55, 0xfd, 0xb9, 0xef, 0xfc, 0x0e, + 0x00, 0x00, 0xff, 0xff, 0x35, 0x71, 0xd7, 0x5d, 0xbb, 0x06, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -1520,7 +1520,7 @@ func (m *QueryCertificates) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - m.DealId |= int64(b&0x7F) << shift + m.DealId |= uint64(b&0x7F) << shift if b < 0x80 { break } diff --git a/x/datadeal/types/query.pb.gw.go b/x/datadeal/types/query.pb.gw.go index 601ea23f..006286fc 100644 --- a/x/datadeal/types/query.pb.gw.go +++ b/x/datadeal/types/query.pb.gw.go @@ -141,7 +141,7 @@ func request_Query_Certificates_0(ctx context.Context, marshaler runtime.Marshal return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "deal_id") } - protoReq.DealId, err = runtime.Int64(val) + protoReq.DealId, err = runtime.Uint64(val) if err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "deal_id", err) @@ -175,7 +175,7 @@ func local_request_Query_Certificates_0(ctx context.Context, marshaler runtime.M return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "deal_id") } - protoReq.DealId, err = runtime.Int64(val) + protoReq.DealId, err = runtime.Uint64(val) if err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "deal_id", err) diff --git a/x/oracle/keeper/keeper.go b/x/oracle/keeper/keeper.go index b651643f..61e62021 100644 --- a/x/oracle/keeper/keeper.go +++ b/x/oracle/keeper/keeper.go @@ -1,6 +1,9 @@ package keeper import ( + "fmt" + + "github.com/btcsuite/btcd/btcec" "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/medibloc/panacea-core/v2/x/oracle/types" @@ -35,3 +38,40 @@ func NewKeeper( paramSpace: paramSpace, } } + +func (k Keeper) VerifySignature(ctx sdk.Context, msg codec.ProtoMarshaler, sigBz []byte) error { + bz, err := k.cdc.Marshal(msg) + if err != nil { + return err + } + + oraclePubKeyBz := k.GetParams(ctx).MustDecodeOraclePubKey() + oraclePubKey, err := btcec.ParsePubKey(oraclePubKeyBz, btcec.S256()) + if err != nil { + return err + } + + signature, err := btcec.ParseSignature(sigBz, btcec.S256()) + if err != nil { + return err + } + + if !signature.Verify(bz, oraclePubKey) { + return fmt.Errorf("failed to signature validation") + } + + return nil +} + +func (k Keeper) VerifyOracle(ctx sdk.Context, oracleAddress string) error { + _, err := sdk.AccAddressFromBech32(oracleAddress) + if err != nil { + return err + } + + // TODO Check is oracle registered? + + // TODO Check is registered oracle's uniqueId correct? + + return nil +} diff --git a/x/oracle/types/params.go b/x/oracle/types/params.go index e5fdb39b..581ea325 100644 --- a/x/oracle/types/params.go +++ b/x/oracle/types/params.go @@ -36,7 +36,7 @@ func (p *Params) ParamSetPairs() paramtypes.ParamSetPairs { } } -func (p Params) Validate() error { +func (p *Params) Validate() error { if err := validateOraclePublicKey(p.OraclePublicKey); err != nil { return err } @@ -50,6 +50,18 @@ func (p Params) Validate() error { return nil } +func (p Params) MustDecodeOraclePubKey() []byte { + return mustDecodeBase64Str(p.OraclePublicKey) +} + +func mustDecodeBase64Str(s string) []byte { + decoded, err := base64.StdEncoding.DecodeString(s) + if err != nil { + panic(err) + } + return decoded +} + func validateOraclePublicKey(i interface{}) error { pubKeyBase64, ok := i.(string) if !ok { From 6306f8972c890725402d38b0b63c17ba9af2411c Mon Sep 17 00:00:00 2001 From: gyuguen Date: Thu, 8 Dec 2022 09:19:45 +0900 Subject: [PATCH 10/20] fix --- app/app.go | 11 +++++++++++ x/datadeal/keeper/certificate.go | 14 +++++++------- 2 files changed, 18 insertions(+), 7 deletions(-) diff --git a/app/app.go b/app/app.go index abe7abf1..5bf725c3 100644 --- a/app/app.go +++ b/app/app.go @@ -9,6 +9,8 @@ import ( "strings" "github.com/cosmos/cosmos-sdk/x/authz" + oraclekeeper "github.com/medibloc/panacea-core/v2/x/oracle/keeper" + oracletypes "github.com/medibloc/panacea-core/v2/x/oracle/types" "github.com/CosmWasm/wasmd/x/wasm" wasmclient "github.com/CosmWasm/wasmd/x/wasm/client" @@ -271,6 +273,7 @@ type App struct { burnKeeper burnkeeper.Keeper wasmKeeper wasm.Keeper datadealKeeper datadealkeeper.Keeper + oracleKeeper oraclekeeper.Keeper // the module manager mm *module.Manager @@ -428,12 +431,20 @@ func New( app.BankKeeper, ) + app.oracleKeeper = *oraclekeeper.NewKeeper( + appCodec, + keys[oracletypes.StoreKey], + keys[oracletypes.MemStoreKey], + app.GetSubspace(oracletypes.ModuleName), + ) + app.datadealKeeper = *datadealkeeper.NewKeeper( appCodec, keys[datadealtypes.StoreKey], keys[datadealtypes.MemStoreKey], app.AccountKeeper, app.BankKeeper, + app.oracleKeeper, ) wasmDir := filepath.Join(homePath, wasm.ModuleName) diff --git a/x/datadeal/keeper/certificate.go b/x/datadeal/keeper/certificate.go index 4146775b..af6b4fd7 100644 --- a/x/datadeal/keeper/certificate.go +++ b/x/datadeal/keeper/certificate.go @@ -30,7 +30,7 @@ func (k Keeper) SubmitConsent(ctx sdk.Context, cert *types.Certificate) error { return sdkerrors.Wrapf(types.ErrSubmitConsent, err.Error()) } - if err := k.SetCertificate(ctx, unsignedCert); err != nil { + if err := k.SetCertificate(ctx, cert); err != nil { return sdkerrors.Wrapf(types.ErrSubmitConsent, err.Error()) } @@ -64,7 +64,7 @@ func (k Keeper) sendReward(ctx sdk.Context, deal *types.Deal, unsignedCert *type } providerAccAddr, err := sdk.AccAddressFromBech32(unsignedCert.ProviderAddress) - if err := k.SetCertificate(ctx, unsignedCert); err != nil { + if err != nil { return err } @@ -97,11 +97,11 @@ func (k Keeper) postProcessingOfDeal(ctx sdk.Context, deal *types.Deal) error { return nil } -func (k Keeper) SetCertificate(ctx sdk.Context, unsignedCert *types.UnsignedCertificate) error { +func (k Keeper) SetCertificate(ctx sdk.Context, cert *types.Certificate) error { store := ctx.KVStore(k.storeKey) - key := types.GetCertificateKey(unsignedCert.DealId, unsignedCert.DataHash) + key := types.GetCertificateKey(cert.UnsignedCertificate.DealId, cert.UnsignedCertificate.DataHash) - bz, err := k.cdc.MarshalLengthPrefixed(unsignedCert) + bz, err := k.cdc.MarshalLengthPrefixed(cert) if err != nil { return err @@ -112,7 +112,7 @@ func (k Keeper) SetCertificate(ctx sdk.Context, unsignedCert *types.UnsignedCert return nil } -func (k Keeper) GetCertificate(ctx sdk.Context, dealID uint64, dataHash string) (*types.UnsignedCertificate, error) { +func (k Keeper) GetCertificate(ctx sdk.Context, dealID uint64, dataHash string) (*types.Certificate, error) { store := ctx.KVStore(k.storeKey) key := types.GetCertificateKey(dealID, dataHash) @@ -121,7 +121,7 @@ func (k Keeper) GetCertificate(ctx sdk.Context, dealID uint64, dataHash string) return nil, types.ErrCertificateNotFound } - certificate := &types.UnsignedCertificate{} + certificate := &types.Certificate{} err := k.cdc.UnmarshalLengthPrefixed(bz, certificate) if err != nil { From d498a81517e977b4820322f24f76ea0e8b364737 Mon Sep 17 00:00:00 2001 From: gyuguen Date: Thu, 8 Dec 2022 09:30:56 +0900 Subject: [PATCH 11/20] fix --- x/datadeal/types/errors.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x/datadeal/types/errors.go b/x/datadeal/types/errors.go index 9cc10a8e..eee48b24 100644 --- a/x/datadeal/types/errors.go +++ b/x/datadeal/types/errors.go @@ -11,6 +11,6 @@ var ( ErrDealAlreadyExist = sdkerrors.Register(ModuleName, 2, "deal already exist") ErrDealNotFound = sdkerrors.Register(ModuleName, 3, "deal is not found") ErrCertificateNotFound = sdkerrors.Register(ModuleName, 4, "certificate is not found") - ErrGetCertificate = sdkerrors.Register(ModuleName, 5, "certificate is not found") + ErrGetCertificate = sdkerrors.Register(ModuleName, 5, "error while get certificate") ErrSubmitConsent = sdkerrors.Register(ModuleName, 6, "error while submit consent") ) From 100d34d938246e9bacba7e401f3c1fea6da61797 Mon Sep 17 00:00:00 2001 From: gyuguen Date: Thu, 8 Dec 2022 10:30:23 +0900 Subject: [PATCH 12/20] fix --- x/datadeal/keeper/certificate.go | 2 +- x/datadeal/types/deal.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/x/datadeal/keeper/certificate.go b/x/datadeal/keeper/certificate.go index af6b4fd7..0e3b9a6f 100644 --- a/x/datadeal/keeper/certificate.go +++ b/x/datadeal/keeper/certificate.go @@ -85,7 +85,7 @@ func (k Keeper) sendReward(ctx sdk.Context, deal *types.Deal, unsignedCert *type } func (k Keeper) postProcessingOfDeal(ctx sdk.Context, deal *types.Deal) error { - deal.IncrementCurNumData() + deal.IncreaseCurNumData() if deal.CurNumData == deal.MaxNumData { deal.Status = types.DEAL_STATUS_COMPLETED diff --git a/x/datadeal/types/deal.go b/x/datadeal/types/deal.go index be174a45..2b7a2707 100644 --- a/x/datadeal/types/deal.go +++ b/x/datadeal/types/deal.go @@ -63,6 +63,6 @@ func (m *Deal) GetPricePerData() sdk.Dec { return totalBudget.Quo(maxNumData).TruncateDec() } -func (m *Deal) IncrementCurNumData() { +func (m *Deal) IncreaseCurNumData() { m.CurNumData += 1 } From 26101ad563b4c31ce4c5b1fc132231ee0a2ce657 Mon Sep 17 00:00:00 2001 From: gyuguen Date: Thu, 8 Dec 2022 15:33:05 +0900 Subject: [PATCH 13/20] fix --- x/datadeal/types/message_deal.go | 50 +++++++++++++++++++++++++++++++- 1 file changed, 49 insertions(+), 1 deletion(-) diff --git a/x/datadeal/types/message_deal.go b/x/datadeal/types/message_deal.go index c84bbc0b..bf6ad20d 100644 --- a/x/datadeal/types/message_deal.go +++ b/x/datadeal/types/message_deal.go @@ -16,7 +16,21 @@ func (m *MsgCreateDeal) Type() string { } func (m *MsgCreateDeal) ValidateBasic() error { - + if len(m.DataSchema) == 0 { + return sdkerrors.Wrapf(sdkerrors.ErrInvalidRequest, "dataSchema is empty") + } + if m.MaxNumData <= 0 { + return sdkerrors.Wrapf(sdkerrors.ErrInvalidRequest, "MaxNumData should be bigger than 0") + } + if m.Budget == nil { + return sdkerrors.Wrapf(sdkerrors.ErrInvalidRequest, "budget is empty") + } + if !m.Budget.IsValid() { + return sdkerrors.Wrapf(sdkerrors.ErrInvalidRequest, "budget is not a valid Coin object") + } + if _, err := sdk.AccAddressFromBech32(m.ConsumerAddress); err != nil { + return sdkerrors.Wrapf(err, "consumer address is invalid. address: %s", m.ConsumerAddress) + } return nil } @@ -107,3 +121,37 @@ func (m *UnsignedCertificate) ValidateBasic() error { return nil } + +var _ sdk.Msg = &MsgDeactivateDeal{} + +func (m *MsgDeactivateDeal) Route() string { + return RouterKey +} + +func (m *MsgDeactivateDeal) Type() string { + return "DeactivateDeal" +} + +func (m *MsgDeactivateDeal) ValidateBasic() error { + if _, err := sdk.AccAddressFromBech32(m.RequesterAddress); err != nil { + return sdkerrors.Wrapf(sdkerrors.ErrInvalidRequest, "requesterAddress is invalid. address: %s, error: %s", m.RequesterAddress, err.Error()) + } + if m.DealId <= 0 { + return sdkerrors.Wrapf(sdkerrors.ErrInvalidRequest, "dealId is greater than 0") + } + + return nil +} + +func (m *MsgDeactivateDeal) GetSignBytes() []byte { + bz := ModuleCdc.MustMarshalJSON(m) + return sdk.MustSortJSON(bz) +} + +func (m *MsgDeactivateDeal) GetSigners() []sdk.AccAddress { + requesterAddress, err := sdk.AccAddressFromBech32(m.RequesterAddress) + if err != nil { + panic(err) + } + return []sdk.AccAddress{requesterAddress} +} From f3be8e1a7288abf41554ba2c39dd6db00a4510d7 Mon Sep 17 00:00:00 2001 From: gyuguen Date: Thu, 8 Dec 2022 15:50:58 +0900 Subject: [PATCH 14/20] fix --- types/testsuite/suite.go | 14 +++++++------- x/datadeal/keeper/certificate_test.go | 5 +---- 2 files changed, 8 insertions(+), 11 deletions(-) diff --git a/types/testsuite/suite.go b/types/testsuite/suite.go index 4aa25d2f..7c5d3728 100644 --- a/types/testsuite/suite.go +++ b/types/testsuite/suite.go @@ -213,6 +213,13 @@ func (suite *TestSuite) SetupTest() { ) suite.DIDMsgServer = didkeeper.NewMsgServerImpl(suite.DIDKeeper) + suite.OracleKeeper = *oraclekeeper.NewKeeper( + cdc.Marshaler, + keyParams[oracletypes.StoreKey], + memKeys[oracletypes.MemStoreKey], + paramsKeeper.Subspace(oracletypes.ModuleName), + ) + suite.DataDealKeeper = *datadealkeeper.NewKeeper( cdc.Marshaler, keyParams[datadealtypes.StoreKey], @@ -223,13 +230,6 @@ func (suite *TestSuite) SetupTest() { ) suite.DataDealMsgServer = datadealkeeper.NewMsgServerImpl(suite.DataDealKeeper) - suite.OracleKeeper = *oraclekeeper.NewKeeper( - cdc.Marshaler, - keyParams[oracletypes.StoreKey], - memKeys[oracletypes.MemStoreKey], - paramsKeeper.Subspace(oracletypes.ModuleName), - ) - suite.OracleMsgServer = oraclekeeper.NewMsgServerImpl(suite.OracleKeeper) } diff --git a/x/datadeal/keeper/certificate_test.go b/x/datadeal/keeper/certificate_test.go index 081b52bb..f270fe65 100644 --- a/x/datadeal/keeper/certificate_test.go +++ b/x/datadeal/keeper/certificate_test.go @@ -80,10 +80,7 @@ func (suite *certificateTestSuite) createSampleDeal(budgetAmount, maxNumData uin ConsumerAddress: suite.consumerAccAddr.String(), } - consumer, err := sdk.AccAddressFromBech32(msgCreateDeal.ConsumerAddress) - suite.Require().NoError(err) - - dealID, err := suite.DataDealKeeper.CreateDeal(suite.Ctx, consumer, msgCreateDeal) + dealID, err := suite.DataDealKeeper.CreateDeal(suite.Ctx, msgCreateDeal) suite.Require().NoError(err) return dealID From 47d1350cc41c777a550a568ea9123e26f178d3c7 Mon Sep 17 00:00:00 2001 From: gyuguen Date: Thu, 8 Dec 2022 15:54:32 +0900 Subject: [PATCH 15/20] fix --- x/datadeal/types/message_deal.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/x/datadeal/types/message_deal.go b/x/datadeal/types/message_deal.go index bf6ad20d..edaf9158 100644 --- a/x/datadeal/types/message_deal.go +++ b/x/datadeal/types/message_deal.go @@ -17,10 +17,10 @@ func (m *MsgCreateDeal) Type() string { func (m *MsgCreateDeal) ValidateBasic() error { if len(m.DataSchema) == 0 { - return sdkerrors.Wrapf(sdkerrors.ErrInvalidRequest, "dataSchema is empty") + return sdkerrors.Wrapf(sdkerrors.ErrInvalidRequest, "no data schema") } if m.MaxNumData <= 0 { - return sdkerrors.Wrapf(sdkerrors.ErrInvalidRequest, "MaxNumData should be bigger than 0") + return sdkerrors.Wrapf(sdkerrors.ErrInvalidRequest, "max num of data is negative number") } if m.Budget == nil { return sdkerrors.Wrapf(sdkerrors.ErrInvalidRequest, "budget is empty") @@ -29,7 +29,7 @@ func (m *MsgCreateDeal) ValidateBasic() error { return sdkerrors.Wrapf(sdkerrors.ErrInvalidRequest, "budget is not a valid Coin object") } if _, err := sdk.AccAddressFromBech32(m.ConsumerAddress); err != nil { - return sdkerrors.Wrapf(err, "consumer address is invalid. address: %s", m.ConsumerAddress) + return sdkerrors.Wrapf(sdkerrors.ErrInvalidAddress, "invalid consumer address (%s)", err) } return nil } From 97a018aea26ce21709247dfed7df231553ca53eb Mon Sep 17 00:00:00 2001 From: gyuguen Date: Thu, 8 Dec 2022 17:44:48 +0900 Subject: [PATCH 16/20] feat: apply oracle commission --- x/datadeal/keeper/certificate.go | 15 +++- x/datadeal/keeper/certificate_test.go | 104 +++++++++++++++++++++++++- x/oracle/keeper/keeper.go | 15 ++-- 3 files changed, 124 insertions(+), 10 deletions(-) diff --git a/x/datadeal/keeper/certificate.go b/x/datadeal/keeper/certificate.go index 0e3b9a6f..49bd7d15 100644 --- a/x/datadeal/keeper/certificate.go +++ b/x/datadeal/keeper/certificate.go @@ -75,12 +75,23 @@ func (k Keeper) sendReward(ctx sdk.Context, deal *types.Deal, unsignedCert *type return fmt.Errorf("not enough balance in deal") } - // TODO calculate oracle commission + oracle, err := k.oracleKeeper.GetOracle(ctx, unsignedCert.OracleAddress) + if err != nil { + return fmt.Errorf("failed to get oracle. %w", err) + } + oracleCommissionRate := oracle.OracleCommissionRate - providerReward := sdk.NewCoin(assets.MicroMedDenom, pricePerData.TruncateInt()) + oracleReward := sdk.NewCoin(assets.MicroMedDenom, pricePerData.Mul(oracleCommissionRate).TruncateInt()) + providerReward := sdk.NewCoin(assets.MicroMedDenom, pricePerData.Mul(sdk.OneDec().Sub(oracleCommissionRate)).TruncateInt()) if err := k.bankKeeper.SendCoins(ctx, dealAccAddr, providerAccAddr, sdk.NewCoins(providerReward)); err != nil { return fmt.Errorf("failed to send reward to provider. %w", err) } + + // We already do oracle address verification above. + oracleAccAddr, _ := sdk.AccAddressFromBech32(unsignedCert.OracleAddress) + if err := k.bankKeeper.SendCoins(ctx, dealAccAddr, oracleAccAddr, sdk.NewCoins(oracleReward)); err != nil { + return fmt.Errorf("failed to send reward to oracle. %w", err) + } return nil } diff --git a/x/datadeal/keeper/certificate_test.go b/x/datadeal/keeper/certificate_test.go index f270fe65..ad56c318 100644 --- a/x/datadeal/keeper/certificate_test.go +++ b/x/datadeal/keeper/certificate_test.go @@ -18,6 +18,8 @@ import ( type certificateTestSuite struct { dealTestSuite + uniqueID string + oracleAccPrivKey cryptotypes.PrivKey oracleAccPubKey cryptotypes.PubKey oracleAccAddr sdk.AccAddress @@ -42,6 +44,7 @@ func (suite *certificateTestSuite) BeforeTest(_, _ string) { suite.consumerAccAddr = sdk.AccAddress(secp256k1.GenPrivKey().PubKey().Address()) suite.defaultFunds = sdk.NewCoins(sdk.NewCoin(assets.MicroMedDenom, sdk.NewInt(10000000000))) + suite.uniqueID = "uniqueID" suite.oracleAccPrivKey = secp256k1.GenPrivKey() suite.oracleAccPubKey = suite.oracleAccPrivKey.PubKey() suite.oracleAccAddr = sdk.AccAddress(suite.oracleAccPubKey.Address()) @@ -60,7 +63,7 @@ func (suite *certificateTestSuite) BeforeTest(_, _ string) { suite.OracleKeeper.SetParams(suite.Ctx, oracletypes.Params{ OraclePublicKey: base64.StdEncoding.EncodeToString(suite.oraclePubKey.SerializeCompressed()), OraclePubKeyRemoteReport: "", - UniqueId: "", + UniqueId: suite.uniqueID, }) err := suite.DataDealKeeper.SetNextDealNumber(suite.Ctx, 1) @@ -86,12 +89,27 @@ func (suite *certificateTestSuite) createSampleDeal(budgetAmount, maxNumData uin return dealID } +func (suite *certificateTestSuite) storeSampleOracle(address, uniqueID string, commissionRate sdk.Dec) *oracletypes.Oracle { + oracle := &oracletypes.Oracle{ + OracleAddress: address, + UniqueId: uniqueID, + Endpoint: "https://my-validator.org", + OracleCommissionRate: commissionRate, + } + suite.OracleKeeper.SetOracle(suite.Ctx, oracle) + + return oracle +} + func (suite *certificateTestSuite) TestSubmitConsentSuccess() { budgetAmount := uint64(10000) dealID := suite.createSampleDeal(budgetAmount, 10) deal, err := suite.DataDealKeeper.GetDeal(suite.Ctx, dealID) suite.Require().NoError(err) + oracleCommissionRate := sdk.NewDecWithPrec(1, 1) // 10% + suite.storeSampleOracle(suite.oracleAccAddr.String(), suite.uniqueID, oracleCommissionRate) + unsignedCert := &types.UnsignedCertificate{ Cid: "cid", OracleAddress: suite.oracleAccAddr.String(), @@ -115,6 +133,9 @@ func (suite *certificateTestSuite) TestSubmitConsentSuccess() { providerBalance := suite.BankKeeper.GetBalance(suite.Ctx, suite.providerAccAddr, assets.MicroMedDenom) suite.Require().Equal(sdk.ZeroInt(), providerBalance.Amount) + oracleBalance := suite.BankKeeper.GetBalance(suite.Ctx, suite.oracleAccAddr, assets.MicroMedDenom) + suite.Require().Equal(sdk.ZeroInt(), oracleBalance.Amount) + dealAccAddr, err := sdk.AccAddressFromBech32(deal.Address) suite.Require().NoError(err) dealBalance := suite.BankKeeper.GetBalance(suite.Ctx, dealAccAddr, assets.MicroMedDenom) @@ -124,7 +145,10 @@ func (suite *certificateTestSuite) TestSubmitConsentSuccess() { suite.Require().NoError(err) providerBalance = suite.BankKeeper.GetBalance(suite.Ctx, suite.providerAccAddr, assets.MicroMedDenom) - suite.Require().Equal(sdk.NewInt(1000), providerBalance.Amount) + suite.Require().Equal(sdk.NewInt(900), providerBalance.Amount) + + oracleBalance = suite.BankKeeper.GetBalance(suite.Ctx, suite.oracleAccAddr, assets.MicroMedDenom) + suite.Require().Equal(sdk.NewInt(100), oracleBalance.Amount) dealAccAddr, err = sdk.AccAddressFromBech32(deal.Address) suite.Require().NoError(err) @@ -143,6 +167,9 @@ func (suite *certificateTestSuite) TestSubmitConsentChangeStatusComplete() { deal, err := suite.DataDealKeeper.GetDeal(suite.Ctx, dealID) suite.Require().NoError(err) + oracleCommissionRate := sdk.NewDecWithPrec(1, 1) // 10% + suite.storeSampleOracle(suite.oracleAccAddr.String(), suite.uniqueID, oracleCommissionRate) + unsignedCert := &types.UnsignedCertificate{ Cid: "cid", OracleAddress: suite.oracleAccAddr.String(), @@ -165,6 +192,9 @@ func (suite *certificateTestSuite) TestSubmitConsentChangeStatusComplete() { providerBalance := suite.BankKeeper.GetBalance(suite.Ctx, suite.providerAccAddr, assets.MicroMedDenom) suite.Require().Equal(sdk.ZeroInt(), providerBalance.Amount) + oracleBalance := suite.BankKeeper.GetBalance(suite.Ctx, suite.oracleAccAddr, assets.MicroMedDenom) + suite.Require().Equal(sdk.ZeroInt(), oracleBalance.Amount) + dealAccAddr, err := sdk.AccAddressFromBech32(deal.Address) suite.Require().NoError(err) dealBalance := suite.BankKeeper.GetBalance(suite.Ctx, dealAccAddr, assets.MicroMedDenom) @@ -174,7 +204,10 @@ func (suite *certificateTestSuite) TestSubmitConsentChangeStatusComplete() { suite.Require().NoError(err) providerBalance = suite.BankKeeper.GetBalance(suite.Ctx, suite.providerAccAddr, assets.MicroMedDenom) - suite.Require().Equal(sdk.NewInt(10000), providerBalance.Amount) + suite.Require().Equal(sdk.NewInt(9000), providerBalance.Amount) + + oracleBalance = suite.BankKeeper.GetBalance(suite.Ctx, suite.oracleAccAddr, assets.MicroMedDenom) + suite.Require().Equal(sdk.NewInt(1000), oracleBalance.Amount) dealAccAddr, err = sdk.AccAddressFromBech32(deal.Address) suite.Require().NoError(err) @@ -187,10 +220,72 @@ func (suite *certificateTestSuite) TestSubmitConsentChangeStatusComplete() { suite.Require().Equal(types.DEAL_STATUS_COMPLETED, deal.Status) } +func (suite *certificateTestSuite) TestSubmitConsentNotRegisteredOracle() { + budgetAmount := uint64(10000) + dealID := suite.createSampleDeal(budgetAmount, 1) + + unsignedCert := &types.UnsignedCertificate{ + Cid: "cid", + OracleAddress: suite.providerAccAddr.String(), + DealId: dealID, + ProviderAddress: suite.providerAccAddr.String(), + DataHash: suite.dataHash, + } + + unsignedCertBz, err := unsignedCert.Marshal() + suite.Require().NoError(err) + + sign, err := suite.oraclePrivKey.Sign(unsignedCertBz) + suite.Require().NoError(err) + + certificate := &types.Certificate{ + UnsignedCertificate: unsignedCert, + Signature: sign.Serialize(), + } + + err = suite.DataDealKeeper.SubmitConsent(suite.Ctx, certificate) + suite.Require().ErrorIs(err, types.ErrSubmitConsent) + suite.Require().ErrorContains(err, fmt.Sprintf("failed to oracle validation. address(%s)", suite.providerAccAddr.String())) +} + +func (suite *certificateTestSuite) TestSubmitConsentNotSameUniqueID() { + budgetAmount := uint64(10000) + dealID := suite.createSampleDeal(budgetAmount, 1) + + oracleCommissionRate := sdk.NewDecWithPrec(1, 1) // 10% + suite.storeSampleOracle(suite.oracleAccAddr.String(), "invalidUniqueID", oracleCommissionRate) + + unsignedCert := &types.UnsignedCertificate{ + Cid: "cid", + OracleAddress: suite.oracleAccAddr.String(), + DealId: dealID, + ProviderAddress: suite.providerAccAddr.String(), + DataHash: suite.dataHash, + } + + unsignedCertBz, err := unsignedCert.Marshal() + suite.Require().NoError(err) + + sign, err := suite.oraclePrivKey.Sign(unsignedCertBz) + suite.Require().NoError(err) + + certificate := &types.Certificate{ + UnsignedCertificate: unsignedCert, + Signature: sign.Serialize(), + } + + err = suite.DataDealKeeper.SubmitConsent(suite.Ctx, certificate) + suite.Require().ErrorIs(err, types.ErrSubmitConsent) + suite.Require().ErrorContains(err, "is not active an oracle.") +} + func (suite *certificateTestSuite) TestSubmitConsentInvalidSignature() { budgetAmount := uint64(10000) dealID := suite.createSampleDeal(budgetAmount, 1) + oracleCommissionRate := sdk.NewDecWithPrec(1, 1) // 10% + suite.storeSampleOracle(suite.oracleAccAddr.String(), suite.uniqueID, oracleCommissionRate) + unsignedCert := &types.UnsignedCertificate{ Cid: "cid", OracleAddress: suite.oracleAccAddr.String(), @@ -216,6 +311,9 @@ func (suite *certificateTestSuite) TestSubmitConsentInvalidSignature() { } func (suite *certificateTestSuite) TestSubmitConsentNotExistDeal() { + oracleCommissionRate := sdk.NewDecWithPrec(1, 1) // 10% + suite.storeSampleOracle(suite.oracleAccAddr.String(), suite.uniqueID, oracleCommissionRate) + unsignedCert := &types.UnsignedCertificate{ Cid: "cid", OracleAddress: suite.oracleAccAddr.String(), diff --git a/x/oracle/keeper/keeper.go b/x/oracle/keeper/keeper.go index 61e62021..630df05b 100644 --- a/x/oracle/keeper/keeper.go +++ b/x/oracle/keeper/keeper.go @@ -64,14 +64,19 @@ func (k Keeper) VerifySignature(ctx sdk.Context, msg codec.ProtoMarshaler, sigBz } func (k Keeper) VerifyOracle(ctx sdk.Context, oracleAddress string) error { - _, err := sdk.AccAddressFromBech32(oracleAddress) + oracle, err := k.GetOracle(ctx, oracleAddress) if err != nil { - return err + return fmt.Errorf("failed to oracle validation. address(%s) %w", oracleAddress, err) } - // TODO Check is oracle registered? - - // TODO Check is registered oracle's uniqueId correct? + activeUniqueID := k.GetParams(ctx).UniqueId + if activeUniqueID != oracle.UniqueId { + return fmt.Errorf("is not active an oracle. oracleAddress(%s), oracleUniqueID(%s), activeUniqueID(%s)", + oracle.OracleAddress, + oracle.UniqueId, + activeUniqueID, + ) + } return nil } From fec02e4707f772c7ada78e92414e0aa8d2ea5a30 Mon Sep 17 00:00:00 2001 From: gyuguen Date: Thu, 8 Dec 2022 17:59:39 +0900 Subject: [PATCH 17/20] fix --- x/datadeal/keeper/certificate.go | 19 ++++++------------- x/datadeal/keeper/certificate_test.go | 3 +-- x/oracle/keeper/keeper.go | 2 +- 3 files changed, 8 insertions(+), 16 deletions(-) diff --git a/x/datadeal/keeper/certificate.go b/x/datadeal/keeper/certificate.go index 0e3b9a6f..b089a034 100644 --- a/x/datadeal/keeper/certificate.go +++ b/x/datadeal/keeper/certificate.go @@ -11,7 +11,7 @@ import ( func (k Keeper) SubmitConsent(ctx sdk.Context, cert *types.Certificate) error { unsignedCert := cert.UnsignedCertificate - if err := k.oracleKeeper.VerifySignature(ctx, unsignedCert, cert.Signature); err != nil { + if err := k.oracleKeeper.VerifyOracleSignature(ctx, unsignedCert, cert.Signature); err != nil { return sdkerrors.Wrapf(types.ErrSubmitConsent, err.Error()) } @@ -26,8 +26,8 @@ func (k Keeper) SubmitConsent(ctx sdk.Context, cert *types.Certificate) error { return sdkerrors.Wrapf(types.ErrSubmitConsent, "deal status is not ACTIVE") } - if err := k.verifyExistCertificate(ctx, unsignedCert.DealId, unsignedCert.DataHash); err != nil { - return sdkerrors.Wrapf(types.ErrSubmitConsent, err.Error()) + if k.isProvidedCertificate(ctx, unsignedCert.DealId, unsignedCert.DataHash){ + return sdkerrors.Wrapf(types.ErrSubmitConsent, "already provided certificate") } if err := k.SetCertificate(ctx, cert); err != nil { @@ -45,16 +45,9 @@ func (k Keeper) SubmitConsent(ctx sdk.Context, cert *types.Certificate) error { return nil } -func (k Keeper) verifyExistCertificate(ctx sdk.Context, dealID uint64, dataHash string) error { - existUnsignedCert, err := k.GetCertificate(ctx, dealID, dataHash) - if err != types.ErrCertificateNotFound { - if existUnsignedCert != nil { - return fmt.Errorf("already exist certificate. dataHash: %s", dataHash) - } else { - return err - } - } - return nil +func (k Keeper) isProvidedCertificate(ctx sdk.Context, dealID uint64, dataHash string) bool { + store := ctx.KVStore(k.storeKey) + return store.Has(types.GetCertificateKey(dealID, dataHash)) } func (k Keeper) sendReward(ctx sdk.Context, deal *types.Deal, unsignedCert *types.UnsignedCertificate) error { diff --git a/x/datadeal/keeper/certificate_test.go b/x/datadeal/keeper/certificate_test.go index f270fe65..9d80bc6c 100644 --- a/x/datadeal/keeper/certificate_test.go +++ b/x/datadeal/keeper/certificate_test.go @@ -2,7 +2,6 @@ package keeper_test import ( "encoding/base64" - "fmt" "testing" "github.com/btcsuite/btcd/btcec" @@ -290,5 +289,5 @@ func (suite *certificateTestSuite) TestSubmitConsentExistSameCertificate() { } err = suite.DataDealKeeper.SubmitConsent(suite.Ctx, certificate) suite.Require().ErrorIs(err, types.ErrSubmitConsent) - suite.Require().ErrorContains(err, fmt.Sprintf("already exist certificate. dataHash: %s", suite.dataHash)) + suite.Require().ErrorContains(err, "already provided certificate") } diff --git a/x/oracle/keeper/keeper.go b/x/oracle/keeper/keeper.go index 61e62021..972e883f 100644 --- a/x/oracle/keeper/keeper.go +++ b/x/oracle/keeper/keeper.go @@ -39,7 +39,7 @@ func NewKeeper( } } -func (k Keeper) VerifySignature(ctx sdk.Context, msg codec.ProtoMarshaler, sigBz []byte) error { +func (k Keeper) VerifyOracleSignature(ctx sdk.Context, msg codec.ProtoMarshaler, sigBz []byte) error { bz, err := k.cdc.Marshal(msg) if err != nil { return err From 70098047d34b3d484c82b781ce9db5529246ac09 Mon Sep 17 00:00:00 2001 From: gyuguen Date: Thu, 8 Dec 2022 18:31:17 +0900 Subject: [PATCH 18/20] feat: added verify uniqueID of certificate --- proto/panacea/datadeal/v2/certificate.proto | 9 +- x/datadeal/keeper/certificate.go | 23 ++-- x/datadeal/keeper/certificate_test.go | 45 +++++++- x/datadeal/types/certificate.pb.go | 116 ++++++++++++++------ 4 files changed, 146 insertions(+), 47 deletions(-) diff --git a/proto/panacea/datadeal/v2/certificate.proto b/proto/panacea/datadeal/v2/certificate.proto index d1e857bc..1c067f60 100644 --- a/proto/panacea/datadeal/v2/certificate.proto +++ b/proto/panacea/datadeal/v2/certificate.proto @@ -15,8 +15,9 @@ message Certificate { // UnsignedCertificate defines a certificate information message UnsignedCertificate { string cid = 1; - string oracle_address = 2; - uint64 deal_id = 3; - string provider_address = 4; - string data_hash = 5; + string unique_id = 2; + string oracle_address = 3; + uint64 deal_id = 4; + string provider_address = 5; + string data_hash = 6; } \ No newline at end of file diff --git a/x/datadeal/keeper/certificate.go b/x/datadeal/keeper/certificate.go index 49bd7d15..a1039555 100644 --- a/x/datadeal/keeper/certificate.go +++ b/x/datadeal/keeper/certificate.go @@ -26,7 +26,7 @@ func (k Keeper) SubmitConsent(ctx sdk.Context, cert *types.Certificate) error { return sdkerrors.Wrapf(types.ErrSubmitConsent, "deal status is not ACTIVE") } - if err := k.verifyExistCertificate(ctx, unsignedCert.DealId, unsignedCert.DataHash); err != nil { + if err := k.verifyUnsignedCertificate(ctx, unsignedCert); err != nil { return sdkerrors.Wrapf(types.ErrSubmitConsent, err.Error()) } @@ -45,18 +45,23 @@ func (k Keeper) SubmitConsent(ctx sdk.Context, cert *types.Certificate) error { return nil } -func (k Keeper) verifyExistCertificate(ctx sdk.Context, dealID uint64, dataHash string) error { - existUnsignedCert, err := k.GetCertificate(ctx, dealID, dataHash) - if err != types.ErrCertificateNotFound { - if existUnsignedCert != nil { - return fmt.Errorf("already exist certificate. dataHash: %s", dataHash) - } else { - return err - } +func (k Keeper) verifyUnsignedCertificate(ctx sdk.Context, unsignedCert *types.UnsignedCertificate) error { + activeUniqueID := k.oracleKeeper.GetParams(ctx).UniqueId + if activeUniqueID != unsignedCert.UniqueId { + return fmt.Errorf("does not match active uniqueID. certificateUniqueID(%s) activeUniqueID(%s)", unsignedCert.UniqueId, activeUniqueID) + } + + if k.isProvidedCertificate(ctx, unsignedCert.DealId, unsignedCert.DataHash) { + return fmt.Errorf("already provided certificate") } return nil } +func (k Keeper) isProvidedCertificate(ctx sdk.Context, dealID uint64, dataHash string) bool { + store := ctx.KVStore(k.storeKey) + return store.Has(types.GetCertificateKey(dealID, dataHash)) +} + func (k Keeper) sendReward(ctx sdk.Context, deal *types.Deal, unsignedCert *types.UnsignedCertificate) error { dealAccAddr, err := sdk.AccAddressFromBech32(deal.GetAddress()) if err != nil { diff --git a/x/datadeal/keeper/certificate_test.go b/x/datadeal/keeper/certificate_test.go index ad56c318..e684339a 100644 --- a/x/datadeal/keeper/certificate_test.go +++ b/x/datadeal/keeper/certificate_test.go @@ -112,6 +112,7 @@ func (suite *certificateTestSuite) TestSubmitConsentSuccess() { unsignedCert := &types.UnsignedCertificate{ Cid: "cid", + UniqueId: suite.uniqueID, OracleAddress: suite.oracleAccAddr.String(), DealId: dealID, ProviderAddress: suite.providerAccAddr.String(), @@ -172,6 +173,7 @@ func (suite *certificateTestSuite) TestSubmitConsentChangeStatusComplete() { unsignedCert := &types.UnsignedCertificate{ Cid: "cid", + UniqueId: suite.uniqueID, OracleAddress: suite.oracleAccAddr.String(), DealId: dealID, ProviderAddress: suite.providerAccAddr.String(), @@ -226,6 +228,7 @@ func (suite *certificateTestSuite) TestSubmitConsentNotRegisteredOracle() { unsignedCert := &types.UnsignedCertificate{ Cid: "cid", + UniqueId: suite.uniqueID, OracleAddress: suite.providerAccAddr.String(), DealId: dealID, ProviderAddress: suite.providerAccAddr.String(), @@ -248,7 +251,7 @@ func (suite *certificateTestSuite) TestSubmitConsentNotRegisteredOracle() { suite.Require().ErrorContains(err, fmt.Sprintf("failed to oracle validation. address(%s)", suite.providerAccAddr.String())) } -func (suite *certificateTestSuite) TestSubmitConsentNotSameUniqueID() { +func (suite *certificateTestSuite) TestSubmitConsentNotSameUniqueIDOfOracle() { budgetAmount := uint64(10000) dealID := suite.createSampleDeal(budgetAmount, 1) @@ -257,6 +260,7 @@ func (suite *certificateTestSuite) TestSubmitConsentNotSameUniqueID() { unsignedCert := &types.UnsignedCertificate{ Cid: "cid", + UniqueId: suite.uniqueID, OracleAddress: suite.oracleAccAddr.String(), DealId: dealID, ProviderAddress: suite.providerAccAddr.String(), @@ -288,6 +292,7 @@ func (suite *certificateTestSuite) TestSubmitConsentInvalidSignature() { unsignedCert := &types.UnsignedCertificate{ Cid: "cid", + UniqueId: suite.uniqueID, OracleAddress: suite.oracleAccAddr.String(), DealId: dealID, ProviderAddress: suite.providerAccAddr.String(), @@ -316,6 +321,7 @@ func (suite *certificateTestSuite) TestSubmitConsentNotExistDeal() { unsignedCert := &types.UnsignedCertificate{ Cid: "cid", + UniqueId: suite.uniqueID, OracleAddress: suite.oracleAccAddr.String(), DealId: 1, ProviderAddress: suite.providerAccAddr.String(), @@ -343,6 +349,7 @@ func (suite *certificateTestSuite) TestSubmitConsentAlreadyDealStatusComplete() unsignedCert := &types.UnsignedCertificate{ Cid: "cid", + UniqueId: suite.uniqueID, OracleAddress: suite.oracleAccAddr.String(), DealId: 1, ProviderAddress: suite.providerAccAddr.String(), @@ -370,6 +377,7 @@ func (suite *certificateTestSuite) TestSubmitConsentExistSameCertificate() { unsignedCert := &types.UnsignedCertificate{ Cid: "cid", + UniqueId: suite.uniqueID, OracleAddress: suite.oracleAccAddr.String(), DealId: 1, ProviderAddress: suite.providerAccAddr.String(), @@ -388,5 +396,38 @@ func (suite *certificateTestSuite) TestSubmitConsentExistSameCertificate() { } err = suite.DataDealKeeper.SubmitConsent(suite.Ctx, certificate) suite.Require().ErrorIs(err, types.ErrSubmitConsent) - suite.Require().ErrorContains(err, fmt.Sprintf("already exist certificate. dataHash: %s", suite.dataHash)) + suite.Require().ErrorContains(err, "already provided certificate: error while submit consent") +} + +func (suite *certificateTestSuite) TestSubmitConsentNotSameUniqueIDOfCertificate() { + budgetAmount := uint64(10000) + dealID := suite.createSampleDeal(budgetAmount, 1) + + oracleCommissionRate := sdk.NewDecWithPrec(1, 1) // 10% + suite.storeSampleOracle(suite.oracleAccAddr.String(), suite.uniqueID, oracleCommissionRate) + + invalidUniqueID := "invalidUniqueID" + unsignedCert := &types.UnsignedCertificate{ + Cid: "cid", + UniqueId: invalidUniqueID, + OracleAddress: suite.oracleAccAddr.String(), + DealId: dealID, + ProviderAddress: suite.providerAccAddr.String(), + DataHash: suite.dataHash, + } + + unsignedCertBz, err := unsignedCert.Marshal() + suite.Require().NoError(err) + + sign, err := suite.oraclePrivKey.Sign(unsignedCertBz) + suite.Require().NoError(err) + + certificate := &types.Certificate{ + UnsignedCertificate: unsignedCert, + Signature: sign.Serialize(), + } + + err = suite.DataDealKeeper.SubmitConsent(suite.Ctx, certificate) + suite.Require().ErrorIs(err, types.ErrSubmitConsent) + suite.Require().ErrorContains(err, fmt.Sprintf("does not match active uniqueID. certificateUniqueID(%s) activeUniqueID(%s)", invalidUniqueID, suite.uniqueID)) } diff --git a/x/datadeal/types/certificate.pb.go b/x/datadeal/types/certificate.pb.go index 912fdbc0..13f85a17 100644 --- a/x/datadeal/types/certificate.pb.go +++ b/x/datadeal/types/certificate.pb.go @@ -79,10 +79,11 @@ func (m *Certificate) GetSignature() []byte { // UnsignedCertificate defines a certificate information type UnsignedCertificate struct { Cid string `protobuf:"bytes,1,opt,name=cid,proto3" json:"cid,omitempty"` - OracleAddress string `protobuf:"bytes,2,opt,name=oracle_address,json=oracleAddress,proto3" json:"oracle_address,omitempty"` - DealId uint64 `protobuf:"varint,3,opt,name=deal_id,json=dealId,proto3" json:"deal_id,omitempty"` - ProviderAddress string `protobuf:"bytes,4,opt,name=provider_address,json=providerAddress,proto3" json:"provider_address,omitempty"` - DataHash string `protobuf:"bytes,5,opt,name=data_hash,json=dataHash,proto3" json:"data_hash,omitempty"` + UniqueId string `protobuf:"bytes,2,opt,name=unique_id,json=uniqueId,proto3" json:"unique_id,omitempty"` + OracleAddress string `protobuf:"bytes,3,opt,name=oracle_address,json=oracleAddress,proto3" json:"oracle_address,omitempty"` + DealId uint64 `protobuf:"varint,4,opt,name=deal_id,json=dealId,proto3" json:"deal_id,omitempty"` + ProviderAddress string `protobuf:"bytes,5,opt,name=provider_address,json=providerAddress,proto3" json:"provider_address,omitempty"` + DataHash string `protobuf:"bytes,6,opt,name=data_hash,json=dataHash,proto3" json:"data_hash,omitempty"` } func (m *UnsignedCertificate) Reset() { *m = UnsignedCertificate{} } @@ -125,6 +126,13 @@ func (m *UnsignedCertificate) GetCid() string { return "" } +func (m *UnsignedCertificate) GetUniqueId() string { + if m != nil { + return m.UniqueId + } + return "" +} + func (m *UnsignedCertificate) GetOracleAddress() string { if m != nil { return m.OracleAddress @@ -163,28 +171,29 @@ func init() { } var fileDescriptor_e90678e908dbabdd = []byte{ - // 337 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x6c, 0x91, 0x4f, 0x4f, 0xc2, 0x30, - 0x18, 0x87, 0xa9, 0x20, 0xba, 0xe2, 0x1f, 0x52, 0x48, 0x5c, 0xd0, 0x34, 0x84, 0x84, 0x64, 0x1e, - 0x5c, 0x23, 0x7e, 0x02, 0xf5, 0xa2, 0xf1, 0xb6, 0xc4, 0x8b, 0x1e, 0x96, 0xd2, 0xd6, 0xad, 0x09, - 0xd0, 0xa5, 0xeb, 0x88, 0x7e, 0x03, 0x8f, 0x7e, 0x13, 0xbf, 0x86, 0x47, 0x8e, 0x1e, 0x0d, 0x7c, - 0x11, 0xd3, 0x02, 0x42, 0xe2, 0x6e, 0xdd, 0xd3, 0xdf, 0xfb, 0xbc, 0xef, 0xfa, 0xc2, 0x7e, 0x46, - 0x27, 0x94, 0x09, 0x4a, 0x38, 0x35, 0x94, 0x0b, 0x3a, 0x22, 0xd3, 0x01, 0x61, 0x42, 0x1b, 0xf9, - 0x22, 0x19, 0x35, 0x22, 0xcc, 0xb4, 0x32, 0x0a, 0xb5, 0x56, 0xb1, 0x70, 0x1d, 0x0b, 0xa7, 0x83, - 0x4e, 0x3b, 0x51, 0x89, 0x72, 0xf7, 0xc4, 0x9e, 0x96, 0xd1, 0x0e, 0x2e, 0x33, 0xba, 0x12, 0x77, - 0xdf, 0x7b, 0x07, 0xb0, 0x71, 0xbb, 0x69, 0x80, 0x9e, 0x61, 0xbb, 0x98, 0xe4, 0x32, 0x99, 0x08, - 0x1e, 0x6f, 0x35, 0xf6, 0x41, 0x17, 0x04, 0x8d, 0x41, 0x10, 0x96, 0x74, 0x0e, 0x1f, 0x57, 0x05, - 0x5b, 0x9e, 0xa8, 0x55, 0xfc, 0x87, 0xe8, 0x0c, 0x7a, 0x16, 0x52, 0x53, 0x68, 0xe1, 0xef, 0x74, - 0x41, 0x70, 0x10, 0x6d, 0x40, 0xef, 0x13, 0xc0, 0x56, 0x89, 0x0a, 0x35, 0x61, 0x95, 0x49, 0xee, - 0x26, 0xf0, 0x22, 0x7b, 0x44, 0x7d, 0x78, 0xa4, 0x34, 0x65, 0x23, 0x11, 0x53, 0xce, 0xb5, 0xc8, - 0x73, 0x27, 0xf3, 0xa2, 0xc3, 0x25, 0xbd, 0x5e, 0x42, 0x74, 0x02, 0xf7, 0xec, 0x88, 0xb1, 0xe4, - 0x7e, 0xb5, 0x0b, 0x82, 0x5a, 0x54, 0xb7, 0x9f, 0xf7, 0x1c, 0x9d, 0xc3, 0x66, 0xa6, 0xd5, 0x54, - 0x72, 0xa1, 0xff, 0x0c, 0x35, 0x67, 0x38, 0x5e, 0xf3, 0xb5, 0xe3, 0x14, 0x7a, 0xf6, 0x57, 0xe3, - 0x94, 0xe6, 0xa9, 0xbf, 0xeb, 0x32, 0xfb, 0x16, 0xdc, 0xd1, 0x3c, 0xbd, 0x79, 0xf8, 0x9a, 0x63, - 0x30, 0x9b, 0x63, 0xf0, 0x33, 0xc7, 0xe0, 0x63, 0x81, 0x2b, 0xb3, 0x05, 0xae, 0x7c, 0x2f, 0x70, - 0xe5, 0xe9, 0x32, 0x91, 0x26, 0x2d, 0x86, 0x21, 0x53, 0x63, 0x32, 0x16, 0x5c, 0x0e, 0x47, 0x8a, - 0x91, 0xd5, 0xdb, 0x5d, 0x30, 0xa5, 0x05, 0x79, 0xdd, 0x6c, 0xc4, 0xbc, 0x65, 0x22, 0x1f, 0xd6, - 0xdd, 0x42, 0xae, 0x7e, 0x03, 0x00, 0x00, 0xff, 0xff, 0xc4, 0x19, 0x47, 0xaf, 0x04, 0x02, 0x00, + // 353 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x6c, 0x91, 0x4f, 0x4f, 0xfa, 0x30, + 0x18, 0xc7, 0xe9, 0x0f, 0x7e, 0xe8, 0x8a, 0x7f, 0x48, 0x21, 0x71, 0x01, 0xb3, 0x10, 0x12, 0x92, + 0x79, 0x70, 0x8d, 0xf8, 0x0a, 0xd4, 0x8b, 0xc4, 0xdb, 0x12, 0x2f, 0x7a, 0x58, 0x4a, 0x5b, 0xb7, + 0x26, 0xb0, 0xce, 0xae, 0x23, 0xfa, 0x0e, 0x3c, 0xfa, 0xb2, 0x3c, 0x78, 0xe0, 0xe8, 0xd1, 0xc0, + 0x1b, 0x31, 0xed, 0x40, 0x48, 0xe4, 0xd6, 0x7e, 0xfa, 0xed, 0xe7, 0x79, 0xf2, 0x3c, 0x70, 0x90, + 0x91, 0x94, 0x50, 0x4e, 0x30, 0x23, 0x9a, 0x30, 0x4e, 0x26, 0x78, 0x36, 0xc4, 0x94, 0x2b, 0x2d, + 0x9e, 0x04, 0x25, 0x9a, 0x07, 0x99, 0x92, 0x5a, 0xa2, 0xd6, 0x2a, 0x16, 0xac, 0x63, 0xc1, 0x6c, + 0xd8, 0x69, 0xc7, 0x32, 0x96, 0xf6, 0x1d, 0x9b, 0x53, 0x19, 0xed, 0x78, 0xbb, 0x8c, 0xf6, 0x8b, + 0x7d, 0xef, 0xbf, 0x01, 0xd8, 0xb8, 0xd9, 0x14, 0x40, 0x8f, 0xb0, 0x5d, 0xa4, 0xb9, 0x88, 0x53, + 0xce, 0xa2, 0xad, 0xc2, 0x2e, 0xe8, 0x01, 0xbf, 0x31, 0xf4, 0x83, 0x1d, 0x95, 0x83, 0xfb, 0xd5, + 0x87, 0x2d, 0x4f, 0xd8, 0x2a, 0xfe, 0x42, 0x74, 0x0a, 0x1d, 0x03, 0x89, 0x2e, 0x14, 0x77, 0xff, + 0xf5, 0x80, 0x7f, 0x10, 0x6e, 0x40, 0xff, 0x13, 0xc0, 0xd6, 0x0e, 0x15, 0x6a, 0xc2, 0x2a, 0x15, + 0xcc, 0x76, 0xe0, 0x84, 0xe6, 0x88, 0xba, 0xd0, 0x29, 0x52, 0xf1, 0x5c, 0xf0, 0x48, 0x30, 0xeb, + 0x71, 0xc2, 0xfd, 0x12, 0x8c, 0x18, 0x1a, 0xc0, 0x23, 0xa9, 0x08, 0x9d, 0xf0, 0x88, 0x30, 0xa6, + 0x78, 0x9e, 0xbb, 0x55, 0x9b, 0x38, 0x2c, 0xe9, 0x55, 0x09, 0xd1, 0x09, 0xdc, 0x33, 0xfd, 0x1b, + 0x43, 0xad, 0x07, 0xfc, 0x5a, 0x58, 0x37, 0xd7, 0x11, 0x43, 0x67, 0xb0, 0x99, 0x29, 0x39, 0x13, + 0x8c, 0xab, 0x5f, 0xc3, 0x7f, 0x6b, 0x38, 0x5e, 0xf3, 0xb5, 0xa3, 0x0b, 0x1d, 0x33, 0x87, 0x28, + 0x21, 0x79, 0xe2, 0xd6, 0xcb, 0x3e, 0x0c, 0xb8, 0x25, 0x79, 0x72, 0x7d, 0xf7, 0xb1, 0xf0, 0xc0, + 0x7c, 0xe1, 0x81, 0xef, 0x85, 0x07, 0xde, 0x97, 0x5e, 0x65, 0xbe, 0xf4, 0x2a, 0x5f, 0x4b, 0xaf, + 0xf2, 0x70, 0x11, 0x0b, 0x9d, 0x14, 0xe3, 0x80, 0xca, 0x29, 0x9e, 0x72, 0x26, 0xc6, 0x13, 0x49, + 0xf1, 0x6a, 0xb0, 0xe7, 0x54, 0x2a, 0x8e, 0x5f, 0x36, 0xeb, 0xd2, 0xaf, 0x19, 0xcf, 0xc7, 0x75, + 0xbb, 0xad, 0xcb, 0x9f, 0x00, 0x00, 0x00, 0xff, 0xff, 0x9e, 0x8d, 0x99, 0x75, 0x21, 0x02, 0x00, 0x00, } @@ -255,25 +264,32 @@ func (m *UnsignedCertificate) MarshalToSizedBuffer(dAtA []byte) (int, error) { copy(dAtA[i:], m.DataHash) i = encodeVarintCertificate(dAtA, i, uint64(len(m.DataHash))) i-- - dAtA[i] = 0x2a + dAtA[i] = 0x32 } if len(m.ProviderAddress) > 0 { i -= len(m.ProviderAddress) copy(dAtA[i:], m.ProviderAddress) i = encodeVarintCertificate(dAtA, i, uint64(len(m.ProviderAddress))) i-- - dAtA[i] = 0x22 + dAtA[i] = 0x2a } if m.DealId != 0 { i = encodeVarintCertificate(dAtA, i, uint64(m.DealId)) i-- - dAtA[i] = 0x18 + dAtA[i] = 0x20 } if len(m.OracleAddress) > 0 { i -= len(m.OracleAddress) copy(dAtA[i:], m.OracleAddress) i = encodeVarintCertificate(dAtA, i, uint64(len(m.OracleAddress))) i-- + dAtA[i] = 0x1a + } + if len(m.UniqueId) > 0 { + i -= len(m.UniqueId) + copy(dAtA[i:], m.UniqueId) + i = encodeVarintCertificate(dAtA, i, uint64(len(m.UniqueId))) + i-- dAtA[i] = 0x12 } if len(m.Cid) > 0 { @@ -324,6 +340,10 @@ func (m *UnsignedCertificate) Size() (n int) { if l > 0 { n += 1 + l + sovCertificate(uint64(l)) } + l = len(m.UniqueId) + if l > 0 { + n += 1 + l + sovCertificate(uint64(l)) + } l = len(m.OracleAddress) if l > 0 { n += 1 + l + sovCertificate(uint64(l)) @@ -530,6 +550,38 @@ func (m *UnsignedCertificate) Unmarshal(dAtA []byte) error { m.Cid = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field UniqueId", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCertificate + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthCertificate + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthCertificate + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.UniqueId = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: if wireType != 2 { return fmt.Errorf("proto: wrong wireType = %d for field OracleAddress", wireType) } @@ -561,7 +613,7 @@ func (m *UnsignedCertificate) Unmarshal(dAtA []byte) error { } m.OracleAddress = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex - case 3: + case 4: if wireType != 0 { return fmt.Errorf("proto: wrong wireType = %d for field DealId", wireType) } @@ -580,7 +632,7 @@ func (m *UnsignedCertificate) Unmarshal(dAtA []byte) error { break } } - case 4: + case 5: if wireType != 2 { return fmt.Errorf("proto: wrong wireType = %d for field ProviderAddress", wireType) } @@ -612,7 +664,7 @@ func (m *UnsignedCertificate) Unmarshal(dAtA []byte) error { } m.ProviderAddress = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex - case 5: + case 6: if wireType != 2 { return fmt.Errorf("proto: wrong wireType = %d for field DataHash", wireType) } From 88a34c13ba438082cb475421b06effcb5b5242ca Mon Sep 17 00:00:00 2001 From: gyuguen Date: Fri, 9 Dec 2022 10:47:10 +0900 Subject: [PATCH 19/20] added test code --- x/datadeal/types/certificate.go | 50 ++++++++ x/datadeal/types/message_deal.go | 42 +------ x/datadeal/types/message_deal_test.go | 166 ++++++++++++++++++++++++++ 3 files changed, 217 insertions(+), 41 deletions(-) create mode 100644 x/datadeal/types/certificate.go create mode 100644 x/datadeal/types/message_deal_test.go diff --git a/x/datadeal/types/certificate.go b/x/datadeal/types/certificate.go new file mode 100644 index 00000000..e7af9921 --- /dev/null +++ b/x/datadeal/types/certificate.go @@ -0,0 +1,50 @@ +package types + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" +) + +func (m *Certificate) ValidateBasic() error { + if m.UnsignedCertificate == nil { + return sdkerrors.Wrapf(sdkerrors.ErrInvalidRequest, "unsignedCertificate is empty") + } + + if err := m.UnsignedCertificate.ValidateBasic(); err != nil { + return sdkerrors.Wrapf(err, "failed to validation unsignedCertificate") + } + + if m.Signature == nil { + return sdkerrors.Wrapf(sdkerrors.ErrInvalidRequest, "signature is empty") + } + + return nil +} + +func (m *UnsignedCertificate) ValidateBasic() error { + if len(m.Cid) == 0 { + return sdkerrors.Wrapf(sdkerrors.ErrInvalidRequest, "cid is empty") + } + + if len(m.UniqueId) == 0 { + return sdkerrors.Wrapf(sdkerrors.ErrInvalidRequest, "uniqueId is empty") + } + + if _, err := sdk.AccAddressFromBech32(m.OracleAddress); err != nil { + return sdkerrors.Wrapf(sdkerrors.ErrInvalidRequest, "oracleAddress is invalid. address: %s, error: %s", m.OracleAddress, err.Error()) + } + + if m.DealId <= 0 { + return sdkerrors.Wrapf(sdkerrors.ErrInvalidRequest, "dealId is greater than 0") + } + + if _, err := sdk.AccAddressFromBech32(m.ProviderAddress); err != nil { + return sdkerrors.Wrapf(sdkerrors.ErrInvalidRequest, "providerAddress is invalid. address: %s, error: %s", m.OracleAddress, err.Error()) + } + + if len(m.DataHash) == 0 { + return sdkerrors.Wrapf(sdkerrors.ErrInvalidRequest, "dataHash is empty") + } + + return nil +} diff --git a/x/datadeal/types/message_deal.go b/x/datadeal/types/message_deal.go index edaf9158..609e29f1 100644 --- a/x/datadeal/types/message_deal.go +++ b/x/datadeal/types/message_deal.go @@ -29,7 +29,7 @@ func (m *MsgCreateDeal) ValidateBasic() error { return sdkerrors.Wrapf(sdkerrors.ErrInvalidRequest, "budget is not a valid Coin object") } if _, err := sdk.AccAddressFromBech32(m.ConsumerAddress); err != nil { - return sdkerrors.Wrapf(sdkerrors.ErrInvalidAddress, "invalid consumer address (%s)", err) + return sdkerrors.Wrapf(sdkerrors.ErrInvalidAddress, "invalid consumer address. %v", err) } return nil } @@ -82,46 +82,6 @@ func (m *MsgSubmitConsent) GetSigners() []sdk.AccAddress { return []sdk.AccAddress{oracleAddress} } -func (m *Certificate) ValidateBasic() error { - if m.UnsignedCertificate == nil { - return sdkerrors.Wrapf(sdkerrors.ErrInvalidRequest, "unsignedCertificate is empty") - } - - if err := m.UnsignedCertificate.ValidateBasic(); err != nil { - return sdkerrors.Wrapf(err, "failed to validation unsignedCertificate") - } - - if m.Signature == nil { - return sdkerrors.Wrapf(sdkerrors.ErrInvalidRequest, "signature is empty") - } - - return nil -} - -func (m *UnsignedCertificate) ValidateBasic() error { - if len(m.Cid) == 0 { - return sdkerrors.Wrapf(sdkerrors.ErrInvalidRequest, "cid is empty") - } - - if _, err := sdk.AccAddressFromBech32(m.OracleAddress); err != nil { - return sdkerrors.Wrapf(sdkerrors.ErrInvalidRequest, "oracleAddress is invalid. address: %s, error: %s", m.OracleAddress, err.Error()) - } - - if m.DealId <= 0 { - return sdkerrors.Wrapf(sdkerrors.ErrInvalidRequest, "dealId is greater than 0") - } - - if _, err := sdk.AccAddressFromBech32(m.ProviderAddress); err != nil { - return sdkerrors.Wrapf(sdkerrors.ErrInvalidRequest, "providerAddress is invalid. address: %s, error: %s", m.OracleAddress, err.Error()) - } - - if len(m.DataHash) == 0 { - return sdkerrors.Wrapf(sdkerrors.ErrInvalidRequest, "dataHash is empty") - } - - return nil -} - var _ sdk.Msg = &MsgDeactivateDeal{} func (m *MsgDeactivateDeal) Route() string { diff --git a/x/datadeal/types/message_deal_test.go b/x/datadeal/types/message_deal_test.go new file mode 100644 index 00000000..c7115ebb --- /dev/null +++ b/x/datadeal/types/message_deal_test.go @@ -0,0 +1,166 @@ +package types + +import ( + "testing" + + "github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1" + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + "github.com/medibloc/panacea-core/v2/types/assets" + "github.com/stretchr/testify/require" +) + +func TestMsgCreateDealValidateBasic(t *testing.T) { + consumerAddress := sdk.AccAddress(secp256k1.GenPrivKey().PubKey().Address()).String() + budget := sdk.NewCoin(assets.MicroMedDenom, sdk.NewInt(10000)) + + msg := &MsgCreateDeal{ + DataSchema: []string{"https://jsonld.com"}, + Budget: &budget, + MaxNumData: 10, + ConsumerAddress: consumerAddress, + } + + err := msg.ValidateBasic() + require.NoError(t, err) +} + +func TestMsgCreateDealValidateBasicEmptyValue(t *testing.T) { + consumerAddress := sdk.AccAddress(secp256k1.GenPrivKey().PubKey().Address()).String() + budget := sdk.NewCoin(assets.MicroMedDenom, sdk.NewInt(10000)) + + msg := &MsgCreateDeal{ + DataSchema: []string{}, + Budget: &budget, + MaxNumData: 10, + ConsumerAddress: consumerAddress, + } + + err := msg.ValidateBasic() + require.ErrorIs(t, err, sdkerrors.ErrInvalidRequest) + require.ErrorContains(t, err, "no data schema") + + msg.DataSchema = []string{"https://jsonld.com"} + msg.MaxNumData = 0 + err = msg.ValidateBasic() + require.ErrorIs(t, err, sdkerrors.ErrInvalidRequest) + require.ErrorContains(t, err, "max num of data is negative number") + + msg.MaxNumData = 10 + msg.Budget = nil + err = msg.ValidateBasic() + require.ErrorIs(t, err, sdkerrors.ErrInvalidRequest) + require.ErrorContains(t, err, "budget is empty") + + msg.Budget = &sdk.Coin{ + Denom: assets.MicroMedDenom, Amount: sdk.NewInt(-1), + } + err = msg.ValidateBasic() + require.ErrorIs(t, err, sdkerrors.ErrInvalidRequest) + require.ErrorContains(t, err, "budget is not a valid Coin object") + + msg.Budget = &budget + msg.ConsumerAddress = "" + err = msg.ValidateBasic() + require.ErrorIs(t, err, sdkerrors.ErrInvalidAddress) + require.ErrorContains(t, err, "invalid consumer address") +} + +func TestMsgSubmitConsentValidateBasic(t *testing.T) { + oracleAddress := sdk.AccAddress(secp256k1.GenPrivKey().PubKey().Address()).String() + providerAddress := sdk.AccAddress(secp256k1.GenPrivKey().PubKey().Address()).String() + msg := &MsgSubmitConsent{ + Certificate: &Certificate{ + UnsignedCertificate: &UnsignedCertificate{ + Cid: "cid", + UniqueId: "uniqueID", + OracleAddress: oracleAddress, + DealId: 1, + ProviderAddress: providerAddress, + DataHash: "dataHash", + }, + Signature: []byte("signature"), + }, + } + + err := msg.ValidateBasic() + require.NoError(t, err) +} + +func TestMsgSubmitConsentValidateBasicEmptyValue(t *testing.T) { + oracleAddress := sdk.AccAddress(secp256k1.GenPrivKey().PubKey().Address()).String() + providerAddress := sdk.AccAddress(secp256k1.GenPrivKey().PubKey().Address()).String() + + msg := &MsgSubmitConsent{} + + err := msg.ValidateBasic() + require.ErrorIs(t, err, sdkerrors.ErrInvalidRequest) + require.ErrorContains(t, err, "certificate is empty") + + msg.Certificate = &Certificate{} + err = msg.ValidateBasic() + require.ErrorIs(t, err, sdkerrors.ErrInvalidRequest) + require.ErrorContains(t, err, "unsignedCertificate is empty") + + msg.Certificate.UnsignedCertificate = &UnsignedCertificate{} + err = msg.ValidateBasic() + require.ErrorIs(t, err, sdkerrors.ErrInvalidRequest) + require.ErrorContains(t, err, "failed to validation certificate") + require.ErrorContains(t, err, "cid is empty") + + msg.Certificate.UnsignedCertificate.Cid = "cid" + err = msg.ValidateBasic() + require.ErrorIs(t, err, sdkerrors.ErrInvalidRequest) + require.ErrorContains(t, err, "failed to validation certificate") + require.ErrorContains(t, err, "uniqueId is empty") + + msg.Certificate.UnsignedCertificate.UniqueId = "uniqueID" + err = msg.ValidateBasic() + require.ErrorIs(t, err, sdkerrors.ErrInvalidRequest) + require.ErrorContains(t, err, "failed to validation certificate") + require.ErrorContains(t, err, "oracleAddress is invalid") + + msg.Certificate.UnsignedCertificate.OracleAddress = oracleAddress + err = msg.ValidateBasic() + require.ErrorIs(t, err, sdkerrors.ErrInvalidRequest) + require.ErrorContains(t, err, "failed to validation certificate") + require.ErrorContains(t, err, "dealId is greater than 0") + + msg.Certificate.UnsignedCertificate.DealId = 1 + err = msg.ValidateBasic() + require.ErrorIs(t, err, sdkerrors.ErrInvalidRequest) + require.ErrorContains(t, err, "failed to validation certificate") + require.ErrorContains(t, err, "providerAddress is invalid") + + msg.Certificate.UnsignedCertificate.ProviderAddress = providerAddress + err = msg.ValidateBasic() + require.ErrorIs(t, err, sdkerrors.ErrInvalidRequest) + require.ErrorContains(t, err, "failed to validation certificate") + require.ErrorContains(t, err, "dataHash is empty") +} + +func TestMsgDeactivateDeal(t *testing.T) { + requesterAddress := sdk.AccAddress(secp256k1.GenPrivKey().PubKey().Address()).String() + + msg := &MsgDeactivateDeal{ + DealId: 1, + RequesterAddress: requesterAddress, + } + + err := msg.ValidateBasic() + require.NoError(t, err) +} + +func TestMsgDeactivateDealEmptyValue(t *testing.T) { + requesterAddress := sdk.AccAddress(secp256k1.GenPrivKey().PubKey().Address()).String() + + msg := &MsgDeactivateDeal{} + err := msg.ValidateBasic() + require.ErrorIs(t, err, sdkerrors.ErrInvalidRequest) + require.ErrorContains(t, err, "requesterAddress is invalid") + + msg.RequesterAddress = requesterAddress + err = msg.ValidateBasic() + require.ErrorIs(t, err, sdkerrors.ErrInvalidRequest) + require.ErrorContains(t, err, "dealId is greater than 0") +} \ No newline at end of file From 64000e3497adf9b40c2fc017f1a167d493d01b6f Mon Sep 17 00:00:00 2001 From: gyuguen Date: Fri, 9 Dec 2022 10:51:51 +0900 Subject: [PATCH 20/20] fix --- x/datadeal/keeper/certificate_test.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/x/datadeal/keeper/certificate_test.go b/x/datadeal/keeper/certificate_test.go index dc6998c9..c2165689 100644 --- a/x/datadeal/keeper/certificate_test.go +++ b/x/datadeal/keeper/certificate_test.go @@ -2,6 +2,7 @@ package keeper_test import ( "encoding/base64" + "fmt" "testing" "github.com/btcsuite/btcd/btcec" @@ -95,7 +96,8 @@ func (suite *certificateTestSuite) storeSampleOracle(address, uniqueID string, c Endpoint: "https://my-validator.org", OracleCommissionRate: commissionRate, } - suite.OracleKeeper.SetOracle(suite.Ctx, oracle) + err := suite.OracleKeeper.SetOracle(suite.Ctx, oracle) + suite.Require().NoError(err) return oracle }