From f6b200d25e75e2bf7a5dee723aceb6a82f829be3 Mon Sep 17 00:00:00 2001 From: mfahampshire Date: Fri, 14 Jul 2023 15:52:36 +0200 Subject: [PATCH] tidied up logging for demo recording --- demos/rust-cosmos-broadcaster/README.md | 20 +++++---- demos/rust-cosmos-broadcaster/bin/client.rs | 21 ++++----- demos/rust-cosmos-broadcaster/bin/service.rs | 25 +++++------ demos/rust-cosmos-broadcaster/src/client.rs | 47 +++++++++++++++++--- demos/rust-cosmos-broadcaster/src/lib.rs | 4 +- demos/rust-cosmos-broadcaster/src/service.rs | 20 ++++++--- 6 files changed, 88 insertions(+), 49 deletions(-) diff --git a/demos/rust-cosmos-broadcaster/README.md b/demos/rust-cosmos-broadcaster/README.md index 2f7856d402..b9b0d14ea0 100644 --- a/demos/rust-cosmos-broadcaster/README.md +++ b/demos/rust-cosmos-broadcaster/README.md @@ -1,11 +1,10 @@ TODO FOR DEMO -- clippy -- pass mnemonic as file -- nicer logging - show sequence response etc -- pass tx hash back to client nicely & remove from service +- flags for cli +- single parse_incoming fn in lib and call from everywhere +- pass mnemonic as file (otherwise pass as env var) +- create signer in main.rs and pass to commands (client/src) ### Nym mixnet cosmos tx broadcaster demo - A demo showing how to: * sign a cosmos tx (simple token transfer) offline * broadcast this tx from a service on the other side of the mixnet @@ -21,15 +20,20 @@ Built using: # compile cargo build --release -example 1: sign & send @ same time +example 1: sign & send in one call # start service ../../target/release/service # sign tx - when prompted enter 'y' -../../target/release/client offline-sign-tx "" " +../../target/release/client offline-sign-tx ${SENDER_MNEMONIC} ${RECIPIENT_NYX_ADDRESS} -example 2: sign first, send later +example 2: create signed tx # start service +../../target/release/service + # sign tx - when prompted enter 'n' and copy encoded tx bytes from terminal +../../target/release/client offline-sign-tx ${SENDER_MNEMONIC} ${RECIPIENT_NYX_ADDRESS} + # send tx using encoded bytes as arg +../../target/release/client send-tx ${} ``` diff --git a/demos/rust-cosmos-broadcaster/bin/client.rs b/demos/rust-cosmos-broadcaster/bin/client.rs index 406a719f8d..6acc7a83e0 100644 --- a/demos/rust-cosmos-broadcaster/bin/client.rs +++ b/demos/rust-cosmos-broadcaster/bin/client.rs @@ -2,6 +2,7 @@ use clap::{Parser, Subcommand, Args}; use nym_sdk::mixnet::Recipient; use nym_validator_client::nyxd::AccountId; use rust_cosmos_broadcaster::{client::{offline_sign, send_tx}, create_client}; +use nym_bin_common::logging::setup_logging; #[derive(Debug, Parser)] #[clap(name = "nym cosmos tx signer ")] @@ -39,17 +40,16 @@ async fn main() { let cli = Cli::parse(); let mut client = create_client("/tmp/cosmos-broadcaster-mixnet-client-2".into()).await; let our_address = client.nym_address(); - println!("\nour client nym address is: {our_address}"); + println!("\nclient's nym address: {our_address}\n"); - // TODO take from args as Option otherwise set as default this logic moves to src/client and remove this from here let sp_address = Recipient::try_from_base58_string("HfbesQm2pRYCN4BAdYXhkqXBbV1Pp929mtKsESVeWXh8.8AgoUPUQbXNBCPaqAaWd3vnxhc9484qwfgrrQwBngQk2@Ck8zpXTSXMtS9YZ7k7a5BiaoLZfffWuqGWLndujh4Lw4").unwrap(); match &cli.command { Some(Commands::OfflineSignTx(OfflineSignTx { mnemonic, nyx_token_receipient} )) => { - println!("sending offline sign info"); + println!("sending offline sign info to broadcaster via the mixnet: getting signing account sequence and chain ID"); let base58_tx_bytes = offline_sign(mnemonic.clone(), nyx_token_receipient.clone(), &mut client, sp_address).await; - println!("base58 encoded signed tx payload: \n\n{}\n\n", &base58_tx_bytes); + println!("Encoded response (signed tx data) as base58 for tx broadcast: \n\n{}\n", &base58_tx_bytes); println!("do you wish to send the tx? y/n"); let mut input = String::new(); @@ -58,19 +58,20 @@ async fn main() { if input.starts_with('y') { println!("\nsending tx thru the mixnet to broadcaster service"); - let tx_hash = send_tx(base58_tx_bytes, sp_address, &mut client).await; - println!("the response from the broadcaster: {:#?}", tx_hash); + let (tx_hash, success) = send_tx(base58_tx_bytes, sp_address, &mut client).await; + println!("tx hash returned from the broadcaster: {}\ntx was successful: {}", tx_hash, success); } else if input.starts_with('n') { - println!("\nok, you can send the signed tx at a later date by passing the base58 string above as the argument for send-tx") + println!("\nok, you can send the signed tx at a later date by passing the base58 string above as the argument for send-tx"); } else { println!("\nunrecognised user input"); } } Some(Commands::SendTx(SendTx { base58_payload } )) => { let tx_hash = send_tx(base58_payload.clone(), sp_address, &mut client).await; - println!("the response from the broadcaster: {:#?}", tx_hash); + println!("response from the broadcaster (tx hash) {:#?}", tx_hash); } - None => {println!("no command specified - nothing to do")} + None => {println!("\nno command specified - nothing to do")} } - println!("\nend") + println!("\ndisconnecting client"); + println!("end") } diff --git a/demos/rust-cosmos-broadcaster/bin/service.rs b/demos/rust-cosmos-broadcaster/bin/service.rs index f3bb298e94..f433abe8cb 100644 --- a/demos/rust-cosmos-broadcaster/bin/service.rs +++ b/demos/rust-cosmos-broadcaster/bin/service.rs @@ -1,5 +1,5 @@ use nym_sdk::mixnet::ReconstructedMessage; - +use nym_bin_common::logging::setup_logging; use nym_sphinx_anonymous_replies::{self, requests::AnonymousSenderTag}; use rust_cosmos_broadcaster::{RequestTypes, SequenceRequestResponse, BroadcastResponse, service::{get_sequence, broadcast, create_broadcaster}, create_client}; @@ -8,16 +8,12 @@ async fn main() { // setup_logging(); let mut client = create_client("/tmp/cosmos-broadcaster-mixnet-server-2".into()).await; let our_address = client.nym_address(); - println!("\nour client nym address is: {our_address}"); + println!("\nservice's nym address: {our_address}"); // the httpclient we will use to broadcast our signed tx to the Nyx blockchain let broadcaster = create_broadcaster().await; - /* - TODO - * add threads - loop just to check everything works quickly - */ loop { - println!("\nWaiting for message"); + println!("\nWaiting for new message"); // check incoming is empty - SURB requests also send data ( empty vec ) along let mut received: Vec = Vec::new(); // get the actual message - discard the empty vec sent along with the SURB request @@ -26,28 +22,27 @@ async fn main() { continue; } received = new_message; - println!("recieved: {:#?}", &received); break } for r in received.iter() { // convert incoming vec -> String let s = String::from_utf8(r.message.clone()); - println!("{:#?}", &s); + // println!("{:#?}", &s); if s.is_ok() { let p = s.unwrap(); - println!("{:#?}", &p); + // println!("{:#?}", &p); // parse JSON string -> request type & match let request: RequestTypes = serde_json::from_str(&p).unwrap(); - println!("incoming request: {:#?}", &request); + // println!("\nincoming request: {:#?}", &request); match request { RequestTypes::Sequence(request) => { - println!("\nincoming sequence request details:\nsigner address: {}\n", request.signer_address); + println!("\nincoming sequence request details:\nsigner address: {}", request.signer_address); let sequence: SequenceRequestResponse = get_sequence(broadcaster.clone(), request.signer_address).await; if Some(r.sender_tag).is_some() { - let return_recipient: AnonymousSenderTag = r.sender_tag.unwrap(); + let return_recipient: AnonymousSenderTag = r.sender_tag.unwrap(); + println!("replying to sender with sequence response from Nyx chain"); println!("return recipient surb bucket: {}", &return_recipient); - // todo actually return sequence serialised as json client.send_str_reply(return_recipient, &serde_json::to_string(&sequence).unwrap()).await; } else { // TODO replace with actual error type to return @@ -55,7 +50,7 @@ async fn main() { } }, RequestTypes::Broadcast(request) => { - println!("\nincoming sequence request details: {}\n", request.base58_tx_bytes); + println!("\nincoming broadcast request: {}\n", request.base58_tx_bytes); let tx_hash: BroadcastResponse = broadcast(request.base58_tx_bytes, broadcaster.clone()).await; if Some(r.sender_tag).is_some() { let return_recipient: AnonymousSenderTag = r.sender_tag.unwrap(); diff --git a/demos/rust-cosmos-broadcaster/src/client.rs b/demos/rust-cosmos-broadcaster/src/client.rs index 4a526906bf..a09560bb31 100644 --- a/demos/rust-cosmos-broadcaster/src/client.rs +++ b/demos/rust-cosmos-broadcaster/src/client.rs @@ -5,7 +5,7 @@ use nym_validator_client::signing::SignerData; use nym_validator_client::nyxd::cosmwasm_client::types; use cosmrs::bank::MsgSend; use cosmrs::tx::Msg; -use cosmrs::{tx, AccountId, Coin, Denom}; +use cosmrs::{tx, AccountId, Coin, Denom, ErrorReport}; use bip39; use bs58; use nym_sdk::mixnet::{self, MixnetClient, ReconstructedMessage}; @@ -36,7 +36,7 @@ pub async fn offline_sign(mnemonic: bip39::Mnemonic, to: AccountId, client: &mut while let Some(new_message) = client.wait_for_messages().await { if new_message.is_empty() { continue; - } println!("got a response"); + } message = new_message; break } @@ -104,7 +104,7 @@ pub async fn offline_sign(mnemonic: bip39::Mnemonic, to: AccountId, client: &mut } -pub async fn send_tx(base58_tx: String, sp_address: Recipient, client: &mut MixnetClient) -> Option> { +pub async fn send_tx(base58_tx: String, sp_address: Recipient, client: &mut MixnetClient) -> (String, bool) { let broadcast_request = crate::BroadcastRequest { base58_tx_bytes: base58_tx @@ -112,8 +112,41 @@ pub async fn send_tx(base58_tx: String, sp_address: Recipient, client: &mut Mixn client.send_str(sp_address, &serde_json::to_string(&broadcast_request).unwrap()).await; - println!("\nWaiting for reply\n"); - + println!("Waiting for reply"); + + // handle incoming message - we presume its a reply from the SP + 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() { + continue; + } + message = new_message; + break + } + + // parse vec -> JSON String + let mut parsed = String::new(); + for r in message.iter() { + parsed = String::from_utf8(r.message.clone()).unwrap(); + break + }; + let sp_response: crate::ResponseTypes = serde_json::from_str(&parsed).unwrap(); + + let res = match sp_response { + crate::ResponseTypes::Broadcast(response) => { + let broadcast_response = crate::BroadcastResponse { + tx_hash: response.tx_hash, + success: response.success + }; + (broadcast_response.tx_hash, broadcast_response.success) + }, + // TODO make this a proper error + _ => { println!("weird response"); (String::from("placeholder error"), false) } + }; + + res + - client.wait_for_messages().await -} + } diff --git a/demos/rust-cosmos-broadcaster/src/lib.rs b/demos/rust-cosmos-broadcaster/src/lib.rs index ecd8d5b83a..11523607af 100644 --- a/demos/rust-cosmos-broadcaster/src/lib.rs +++ b/demos/rust-cosmos-broadcaster/src/lib.rs @@ -8,7 +8,6 @@ pub mod service; pub const DEFAULT_VALIDATOR_RPC: &str = "https://qwerty-validator.qa.nymte.ch"; pub const DEFAULT_DENOM: &str = "unym"; pub const DEFAULT_PREFIX: &str = "n"; -// pub const DEFAULT_SERVICE_NYM_ADDRESS: &str = "HfbesQm2pRYCN4BAdYXhkqXBbV1Pp929mtKsESVeWXh8.8AgoUPUQbXNBCPaqAaWd3vnxhc9484qwfgrrQwBngQk2@Ck8zpXTSXMtS9YZ7k7a5BiaoLZfffWuqGWLndujh4Lw4"; #[derive(Deserialize, Serialize, Debug)] pub struct SequenceRequest { @@ -29,7 +28,8 @@ pub struct BroadcastRequest { #[derive(Deserialize, Serialize, Debug)] pub struct BroadcastResponse{ - pub tx_hash: String + pub tx_hash: String, + pub success: bool } #[derive(Debug, Deserialize, Serialize)] diff --git a/demos/rust-cosmos-broadcaster/src/service.rs b/demos/rust-cosmos-broadcaster/src/service.rs index d704d6984b..600b53be7c 100644 --- a/demos/rust-cosmos-broadcaster/src/service.rs +++ b/demos/rust-cosmos-broadcaster/src/service.rs @@ -13,14 +13,12 @@ pub async fn get_sequence(broadcaster: HttpClient, signer_address: AccountId) -> // get signer information let sequence = broadcaster.get_sequence(&signer_address).await.unwrap(); let chain_id: tendermint::chain::Id = broadcaster.get_chain_id().await.unwrap(); - crate::SequenceRequestResponse { account_number: sequence.account_number, sequence: sequence.sequence, chain_id } } pub async fn broadcast(base58_tx_bytes: String, broadcaster: HttpClient) -> crate::BroadcastResponse { // decode the base58 tx to vec let tx_bytes = bs58::decode(base58_tx_bytes).into_vec().unwrap(); - println!("decoded tx bytes: {:#?}", tx_bytes); // this is our sender address hardcoded for ease of the demo logging let from_address: AccountId = "n1p8ayfmdash352gh6yy8zlxk24dm6yzc9mdq0p6".parse().unwrap(); @@ -33,6 +31,7 @@ pub async fn broadcast(base58_tx_bytes: String, broadcaster: HttpClient) -> crat .unwrap(); // broadcast the tx + println!("broadcasting the tx to Nyx blockchain"); let broadcast_res = Client::broadcast_tx_commit(&broadcaster, tx_bytes.into()) .await .unwrap(); @@ -43,12 +42,19 @@ pub async fn broadcast(base58_tx_bytes: String, broadcaster: HttpClient) -> crat .unwrap() .unwrap(); - println!("{:#?}", broadcast_res.hash); - println!("balance before: {before}"); - println!("balance after: {after}"); - + println!("returned transaction hash: {:#?}", broadcast_res.hash.to_string()); + println!("balance before transaction: {before}"); + println!("balance after transaction: {after}"); + println!("returning tx hash to sender"); + + let success: bool = if after.amount < before.amount { + true + } else { + false + }; crate::BroadcastResponse { - tx_hash: serde_json::to_string(&broadcast_res.hash).unwrap() + tx_hash: serde_json::to_string(&broadcast_res.hash).unwrap(), + success, } } \ No newline at end of file