diff --git a/documentation/dev-portal/src/tutorials/cosmos-service/client.md b/documentation/dev-portal/src/tutorials/cosmos-service/client.md index c6db01fb6a..c3f6c6ee10 100644 --- a/documentation/dev-portal/src/tutorials/cosmos-service/client.md +++ b/documentation/dev-portal/src/tutorials/cosmos-service/client.md @@ -1 +1,23 @@ # Preparing Your Client + +Start by creating the startup logic of your `client` - creating a Nym client and connecting to the mixnet (or just connecting if your client has been started before and config already exists for it), and defining commands. + +Start in `bin/client.rs`. + +## Dependencies +Import the following dependencies: +``` +use clap::{Args, Parser, Subcommand}; +use nym_sdk::mixnet::Recipient; +use nym_validator_client::nyxd::AccountId; +use nym_cosmos_service::create_client; +use nym_bin_common::logging::setup_logging; +``` + +`clap` is used so different commands can be passed to the `client` (even though we're only defining one function in this first part of the tutorial, more will be added in subsequent chapters). `nym_sdk::mixnet::Recipient` is the type used to define the recipient of a mixnet message, `nym_bin_common::logging::setup_logging` is the logging setup for `client`'s Nym client, and `nym_cosmos_service::create_client` imports the `create_client` function created on the previous page. + +## CLI Command with Clap + +< simple account query first - then maybe a contract query > + +## diff --git a/documentation/dev-portal/src/tutorials/cosmos-service/lib.md b/documentation/dev-portal/src/tutorials/cosmos-service/lib.md index ef041b1838..37a2f46a22 100644 --- a/documentation/dev-portal/src/tutorials/cosmos-service/lib.md +++ b/documentation/dev-portal/src/tutorials/cosmos-service/lib.md @@ -17,7 +17,7 @@ pub mod client; pub mod service; ``` -Since this is the file where client creation and message parsing are handled, the various `nym_sdk` imports, as well as `serde`'s (de)serialisation functionality, are required. This file also imports the `client` and `service` specific logic not found in `bin/`, as well as `PathBuf` to read filepaths, and `cosmrs` types for defining Nyx blockchain accounts. +Since this is the file where client creation and message parsing are handled, the various `nym_sdk` imports, as well as `serde`'s (de)serialisation functionality, are required. `PathBuf` is for reading filepaths, and `cosmrs` types are required for defining Nyx blockchain accounts. ## Constants Below this are the chain-related `const` variables. These have been hardcoded for this demo. @@ -44,7 +44,7 @@ pub struct SequenceRequest { pub struct SequenceRequestResponse { pub account_number: u64, pub sequence: u64, - pub chain_id: tendermint::chain::Id, + pub chain_id: [tendermint](tendermint)::chain::Id, } #[derive(Debug, Deserialize, Serialize)] @@ -60,7 +60,11 @@ pub enum ResponseTypes { } ``` -TODO explainer of each +The above data types are pretty straightforward. Even though there are only one instance of a request type (sent from client to service) and one of a response type (service -> client) so far, a pair of enums has been defined to contain additional response or request types that will be added in the future. + +`SequenceRequest` will be used when requesting the service to query the chain on the client's behalf for an address' sequence information (used for offline signing). You can see the information that will be returned from the chain to the service, and from the service to the client, in `SequenceRequestResponse`. + +> Although `SequenceResponse` would have been more succinct, there is already a `cosmrs` type with this name. As such the response type was given a different name to avoid confusion. ## Shared Functions Now to define functions shared by the `client` and `service` binaries. @@ -87,6 +91,63 @@ pub async fn create_client(config_path: PathBuf) -> MixnetClient { > If keys and config already exist at this location, re-running this function **will not** overwrite them. ### Parsing Incoming messages -TODO smoosh them into one function with the return type being an `Option` instead - Next to define two functions: one for listening _for_ messages from the mixnet (used by our `service`), and one for listening out for a _reply_ after sending a message to another Nym client (in this case, when sending a message from the `client` to the `service`). + +```rust +pub async fn listen_and_parse_response(client: &mut MixnetClient) -> anyhow::Result { + let mut message: Vec = Vec::new(); + + // get the actual message - discard the empty vec sent along with the SURB topup request + while let Some(new_message) = client.wait_for_messages().await { + if new_message.is_empty() { + println!("got a request for more SURBs from service - sending additional SURBs to sender"); + continue; + } + message = new_message; + break; + } + + // parse vec -> JSON String + let mut parsed = String::new(); + if let Some(r) = message.iter().next() { + parsed = String::from_utf8(r.message.clone())?; + } + let sp_response: crate::ResponseTypes = serde_json::from_str(&parsed)?; + Ok(sp_response) +} + +pub async fn listen_and_parse_request( + client: &mut MixnetClient, +) -> anyhow::Result<(RequestTypes, AnonymousSenderTag)> { + let mut message: Vec = Vec::new(); + + while let Some(new_message) = client.wait_for_messages().await { + if new_message.is_empty() { + println!("got empty vec - probably the SURBs sent along with the request"); + continue; + } + message = new_message; + break; + } + + // parse vec -> JSON String + let mut parsed = String::new(); + if let Some(r) = message.iter().next() { + parsed = String::from_utf8(r.message.clone())?; + } + let client_request: crate::RequestTypes = serde_json::from_str(&parsed)?; + + // get the sender_tag for anon reply + let return_recipient = message[0].sender_tag.unwrap(); + + Ok((client_request, return_recipient)) +} +``` + +Aside from the return types that each function has, the main difference is that any incoming requests to the `service` will also have SURB packets attached to it. + +< smol explanation of SURBs + link > + +As such, this function returns a tuple containing the `RequestType` _and_ the `sender_tag` used by the `service` to identify which bucket of pre-addressed replies it will use to respond to a request. + +< note concerning parsing out the empty vecs >