Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

feat: implementation of MsgBuyDataAccessNFT Tx #306

Merged
merged 25 commits into from
Apr 25, 2022
Merged
Show file tree
Hide file tree
Changes from 12 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 13 additions & 7 deletions proto/panacea/datapool/v2/genesis.proto
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,11 @@ import "panacea/datapool/v2/pool.proto";

// GenesisState defines the datapool module's genesis state.
message GenesisState {
repeated panacea.datapool.v2.DataValidator data_validators = 1;
uint64 next_pool_number = 2;
repeated Pool pools = 3;
Params params = 4 [
(gogoproto.nullable) = false
];
bytes nft_contract_address = 5;
repeated DataValidator data_validators = 1 [(gogoproto.nullable) = false];
uint64 next_pool_number = 2;
repeated Pool pools = 3 [(gogoproto.nullable) = false];
Params params = 4 [(gogoproto.nullable) = false];
repeated WhiteList white_list = 5 [(gogoproto.nullable) = false];
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I also add [ (gogoproto.nullable) = false ] to some fields.

When I export genesis.json with multiple values of those fields, all the same values (I guess the last one) are stored and exported. I referred to other projects and they all used the gogoproto extension. I'm not sure of the reason, it was a workaround for now. If you have any idea, please leave some comments.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are you saying this?
expected:

{
  "whiteList": [
    {
      "data_pool_code_id" : 1,
      "data_pool_nft_contract_adress": "panaceaxxxx1"
    },
    {
      "data_pool_code_id" : 2,
      "data_pool_nft_contract_adress": "panaceaxxxx2"
    }
  ]
}

acutally

{
  "whiteList": [
    {
      "data_pool_code_id" : 2,
      "data_pool_nft_contract_adress": "panaceaxxxx2"
    }
  ]
}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In your example,

{
  "whiteList": [
    {
      "data_pool_code_id" : 2,
      "data_pool_nft_contract_adress": "panaceaxxxx2"
    },
    {
      "data_pool_code_id" : 2,
      "data_pool_nft_contract_adress": "panaceaxxxx2"
    }
  ]
}

The last one was duplicated..

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's interesting...

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are also differences of types in GenesisState. Without gogoproto extension, pointer is added to each type.

Without [(gogoproto.nullable) = false],

type GenesisState struct {
    DataValidators []*DataValidator `protobuf:"bytes,1,rep,name=data_validators,json=dataValidators,proto3" json:"data_validators"`
    NextPoolNumber uint64           `protobuf:"varint,2,opt,name=next_pool_number,json=nextPoolNumber,proto3" json:"next_pool_number,omitempty"`
    Pools          []*Pool          `protobuf:"bytes,3,rep,name=pools,proto3" json:"pools"`
    Params         *Params          `protobuf:"bytes,4,opt,name=params,proto3" json:"params"`
}

With [(gogoproto.nullable) = false],

type GenesisState struct {
    DataValidators []DataValidator `protobuf:"bytes,1,rep,name=data_validators,json=dataValidators,proto3" json:"data_validators"`
    NextPoolNumber uint64          `protobuf:"varint,2,opt,name=next_pool_number,json=nextPoolNumber,proto3" json:"next_pool_number,omitempty"`
    Pools          []Pool          `protobuf:"bytes,3,rep,name=pools,proto3" json:"pools"`
    Params         Params          `protobuf:"bytes,4,opt,name=params,proto3" json:"params"`
}

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are also differences of types in GenesisState. Without gogoproto extension, pointer is added to each type.

This behavior is intended. But still, it's weird that the list contains all the same value.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

�> Is this issue still being raised? Then, I will take a look at it.

This issue is resolved now, but I don't know what's going on.

This behavior is intended.

Oh I see. I'm curious this part as well. I'll look at gogoproto extension more.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I just removed [(gogoproto.nullable) = false] and checked that the exported list in the genesis contains two different elements. As I know, [(gogoproto.nullable) = false] shouldn't violate the fundamental behavior of protobuf marshalling/unmarhalling.

In protobuf, the nullability is a bit tricky to handle because everything is optional by default in protobuf 3. That's why all fields are defined with pointer such as []*DataValidator or *Params. Previously, the protobuf 2 had the required keyword which sets some field not nullable, but that feature was deleted in protobuf 3: protocolbuffers/protobuf#2497.

That's why the gogoproto, which is an extension of protobuf, introduced a new feature nullable. If you really want to make each list element not nullable, then you can use [(gogoproto.nullable) = false] so that gogoproto defines the list as []Element, not []*Element. I also agree with using it.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But still, it's weird that the list contains all the same value.

I guess some Go code wasn't implemented correctly at that time.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, I see. I'm very thankful to you for your �detailed explanation.

I guess some Go code wasn't implemented correctly at that time.

I think it could be, because as I remember It was exported correctly when I implement ExportGenesis() of module params in #294.

}

// Params define parameters of datapool module
Expand All @@ -24,4 +22,12 @@ message Params {
(gogoproto.moretags) = "yaml:\"data_pool_deposit\"",
(gogoproto.nullable) = false
];
uint64 data_pool_code_id = 2;
string data_pool_nft_contract_address = 3;
}

// WhiteList define white list of data pool
message WhiteList {
0xHansLee marked this conversation as resolved.
Show resolved Hide resolved
0xHansLee marked this conversation as resolved.
Show resolved Hide resolved
uint64 pool_id = 1;
string address = 2;
}
3 changes: 2 additions & 1 deletion proto/panacea/datapool/v2/pool.proto
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,11 @@ message Pool {
string pool_address = 2;
uint64 round = 3;
PoolParams pool_params = 4;
uint64 cur_num_data = 5; // current number of data
uint64 cur_num_data = 5; // current number of data
uint64 num_issued_nfts = 6; // current issued NFTs
string status = 7;
string curator = 8;
string nft_contract_addr = 9; // NFT contract address of pool
}

// DataValidationCertificate defines the certificate for data validation w/ data validator signature.
Expand Down
27 changes: 14 additions & 13 deletions proto/panacea/datapool/v2/query.proto
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ option go_package = "github.com/medibloc/panacea-core/x/datapool/types";

import "google/api/annotations.proto";
import "panacea/datapool/v2/pool.proto";
import "panacea/datapool/v2/genesis.proto";

// Query defines the gRPC querier service.
service Query {
Expand All @@ -13,15 +14,15 @@ service Query {
option (google.api.http).get = "/panacea/datapool/v2/pools/{pool_id}";
}

// NFTContract returns a NFT contract address registered to x/datapool module
rpc NFTContract(QueryNFTContractRequest) returns (QueryNFTContractResponse) {
option (google.api.http).get = "/panacea/datapool/v2/nft_contract";
}

// DataValidator returns a DataValidator.
rpc DataValidator(QueryDataValidatorRequest) returns (QueryDataValidatorResponse) {
option (google.api.http).get = "/panacea/datapool/v2/data_validator";
}

// DataPoolParams returns params of x/datapool module
rpc DataPoolParams(QueryDataPoolParamsRequest) returns (QueryDataPoolParamsResponse) {
option (google.api.http).get = "/panacea/datapool/v2/params";
}
}

// QueryPoolRequest is the request type for the Query/Pool RPC method.
Expand All @@ -34,14 +35,6 @@ message QueryPoolResponse {
Pool pool = 1;
}

// QueryNFTContractRequest is the request type for the Query/NFTContract RPC method.
message QueryNFTContractRequest {}

// QueryNFTContractResponse is the response type for the Query/NFTContract RPC method.
message QueryNFTContractResponse {
string nft_contract_address = 1;
}

// QueryDataValidatorRequest is the request type for the Query/DataValidator RPC method.
message QueryDataValidatorRequest {
string address = 1 ;
Expand All @@ -50,4 +43,12 @@ message QueryDataValidatorRequest {
// QueryDataValidatorResponse is the response type for the Query/DataValidator RPC method.
message QueryDataValidatorResponse {
DataValidator data_validator = 1;
}

// QueryDataPoolParamsRequest is the request type for the Query/DataPoolParamsRequest RPC method.
message QueryDataPoolParamsRequest {}

// QueryDataPoolParamsResponse is the response type for the Query/DataPoolParamsResponse RPC method.
message QueryDataPoolParamsResponse {
Params params = 1;
}
26 changes: 1 addition & 25 deletions proto/panacea/datapool/v2/tx.proto
Original file line number Diff line number Diff line change
Expand Up @@ -29,12 +29,6 @@ service Msg {

// RedeemDataAccessNFT defines a method for redeeming data access NFT to get data
rpc RedeemDataAccessNFT(MsgRedeemDataAccessNFT) returns (MsgRedeemDataAccessNFTResponse);

// RegisterNFTContract defines a method for deployment and registration of NFT contract
rpc RegisterNFTContract(MsgRegisterNFTContract) returns (MsgRegisterNFTContractResponse);

// UpgradeNFTContract defines a method for upgrade and migration of NFT contract
rpc UpgradeNFTContract(MsgUpgradeNFTContract) returns (MsgUpgradeNFTContractResponse);
}

// MsgRegisterDataValidator defines the Msg/RegisterDataValidator request type.
Expand Down Expand Up @@ -107,22 +101,4 @@ message MsgRedeemDataAccessNFT {
// MsgRedeemDataAccessNFTResponse defines the Msg/RedeemDataAccessNFT response type.
message MsgRedeemDataAccessNFTResponse {
DataAccessNFTRedeemReceipt receipt = 1;
}

// MsgRegisterNFTContract defines the Msg/RegisterNFTContract type.
message MsgRegisterNFTContract {
bytes wasm_code = 1; // wasm byte code of NFT contract
string sender = 2;
}

// MsgRegisterNFTContractResponse defines the Msg/RegisterNFTContract response type.
message MsgRegisterNFTContractResponse {}

// MsgUpgradeNFTContract defines the Msg/UpgradeNFTContract type.
message MsgUpgradeNFTContract {
bytes new_wasm_code = 1; // wasm byte code of NFT contract
string sender = 2;
}

// MsgUpgradeNFTContractResponse defines the Msg/UpgradeNFTContract response type.
message MsgUpgradeNFTContractResponse {}
}
10 changes: 2 additions & 8 deletions types/testsuite/suite.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@ import (
paramstypes "github.com/cosmos/cosmos-sdk/x/params/types"
stakingkeeper "github.com/cosmos/cosmos-sdk/x/staking/keeper"
stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types"
"github.com/medibloc/panacea-core/v2/types/assets"
aolkeeper "github.com/medibloc/panacea-core/v2/x/aol/keeper"
aoltypes "github.com/medibloc/panacea-core/v2/x/aol/types"
burnkeeper "github.com/medibloc/panacea-core/v2/x/burn/keeper"
Expand Down Expand Up @@ -241,13 +240,8 @@ func (suite *TestSuite) SetupTest() {
)
suite.DataPoolMsgServer = datapoolkeeper.NewMsgServerImpl(suite.DataPoolKeeper)

dataPoolGenState := datapooltypes.GenesisState{
DataValidators: []*datapooltypes.DataValidator{},
NextPoolNumber: 1,
Pools: []*datapooltypes.Pool{},
Params: datapooltypes.Params{DataPoolDeposit: sdk.NewCoin(assets.MicroMedDenom, sdk.NewInt(1000000))},
}
datapool.InitGenesis(suite.Ctx, suite.DataPoolKeeper, dataPoolGenState)
dataPoolGenState := datapooltypes.DefaultGenesis()
datapool.InitGenesis(suite.Ctx, suite.DataPoolKeeper, *dataPoolGenState)
}

func (suite *TestSuite) BeforeTest(suiteName, testName string) {
Expand Down
103 changes: 86 additions & 17 deletions x/datapool/README.md
Original file line number Diff line number Diff line change
@@ -1,43 +1,113 @@
## Deploy and Register NFT smart contract
## Deploy and instantiate NFT smart contract

### Setting voter
```shell
TX_FLAG=(--chain-id {your chainID} --gas auto --gas-prices 5umed --gas-adjustment 1.3)
SENDER=$(panacead keys show {your address or key of sender} -a)
panacead tx datapool register-contract {your wasm code} --from $SENDER $TX_FLAG -y
VOTER=$(panacead keys show {your voter} -a)
panacead tx staking delegate {validator address} 1000000umed --from $VOTER $TX_FLAG -y
```

In this example, the `SENDER` doesn't do anything except paying tx fees for registration of NFT contract.
### Submit proposal (1): store NFT contract
```shell
PROPOSER=$(panacead keys show {your proposer} -a)

MODULE_ADDR="panacea1xacc5pqnn00vf4mf8qvhe3y7k0xj4ky2hxgzvz" // TODO: add GetParam query to get module address

## Create data pool
panacead tx gov submit-proposal wasm-store cw721_base.wasm \
--title "store NFT contract wasm code" \
--description "store wasm code for x/datapool module" \
--instantiate-only-address $MODULE_ADDR \
--run-as $MODULE_ADDR \
--deposit "10000000000umed" \
--from $PROPOSER $TX_FLAG -y
```

The module is the only allowed address to instantiate the contract

### Vote yes
```shell
CURATOR=$(panacead keys show {your address or key of curator} -a)
panacead tx datapool create-pool create_pool_sample.json --from $CURATOR $TX_FLAG -y
panacead tx gov vote {store proposal id} yes --from $VOTER $TX_FLAG -y
```

### Submit proposal (2): instantiate NFT contract

After store NFT contract passed, instantiate the contract

```shell
INST_MSG=$(jq -n --arg name "curator" --arg symbol "CUR" --arg minter $MODULE_ADDR '{"name": $name, "symbol": $symbol, "minter": $minter}')

panacead tx gov submit-proposal instantiate-contract {code id} "$INST_MSG" \
--label "curator NFT" \
--title "instantiate NFT contract" \
--description "instantiate NFT contract for x/datapool module" \
--run-as MODULE_ADDR \
--admin MODULE_ADDR \
--deposit "100000000umed" \
--from $PROPOSER $TX_FLAG -y
```

### Vote yes
```shell
panacead tx gov vote {instantiation proposal id} yes --from $VOTER $TX_FLAG -y
```

### Submit proposal (3): change parameter of code ID & NFT contract address

param_change_sample.json (when codeID=1, contractAddress=panacea14hj2tavq8fpesdwxxcu44rty3hh90vhu4mda6e)
```json
{
"title": "parameter change of datapool module",
"description": "register code ID and address of NFT contract",
"changes": [
{
"subspace": "datapool",
"key": "datapoolcodeid",
"value": "1"
},
{
"subspace": "datapool",
"key": "datapoolnftcontractaddress",
"value": "panacea14hj2tavq8fpesdwxxcu44rty3hh90vhu4mda6e"
}
],
"deposit": "1000000umed"
}
```

## Upgrade NFT contract
```shell
panacead tx datapool upgrade-contract cw721_new.wasm --from $SENDER $TX_FLAG -y
panacead tx gov submit-proposal param-change param_change_sample.json --from $PROPOSER $TX_FLAG -y
```

### Vote yes
```shell
panacead tx gov vote {param-change proposal id} yes --from $VOTER $TX_FLAG -y
```

### Create data pool

```shell
CURATOR=$(panacead keys show {your address or key of curator} -a)
panacead tx datapool create-pool create_pool_sample.json --from $CURATOR $TX_FLAG -y
```

## Query curator NFT
### Query curator NFT
```shell
CONTRACT=$(panacead q datapool get-contract | cut -d' ' -f2)
CONTRACT=$(panacead q datapool params -o json | jq -r '.data_pool_nft_contract_address')
QUERY_TOKEN_INFO=$(jq -n --arg owner $CURATOR '{"tokens":{"owner":$owner}}')
panacead q wasm contract-state smart $CONTRACT $QUERY_TOKEN_INFO -o json
```
### results
result
```json
{
"data": {
"tokens":["data_pool_0"]
"tokens":["data_pool_1"]
}
}
```

### Change parameter by proposal
## Change parameter of data pool deposit by proposal

proposal-example.json
proposal_example.json
```json
{
"title": "title",
Expand All @@ -53,7 +123,6 @@ proposal-example.json
}
```

submit-proposal cli command
```shell
panacead tx gov submit-proposal param-change param-example.json --from {proposer account} --chain-id {your chainID} --gas auto --gas-prices 5umed --gas-adjustment 1.3 -y
panacead tx gov submit-proposal param-change param_example.json --from {proposer account} --chain-id {your chainID} --gas auto --gas-prices 5umed --gas-adjustment 1.3 -y
```
2 changes: 1 addition & 1 deletion x/datapool/client/cli/query.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@ func GetQueryCmd(queryRoute string) *cobra.Command {

// this line is used by starport scaffolding # 1

cmd.AddCommand(CmdGetNFTContract())
cmd.AddCommand(CmdGetDataValidator())
cmd.AddCommand(CmdGetPool())
cmd.AddCommand(CmdGetParams())
return cmd
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@ import (
"github.com/spf13/cobra"
)

func CmdGetNFTContract() *cobra.Command {
func CmdGetParams() *cobra.Command {
cmd := &cobra.Command{
Use: "get-nft-contract",
Short: "Query registered NFT contract address",
Use: "params",
Short: "Query params of datapool module",
Args: cobra.ExactArgs(0),
RunE: func(cmd *cobra.Command, args []string) error {
clientCtx, err := client.GetClientQueryContext(cmd)
Expand All @@ -20,7 +20,7 @@ func CmdGetNFTContract() *cobra.Command {

queryClient := types.NewQueryClient(clientCtx)

res, err := queryClient.NFTContract(cmd.Context(), &types.QueryNFTContractRequest{})
res, err := queryClient.DataPoolParams(cmd.Context(), &types.QueryDataPoolParamsRequest{})
if err != nil {
return err
}
Expand All @@ -30,5 +30,6 @@ func CmdGetNFTContract() *cobra.Command {
}

flags.AddQueryFlagsToCmd(cmd)

return cmd
}
17 changes: 17 additions & 0 deletions x/datapool/client/cli/testdata/param_change_sample.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"title": "parameter change of datapool module",
"description": "register code ID and address of NFT contract",
"changes": [
{
"subspace": "datapool",
"key": "datapoolcodeid",
"value": "1"
},
{
"subspace": "datapool",
"key": "datapoolnftcontractaddress",
"value": "panacea14hj2tavq8fpesdwxxcu44rty3hh90vhu4mda6e"
}
],
"deposit": "1000000umed"
}
4 changes: 2 additions & 2 deletions x/datapool/client/cli/tx.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ func GetTxCmd() *cobra.Command {
cmd.AddCommand(CmdRegisterDataValidator())
cmd.AddCommand(CmdUpdateDataValidator())
cmd.AddCommand(CmdCreatePool())
cmd.AddCommand(CmdRegisterNFTContract())
cmd.AddCommand(CmdUpgradeNFTContract())
cmd.AddCommand(CmdBuyDataAccessNFT())

return cmd
}
Loading