From 34c143e6d7dbce5721e6e9095fceb5a856a3b431 Mon Sep 17 00:00:00 2001 From: Reece Williams Date: Thu, 12 Sep 2024 06:16:25 -0500 Subject: [PATCH] fix(docs): some typos + new nameservice challenge --- .../01-nameservice.md | 0 .../02-proto-logic.md | 3 +- .../03-application-logic.md | 7 +- .../04-cli.md | 19 +- .../05-testnet.md | 0 .../06-extra-challenge.md | 188 ++++++++++++++++++ .../07-conclusion.md | 5 +- .../02-build-your-application/_category_.json | 5 + .../02-build-your-chain/06-extra-challenge.md | 37 ---- .../02-build-your-chain/_category_.json | 5 - .../version-v0.50.x/03-demos/02-ibc-module.md | 45 +++-- .../version-v0.50.x/03-demos/_category_.json | 2 +- 12 files changed, 245 insertions(+), 71 deletions(-) rename docs/versioned_docs/version-v0.50.x/{02-build-your-chain => 02-build-your-application}/01-nameservice.md (100%) rename docs/versioned_docs/version-v0.50.x/{02-build-your-chain => 02-build-your-application}/02-proto-logic.md (95%) rename docs/versioned_docs/version-v0.50.x/{02-build-your-chain => 02-build-your-application}/03-application-logic.md (92%) rename docs/versioned_docs/version-v0.50.x/{02-build-your-chain => 02-build-your-application}/04-cli.md (79%) rename docs/versioned_docs/version-v0.50.x/{02-build-your-chain => 02-build-your-application}/05-testnet.md (100%) create mode 100644 docs/versioned_docs/version-v0.50.x/02-build-your-application/06-extra-challenge.md rename docs/versioned_docs/version-v0.50.x/{02-build-your-chain => 02-build-your-application}/07-conclusion.md (94%) create mode 100644 docs/versioned_docs/version-v0.50.x/02-build-your-application/_category_.json delete mode 100644 docs/versioned_docs/version-v0.50.x/02-build-your-chain/06-extra-challenge.md delete mode 100644 docs/versioned_docs/version-v0.50.x/02-build-your-chain/_category_.json diff --git a/docs/versioned_docs/version-v0.50.x/02-build-your-chain/01-nameservice.md b/docs/versioned_docs/version-v0.50.x/02-build-your-application/01-nameservice.md similarity index 100% rename from docs/versioned_docs/version-v0.50.x/02-build-your-chain/01-nameservice.md rename to docs/versioned_docs/version-v0.50.x/02-build-your-application/01-nameservice.md diff --git a/docs/versioned_docs/version-v0.50.x/02-build-your-chain/02-proto-logic.md b/docs/versioned_docs/version-v0.50.x/02-build-your-application/02-proto-logic.md similarity index 95% rename from docs/versioned_docs/version-v0.50.x/02-build-your-chain/02-proto-logic.md rename to docs/versioned_docs/version-v0.50.x/02-build-your-application/02-proto-logic.md index f19865c5..05ad03d0 100644 --- a/docs/versioned_docs/version-v0.50.x/02-build-your-chain/02-proto-logic.md +++ b/docs/versioned_docs/version-v0.50.x/02-build-your-application/02-proto-logic.md @@ -46,7 +46,7 @@ Find `query.proto` and add the following // ResolveName allows a user to resolve the name of an account. rpc ResolveName(QueryResolveNameRequest) returns (QueryResolveNameResponse) { - option (google.api.http).get = "/nameservice/v1/names/{wallet}"; + option (google.api.http).get = "/nameservice/v1/name/{wallet}"; } } @@ -72,7 +72,6 @@ proto/nameservice/v1/query.proto These .proto file templates will be converted into Golang source code for you to use. Build the Go source code using the command: ```bash -// highlight-next-line make proto-gen ``` diff --git a/docs/versioned_docs/version-v0.50.x/02-build-your-chain/03-application-logic.md b/docs/versioned_docs/version-v0.50.x/02-build-your-application/03-application-logic.md similarity index 92% rename from docs/versioned_docs/version-v0.50.x/02-build-your-chain/03-application-logic.md rename to docs/versioned_docs/version-v0.50.x/02-build-your-application/03-application-logic.md index 472ca82e..09f36430 100644 --- a/docs/versioned_docs/version-v0.50.x/02-build-your-chain/03-application-logic.md +++ b/docs/versioned_docs/version-v0.50.x/02-build-your-application/03-application-logic.md @@ -13,6 +13,7 @@ You now need to set the data structure in the keeper to store the wallet to name type Keeper struct { ... + // highlight-next-line NameMapping collections.Map[string, string] } @@ -23,7 +24,7 @@ func NewKeeper() Keeper { k := Keeper{ ... - + // highlight-next-line NameMapping: collections.NewMap(sb, collections.NewPrefix(1), "name_mapping", collections.StringKey, collections.StringValue), } @@ -40,11 +41,13 @@ Update the msg_server logic to set the name upon request from a user. ```go title="x/nameservice/keeper/msg_server.go" func (ms msgServer) SetServiceName(ctx context.Context, msg *types.MsgSetServiceName) (*types.MsgSetServiceNameResponse, error) { + // highlight-start if err := ms.k.NameMapping.Set(ctx, msg.Sender, msg.Name); err != nil { return nil, err } return &types.MsgSetServiceNameResponse{}, nil + // highlight-end } ``` @@ -52,6 +55,7 @@ and also for the query_server to retrieve the name. ```go title="x/nameservice/keeper/query_server.go" func (k Querier) ResolveName(goCtx context.Context, req *types.QueryResolveNameRequest) (*types.QueryResolveNameResponse, error) { + // highlight-start v, err := k.Keeper.NameMapping.Get(goCtx, req.Wallet) if err != nil { return nil, err @@ -60,6 +64,7 @@ func (k Querier) ResolveName(goCtx context.Context, req *types.QueryResolveNameR return &types.QueryResolveNameResponse{ Name: v, }, nil + // highlight-end } ``` diff --git a/docs/versioned_docs/version-v0.50.x/02-build-your-chain/04-cli.md b/docs/versioned_docs/version-v0.50.x/02-build-your-application/04-cli.md similarity index 79% rename from docs/versioned_docs/version-v0.50.x/02-build-your-chain/04-cli.md rename to docs/versioned_docs/version-v0.50.x/02-build-your-application/04-cli.md index 66b8a328..93107222 100644 --- a/docs/versioned_docs/version-v0.50.x/02-build-your-chain/04-cli.md +++ b/docs/versioned_docs/version-v0.50.x/02-build-your-application/04-cli.md @@ -17,6 +17,7 @@ Update the autocli to allow someone to get the name of a wallet account. Query: &autocliv1.ServiceCommandDescriptor{ Service: modulev1.Query_ServiceDesc.ServiceName, RpcCommandOptions: []*autocliv1.RpcCommandOptions{ + // highlight-start { RpcMethod: "ResolveName", Use: "resolve [wallet]", @@ -25,6 +26,7 @@ Update the autocli to allow someone to get the name of a wallet account. {ProtoField: "wallet"}, }, }, + // highlight-end { RpcMethod: "Params", Use: "params", @@ -34,7 +36,12 @@ Update the autocli to allow someone to get the name of a wallet account. }, ``` -![AutoCLI Query](https://github.com/rollchains/spawn/assets/31943163/fefe8c7d-88b5-42d5-afd9-cb33cd22df16) +
+ AutoCLI Query + + ![AutoCLI Query](https://github.com/rollchains/spawn/assets/31943163/fefe8c7d-88b5-42d5-afd9-cb33cd22df16) +
+ ### Transaction @@ -45,6 +52,7 @@ Also add interaction in `x/nameservice/autocli.go` to set the name of a wallet a Tx: &autocliv1.ServiceCommandDescriptor{ Service: modulev1.Msg_ServiceDesc.ServiceName, RpcCommandOptions: []*autocliv1.RpcCommandOptions{ + // highlight-start { RpcMethod: "SetServiceName", Use: "set [name]", @@ -53,6 +61,7 @@ Also add interaction in `x/nameservice/autocli.go` to set the name of a wallet a {ProtoField: "name"}, }, }, + // highlight-end { // NOTE: this is already included in the current source RpcMethod: "UpdateParams", @@ -62,4 +71,10 @@ Also add interaction in `x/nameservice/autocli.go` to set the name of a wallet a }, ``` -![AutoCLI Tx](https://github.com/rollchains/spawn/assets/31943163/e945c898-415c-4d22-8bb3-b8af34a44cee) +
+ AutoCLI Tx + + ![AutoCLI Tx](https://github.com/rollchains/spawn/assets/31943163/e945c898-415c-4d22-8bb3-b8af34a44cee) +
+ + diff --git a/docs/versioned_docs/version-v0.50.x/02-build-your-chain/05-testnet.md b/docs/versioned_docs/version-v0.50.x/02-build-your-application/05-testnet.md similarity index 100% rename from docs/versioned_docs/version-v0.50.x/02-build-your-chain/05-testnet.md rename to docs/versioned_docs/version-v0.50.x/02-build-your-application/05-testnet.md diff --git a/docs/versioned_docs/version-v0.50.x/02-build-your-application/06-extra-challenge.md b/docs/versioned_docs/version-v0.50.x/02-build-your-application/06-extra-challenge.md new file mode 100644 index 00000000..9ff08e77 --- /dev/null +++ b/docs/versioned_docs/version-v0.50.x/02-build-your-application/06-extra-challenge.md @@ -0,0 +1,188 @@ +--- +title: "Name Service" +sidebar_label: "Bonus" +sidebar_position: 6 +slug: /build/name-service-bonus +--- + +# Extra Challenges + +## Challenge 1: Limit Input + +It seems the nameservice will let you set any name length you want. Add a validation check in `SetServiceName` to ensure the name is less than 32 characters long. + +
+Hint #1 +

The `SetServiceName` in the msg_server.go looks like an interesting place to start. It should return an error if the name is too long.

+
+ +
+Solution + +If a user attempts to submit a name longer than 32 characters, it will return an error that is not allowed. +```go title="x/nameservice/keeper/msg_server.go" +// SetServiceName implements types.MsgServer. +func (ms msgServer) SetServiceName(ctx context.Context, msg *types.MsgSetServiceName) (*types.MsgSetServiceNameResponse, error) { + if len(msg.Name) > 32 { + return nil, fmt.Errorf("name cannot be longer than 32 characters") + } + + if err := ms.k.NameMapping.Set(ctx, msg.Sender, msg.Name); err != nil { + return nil, err + } + + return &types.MsgSetServiceNameResponse{}, nil +} +``` +
+ + +## Challenge 2: Resolve Wallet From Name + +Currently the nameservice only allows you to resolve a name given a wallet. If someone has a name they should be able to resolve the wallet address. Add a new query to the `query_server` and autocli client to resolve a wallet address from a name. + +> This challenge is signinicantly harder and will some previous Go programming knowledge with iterators. You can also just copy the solutions. + +
+Hint #1 +

Create a new query.proto for ResolveWallet that takes in a name string

+
+ +
+Solution #1 + +```protobuf title="proto/nameservice/v1/query.proto" +// Query provides defines the gRPC querier service. +service Query { + // Params queries all parameters of the module. + rpc Params(QueryParamsRequest) returns (QueryParamsResponse) { + option (google.api.http).get = "/nameservice/v1/params"; + } + + // ResolveName allows a user to resolve the name of an account. + rpc ResolveName(QueryResolveNameRequest) returns (QueryResolveNameResponse) { + option (google.api.http).get = "/nameservice/v1/name/{wallet}"; + } + + // highlight-start + // ResolveWallet allows a user to resolve the wallet of a name. + rpc ResolveWallet(QueryResolveWalletRequest) returns (QueryResolveWalletResponse) { + option (google.api.http).get = "/nameservice/v1/wallet/{name}"; + } + // highlight-end +} + +// highlight-start +message QueryResolveWalletRequest { + string name = 1; +} + +message QueryResolveWalletResponse { + string wallet = 1; +} +// highlight-end +``` + +```bash +make proto-gen +``` + +
+ +
+Hint #2 +

Iterate through the `k.Keeper.NameMapping`, check the Value(). if it matches the name we requested, return that wallet (Key)

+
+ +
+Solution #2 + +```go title="x/nameservice/keeper/query_server.go" +// ResolveWallet implements types.QueryServer. +func (k Querier) ResolveWallet(goCtx context.Context, req *types.QueryResolveWalletRequest) (*types.QueryResolveWalletResponse, error) { + // highlight-start + // create a way to iterate over all the name mappings. + iter, err := k.Keeper.NameMapping.Iterate(goCtx, nil) + if err != nil { + return nil, err + } + defer iter.Close() + + for ; iter.Valid(); iter.Next() { + // get the value (name) + v, err := iter.Value() + if err != nil { + return nil, err + } + + // if current name matches the requested name, + // return the wallet address for the name + if v == req.Name { + walletAddr, err := iter.Key() + if err != nil { + return nil, err + } + + return &types.QueryResolveWalletResponse{ + Wallet: walletAddr, + }, nil + } + } + + return nil, fmt.Errorf("wallet not found for name %s", req.Name) + // highlight-end +} + + +``` +This is not the most efficient way to do this. If you would like, create a new WalletMapping collection that maps name->sender when `SetServiceName` is called. This way you can resolve the wallet from the name in O(1) time (i.e. instant) instead of looping through all possible wallets. + +
+ + +
+Hint #3 +

Add the AutoCLI method to `ResolveWallet` with the `ProtoField` "name" to match the .proto file

+
+ + +
+Solution #3 + +```go title="x/nameservice/autocli.go" +func (am AppModule) AutoCLIOptions() *autocliv1.ModuleOptions { + return &autocliv1.ModuleOptions{ + Query: &autocliv1.ServiceCommandDescriptor{ + Service: modulev1.Query_ServiceDesc.ServiceName, + RpcCommandOptions: []*autocliv1.RpcCommandOptions{ + { + RpcMethod: "ResolveName", + Use: "resolve [wallet]", + Short: "Resolve the name of a wallet address", + PositionalArgs: []*autocliv1.PositionalArgDescriptor{ + {ProtoField: "wallet"}, + }, + }, + // highlight-start + { + RpcMethod: "ResolveWallet", + Use: "wallet [name]", + Short: "Resolve the wallet address from a given name", + PositionalArgs: []*autocliv1.PositionalArgDescriptor{ + {ProtoField: "name"}, + }, + }, + // highlight-end + { + RpcMethod: "Params", + Use: "params", + Short: "Query the current module parameters", + }, + }, + }, + ... +``` + +Then `make install` and re-run the testnet to verify `rolld q nameservice wallet ` returns the expected wallet address. + +
diff --git a/docs/versioned_docs/version-v0.50.x/02-build-your-chain/07-conclusion.md b/docs/versioned_docs/version-v0.50.x/02-build-your-application/07-conclusion.md similarity index 94% rename from docs/versioned_docs/version-v0.50.x/02-build-your-chain/07-conclusion.md rename to docs/versioned_docs/version-v0.50.x/02-build-your-application/07-conclusion.md index 3d5e7169..b5c594c8 100644 --- a/docs/versioned_docs/version-v0.50.x/02-build-your-chain/07-conclusion.md +++ b/docs/versioned_docs/version-v0.50.x/02-build-your-application/07-conclusion.md @@ -19,10 +19,9 @@ You just crafted your first blockchain, module, and custom logic with Spawn. You * Running a local testnet * Interacting with the network -# What's Next? +## What's Next? Extend the NameService to include IBC support with the [ibc-module](../03-demos/02-ibc-module.md) tutorial. - - + diff --git a/docs/versioned_docs/version-v0.50.x/02-build-your-application/_category_.json b/docs/versioned_docs/version-v0.50.x/02-build-your-application/_category_.json new file mode 100644 index 00000000..a288d2c0 --- /dev/null +++ b/docs/versioned_docs/version-v0.50.x/02-build-your-application/_category_.json @@ -0,0 +1,5 @@ +{ + "label": "Your First Application", + "position": 2, + "link": null +} diff --git a/docs/versioned_docs/version-v0.50.x/02-build-your-chain/06-extra-challenge.md b/docs/versioned_docs/version-v0.50.x/02-build-your-chain/06-extra-challenge.md deleted file mode 100644 index eb91d8c6..00000000 --- a/docs/versioned_docs/version-v0.50.x/02-build-your-chain/06-extra-challenge.md +++ /dev/null @@ -1,37 +0,0 @@ ---- -title: "Name Service" -sidebar_label: "Bonus Challenge" -sidebar_position: 6 -slug: /build/name-service-bonus ---- - -# Extra Challenge - -It seems the nameservice will let you set any name length you want. Add a validation check in `SetServiceName` to ensure the name is less than 32 characters long. - -
-Hint #1 -

The `SetServiceName` in the msg_server.go looks like an interesting place to start. It should return an error if the name is too long.

-
- -
-Solution - -If a user attempts to submit a name longer than 32 characters, it will return an error that is not allowed. -```go title="x/nameservice/keeper/msg_server.go" -// SetServiceName implements types.MsgServer. -func (ms msgServer) SetServiceName(ctx context.Context, msg *types.MsgSetServiceName) (*types.MsgSetServiceNameResponse, error) { - if len(msg.Name) > 32 { - return nil, fmt.Errorf("name cannot be longer than 32 characters") - } - - if err := ms.k.NameMapping.Set(ctx, msg.Sender, msg.Name); err != nil { - return nil, err - } - - return &types.MsgSetServiceNameResponse{}, nil -} -``` -
- - diff --git a/docs/versioned_docs/version-v0.50.x/02-build-your-chain/_category_.json b/docs/versioned_docs/version-v0.50.x/02-build-your-chain/_category_.json deleted file mode 100644 index db6d5599..00000000 --- a/docs/versioned_docs/version-v0.50.x/02-build-your-chain/_category_.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "label": "Your First Chain", - "position": 2, - "link": null -} diff --git a/docs/versioned_docs/version-v0.50.x/03-demos/02-ibc-module.md b/docs/versioned_docs/version-v0.50.x/03-demos/02-ibc-module.md index ba87b067..b7bd356a 100644 --- a/docs/versioned_docs/version-v0.50.x/03-demos/02-ibc-module.md +++ b/docs/versioned_docs/version-v0.50.x/03-demos/02-ibc-module.md @@ -31,20 +31,26 @@ cd rollchain # scaffold the base IBC module for The # cross chain name service spawn module new nsibc --ibc-module + +# compile latest code with matching module name +# failure to do this will result in: `panic: reflect: New(nil)` +make proto-gen ``` -## Import the other NameService Module +## Use the NameService Module -You now reference the nameservice module you built within this new IBC module. This will allow you to save the name mapping on the name service, making it available for both IBC and native chain interactions. +You now use the nameservice module you built previously within this new IBC module. This will allow you to save the name mapping on the name service, making it available for both IBC and native chain interactions. ```go title="x/nsibc/keeper/keeper.go" import ( ... + // highlight-next-line nameservicekeeper "github.com/rollchains/rollchain/x/nameservice/keeper" ) type Keeper struct { ... + // highlight-next-line NameServiceKeeper *nameservicekeeper.Keeper } ``` @@ -60,12 +66,14 @@ type Keeper struct { // NewKeeper creates a new Keeper instance. func NewKeeper( ... + // highlight-next-line nsk *nameservicekeeper.Keeper, ) Keeper { ... k := Keeper{ ... + // highlight-next-line NameServiceKeeper: nsk, } ``` @@ -77,22 +85,11 @@ func NewKeeper( ## Provide NameService to the IBC Module -You must now give the IBC module access to nameservice keeper. It needs this reference so that the logic and connections can be shared. This is done in the `app/app.go` file. Find where the EvidenceKeeper line is, and overwrite the current lines with the following. +You must now give the IBC module access to nameservice keeper. It needs this reference so that the logic and connections can be shared. This is done in the `app/app.go` file. Find where the NameService IBC line is and update it to include the `&app.NameserviceKeeper,` reference. -This moves the `NameserviceKeeper` above the IBC keeper (since you need to set that first so you can use it), and adds the `&app.NameserviceKeeper,` to the IBC Name Service keeper. +You can find the `NameserviceKeeper` set just after the `NsibcKeeper` is set. If you would like to re-order the original NameService keeper, you can do so. ```go title="app/app.go" - // If evidence needs to be handled for the app, set routes in router here and seal - app.EvidenceKeeper = *evidenceKeeper - - // Create the nameservice Keeper - app.NameserviceKeeper = nameservicekeeper.NewKeeper( - appCodec, - runtime.NewKVStoreService(keys[nameservicetypes.StoreKey]), - logger, - authtypes.NewModuleAddress(govtypes.ModuleName).String(), - ) - // Create the nsibc IBC Module Keeper app.NsibcKeeper = nsibckeeper.NewKeeper( appCodec, @@ -100,7 +97,8 @@ This moves the `NameserviceKeeper` above the IBC keeper (since you need to set t app.IBCKeeper.ChannelKeeper, app.IBCKeeper.PortKeeper, scopedNsibc, - &app.NameserviceKeeper, + // highlight-next-line + &app.NameserviceKeeper, // This line added here authtypes.NewModuleAddress(govtypes.ModuleName).String(), ) ``` @@ -108,7 +106,7 @@ This moves the `NameserviceKeeper` above the IBC keeper (since you need to set t
Application NameService Reference Image - ![View](https://github.com/user-attachments/assets/af456634-d7b7-475f-b468-7c14411803da) + ![View](https://github.com/user-attachments/assets/6da58e1d-481b-46ba-bb66-d6c4a96971d0)
@@ -137,7 +135,12 @@ Once found, remove the lines within and replace with the following return. ```go title="x/nsibc/ibc_module.go" func (im ExampleIBCModule) handleOnRecvLogic(ctx context.Context, data types.ExamplePacketData) error { + // highlight-start + if len(data.SomeData) > 32 { + return fmt.Errorf("name cannot be longer than 32 characters") + } return im.keeper.NameServiceKeeper.NameMapping.Set(ctx, data.Sender, data.SomeData) + // highlight-end } ``` @@ -154,7 +157,8 @@ You could just as easily write the NameMapping in the ibc keeper store as well. # build chain binary make install -# verify the binary works +# verify the binary works. if you get a panic, +# `make proto-gen`, then re make install rolld # build docker image @@ -168,7 +172,7 @@ local-ic start self-ibc ## Import Testnet Helpers Pasting the following lines in your terminal will import helper functions to interact with the testnet. -The source is publicly available on GitHub to review. +The source is publicly available on GitHub to review. It gives you the ability to interact with the testnet easily using special `ICT_` commands. ```bash # Import the testnet interaction helper functions @@ -182,7 +186,7 @@ ICT_POLL_FOR_START $API_ADDR 50 && echo "Testnet started" ## Connect Your IBC Modules -You are ready to connect the two chains with your IBC module protocol. The [cosmos/relayer](https://github.com/cosmos/relayer) is already running between the 2 networks now. You will just send a command to connect the new logic. +You are ready to connect the two chains with your IBC module protocol. The [cosmos/relayer](https://github.com/cosmos/relayer) is already running between the 2 networks now. :::note A Channel is a connection between two chains, like a highway. A port is a specific protocol (or logic) that can connect with itself on another chain. @@ -191,6 +195,7 @@ For example; transfer to transfer, nsibc to nsibc, but transfer to nsibc can not These values are found in the keys.go file as the module name. By default version is just the module name + "-1". ::: +Execute the command on the testnet to connect the two chains with the IBC module. ```bash # This will take a minute. diff --git a/docs/versioned_docs/version-v0.50.x/03-demos/_category_.json b/docs/versioned_docs/version-v0.50.x/03-demos/_category_.json index 56fa22bb..043e9d6b 100644 --- a/docs/versioned_docs/version-v0.50.x/03-demos/_category_.json +++ b/docs/versioned_docs/version-v0.50.x/03-demos/_category_.json @@ -1,5 +1,5 @@ { - "label": "Chain Demos", + "label": "Application Demos", "position": 3, "link": null }