From ffb9d0e0006da3f79134a29e7b417cf468d4d95d Mon Sep 17 00:00:00 2001 From: Daniel Karzel Date: Fri, 4 Dec 2020 19:54:12 +1100 Subject: [PATCH] WIP - Refactor monerod to use @thomaseizinger rust-jsonrpc-client --- Cargo.lock | 24 ++++++ monero-harness/Cargo.toml | 2 + monero-harness/src/lib.rs | 18 +++-- monero-harness/src/rpc.rs | 1 + monero-harness/src/rpc/monerod.rs | 103 +++++--------------------- monero-harness/src/rpc/monerod_api.rs | 11 +++ monero-harness/tests/monerod.rs | 7 +- monero-harness/tests/wallet.rs | 1 + swap/src/bitcoin.rs | 10 --- 9 files changed, 76 insertions(+), 101 deletions(-) create mode 100644 monero-harness/src/rpc/monerod_api.rs diff --git a/Cargo.lock b/Cargo.lock index 116a079b..baae4663 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1550,6 +1550,28 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "jsonrpc_client" +version = "0.3.0" +source = "git+https://github.com/thomaseizinger/rust-jsonrpc-client?rev=c7010817e0f86ab24b3dc10d6bb0463faa0aace4#c7010817e0f86ab24b3dc10d6bb0463faa0aace4" +dependencies = [ + "async-trait", + "jsonrpc_client_macro", + "reqwest", + "serde", + "serde_json", + "url", +] + +[[package]] +name = "jsonrpc_client_macro" +version = "0.1.0" +source = "git+https://github.com/thomaseizinger/rust-jsonrpc-client?rev=c7010817e0f86ab24b3dc10d6bb0463faa0aace4#c7010817e0f86ab24b3dc10d6bb0463faa0aace4" +dependencies = [ + "quote 1.0.7", + "syn 1.0.48", +] + [[package]] name = "keccak" version = "0.1.0" @@ -2000,8 +2022,10 @@ name = "monero-harness" version = "0.1.0" dependencies = [ "anyhow", + "async-trait", "digest_auth", "futures", + "jsonrpc_client", "port_check", "rand 0.7.3", "reqwest", diff --git a/monero-harness/Cargo.toml b/monero-harness/Cargo.toml index 060df781..01a60759 100644 --- a/monero-harness/Cargo.toml +++ b/monero-harness/Cargo.toml @@ -5,9 +5,11 @@ authors = ["CoBloX Team "] edition = "2018" [dependencies] +async-trait = "0.1" anyhow = "1" digest_auth = "0.2.3" futures = "0.3" +jsonrpc_client = { git = "https://github.com/thomaseizinger/rust-jsonrpc-client", rev = "c7010817e0f86ab24b3dc10d6bb0463faa0aace4", features = ["reqwest"] } port_check = "0.1" rand = "0.7" reqwest = { version = "0.10", default-features = false, features = ["json", "native-tls"] } diff --git a/monero-harness/src/lib.rs b/monero-harness/src/lib.rs index 7d42a586..394d315e 100644 --- a/monero-harness/src/lib.rs +++ b/monero-harness/src/lib.rs @@ -118,7 +118,10 @@ impl<'c> Monero { // generate the first 70 as bulk let monerod = &self.monerod; - let block = monerod.client().generate_blocks(70, &miner_address).await?; + let block = monerod + .client()? + .generate_blocks(70, &miner_address) + .await?; tracing::info!("Generated {:?} blocks", block); miner_wallet.refresh().await?; @@ -128,7 +131,10 @@ impl<'c> Monero { let address = wallet.address().await?.address; miner_wallet.transfer(&address, *amount).await?; tracing::info!("Funded {} wallet with {}", wallet.name, amount); - monerod.client().generate_blocks(10, &miner_address).await?; + monerod + .client()? + .generate_blocks(10, &miner_address) + .await?; wallet.refresh().await?; } } @@ -136,7 +142,7 @@ impl<'c> Monero { monerod.start_miner(&miner_address).await?; tracing::info!("Waiting for miner wallet to catch up..."); - let block_height = monerod.client().get_block_count().await?; + let block_height = monerod.client()?.get_block_count_rpc().await?; miner_wallet .wait_for_wallet_height(block_height) .await @@ -204,14 +210,14 @@ impl<'c> Monerod { )) } - pub fn client(&self) -> monerod::Client { - monerod::Client::localhost(self.rpc_port) + pub fn client(&self) -> anyhow::Result { + Ok(monerod::Client::localhost(self.rpc_port)?) } /// Spawns a task to mine blocks in a regular interval to the provided /// address pub async fn start_miner(&self, miner_wallet_address: &str) -> Result<()> { - let monerod = self.client(); + let monerod = self.client()?; let _ = tokio::spawn(mine(monerod, miner_wallet_address.to_string())); Ok(()) } diff --git a/monero-harness/src/rpc.rs b/monero-harness/src/rpc.rs index eae827c1..306c15e4 100644 --- a/monero-harness/src/rpc.rs +++ b/monero-harness/src/rpc.rs @@ -1,5 +1,6 @@ //! JSON RPC clients for `monerd` and `monero-wallet-rpc`. pub mod monerod; +pub mod monerod_api; pub mod wallet; use serde::{Deserialize, Serialize}; diff --git a/monero-harness/src/rpc/monerod.rs b/monero-harness/src/rpc/monerod.rs index e27f2556..773558e1 100644 --- a/monero-harness/src/rpc/monerod.rs +++ b/monero-harness/src/rpc/monerod.rs @@ -1,106 +1,41 @@ -use crate::rpc::{Request, Response}; - -use anyhow::Result; -use reqwest::Url; +use crate::rpc::monerod_api::MonerodRpcApi; use serde::{Deserialize, Serialize}; -use tracing::debug; -/// RPC client for monerod and monero-wallet-rpc. +#[jsonrpc_client::implement(MonerodRpcApi)] #[derive(Debug, Clone)] pub struct Client { - pub inner: reqwest::Client, - pub url: Url, + inner: reqwest::Client, + base_url: reqwest::Url, } impl Client { - /// New local host monerod RPC client. - pub fn localhost(port: u16) -> Self { - let url = format!("http://127.0.0.1:{}/json_rpc", port); - let url = Url::parse(&url).expect("url is well formed"); - - Self { + pub fn localhost(port: u16) -> anyhow::Result { + Ok(Client { inner: reqwest::Client::new(), - url, - } + base_url: reqwest::Url::parse(format!("http://127.0.0.1:{}/json_rpc", port).as_str())?, + }) } pub async fn generate_blocks( &self, amount_of_blocks: u32, wallet_address: &str, - ) -> Result { - let params = GenerateBlocksParams { - amount_of_blocks, - wallet_address: wallet_address.to_owned(), - }; - let url = self.url.clone(); - // // Step 1: Get the auth header - // let res = self.inner.get(url.clone()).send().await?; - // let headers = res.headers(); - // let wwwauth = headers["www-authenticate"].to_str()?; - // - // // Step 2: Given the auth header, sign the digest for the real req. - // let tmp_url = url.clone(); - // let context = AuthContext::new("username", "password", tmp_url.path()); - // let mut prompt = digest_auth::parse(wwwauth)?; - // let answer = prompt.respond(&context)?.to_header_string(); - - let request = Request::new("generateblocks", params); - - let response = self - .inner - .post(url) - .json(&request) - .send() - .await? - .text() + ) -> anyhow::Result { + let res: GenerateBlocks = self + .generateblocks(amount_of_blocks, wallet_address) .await?; - - debug!("generate blocks response: {}", response); - - let res: Response = serde_json::from_str(&response)?; - - Ok(res.result) + Ok(res) } - // $ curl http://127.0.0.1:18081/json_rpc -d '{"jsonrpc":"2.0","id":"0","method":"get_block_header_by_height","params":{"height":1}}' -H 'Content-Type: application/json' - pub async fn get_block_header_by_height(&self, height: u32) -> Result { - let params = GetBlockHeaderByHeightParams { height }; - let request = Request::new("get_block_header_by_height", params); - - let response = self - .inner - .post(self.url.clone()) - .json(&request) - .send() - .await? - .text() - .await?; - - debug!("get block header by height response: {}", response); - - let res: Response = serde_json::from_str(&response)?; - - Ok(res.result.block_header) + // TODO: We should not need wrapper functions, why does it not compile without? + pub async fn get_block_header_by_height_rpc(&self, height: u32) -> anyhow::Result { + let res: BlockHeader = self.get_block_header_by_height(height).await?; + Ok(res) } - pub async fn get_block_count(&self) -> Result { - let request = Request::new("get_block_count", ""); - - let response = self - .inner - .post(self.url.clone()) - .json(&request) - .send() - .await? - .text() - .await?; - - debug!("get block count response: {}", response); - - let res: Response = serde_json::from_str(&response)?; - - Ok(res.result.count) + pub async fn get_block_count_rpc(&self) -> anyhow::Result { + let res: u32 = self.get_block_count().await?; + Ok(res) } } diff --git a/monero-harness/src/rpc/monerod_api.rs b/monero-harness/src/rpc/monerod_api.rs new file mode 100644 index 00000000..f9c7cb22 --- /dev/null +++ b/monero-harness/src/rpc/monerod_api.rs @@ -0,0 +1,11 @@ +use crate::rpc::monerod::{BlockHeader, GenerateBlocks}; + +#[jsonrpc_client::api(version = "1.0")] +#[async_trait::async_trait] +pub trait MonerodRpcApi { + async fn generateblocks(&self, amount_of_blocks: u32, wallet_address: &str) -> GenerateBlocks; + + async fn get_block_header_by_height(&self, height: u32) -> BlockHeader; + + async fn get_block_count(&self) -> u32; +} diff --git a/monero-harness/tests/monerod.rs b/monero-harness/tests/monerod.rs index 35f12744..2c72c66b 100644 --- a/monero-harness/tests/monerod.rs +++ b/monero-harness/tests/monerod.rs @@ -20,7 +20,12 @@ async fn init_miner_and_mine_to_miner_address() { time::delay_for(Duration::from_millis(1010)).await; // after a bit more than 1 sec another block should have been mined - let block_height = monerod.client().get_block_count().await.unwrap(); + let block_height = monerod + .client() + .unwrap() + .get_block_count_rpc() + .await + .unwrap(); assert_that(&block_height).is_greater_than(70); } diff --git a/monero-harness/tests/wallet.rs b/monero-harness/tests/wallet.rs index 44fc6ec5..191d73f0 100644 --- a/monero-harness/tests/wallet.rs +++ b/monero-harness/tests/wallet.rs @@ -42,6 +42,7 @@ async fn fund_transfer_and_check_tx_key() { monero .monerod() .client() + .unwrap() .generate_blocks(10, &miner_address) .await .unwrap(); diff --git a/swap/src/bitcoin.rs b/swap/src/bitcoin.rs index bcef2462..6135ce60 100644 --- a/swap/src/bitcoin.rs +++ b/swap/src/bitcoin.rs @@ -38,16 +38,6 @@ impl Wallet { pub async fn new_address(&self) -> Result
{ self.0.new_address().await.map_err(Into::into) } - - pub async fn transaction_fee(&self, txid: Txid) -> Result { - let fee = self - .0 - .get_wallet_transaction(txid) - .await - .map(|res| bitcoin::Amount::from_btc(-res.fee))??; - - Ok(fee) - } } #[async_trait]