From 1e176f440b53e5d00339b158af7dcc0a5250a637 Mon Sep 17 00:00:00 2001 From: JeongHunP Date: Sat, 17 Sep 2022 21:12:41 +0900 Subject: [PATCH 1/5] feat: add queries for getting latest block information --- interact/src/query.rs | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/interact/src/query.rs b/interact/src/query.rs index b04e14b..42a04be 100644 --- a/interact/src/query.rs +++ b/interact/src/query.rs @@ -22,6 +22,32 @@ pub async fn send_query( Ok(result) } +pub async fn get_latest_block_height(rest_api_endpoint: &str) -> Result> { + let client = reqwest::Client::new(); + + let response = request(&client, &format!("{}/status?", rest_api_endpoint), None).await?; + + let latest_block_height = response["result"]["sync_info"]["latest_block_height"] + .as_str() + .ok_or("Failed to convert code id to &str")? + .parse::()?; + + Ok(latest_block_height) +} + +pub async fn get_latest_block_timestamp(rest_api_endpoint: &str) -> Result> { + let client = reqwest::Client::new(); + + let response = request(&client, &format!("{}/status?", rest_api_endpoint), None).await?; + + let latest_block_timestamp = response["result"]["sync_info"]["latest_block_time"] + .as_str() + .ok_or("Failed to convert code id to &str")? + .parse::()?; + + Ok(latest_block_timestamp) +} + pub async fn get_code_id( rest_api_endpoint: &str, contract_address: &str, From 43a7c6335966099ca4d0ce40574c103e6f0f52f5 Mon Sep 17 00:00:00 2001 From: JeongHunP Date: Sat, 17 Sep 2022 21:21:30 +0900 Subject: [PATCH 2/5] feat: implement get_last_block, check_connection, get_contract_list in ColonyChain --- colony-chain/Cargo.toml | 1 + colony-chain/src/lib.rs | 23 ++++++++++++++++------- colony-chain/src/main.rs | 7 ++++++- 3 files changed, 23 insertions(+), 8 deletions(-) diff --git a/colony-chain/Cargo.toml b/colony-chain/Cargo.toml index 00bb41d..5fc37e3 100644 --- a/colony-chain/Cargo.toml +++ b/colony-chain/Cargo.toml @@ -13,6 +13,7 @@ rust_decimal = "1.25.0" rust_decimal_macros = "1.25.0" pdao-colony-common = { version = "0.0.0" } pdao-colony-contract-common = { version = "0.0.0" } +pdao-cosmos-interact = { path = "../interact"} serde-tc = "0.3.3" serde_json = { version = "1.0" } anyhow = { version = "1.0" } diff --git a/colony-chain/src/lib.rs b/colony-chain/src/lib.rs index 06594e3..54f6627 100644 --- a/colony-chain/src/lib.rs +++ b/colony-chain/src/lib.rs @@ -1,11 +1,17 @@ use async_trait::async_trait; use pdao_colony_common::*; use pdao_colony_contract_common::*; +use pdao_cosmos_interact::query; use rust_decimal::prelude::*; use rust_decimal_macros::dec; use std::collections::HashMap; -pub struct Juno {} +pub struct Juno { + pub full_node_url: String, + pub rpc_url: String, + pub treasury_address: String, + pub lightclient_address: String, +} #[async_trait] impl ColonyChain for Juno { @@ -14,25 +20,28 @@ impl ColonyChain for Juno { } async fn get_last_block(&self) -> Result { - Ok(Block { - height: 0, - timestamp: 0, - }) + let height = query::get_latest_block_height(&self.rpc_url).await.unwrap(); + let timestamp = query::get_latest_block_timestamp(&self.rpc_url) + .await + .unwrap(); + + Ok(Block { height, timestamp }) } async fn check_connection(&self) -> Result<(), Error> { + let _height = query::get_latest_block_height(&self.rpc_url).await; Ok(()) } async fn get_contract_list(&self) -> Result, Error> { Ok(vec![ ContractInfo { - address: "0xabcd".to_owned(), + address: self.lightclient_address.clone(), contract_type: ContractType::LightClient, sequence: 0, }, ContractInfo { - address: "0x1234".to_owned(), + address: self.treasury_address.clone(), contract_type: ContractType::Treasury, sequence: 0, }, diff --git a/colony-chain/src/main.rs b/colony-chain/src/main.rs index 5e2d44c..633cbb6 100644 --- a/colony-chain/src/main.rs +++ b/colony-chain/src/main.rs @@ -14,7 +14,12 @@ async fn main() { port, vec![( "juno".to_owned(), - serde_tc::http::create_http_object(Arc::new(Juno {}) as Arc), + serde_tc::http::create_http_object(Arc::new(Juno { + full_node_url: "https://lcd.uni.juno.deuslabs.fi".to_string(), + rpc_url: "https://rpc.uni.juno.deuslabs.fi".to_string(), + treasury_address: "".to_string(), + lightclient_address: "".to_string(), + }) as Arc), )] .into_iter() .collect(), From 6d1b6dabf024df92f662728d59b83a71339bcc1e Mon Sep 17 00:00:00 2001 From: JeongHunP Date: Wed, 28 Sep 2022 21:27:58 +0900 Subject: [PATCH 3/5] feat: implement light client functions --- colony-chain/Cargo.toml | 1 + colony-chain/src/lib.rs | 62 +++++++++++++++++++++++++++++++++++++---- interact/src/execute.rs | 23 ++++++++++----- interact/src/query.rs | 24 ++++++++++++++++ 4 files changed, 97 insertions(+), 13 deletions(-) diff --git a/colony-chain/Cargo.toml b/colony-chain/Cargo.toml index 5fc37e3..5a377f6 100644 --- a/colony-chain/Cargo.toml +++ b/colony-chain/Cargo.toml @@ -17,3 +17,4 @@ pdao-cosmos-interact = { path = "../interact"} serde-tc = "0.3.3" serde_json = { version = "1.0" } anyhow = { version = "1.0" } +cosmwasm-std = "1.0.0" diff --git a/colony-chain/src/lib.rs b/colony-chain/src/lib.rs index 54f6627..532aeed 100644 --- a/colony-chain/src/lib.rs +++ b/colony-chain/src/lib.rs @@ -1,9 +1,15 @@ use async_trait::async_trait; +use cosmwasm_std::from_binary; +use cosmwasm_std::testing::{mock_dependencies, mock_env}; use pdao_colony_common::*; use pdao_colony_contract_common::*; -use pdao_cosmos_interact::query; +use pdao_cosmos_interact::{execute, query}; +use pdao_cosmos_light_client::query; //needs to be change use rust_decimal::prelude::*; use rust_decimal_macros::dec; + + +use serde_json::json; use std::collections::HashMap; pub struct Juno { @@ -11,6 +17,13 @@ pub struct Juno { pub rpc_url: String, pub treasury_address: String, pub lightclient_address: String, + pub relayer_account: String, + + pub chain_id: String, + pub denom: String, + pub mnemonic: String, + pub password: String, + pub account_prefix: String, } #[async_trait] @@ -23,13 +36,16 @@ impl ColonyChain for Juno { let height = query::get_latest_block_height(&self.rpc_url).await.unwrap(); let timestamp = query::get_latest_block_timestamp(&self.rpc_url) .await - .unwrap(); + .map_err(|_| Error::ConnectionError("test".to_string()))?; Ok(Block { height, timestamp }) } async fn check_connection(&self) -> Result<(), Error> { - let _height = query::get_latest_block_height(&self.rpc_url).await; + let _height = query::get_latest_block_height(&self.rpc_url) + .await + .map_err(|_| Error::ConnectionError("test".to_string()))?; + Ok(()) } @@ -49,11 +65,21 @@ impl ColonyChain for Juno { } async fn get_relayer_account_info(&self) -> Result<(String, Decimal), Error> { - Ok(("0x12341234".to_owned(), dec!(12.34))) + let balance_str = pdao_cosmos_interact::query::get_balance_amount(&self.full_node_url, &self.relayer_account) + .await + .map_err(|_| Error::ConnectionError("test".to_string()))? + .as_str(); + let balance = Decimal::from_str(balance_str).map_err(|_| Error::ConnectionError("test".to_string()))?; + + Ok((self.relayer_account, balance)) } async fn get_light_client_header(&self) -> Result { - Ok("Hmm".to_owned()) + let mut deps = mock_dependencies(); + let res = pdao_cosmos_light_client::query(deps.as_ref(), mock_env(), QueryMsg::GetHeader {})?; + let response: GetHeaderResponse = from_binary(&res).map_err(|_| pdao_colony_common::Error::ConnectionError("test".to_string())); + + Ok(response.header.to_owned()) } async fn get_treasury_fungible_token_balance(&self) -> Result, Error> { @@ -75,7 +101,31 @@ impl ColonyChain for Juno { } async fn update_light_client(&self, _message: LightClientUpdateMessage) -> Result<(), Error> { - Ok(()) + let msg = json!({ + "update": { + "header": _message.header, + "proof": _message.proof + } + }); + + let result = execute::send_execute_test( + self.mnemonic.clone(), + &self.password, + &self.chain_id, + &self.rpc_url, + &self.full_node_url, + &self.denom, + &self.account_prefix, + 10000, + &self.lightclient_address, + serde_json::to_vec(&msg).unwrap(), + 2000000, + 2000000, + None, + ).await + .map_err(|_| pdao_colony_common::Error::TransactionRejected("test".to_string())); + + result } async fn transfer_treasury_fungible_token( diff --git a/interact/src/execute.rs b/interact/src/execute.rs index aeb1be8..395c8fe 100644 --- a/interact/src/execute.rs +++ b/interact/src/execute.rs @@ -1,16 +1,17 @@ use cosmrs::{ - crypto, dev, rpc, + dev, rpc, tx::{self, Fee, Msg, SignDoc, SignerInfo}, Coin, }; use super::query::{get_account_number, get_sequence_number}; -use super::utils::private_to_pub_and_account; +use super::utils::{mnemonic_to_private_key, private_to_pub_and_account}; use std::error::Error; #[allow(clippy::too_many_arguments)] pub async fn send_execute( - sender_private_key: &crypto::secp256k1::SigningKey, + mnemonic: String, + password: &str, chain_id: &str, rpc_address: &str, api_address: &str, @@ -23,8 +24,12 @@ pub async fn send_execute( gas_limit: u64, tx_memo: Option<&str>, ) -> Result<(), Box> { - let (sender_public_key, sender_account_id) = - private_to_pub_and_account(sender_private_key, account_id)?; + let (sender_public_key, sender_account_id) = { + let sender_private_key = mnemonic_to_private_key(mnemonic.clone(), password) + .unwrap() + .into(); + private_to_pub_and_account(&sender_private_key, account_id)? + }; let funds = Coin { amount: funds.into(), @@ -54,7 +59,11 @@ pub async fn send_execute( SignerInfo::single_direct(Some(sender_public_key), sequence_number).auth_info(fee); let account_number = get_account_number(api_address, sender_account_id.as_ref()).await?; let sign_doc = SignDoc::new(&tx_body, &auth_info, &chain_id, account_number)?; - let tx_raw = sign_doc.sign(sender_private_key)?; + + let tx_raw = { + let sender_private_key = mnemonic_to_private_key(mnemonic, password).unwrap().into(); + sign_doc.sign(&sender_private_key)? + }; let rpc_address = rpc_address.to_owned(); let rpc_client = rpc::HttpClient::new(rpc_address.as_str())?; @@ -79,4 +88,4 @@ pub async fn send_execute( assert_eq!(&auth_info, &tx.auth_info); Ok(()) -} +} \ No newline at end of file diff --git a/interact/src/query.rs b/interact/src/query.rs index 42a04be..da01205 100644 --- a/interact/src/query.rs +++ b/interact/src/query.rs @@ -22,6 +22,30 @@ pub async fn send_query( Ok(result) } +pub async fn get_balance_amount( + rest_api_endpoint: &str, + account_address: &str +) -> Result> { + let client = reqwest::Client::new(); + let response = request( + &client, + &format!( + "{}/cosmos/bank/v1beta1/balances/{}", + rest_api_endpoint, account_address + ), + None, + ) + .await?; + + let current_balance = response["balances"] + .as_array() + .ok_or("Failed to convert balance to array")?[0]["amount"] + .to_string(); + + + Ok(current_balance) +} + pub async fn get_latest_block_height(rest_api_endpoint: &str) -> Result> { let client = reqwest::Client::new(); From 5f6fa85a3dad63676abbbd84b49ccf422b0c89b1 Mon Sep 17 00:00:00 2001 From: JeongHunP Date: Fri, 30 Sep 2022 00:37:44 +0900 Subject: [PATCH 4/5] refractor: modify suite1.rs as send_execute changes --- colony-chain/src/lib.rs | 2 +- interact/tests/suite1.rs | 21 ++++++--------------- 2 files changed, 7 insertions(+), 16 deletions(-) diff --git a/colony-chain/src/lib.rs b/colony-chain/src/lib.rs index 532aeed..fe73c3f 100644 --- a/colony-chain/src/lib.rs +++ b/colony-chain/src/lib.rs @@ -108,7 +108,7 @@ impl ColonyChain for Juno { } }); - let result = execute::send_execute_test( + let result = execute::send_execute( self.mnemonic.clone(), &self.password, &self.chain_id, diff --git a/interact/tests/suite1.rs b/interact/tests/suite1.rs index 5b1f6ad..281c53c 100644 --- a/interact/tests/suite1.rs +++ b/interact/tests/suite1.rs @@ -178,17 +178,14 @@ async fn test_execute_increment_fail() { ); let _config = Config::read_from_path(full_path); - let sender_private_key = mnemonic_to_private_key(_config.mnemonic, &_config.password) - .unwrap() - .into(); - // This should be failed since the count is above 10 let msg = json!({ "increment": {"count": 20u64} }); let _result = execute::send_execute( - &sender_private_key, + _config.mnemonic.clone(), + &_config.password, &_config.chain_id, &_config.rpc, &_config.full_node_url, @@ -215,16 +212,13 @@ async fn test_execute_increment() { ); let _config = Config::read_from_path(full_path); - let sender_private_key = mnemonic_to_private_key(_config.mnemonic, &_config.password) - .unwrap() - .into(); - let msg = json!({ "increment": {"count": 5u64} }); let _result = execute::send_execute( - &sender_private_key, + _config.mnemonic.clone(), + &_config.password, &_config.chain_id, &_config.rpc, &_config.full_node_url, @@ -251,16 +245,13 @@ async fn test_execute_reset() { ); let _config = Config::read_from_path(full_path); - let sender_private_key = mnemonic_to_private_key(_config.mnemonic, &_config.password) - .unwrap() - .into(); - let msg = json!({ "reset": {"count": 50u64} }); let _result = execute::send_execute( - &sender_private_key, + _config.mnemonic.clone(), + &_config.password, &_config.chain_id, &_config.rpc, &_config.full_node_url, From c61eb1f06cc945c2e4f9322bfa0fd848033f9be8 Mon Sep 17 00:00:00 2001 From: JeongHunP Date: Wed, 5 Oct 2022 20:40:25 +0900 Subject: [PATCH 5/5] feat: implement functions about light client --- colony-chain/Cargo.toml | 2 ++ colony-chain/src/lib.rs | 71 +++++++++++++++++++++++++--------------- colony-chain/src/main.rs | 6 ++++ interact/src/execute.rs | 4 +-- interact/src/query.rs | 3 +- 5 files changed, 55 insertions(+), 31 deletions(-) diff --git a/colony-chain/Cargo.toml b/colony-chain/Cargo.toml index 5a377f6..735a69f 100644 --- a/colony-chain/Cargo.toml +++ b/colony-chain/Cargo.toml @@ -14,7 +14,9 @@ rust_decimal_macros = "1.25.0" pdao-colony-common = { version = "0.0.0" } pdao-colony-contract-common = { version = "0.0.0" } pdao-cosmos-interact = { path = "../interact"} +pdao-cosmos-light-client = {path = "../contracts/light-client"} serde-tc = "0.3.3" serde_json = { version = "1.0" } anyhow = { version = "1.0" } cosmwasm-std = "1.0.0" +base64 = "0.13.0" \ No newline at end of file diff --git a/colony-chain/src/lib.rs b/colony-chain/src/lib.rs index fe73c3f..d7c4b2d 100644 --- a/colony-chain/src/lib.rs +++ b/colony-chain/src/lib.rs @@ -1,14 +1,10 @@ use async_trait::async_trait; -use cosmwasm_std::from_binary; -use cosmwasm_std::testing::{mock_dependencies, mock_env}; use pdao_colony_common::*; use pdao_colony_contract_common::*; use pdao_cosmos_interact::{execute, query}; -use pdao_cosmos_light_client::query; //needs to be change use rust_decimal::prelude::*; use rust_decimal_macros::dec; - use serde_json::json; use std::collections::HashMap; @@ -33,10 +29,13 @@ impl ColonyChain for Juno { } async fn get_last_block(&self) -> Result { - let height = query::get_latest_block_height(&self.rpc_url).await.unwrap(); + let height = query::get_latest_block_height(&self.rpc_url) + .await + .map_err(|_| Error::ConnectionError("test".to_string()))?; //TODO: error message + let timestamp = query::get_latest_block_timestamp(&self.rpc_url) .await - .map_err(|_| Error::ConnectionError("test".to_string()))?; + .map_err(|_| Error::ConnectionError("test".to_string()))?; //TODO: error message Ok(Block { height, timestamp }) } @@ -44,8 +43,8 @@ impl ColonyChain for Juno { async fn check_connection(&self) -> Result<(), Error> { let _height = query::get_latest_block_height(&self.rpc_url) .await - .map_err(|_| Error::ConnectionError("test".to_string()))?; - + .map_err(|_| Error::ConnectionError("test".to_string()))?; //TODO: error message + Ok(()) } @@ -65,21 +64,37 @@ impl ColonyChain for Juno { } async fn get_relayer_account_info(&self) -> Result<(String, Decimal), Error> { - let balance_str = pdao_cosmos_interact::query::get_balance_amount(&self.full_node_url, &self.relayer_account) + let res = query::get_balance_amount(&self.full_node_url, &self.relayer_account) .await - .map_err(|_| Error::ConnectionError("test".to_string()))? - .as_str(); - let balance = Decimal::from_str(balance_str).map_err(|_| Error::ConnectionError("test".to_string()))?; + .map_err(|_| Error::ConnectionError("test".to_string()))?; //TODO: error message - Ok((self.relayer_account, balance)) + let balance = Decimal::from_str(res.as_ref()) + .map_err(|_| Error::ConnectionError("test".to_string()))?; //TODO: error message + + Ok((self.relayer_account.to_owned(), balance)) } async fn get_light_client_header(&self) -> Result { - let mut deps = mock_dependencies(); - let res = pdao_cosmos_light_client::query(deps.as_ref(), mock_env(), QueryMsg::GetHeader {})?; - let response: GetHeaderResponse = from_binary(&res).map_err(|_| pdao_colony_common::Error::ConnectionError("test".to_string())); + let msg = json!({ + "get_header": {} + }); - Ok(response.header.to_owned()) + let encode_msg = base64::encode( + &serde_json::to_vec(&msg) + .map_err(|_| Error::InvalidMessageArgument("test".to_string()))?, + ); //TODO: error message + + let response = query::send_query( + &self.full_node_url, + &self.lightclient_address, + encode_msg.as_str(), + ) + .await + .map_err(|_| Error::ConnectionError("test".to_string()))?; //TODO: error message + + let header = response["data"]["header"].to_string(); //TODO: current type of header is string + + Ok(header) } async fn get_treasury_fungible_token_balance(&self) -> Result, Error> { @@ -107,8 +122,11 @@ impl ColonyChain for Juno { "proof": _message.proof } }); - - let result = execute::send_execute( + + let execute_msg = + serde_json::to_vec(&msg).map_err(|_| Error::ConnectionError("test".to_string()))?; //TODO: error type and message + + execute::send_execute( self.mnemonic.clone(), &self.password, &self.chain_id, @@ -116,16 +134,15 @@ impl ColonyChain for Juno { &self.full_node_url, &self.denom, &self.account_prefix, - 10000, + 10000, //TODO: fix &self.lightclient_address, - serde_json::to_vec(&msg).unwrap(), - 2000000, - 2000000, + execute_msg, + 2000000, //TODO: fix + 2000000, //TODO: fix None, - ).await - .map_err(|_| pdao_colony_common::Error::TransactionRejected("test".to_string())); - - result + ) + .await + .map_err(|_| pdao_colony_common::Error::TransactionRejected("test".to_string())) } async fn transfer_treasury_fungible_token( diff --git a/colony-chain/src/main.rs b/colony-chain/src/main.rs index 633cbb6..19584a4 100644 --- a/colony-chain/src/main.rs +++ b/colony-chain/src/main.rs @@ -19,6 +19,12 @@ async fn main() { rpc_url: "https://rpc.uni.juno.deuslabs.fi".to_string(), treasury_address: "".to_string(), lightclient_address: "".to_string(), + relayer_account: "".to_string(), + chain_id: "".to_string(), + denom: "".to_string(), + mnemonic: "".to_string(), + password: "".to_string(), + account_prefix: "".to_string(), }) as Arc), )] .into_iter() diff --git a/interact/src/execute.rs b/interact/src/execute.rs index 395c8fe..fb3fbe1 100644 --- a/interact/src/execute.rs +++ b/interact/src/execute.rs @@ -59,7 +59,7 @@ pub async fn send_execute( SignerInfo::single_direct(Some(sender_public_key), sequence_number).auth_info(fee); let account_number = get_account_number(api_address, sender_account_id.as_ref()).await?; let sign_doc = SignDoc::new(&tx_body, &auth_info, &chain_id, account_number)?; - + let tx_raw = { let sender_private_key = mnemonic_to_private_key(mnemonic, password).unwrap().into(); sign_doc.sign(&sender_private_key)? @@ -88,4 +88,4 @@ pub async fn send_execute( assert_eq!(&auth_info, &tx.auth_info); Ok(()) -} \ No newline at end of file +} diff --git a/interact/src/query.rs b/interact/src/query.rs index da01205..4bf4553 100644 --- a/interact/src/query.rs +++ b/interact/src/query.rs @@ -24,7 +24,7 @@ pub async fn send_query( pub async fn get_balance_amount( rest_api_endpoint: &str, - account_address: &str + account_address: &str, ) -> Result> { let client = reqwest::Client::new(); let response = request( @@ -42,7 +42,6 @@ pub async fn get_balance_amount( .ok_or("Failed to convert balance to array")?[0]["amount"] .to_string(); - Ok(current_balance) }