├── types ├── src │ ├── error.rs │ └── lib.rs └── Cargo.toml ├── .gitignore ├── rpc ├── .gitignore ├── src │ ├── lib.rs │ ├── error.rs │ ├── chain.rs │ ├── client.rs │ ├── network.rs │ ├── names.rs │ ├── node.rs │ ├── tx.rs │ ├── mining.rs │ ├── mempool.rs │ └── block.rs ├── tests │ ├── client_name_tests.rs │ ├── common │ │ └── mod.rs │ ├── client_chain_test.rs │ ├── network_test.rs │ ├── client_tx_test.rs │ ├── client_mempool_test.rs │ ├── client_block_test.rs │ ├── client_node_test.rs │ └── client_mining_test.rs └── Cargo.toml ├── Cargo.toml ├── wallet-rpc ├── tests │ ├── common │ │ └── mod.rs │ └── wallet_basic_test.rs ├── src │ ├── lib.rs │ ├── client.rs │ ├── error.rs │ └── basic.rs └── Cargo.toml ├── README.md ├── .github └── workflows │ ├── audit.yml │ └── pr.yml └── LICENSE /types/src/error.rs: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | **/*.rs.bk 3 | Cargo.lock 4 | -------------------------------------------------------------------------------- /rpc/.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | **/*.rs.bk 3 | Cargo.lock 4 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | 3 | members = [ 4 | "rpc", 5 | "wallet-rpc", 6 | "types" 7 | ] 8 | -------------------------------------------------------------------------------- /wallet-rpc/tests/common/mod.rs: -------------------------------------------------------------------------------- 1 | use handshake_wallet_rpc::HandshakeWalletRpcClient; 2 | 3 | pub fn setup() -> HandshakeWalletRpcClient { 4 | HandshakeWalletRpcClient::new("http://localhost:12039") 5 | } 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | handshake-rpc 2 | =============== 3 | 4 | Rust client library for the Handshake daemon's JSON-RPC API. 5 | 6 | # License 7 | 8 | All code is licensed using the MIT license, as per the LICENSE file. 9 | -------------------------------------------------------------------------------- /wallet-rpc/src/lib.rs: -------------------------------------------------------------------------------- 1 | pub mod basic; 2 | pub mod client; 3 | pub mod error; 4 | 5 | pub use client::HandshakeWalletRpcClient; 6 | pub use error::Error; 7 | 8 | pub type Result = std::result::Result; 9 | -------------------------------------------------------------------------------- /rpc/src/lib.rs: -------------------------------------------------------------------------------- 1 | mod block; 2 | mod chain; 3 | mod mempool; 4 | mod mining; 5 | mod names; 6 | mod network; 7 | mod node; 8 | // mod tx; 9 | pub mod client; 10 | pub mod error; 11 | 12 | pub use client::HandshakeRpcClient; 13 | pub use error::Error; 14 | 15 | pub type Result = std::result::Result; 16 | -------------------------------------------------------------------------------- /rpc/tests/client_name_tests.rs: -------------------------------------------------------------------------------- 1 | mod common; 2 | 3 | use common::setup; 4 | 5 | #[async_std::test] 6 | async fn test_grind_name() { 7 | let client = setup(); 8 | 9 | let name = client.grind_name(None).await; 10 | 11 | assert!(name.is_ok()); 12 | } 13 | 14 | //@todo tests for the rest of names here. 15 | -------------------------------------------------------------------------------- /.github/workflows/audit.yml: -------------------------------------------------------------------------------- 1 | name: Security audit 2 | on: 3 | push: 4 | paths: 5 | - '**/Cargo.toml' 6 | - '**/Cargo.lock' 7 | schedule: 8 | - cron: '0 0 * * *' 9 | jobs: 10 | security_audit: 11 | runs-on: ubuntu-latest 12 | steps: 13 | - uses: actions/checkout@v1 14 | - uses: actions-rs/audit-check@v1 15 | with: 16 | token: ${{ secrets.GITHUB_TOKEN }} 17 | -------------------------------------------------------------------------------- /types/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "handshake-client-types" 3 | version = "0.1.0" 4 | authors = ["Urkel Labs "] 5 | edition = "2018" 6 | 7 | [dependencies] 8 | 9 | # Known External 10 | extended-primitives = { version="0.3.4", features=["serialization"]} 11 | handshake-primitives = { git="https://github.com/UrkelLabs/rsd", features=["json"]} 12 | handshake-types = { git="https://github.com/UrkelLabs/rsd", features=["json"]} 13 | 14 | # Unknown External 15 | serde = "1" 16 | serde_derive = "1" 17 | serde_json = "1" 18 | -------------------------------------------------------------------------------- /wallet-rpc/tests/wallet_basic_test.rs: -------------------------------------------------------------------------------- 1 | mod common; 2 | 3 | use common::setup; 4 | 5 | #[async_std::test] 6 | async fn test_get_balance() { 7 | let client = setup(); 8 | 9 | // let info = client.get_blockchain_info().await; 10 | // 11 | client.select_wallet("pool").await; 12 | 13 | let balance = client.get_balance(None).await; 14 | 15 | dbg!(balance); 16 | 17 | // assert!(info.is_ok()); 18 | } 19 | 20 | #[async_std::test] 21 | async fn test_history() { 22 | let client = setup(); 23 | 24 | client.select_wallet("pool").await; 25 | 26 | let history = client.history(None, None, None, None).await; 27 | 28 | dbg!(history); 29 | } 30 | -------------------------------------------------------------------------------- /rpc/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "handshake-rpc" 3 | version = "0.1.0" 4 | authors = ["Urkel Labs "] 5 | edition = "2018" 6 | 7 | [dependencies] 8 | 9 | # Local 10 | handshake-client-types = { path="../types" } 11 | 12 | # Known External 13 | extended-primitives = { git="https://github.com/UrkelLabs/extended-primitives", features=["serialization"]} 14 | rpc-json-client = { git= "https://github.com/UrkelLabs/rpc"} 15 | handshake-primitives = { git="https://github.com/UrkelLabs/rsd"} 16 | 17 | # Unknown External 18 | serde = "1" 19 | serde_derive = "1" 20 | serde_json = "1" 21 | futures = "0.3.1" 22 | 23 | [dev-dependencies] 24 | async-std = { version = "1.5.0", features = ["attributes"] } 25 | 26 | 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /rpc/tests/common/mod.rs: -------------------------------------------------------------------------------- 1 | use handshake_rpc::HandshakeRpcClient; 2 | 3 | pub fn setup() -> HandshakeRpcClient { 4 | HandshakeRpcClient::new("http://127.0.0.1:12037") 5 | } 6 | 7 | //@todo make this global, so we only do once. 8 | pub async fn get_txid(client: &HandshakeRpcClient) -> String { 9 | let tip = client.get_block_count().await.unwrap(); 10 | 11 | let block = client.get_block_by_height_verbose(tip).await.unwrap(); 12 | 13 | block.tx[0].clone() 14 | } 15 | 16 | pub fn get_tx_hex() -> String { 17 | "00000000010000000000000000000000000000000000000000000000000000000000000000ffffffff6a8a34ba0100ca9a3b00000000001409e0b3bc9c04a4589d1cb8ba5fdbd521055fac0300001f120000030c6d696e65642062792068736408647f83f2c65dbf88080000000000000000".to_string() 18 | } 19 | -------------------------------------------------------------------------------- /wallet-rpc/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "handshake-wallet-rpc" 3 | version = "0.1.0" 4 | authors = ["kilpatty "] 5 | edition = "2018" 6 | 7 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 8 | 9 | [dependencies] 10 | # Local 11 | handshake-client-types = { path="../types" } 12 | 13 | # Known External 14 | extended-primitives = { git="https://github.com/UrkelLabs/extended-primitives", features=["serialization"]} 15 | rpc-json-client = { git= "https://github.com/UrkelLabs/rpc"} 16 | handshake-primitives = { git="https://github.com/UrkelLabs/rsd"} 17 | 18 | # Unknown External 19 | serde = "1" 20 | serde_derive = "1" 21 | serde_json = "1" 22 | futures = "0.3.1" 23 | 24 | [dev-dependencies] 25 | async-std = { version = "1.2.0", features = ["attributes"] } 26 | -------------------------------------------------------------------------------- /wallet-rpc/src/client.rs: -------------------------------------------------------------------------------- 1 | use crate::Result; 2 | use rpc_json_client::{ClientBuilder, RpcClient}; 3 | use std::sync::Arc; 4 | 5 | #[derive(Clone)] 6 | pub struct HandshakeWalletRpcClient { 7 | client: Arc, 8 | } 9 | 10 | impl HandshakeWalletRpcClient { 11 | pub fn new(uri: &str) -> Self { 12 | let client = ClientBuilder::new(uri).with_retry().build(); 13 | 14 | HandshakeWalletRpcClient { 15 | client: Arc::new(client), 16 | } 17 | } 18 | 19 | //TODO can we change params to be an Into? Then we can remove all those serde json 20 | //macros in all the requests. 21 | pub(crate) async fn call(&self, method: &str, params: &[serde_json::Value]) -> Result 22 | where 23 | T: for<'a> serde::de::Deserialize<'a>, 24 | // V: Into 25 | { 26 | let res = self.client.execute(method, params).await?; 27 | 28 | Ok(res) 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright <2019> 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 8 | -------------------------------------------------------------------------------- /rpc/src/error.rs: -------------------------------------------------------------------------------- 1 | // use std::error; 2 | use std::fmt; 3 | 4 | use rpc_json_client; 5 | use serde_json; 6 | 7 | #[derive(Debug)] 8 | pub enum Error { 9 | JsonRpc(rpc_json_client::Error), 10 | Json(serde_json::error::Error), 11 | } 12 | 13 | impl From for Error { 14 | fn from(e: rpc_json_client::Error) -> Error { 15 | Error::JsonRpc(e) 16 | } 17 | } 18 | 19 | impl From for Error { 20 | fn from(e: serde_json::error::Error) -> Error { 21 | Error::Json(e) 22 | } 23 | } 24 | 25 | impl fmt::Display for Error { 26 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 27 | match *self { 28 | Error::JsonRpc(ref e) => write!(f, "JSON-RPC error: {}", e), 29 | Error::Json(ref e) => write!(f, "JSON error: {}", e), 30 | } 31 | } 32 | } 33 | 34 | impl std::error::Error for Error { 35 | fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { 36 | match *self { 37 | Error::JsonRpc(ref e) => Some(e), 38 | Error::Json(ref e) => Some(e), 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /wallet-rpc/src/error.rs: -------------------------------------------------------------------------------- 1 | // use std::error; 2 | // use std::fmt; 3 | 4 | use rpc_json_client; 5 | use serde_json; 6 | use std::error::Error as StdError; 7 | use std::fmt; 8 | 9 | #[derive(Debug)] 10 | pub enum Error { 11 | JsonRpc(rpc_json_client::Error), 12 | Json(serde_json::error::Error), 13 | } 14 | 15 | impl From for Error { 16 | fn from(e: rpc_json_client::Error) -> Error { 17 | Error::JsonRpc(e) 18 | } 19 | } 20 | 21 | impl From for Error { 22 | fn from(e: serde_json::error::Error) -> Error { 23 | Error::Json(e) 24 | } 25 | } 26 | 27 | impl StdError for Error { 28 | fn source(&self) -> Option<&(dyn StdError + 'static)> { 29 | match *self { 30 | Error::JsonRpc(ref e) => Some(e), 31 | Error::Json(ref e) => Some(e), 32 | } 33 | } 34 | } 35 | 36 | impl fmt::Display for Error { 37 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 38 | match *self { 39 | Error::JsonRpc(ref e) => write!(f, "JSON-RPC error: {}", e), 40 | Error::Json(ref e) => write!(f, "JSON error: {}", e), 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /rpc/src/chain.rs: -------------------------------------------------------------------------------- 1 | use crate::client::HandshakeRpcClient; 2 | use crate::Result; 3 | use handshake_client_types::ChainTip; 4 | use serde_json::json; 5 | 6 | impl HandshakeRpcClient { 7 | pub async fn get_chain_tips(&self) -> Result> { 8 | self.call("getchaintips", &[]).await 9 | } 10 | 11 | //@todo move to Handshake difficulty type. 12 | pub async fn get_difficulty(&self) -> Result { 13 | self.call("getdifficulty", &[]).await 14 | } 15 | 16 | pub async fn prune_blockchain(&self) -> Result<()> { 17 | self.call("pruneblockchain", &[]).await 18 | } 19 | 20 | pub async fn invalidate_block(&self, hash: &str) -> Result<()> { 21 | let params = vec![json!(hash)]; 22 | self.call("invalidateblock", ¶ms).await 23 | } 24 | 25 | pub async fn reconsider_block(&self, hash: &str) -> Result<()> { 26 | let params = vec![json!(hash)]; 27 | self.call("reconsiderblock", ¶ms).await 28 | } 29 | 30 | pub async fn verify_chain(&self, level: u32, blocks: u32) -> Result<()> { 31 | let params = vec![json!(level), json!(blocks)]; 32 | self.call("verifychain", ¶ms).await 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /wallet-rpc/src/basic.rs: -------------------------------------------------------------------------------- 1 | use crate::client::HandshakeWalletRpcClient; 2 | use crate::Result; 3 | use handshake_client_types::WalletTransaction; 4 | use serde_json::json; 5 | 6 | impl HandshakeWalletRpcClient { 7 | pub async fn select_wallet(&self, id: &str) -> Result<()> { 8 | self.call("selectwallet", &[json!(id)]).await 9 | } 10 | 11 | pub async fn get_balance(&self, account: Option) -> Result { 12 | self.call("getbalance", &[json!(account)]).await 13 | } 14 | 15 | pub async fn get_unconfirmed_balance(&self) -> Result { 16 | self.call("getunconfirmedbalance", &[]).await 17 | } 18 | 19 | pub async fn get_address_by_account(&self, account: &str) -> Result { 20 | self.call("getaccountaddress", &[json!(account)]).await 21 | } 22 | 23 | ///Send Handshake to a specific address. Important to note that amount 24 | ///is notated in HNS whole units, not doos. amount = 1 = 1 HNS 25 | pub async fn send_to_address(&self, address: String, amount: f64) -> Result { 26 | self.call("sendtoaddress", &[json!(address), json!(amount)]) 27 | .await 28 | } 29 | 30 | //@todo result of transactions. 31 | pub async fn history( 32 | &self, 33 | account: Option, 34 | count: Option, 35 | from: Option, 36 | watch_only: Option, 37 | ) -> Result> { 38 | self.call( 39 | "listtransactions", 40 | &[json!(account), json!(count), json!(from), json!(watch_only)], 41 | ) 42 | .await 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /.github/workflows/pr.yml: -------------------------------------------------------------------------------- 1 | name: PR Review 2 | 3 | on: 4 | pull_request: 5 | 6 | jobs: 7 | build_and_test: 8 | name: Build and test 9 | runs-on: ${{ matrix.os }} 10 | strategy: 11 | matrix: 12 | os: [ubuntu-latest] 13 | rust: [nightly, beta, stable] 14 | 15 | steps: 16 | - uses: actions/checkout@master 17 | 18 | - name: Install ${{ matrix.rust }} 19 | uses: actions-rs/toolchain@v1 20 | with: 21 | toolchain: ${{ matrix.rust }} 22 | override: true 23 | 24 | - name: check 25 | uses: actions-rs/cargo@v1 26 | with: 27 | command: check 28 | args: --all --bins --tests 29 | 30 | # - name: tests 31 | # uses: actions-rs/cargo@v1 32 | # with: 33 | # command: test 34 | # args: --all 35 | 36 | check_fmt_and_docs: 37 | name: Checking fmt and docs 38 | runs-on: ubuntu-latest 39 | steps: 40 | - uses: actions/checkout@master 41 | 42 | - uses: actions-rs/toolchain@v1 43 | with: 44 | profile: minimal 45 | toolchain: nightly 46 | override: true 47 | components: rustfmt 48 | 49 | - name: setup 50 | run: | 51 | rustup component add rustfmt 52 | rustc --version 53 | - name: fmt 54 | run: cargo fmt --all -- --check 55 | 56 | clippy_check: 57 | name: Clippy check 58 | runs-on: ubuntu-latest 59 | steps: 60 | - uses: actions/checkout@v1 61 | - name: Install rust 62 | run: rustup update beta && rustup default beta 63 | - name: Install clippy 64 | run: rustup component add clippy 65 | - name: clippy 66 | run: cargo clippy --all 67 | -------------------------------------------------------------------------------- /rpc/src/client.rs: -------------------------------------------------------------------------------- 1 | use crate::Result; 2 | use futures::future::try_join_all; 3 | use rpc_json_client::{ClientBuilder, RpcClient}; 4 | use std::sync::Arc; 5 | 6 | #[derive(Clone)] 7 | pub struct HandshakeRpcClient { 8 | client: Arc, 9 | } 10 | 11 | impl HandshakeRpcClient { 12 | pub fn new(uri: &str) -> Self { 13 | //@todo probably expose this with a with_builder as well here. 14 | let client = ClientBuilder::new(uri).with_retry().build(); 15 | HandshakeRpcClient { 16 | client: Arc::new(client), 17 | } 18 | } 19 | 20 | pub fn new_with_backups(uri: &str, backups: Vec) -> Self { 21 | let client = ClientBuilder::new(uri) 22 | .with_retry() 23 | .with_backups(backups) 24 | .build(); 25 | HandshakeRpcClient { 26 | client: Arc::new(client), 27 | } 28 | } 29 | 30 | //TODO can we change params to be an Into? Then we can remove all those serde json 31 | //macros in all the requests. 32 | pub(crate) async fn call(&self, method: &str, params: &[serde_json::Value]) -> Result 33 | where 34 | T: for<'a> serde::de::Deserialize<'a>, 35 | // V: Into 36 | { 37 | let res = self.client.execute(method, params).await?; 38 | 39 | Ok(res) 40 | } 41 | 42 | pub(crate) async fn batch( 43 | &self, 44 | method: &str, 45 | params_set: &[Vec], 46 | ) -> Result> 47 | where 48 | T: for<'a> serde::de::Deserialize<'a>, 49 | // V: Into 50 | { 51 | let mut requests = Vec::new(); 52 | for params in params_set { 53 | requests.push(self.client.execute(method, params)); 54 | } 55 | 56 | Ok(try_join_all(requests).await?) 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /rpc/src/network.rs: -------------------------------------------------------------------------------- 1 | use crate::client::HandshakeRpcClient; 2 | use crate::Result; 3 | use handshake_client_types::{AddedNodeInfo, BannedNode, NetTotals, NetworkInfo, PeerInfo}; 4 | use serde_json::json; 5 | 6 | impl HandshakeRpcClient { 7 | pub async fn get_connection_count(&self) -> Result { 8 | self.call("getconnectioncount", &[]).await 9 | } 10 | 11 | pub async fn ping(&self) -> Result<()> { 12 | self.call("ping", &[]).await 13 | } 14 | 15 | pub async fn get_peer_info(&self) -> Result> { 16 | self.call("getpeerinfo", &[]).await 17 | } 18 | 19 | pub async fn add_node(&self, addr: &str, cmd: &str) -> Result<()> { 20 | let params = vec![json!(addr), json!(cmd)]; 21 | self.call("addnode", ¶ms).await 22 | } 23 | 24 | pub async fn disconnect_node(&self, addr: &str) -> Result<()> { 25 | let params = vec![json!(addr)]; 26 | self.call("disconnectnode", ¶ms).await 27 | } 28 | 29 | pub async fn get_added_node_info(&self, addr: &str) -> Result { 30 | let params = vec![json!(addr)]; 31 | self.call("getaddednodeinfo", ¶ms).await 32 | } 33 | 34 | pub async fn get_net_totals(&self) -> Result { 35 | self.call("getnettotals", &[]).await 36 | } 37 | 38 | pub async fn get_network_info(&self) -> Result { 39 | self.call("getnetworkinfo", &[]).await 40 | } 41 | 42 | pub async fn set_ban(&self, addr: &str, cmd: &str) -> Result<()> { 43 | let params = vec![json!(addr), json!(cmd)]; 44 | self.call("setban", ¶ms).await 45 | } 46 | 47 | pub async fn list_banned(&self) -> Result> { 48 | self.call("listbanned", &[]).await 49 | } 50 | 51 | pub async fn clear_banned(&self) -> Result<()> { 52 | self.call("clearbanned", &[]).await 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /rpc/src/names.rs: -------------------------------------------------------------------------------- 1 | use crate::client::HandshakeRpcClient; 2 | use crate::Result; 3 | use handshake_client_types::{CreateClaim, Name, NameInfo, NameProof, NameResource}; 4 | use serde_json::json; 5 | 6 | impl HandshakeRpcClient { 7 | //TODO check that the endpoint only parses result{} and not the error or id. 8 | pub async fn get_name_info(&self, name: &str) -> Result { 9 | self.call("getnameinfo", &[json!(name)]).await 10 | } 11 | 12 | ////TODO finish output with enums 13 | pub async fn get_names(&self) -> Result> { 14 | self.call("getnames", &[]).await 15 | } 16 | 17 | pub async fn get_name_by_hash(&self, name_hash: &str) -> Result { 18 | self.call("getnamebyhash", &[json!(name_hash)]).await 19 | } 20 | 21 | ////TODO test return value. 22 | pub async fn get_name_resource(&self, name: &str) -> Result { 23 | self.call("getnameresource", &[json!(name)]).await 24 | } 25 | 26 | pub async fn get_name_proof(&self, name: &str) -> Result { 27 | self.call("getnameproof", &[json!(name)]).await 28 | } 29 | 30 | pub async fn create_claim(&self, name: &str) -> Result { 31 | self.call("createclaim", &[json!(name)]).await 32 | } 33 | 34 | pub async fn send_claim(&self, name: &str) -> Result<()> { 35 | self.call("sendclaim", &[json!(name)]).await 36 | } 37 | 38 | pub async fn send_raw_claim(&self, claim: &str) -> Result<()> { 39 | self.call("sendrawclaim", &[json!(claim)]).await 40 | } 41 | 42 | //@todo DNSSEC request. 43 | 44 | pub async fn send_raw_airdrop(&self, airdrop: &str) -> Result<()> { 45 | self.call("sendrawairdrop", &[json!(airdrop)]).await 46 | } 47 | 48 | pub async fn grind_name(&self, length: Option) -> Result { 49 | self.call("grindname", &[json!(length)]).await 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /rpc/tests/client_chain_test.rs: -------------------------------------------------------------------------------- 1 | mod common; 2 | 3 | use common::setup; 4 | 5 | #[async_std::test] 6 | async fn test_get_chain_tips() { 7 | let client = setup(); 8 | 9 | let result = client.get_chain_tips().await; 10 | 11 | assert!(result.is_ok()); 12 | } 13 | 14 | #[async_std::test] 15 | async fn test_get_difficulty() { 16 | let client = setup(); 17 | 18 | let result = client.get_difficulty().await; 19 | 20 | assert!(result.is_ok()); 21 | } 22 | 23 | //@todo as of right now prune is irreversable - let's not re-enable until we either have 24 | //an easy destructable test chain, or we have a way to reverse quickly. 25 | //#[runtime::test] 26 | //async fn test_prune_blockchain() { 27 | // let client = setup(); 28 | 29 | // //@todo not a great way to test this since an error technically is still valid. 30 | // client.prune_blockchain().await; 31 | //} 32 | 33 | //@todo see above, reconsider will fail if we are pruned. Also these are potentially dangerous 34 | //tests since they are temporarily irreversable - e.g. if we invalidate a block, and at the same 35 | //time "getblock" is being tested on that. Re-enable these when we have a more atomic testing 36 | //structure. 37 | //#[runtime::test] 38 | //async fn test_invalidate_and_reconsider_block() { 39 | // let client = setup(); 40 | 41 | //@todo this is now taken care of in common 42 | // let hash = client.get_best_block_hash().await.unwrap().to_string(); 43 | 44 | // //We invalidate and then immediately reconsider the latest block. 45 | // //This might cause race conditions. Let's run this a number of times to test. 46 | // client.invalidate_block(&hash).await.unwrap(); 47 | 48 | // client.reconsider_block(&hash).await.unwrap(); 49 | 50 | //} 51 | 52 | //@todo can't be run w/ pruning... See above todos 53 | // #[runtime::test] 54 | // async fn test_verify_chain() { 55 | // let client = setup(); 56 | 57 | // let result = client.verify_chain(0, 1).await; 58 | 59 | // assert!(result.is_ok()); 60 | // } 61 | -------------------------------------------------------------------------------- /rpc/tests/network_test.rs: -------------------------------------------------------------------------------- 1 | mod common; 2 | 3 | use common::setup; 4 | 5 | #[async_std::test] 6 | async fn test_get_connection_count() { 7 | let client = common::setup(); 8 | 9 | let connections = client.get_connection_count().await; 10 | 11 | assert!(connections.is_ok()); 12 | } 13 | 14 | #[async_std::test] 15 | async fn test_ping() { 16 | let client = common::setup(); 17 | 18 | client.ping().await.unwrap(); 19 | } 20 | 21 | #[async_std::test] 22 | async fn test_get_peer_info() { 23 | let client = common::setup(); 24 | 25 | let peers = client.get_peer_info().await; 26 | 27 | dbg!(&peers); 28 | 29 | assert!(peers.is_ok()); 30 | } 31 | 32 | // #[runtime::test] 33 | // async fn test_add_node() { 34 | // let client = common::setup(); 35 | // @todo 36 | // } 37 | 38 | //#[runtime::test] 39 | //async fn test_disconnect_node() { 40 | // let client = common::setup(); 41 | // //@todo 42 | //} 43 | 44 | //#[runtime::test] 45 | //async fn test_get_added_node_info() { 46 | // let client = common::setup(); 47 | // //@todo 48 | //} 49 | 50 | #[async_std::test] 51 | async fn test_get_net_totals() { 52 | let client = common::setup(); 53 | 54 | let totals = client.get_net_totals().await; 55 | 56 | assert!(totals.is_ok()); 57 | } 58 | 59 | #[async_std::test] 60 | async fn test_get_network_info() { 61 | let client = common::setup(); 62 | 63 | let info = client.get_network_info().await; 64 | 65 | dbg!(&info); 66 | 67 | assert!(info.is_ok()); 68 | } 69 | 70 | // #[runtime::test] 71 | // async fn test_set_ban() { 72 | // let client = common::setup(); 73 | // @todo 74 | // } 75 | 76 | #[async_std::test] 77 | async fn test_list_banned() { 78 | let client = common::setup(); 79 | 80 | let names = client.list_banned().await; 81 | 82 | assert!(names.is_ok()); 83 | } 84 | 85 | #[async_std::test] 86 | async fn test_clear_banned() { 87 | let client = common::setup(); 88 | 89 | client.clear_banned().await.unwrap(); 90 | } 91 | -------------------------------------------------------------------------------- /rpc/tests/client_tx_test.rs: -------------------------------------------------------------------------------- 1 | //mod common; 2 | 3 | //use common::{get_tx_hex, get_txid, setup}; 4 | 5 | //#[test] 6 | ////TODO 7 | //// fn test_gettxout() { 8 | //// let mut client = common::setup(); 9 | 10 | //// let txout = client.gettxout(); 11 | 12 | //// assert!(txout.is_ok()); 13 | 14 | //// } 15 | //// 16 | //#[test] 17 | //fn test_get_tx_out_set_info() { 18 | // let client = setup(); 19 | 20 | // let outsetinfo = client.get_tx_out_set_info(); 21 | 22 | // assert!(outsetinfo.is_ok()); 23 | //} 24 | 25 | //#[test] 26 | //fn test_get_raw_transaction() { 27 | // let client = setup(); 28 | 29 | // let txid = get_txid(); 30 | 31 | // let tx = client.get_raw_transaction(&txid); 32 | 33 | // assert!(tx.is_ok()) 34 | //} 35 | 36 | //#[test] 37 | //fn test_get_raw_transaction_verbose() { 38 | // let client = setup(); 39 | 40 | // let txid = get_txid(); 41 | 42 | // let tx = client.get_raw_transaction_verbose(&txid); 43 | 44 | // assert!(tx.is_ok()); 45 | //} 46 | 47 | //#[test] 48 | //fn test_decode_raw_transaction() { 49 | // let client = setup(); 50 | 51 | // let txhex = get_tx_hex(); 52 | 53 | // let tx = client.decode_raw_transaction(&txhex); 54 | 55 | // assert!(tx.is_ok()); 56 | //} 57 | 58 | //#[test] 59 | //fn test_decode_script() { 60 | // let client = setup(); 61 | 62 | // let script = "76c014af92ad98c7f77559f96430dfef2a6805b87b24f888ac"; 63 | 64 | // let decodedscript = client.decode_script(script); 65 | 66 | // assert!(decodedscript.is_ok()); 67 | //} 68 | 69 | //// #[test] 70 | //// fn test_sendrawtransaction() { 71 | //// let mut client = common::setup(); 72 | //// TODO 73 | 74 | //// let rawtx = ""; 75 | 76 | //// let sent = client.sendrawtransaction(rawtx); 77 | 78 | //// assert!(sent.is_ok()); 79 | //// } 80 | //// 81 | //// #[test] 82 | //// fn test_gettxoutproof() { 83 | 84 | //// let mut client = common::setup(); 85 | 86 | //// } 87 | //// 88 | //// #[test] 89 | //// fn test_verifytxoutproof() { 90 | //// TODO 91 | 92 | //// } 93 | -------------------------------------------------------------------------------- /rpc/src/node.rs: -------------------------------------------------------------------------------- 1 | use crate::client::HandshakeRpcClient; 2 | use crate::Result; 3 | use handshake_client_types::{CreateMultiSig, GetInfo, GetMemoryInfo, ValidateAddress}; 4 | use serde_json::json; 5 | 6 | impl HandshakeRpcClient { 7 | /// Show information about this node. 8 | pub async fn get_info(&self) -> Result { 9 | self.call("getinfo", &[]).await 10 | } 11 | 12 | pub async fn get_memory_info(&self) -> Result { 13 | self.call("getmemoryinfo", &[]).await 14 | } 15 | 16 | /// Set the log level on the node. 17 | pub async fn set_log_level(&self, level: &str) -> Result<()> { 18 | let params = vec![json!(level)]; 19 | self.call("setloglevel", ¶ms).await 20 | } 21 | 22 | /// validate an address 23 | pub async fn validate_address(&self, address: &str) -> Result { 24 | let params = vec![json!(address)]; 25 | self.call("validateaddress", ¶ms).await 26 | } 27 | 28 | pub async fn stop(&self) -> Result { 29 | self.call("stop", &[]).await 30 | } 31 | 32 | pub async fn create_multisig(&self, nrequired: u32, keys: &[&str]) -> Result { 33 | let params = vec![json!(nrequired), json!(keys)]; 34 | self.call("createmultisig", ¶ms).await 35 | } 36 | 37 | pub async fn sign_message_with_priv_key(&self, privkey: &str, message: &str) -> Result { 38 | let params = vec![json!(privkey), json!(message)]; 39 | self.call("signmessagewithprivkey", ¶ms).await 40 | } 41 | 42 | pub async fn verify_message( 43 | &self, 44 | address: &str, 45 | signature: &str, 46 | message: &str, 47 | ) -> Result { 48 | let params = vec![json!(address), json!(signature), json!(message)]; 49 | self.call("verifymessage", ¶ms).await 50 | } 51 | 52 | pub async fn set_mock_time(&self, time: u64) -> Result<()> { 53 | let params = vec![json!(time)]; 54 | self.call("setmocktime", ¶ms).await 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /rpc/src/tx.rs: -------------------------------------------------------------------------------- 1 | use crate::client::HandshakeRpcClient; 2 | use crate::responses; 3 | use crate::Result; 4 | use serde_json::json; 5 | 6 | impl HandshakeRpcClient { 7 | pub async fn get_tx_out( 8 | &self, 9 | txid: &str, 10 | index: &u32, 11 | includemempool: bool, 12 | ) -> Result { 13 | let params = vec![json!(txid), json!(index), json!(includemempool)]; 14 | self.call("gettxout", ¶ms).await 15 | } 16 | 17 | pub async fn get_tx_out_set_info(&self) -> Result { 18 | self.call("gettxoutsetinfo", &[]).await 19 | } 20 | 21 | pub async fn get_raw_transaction(&self, txhash: &str) -> Result { 22 | let params = vec![json!(txhash), json!(false)]; 23 | self.call("getrawtransaction", ¶ms).await 24 | } 25 | 26 | pub async fn get_raw_transaction_verbose( 27 | &self, 28 | txhash: &str, 29 | ) -> Result { 30 | let params = vec![json!(txhash), json!(true)]; 31 | self.call("getrawtransaction", ¶ms).await 32 | } 33 | 34 | pub async fn decode_raw_transaction(&self, rawtx: &str) -> Result { 35 | let params = vec![json!(rawtx)]; 36 | self.call("decoderawtransaction", ¶ms).await 37 | } 38 | 39 | pub async fn decode_script(&self, script: &str) -> Result { 40 | let params = vec![json!(script)]; 41 | self.call("decodescript", ¶ms).await 42 | } 43 | 44 | pub async fn send_raw_transaction(&self, rawtx: &str) -> Result { 45 | let params = vec![json!(rawtx)]; 46 | self.call("sendrawtransaction", ¶ms).await 47 | } 48 | 49 | ////Not sure how we are going to implement this one - TODO 50 | //// pub fn createrawtransaction( 51 | //// 52 | ////TODO signrawtransaction 53 | 54 | pub async fn get_tx_out_proof( 55 | &self, 56 | txidlist: &Vec, 57 | blockhash: &str, 58 | ) -> Result { 59 | let params = vec![json!(txidlist), json!(blockhash)]; 60 | self.call("gettxoutproof", ¶ms).await 61 | } 62 | 63 | pub async fn verify_tx_out_proof(&self, proof: &str) -> Result { 64 | let params = vec![json!(proof)]; 65 | self.call("verifytxoutproof", ¶ms).await 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /rpc/src/mining.rs: -------------------------------------------------------------------------------- 1 | use crate::client::HandshakeRpcClient; 2 | use crate::Result; 3 | use handshake_client_types::{GetMiningInfo, GetWork}; 4 | use handshake_primitives::block_template::json::BlockTemplateJSON; 5 | use serde_json::json; 6 | 7 | impl HandshakeRpcClient { 8 | /// Get network hash per second 9 | pub async fn get_network_hashps(&self, blocks: u32, height: Option) -> Result { 10 | let params = vec![json!(blocks), json!(height)]; 11 | self.call("getnetworkhashps", ¶ms).await 12 | } 13 | 14 | pub async fn get_mining_info(&self) -> Result { 15 | self.call("getmininginfo", &[]).await 16 | } 17 | 18 | pub async fn get_work(&self) -> Result { 19 | self.call("getwork", &[]).await 20 | } 21 | 22 | //TODO implement long polling for this. 23 | // pub fn get_work_lp(&self) -> Result { 24 | // self.call("getworklp", &[]) 25 | // } 26 | 27 | //@todo not sure this return type is correct. 28 | pub async fn submit_work(&self, work: &str) -> Result { 29 | let params = vec![json!(work)]; 30 | self.call("submitwork", ¶ms).await 31 | } 32 | 33 | //TODO this needs to be totally revamped. See here for all params: https://bitcoincore.org/en/doc/0.17.0/rpc/mining/getblocktemplate/ 34 | //Make them optional as well. 35 | //For now, going to remove them entirely. 36 | pub async fn get_block_template( 37 | &self, 38 | // json_request_object: &serde_json::Value, 39 | ) -> Result { 40 | let params = vec![json!({})]; 41 | self.call("getblocktemplate", ¶ms).await 42 | } 43 | 44 | pub async fn submit_block(&self, block_data: &str) -> Result<()> { 45 | let params = vec![json!(block_data)]; 46 | self.call("submitblock", ¶ms).await 47 | } 48 | 49 | pub async fn verify_block(&self, block_data: &str) -> Result<()> { 50 | let params = vec![json!(block_data)]; 51 | self.call("verifyblock", ¶ms).await 52 | } 53 | 54 | //@todo prolimit appears to not be used at all in hsd from this call. Open up an 55 | //issue/investigate further. 56 | pub async fn set_generate(&self, mining: bool, proclimit: Option) -> Result { 57 | let params = vec![json!(mining), json!(proclimit)]; 58 | self.call("setgenerate", ¶ms).await 59 | } 60 | 61 | pub async fn get_generate(&self) -> Result { 62 | self.call("getgenerate", &[]).await 63 | } 64 | 65 | pub async fn generate(&self, num_blocks: u32, max_tries: Option) -> Result> { 66 | let params = vec![json!(num_blocks), json!(max_tries)]; 67 | self.call("generate", ¶ms).await 68 | } 69 | 70 | pub async fn generate_to_address( 71 | &self, 72 | num_blocks: u32, 73 | address: &str, 74 | max_tries: Option, 75 | ) -> Result> { 76 | let params = vec![json!(num_blocks), json!(address), json!(max_tries)]; 77 | self.call("generatetoaddress", ¶ms).await 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /rpc/src/mempool.rs: -------------------------------------------------------------------------------- 1 | use crate::client::HandshakeRpcClient; 2 | use crate::Result; 3 | use handshake_client_types::{ 4 | EstimateSmartFee, EstimateSmartPriority, GetMempoolInfo, MempoolEntry, 5 | }; 6 | use serde_json::json; 7 | use std::collections::HashMap; 8 | 9 | impl HandshakeRpcClient { 10 | pub async fn get_mempool_info(&self) -> Result { 11 | self.call("getmempoolinfo", &[]).await 12 | } 13 | 14 | //@todo should this be txhashes? 15 | pub async fn get_mempool_ancestors(&self, txhash: &str) -> Result> { 16 | let params = vec![json!(txhash), json!(false)]; 17 | self.call("getmempoolancestors", ¶ms).await 18 | } 19 | 20 | pub async fn get_mempool_ancestors_verbose( 21 | &self, 22 | txhash: &str, 23 | ) -> Result> { 24 | let params = vec![json!(txhash), json!(true)]; 25 | self.call("getmempoolancestors", ¶ms).await 26 | } 27 | 28 | pub async fn get_mempool_descendants(&self, txhash: &str) -> Result> { 29 | let params = vec![json!(txhash), json!(false)]; 30 | self.call("getmempooldescendants", ¶ms).await 31 | } 32 | 33 | pub async fn get_mempool_descendants_verbose(&self, txhash: &str) -> Result> { 34 | let params = vec![json!(txhash), json!(true)]; 35 | self.call("getmempooldescendants", ¶ms).await 36 | } 37 | 38 | pub async fn get_mempool_entry(&self, txhash: &str) -> Result { 39 | let params = vec![json!(txhash)]; 40 | self.call("getmempoolentry", ¶ms).await 41 | } 42 | 43 | pub async fn get_raw_mempool(&self) -> Result> { 44 | let params = vec![json!(false)]; 45 | self.call("getrawmempool", ¶ms).await 46 | } 47 | 48 | pub async fn get_raw_mempool_verbose(&self) -> Result> { 49 | let params = vec![json!(true)]; 50 | self.call("getrawmempool", ¶ms).await 51 | } 52 | 53 | pub async fn prioritise_transaction( 54 | &self, 55 | txhash: &str, 56 | priority_delta: u32, 57 | fee_delta: u32, 58 | ) -> Result { 59 | let params = vec![json!(txhash), json!(priority_delta), json!(fee_delta)]; 60 | self.call("prioritisetransaction", ¶ms).await 61 | } 62 | 63 | //@todo return Amount from RSD 64 | pub async fn estimate_fee(&self, nblocks: u32) -> Result { 65 | let params = vec![json!(nblocks)]; 66 | self.call("estimatefee", ¶ms).await 67 | } 68 | 69 | pub async fn estimate_priority(&self, nblocks: u32) -> Result { 70 | let params = vec![json!(nblocks)]; 71 | self.call("estimatepriority", ¶ms).await 72 | } 73 | 74 | //@todo return Amount from RSD 75 | pub async fn estimate_smart_fee(&self, nblocks: u32) -> Result { 76 | let params = vec![json!(nblocks)]; 77 | self.call("estimatesmartfee", ¶ms).await 78 | } 79 | 80 | pub async fn estimate_smart_priority(&self, nblocks: u32) -> Result { 81 | let params = vec![json!(nblocks)]; 82 | self.call("estimatesmartpriority", ¶ms).await 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /rpc/tests/client_mempool_test.rs: -------------------------------------------------------------------------------- 1 | mod common; 2 | 3 | use common::get_txid; 4 | use common::setup; 5 | 6 | #[async_std::test] 7 | async fn test_get_mempool_info() { 8 | let client = setup(); 9 | 10 | let info = client.get_mempool_info().await; 11 | 12 | assert!(info.is_ok()); 13 | } 14 | 15 | //@todo we need a way of creating a new tx, and then checking it in the mempool. Disabling for now. 16 | // #[runtime::test] 17 | // async fn test_get_mempool_ancestors() { 18 | // let client = setup(); 19 | 20 | // let ancestors = client.get_mempool_ancestors(&tx_hash).await; 21 | 22 | // assert!(ancestors.is_ok()); 23 | 24 | // } 25 | 26 | // #[runtime::test] 27 | // async fn test_get_mempool_ancestors_verbose() { 28 | // let client = setup(); 29 | 30 | // let ancestors = client.get_mempool_ancestors_verbose(&tx_hash).await; 31 | 32 | // assert!(ancestors.is_ok()); 33 | 34 | // } 35 | 36 | // #[runtime::test] 37 | // async fn test_get_mempool_descendants() { 38 | // let client = setup(); 39 | 40 | // let ancestors = client.get_mempool_descendants(&tx_hash).await; 41 | 42 | // assert!(ancestors.is_ok()); 43 | // } 44 | 45 | // #[runtime::test] 46 | // async fn test_get_mempool_descendants_verbose() { 47 | // let client = setup(); 48 | 49 | // let ancestors = client.get_mempool_ancestors_verbose(&tx_hash).await; 50 | 51 | // assert!(ancestors.is_ok()); 52 | // } 53 | 54 | // #[runtime::test] 55 | // async fn test_get_mempool_entry() { 56 | // let client = setup(); 57 | 58 | // let ancestors = client.get_mempool_ancestors(&tx_hash).await; 59 | 60 | // assert!(ancestors.is_ok()); 61 | 62 | // } 63 | 64 | #[async_std::test] 65 | async fn test_get_raw_mempool() { 66 | let client = common::setup(); 67 | 68 | let mempool = client.get_raw_mempool().await; 69 | 70 | assert!(mempool.is_ok()); 71 | } 72 | 73 | #[async_std::test] 74 | async fn test_get_raw_mempool_verbose() { 75 | let client = common::setup(); 76 | 77 | let mempool = client.get_raw_mempool_verbose().await; 78 | 79 | assert!(mempool.is_ok()); 80 | } 81 | 82 | //@todo prioritize transaction - see above. 83 | // #[runtime::test] 84 | // async fn test_prioritize_transaction() { 85 | // let client = common::setup(); 86 | 87 | // client.prioritize_transaction(&tx_hash).await.unwrap(); 88 | // } 89 | 90 | #[async_std::test] 91 | async fn test_estimate_fee() { 92 | let client = common::setup(); 93 | 94 | let fee = client.estimate_fee(10).await; 95 | 96 | assert!(fee.is_ok()); 97 | } 98 | 99 | #[async_std::test] 100 | async fn test_estimate_priority() { 101 | let client = common::setup(); 102 | 103 | let priority = client.estimate_priority(10).await; 104 | 105 | assert!(priority.is_ok()); 106 | } 107 | 108 | #[async_std::test] 109 | async fn test_estimate_smart_fee() { 110 | let client = common::setup(); 111 | 112 | let smartfee = client.estimate_smart_fee(10).await; 113 | 114 | assert!(smartfee.is_ok()); 115 | } 116 | 117 | #[async_std::test] 118 | async fn test_estimate_smart_priority() { 119 | let client = common::setup(); 120 | 121 | let smartpriority = client.estimate_smart_priority(10).await; 122 | 123 | assert!(smartpriority.is_ok()); 124 | } 125 | -------------------------------------------------------------------------------- /rpc/tests/client_block_test.rs: -------------------------------------------------------------------------------- 1 | mod common; 2 | 3 | use common::setup; 4 | 5 | #[async_std::test] 6 | async fn test_get_blockchain_info() { 7 | let client = setup(); 8 | 9 | let info = client.get_blockchain_info().await; 10 | 11 | assert!(info.is_ok()); 12 | } 13 | 14 | #[async_std::test] 15 | async fn test_get_best_blockhash() { 16 | let client = common::setup(); 17 | 18 | let besthash = client.get_best_block_hash().await; 19 | 20 | assert!(besthash.is_ok()); 21 | } 22 | 23 | #[async_std::test] 24 | async fn test_get_block_count() { 25 | let client = common::setup(); 26 | 27 | let blockcount = client.get_block_count().await; 28 | 29 | assert!(blockcount.is_ok()); 30 | } 31 | 32 | #[async_std::test] 33 | async fn test_get_block() { 34 | let client = common::setup(); 35 | 36 | let hash = client.get_best_block_hash().await.unwrap().to_string(); 37 | 38 | let block = client.get_block(&hash).await; 39 | 40 | assert!(block.is_ok()); 41 | } 42 | 43 | #[async_std::test] 44 | async fn test_get_block_verbose() { 45 | let client = common::setup(); 46 | 47 | let hash = client.get_best_block_hash().await.unwrap().to_string(); 48 | 49 | let block = client.get_block_verbose(&hash).await; 50 | 51 | assert!(block.is_ok()); 52 | } 53 | 54 | //@todo failing - details not working. 55 | #[async_std::test] 56 | async fn test_get_block_verbose_and_details() { 57 | let client = common::setup(); 58 | 59 | let hash = client.get_best_block_hash().await.unwrap().to_string(); 60 | 61 | let block = client.get_block_detailed(&hash).await; 62 | 63 | dbg!(&block.unwrap().tx[0].vin); 64 | 65 | // assert!(block.is_ok()); 66 | } 67 | 68 | #[async_std::test] 69 | async fn test_get_block_by_height() { 70 | let client = common::setup(); 71 | 72 | let height = 100; 73 | 74 | let block = client.get_block_by_height(height).await; 75 | 76 | dbg!(&block); 77 | 78 | assert!(block.is_ok()); 79 | } 80 | 81 | #[async_std::test] 82 | async fn test_get_block_by_height_verbose() { 83 | let client = common::setup(); 84 | 85 | let height = 7760; 86 | 87 | let block = client.get_block_by_height_verbose(height).await; 88 | 89 | dbg!(&block); 90 | 91 | assert!(block.is_ok()); 92 | } 93 | 94 | #[async_std::test] 95 | async fn test_get_block_by_height_verbose_and_details() { 96 | let client = common::setup(); 97 | 98 | let height = 7760; 99 | 100 | let block = client.get_block_by_height_detailed(height).await; 101 | 102 | dbg!(&block); 103 | 104 | assert!(block.is_ok()); 105 | } 106 | 107 | #[async_std::test] 108 | async fn test_get_block_hash() { 109 | let client = common::setup(); 110 | 111 | let height = 100; 112 | 113 | let blockhash = client.get_block_hash(height).await; 114 | 115 | assert!(blockhash.is_ok()); 116 | } 117 | 118 | #[async_std::test] 119 | async fn test_get_block_header() { 120 | let client = common::setup(); 121 | 122 | //@todo if we use this a lot, wrap this into common. 123 | let hash = client.get_best_block_hash().await.unwrap().to_string(); 124 | 125 | let blockheader = client.get_block_header(&hash).await; 126 | 127 | assert!(blockheader.is_ok()); 128 | } 129 | 130 | #[async_std::test] 131 | async fn test_get_block_header_verbose() { 132 | let client = common::setup(); 133 | 134 | //@todo if we use this a lot, wrap this into common. 135 | let hash = client.get_best_block_hash().await.unwrap().to_string(); 136 | 137 | let blockheader = client.get_block_header_verbose(&hash).await; 138 | 139 | assert!(blockheader.is_ok()); 140 | } 141 | -------------------------------------------------------------------------------- /rpc/tests/client_node_test.rs: -------------------------------------------------------------------------------- 1 | mod common; 2 | use common::setup; 3 | 4 | #[async_std::test] 5 | async fn test_get_info() { 6 | let client = setup(); 7 | 8 | let info = client.get_info().await; 9 | 10 | assert!(info.is_ok()); 11 | } 12 | 13 | #[async_std::test] 14 | async fn test_get_memory_info() { 15 | let client = common::setup(); 16 | 17 | let memoryinfo = client.get_memory_info().await; 18 | 19 | assert!(memoryinfo.is_ok()); 20 | } 21 | 22 | #[async_std::test] 23 | async fn test_set_log_level() { 24 | let client = common::setup(); 25 | 26 | let result = client.set_log_level("WARNING").await; 27 | 28 | assert!(result.is_ok()); 29 | } 30 | 31 | // #[async_std::test] 32 | // async fn test_validate_address_ok() { 33 | // let client = common::setup(); 34 | 35 | // let validateaddress = client 36 | // .validate_address("ts1qq79hzunlkj50fvm7rxg3xetx4kml4e0am43htk") 37 | // .await; 38 | 39 | // assert!(validateaddress.is_ok()); 40 | 41 | // let address = validateaddress.unwrap(); 42 | 43 | // assert!(address.is_valid); 44 | // } 45 | 46 | #[async_std::test] 47 | async fn test_validate_address_fail() { 48 | let client = common::setup(); 49 | 50 | let validateaddress = client.validate_address("notanaddress").await; 51 | 52 | assert!(validateaddress.is_ok()); 53 | 54 | let address = validateaddress.unwrap(); 55 | 56 | assert!(!address.is_valid); 57 | } 58 | 59 | ////This turns off the code... Let's see if there is a way to restart. 60 | //// #[test] 61 | //// fn test_stop() { 62 | //// let mut client = common::setup(); 63 | 64 | //// let stop = client.stop(); 65 | 66 | //// assert!(stop.is_ok()); 67 | 68 | //// } 69 | 70 | #[async_std::test] 71 | async fn test_create_multisig() { 72 | let client = common::setup(); 73 | let pub1 = "02e3d6bb36b0261628101ee67abd89d678522dc1199912512f814e70803652f395"; 74 | let pub2 = "03d7ded41bb871936bf4d411371b25d706c572f28ef8d2613b45392e9f9c4348a5"; 75 | let pub3 = "034bc2280e68d3bdd0ef0664e0ad2949a467344d8e59e435fe2d9be81e39f70f76"; 76 | 77 | let params = vec![pub1, pub2, pub3]; 78 | 79 | let multisig = client.create_multisig(1, ¶ms).await; 80 | 81 | assert!(multisig.is_ok()); 82 | } 83 | 84 | ////Hard to test _ok() without exposing priv keys 85 | #[async_std::test] 86 | async fn test_sign_message_with_priv_key_fail() { 87 | let client = common::setup(); 88 | 89 | let privkey = "ENced8VD7YWkzPC8FTJ3gTTq4pQhF2PF79QS51mgZq7BgCfiEP5A"; 90 | 91 | let message = "hello"; 92 | 93 | let signedmessage = client.sign_message_with_priv_key(privkey, message).await; 94 | 95 | assert!(signedmessage.is_err()); 96 | } 97 | 98 | ////TODO need valid _ok() test 99 | #[async_std::test] 100 | async fn test_verify_message_fail() { 101 | let client = common::setup(); 102 | 103 | //Address is bad. 104 | let address = "ts1q7qumafugfglg268djelwr7ps4l2uh2vsdpfnuc"; 105 | 106 | let signature = 107 | "arjD5y4glPea270IiExx04E+tTvryHKhWZcA2oy8svVHr9q/AvGA647UF2ICaIGJHazbRyyj3draiNnBns9aWQ=="; 108 | 109 | let message = "hello"; 110 | 111 | let verified = client.verify_message(address, signature, message).await; 112 | 113 | assert!(verified.is_err()); 114 | } 115 | 116 | ////TODO this will break current tests -> Need to find a way to not have this break things. 117 | //// #[test] 118 | //// fn test_setmocktime() { 119 | //// let mut client = common::setup(); 120 | 121 | //// let time = 1503058155; 122 | 123 | //// let result = client.setmocktime(time); 124 | 125 | //// assert!(result.is_ok()); 126 | 127 | //// } 128 | -------------------------------------------------------------------------------- /rpc/tests/client_mining_test.rs: -------------------------------------------------------------------------------- 1 | mod common; 2 | 3 | use common::setup; 4 | // use handshake_primitives::BlockTemplate; 5 | // use handshake_primitives::block_template::json::BlockTemplateJSON; 6 | use handshake_primitives::block_template::builder::BlockTemplateBuilder; 7 | 8 | #[async_std::test] 9 | async fn test_get_network_hashps() { 10 | let client = setup(); 11 | 12 | let networkhashps = client.get_network_hashps(120, Some(1)).await; 13 | 14 | assert!(networkhashps.is_ok()); 15 | } 16 | 17 | #[async_std::test] 18 | async fn test_get_mining_info() { 19 | let client = common::setup(); 20 | 21 | let info = client.get_mining_info().await; 22 | 23 | assert!(info.is_ok()); 24 | } 25 | 26 | #[async_std::test] 27 | async fn test_get_work() { 28 | let client = common::setup(); 29 | 30 | let work = client.get_work().await; 31 | 32 | assert!(work.is_ok()); 33 | } 34 | 35 | //@todo submit work is currently failing with out of bounds read. 36 | // #[runtime::test] 37 | // async fn test_submit_work() { 38 | // let client = common::setup(); 39 | 40 | // let hash = "abcd"; 41 | // let work = client.submit_work(&hash).await; 42 | 43 | // assert!(work.is_ok()); 44 | // } 45 | 46 | #[async_std::test] 47 | async fn test_getblocktemplate() { 48 | let client = common::setup(); 49 | 50 | let template = client.get_block_template().await; 51 | 52 | dbg!(&template); 53 | 54 | let mut block_template = BlockTemplateBuilder::new() 55 | .with_json(template.unwrap()) 56 | //@todo would be great to have this function accept T: Into
57 | .with_address( 58 | "hs1qjhgt8dwvhwapf2a5v9865nmrrqhhqlz38w3zze" 59 | .parse() 60 | .unwrap(), 61 | ) 62 | .with_create_coinbase() 63 | .with_create_merkle_root() 64 | .with_create_witness_root() 65 | .build(); 66 | 67 | // dbg!(&block_template); 68 | dbg!(block_template.coinbase); 69 | 70 | // assert!(template.is_ok()); 71 | } 72 | 73 | // #[runtime::test] 74 | // async fn test_submit_block() { 75 | // let client = common::setup(); 76 | 77 | // let block = "abcd"; 78 | 79 | // client.submit_block(&block).await.unwrap(); 80 | // } 81 | 82 | // #[runtime::test] 83 | // async fn test_verify_block() { 84 | // let client = common::setup(); 85 | 86 | // let block = "abcd"; 87 | 88 | // client.verify_block(&block).await.unwrap(); 89 | // } 90 | 91 | #[async_std::test] 92 | async fn test_set_and_get_generate() { 93 | let client = common::setup(); 94 | 95 | //@todo might be excessive... this test takes awhile. 96 | client.set_generate(false, None).await.unwrap(); 97 | assert_eq!(false, client.get_generate().await.unwrap()); 98 | // client.set_generate(true, None).await.unwrap(); 99 | // assert_eq!(true, client.get_generate().await.unwrap()); 100 | // client.set_generate(false, Some(1)).await.unwrap(); 101 | // assert_eq!(false, client.get_generate().await.unwrap()); 102 | // client.set_generate(true, Some(1)).await.unwrap(); 103 | // assert_eq!(true, client.get_generate().await.unwrap()); 104 | } 105 | 106 | // #[runtime::test] 107 | // async fn test_generate() { 108 | // let client = common::setup(); 109 | 110 | // let blocks = client.generate(2, None).await; 111 | // assert!(blocks.is_ok()); 112 | 113 | // let blocks = client.generate(2, Some(2)).await; 114 | // assert!(blocks.is_ok()); 115 | // } 116 | 117 | //#[runtime::test] 118 | //async fn test_generate_to_address() { 119 | // let client = common::setup(); 120 | // //@todo get a new address generated here to use 121 | 122 | // let blocks = client.generate(2, &addr, 2).await; 123 | 124 | // assert!(blocks.is_ok()); 125 | //} 126 | -------------------------------------------------------------------------------- /rpc/src/block.rs: -------------------------------------------------------------------------------- 1 | use crate::client::HandshakeRpcClient; 2 | use crate::Result; 3 | use extended_primitives::Hash; 4 | use handshake_client_types::{GetBlock, GetBlockDetailed, GetBlockHeader, GetBlockchainInfo}; 5 | use serde_json::json; 6 | 7 | impl HandshakeRpcClient { 8 | pub async fn get_blockchain_info(&self) -> Result { 9 | self.call("getblockchaininfo", &[]).await 10 | } 11 | 12 | pub async fn get_best_block_hash(&self) -> Result { 13 | self.call("getbestblockhash", &[]).await 14 | } 15 | 16 | pub async fn get_block_count(&self) -> Result { 17 | self.call("getblockcount", &[]).await 18 | } 19 | 20 | pub async fn get_block(&self, blockhash: T) -> Result { 21 | let params = vec![json!(blockhash.to_string()), json!(false), json!(false)]; 22 | 23 | self.call("getblock", ¶ms).await 24 | } 25 | 26 | pub async fn get_blocks(&self, blockhashes: &[T]) -> Result> { 27 | let mut params_set = Vec::new(); 28 | for hash in blockhashes { 29 | params_set.push(vec![json!(hash.to_string()), json!(false), json!(false)]); 30 | } 31 | 32 | self.batch("getblock", ¶ms_set).await 33 | } 34 | 35 | pub async fn get_block_verbose(&self, blockhash: T) -> Result { 36 | let params = vec![json!(blockhash.to_string()), json!(true), json!(false)]; 37 | 38 | self.call("getblock", ¶ms).await 39 | } 40 | 41 | //Batch 42 | pub async fn get_blocks_verbose( 43 | &self, 44 | blockhashes: &[T], 45 | ) -> Result> { 46 | let mut params_set = Vec::new(); 47 | for hash in blockhashes { 48 | params_set.push(vec![json!(hash.to_string()), json!(true), json!(false)]); 49 | } 50 | 51 | self.batch("getblock", ¶ms_set).await 52 | } 53 | 54 | pub async fn get_block_detailed(&self, blockhash: T) -> Result { 55 | let params = vec![json!(blockhash.to_string()), json!(true), json!(true)]; 56 | 57 | self.call("getblock", ¶ms).await 58 | } 59 | 60 | //Batch 61 | pub async fn get_blocks_detailed( 62 | &self, 63 | blockhashes: &[T], 64 | ) -> Result> { 65 | let mut params_set = Vec::new(); 66 | for hash in blockhashes { 67 | params_set.push(vec![json!(hash.to_string()), json!(true), json!(true)]); 68 | } 69 | 70 | self.batch("getblock", ¶ms_set).await 71 | } 72 | 73 | //Returns a hex of the block 74 | pub async fn get_block_by_height(&self, blockheight: u32) -> Result { 75 | let params = vec![json!(blockheight), json!(false), json!(false)]; 76 | 77 | self.call("getblockbyheight", ¶ms).await 78 | } 79 | 80 | //Batch 81 | pub async fn get_blocks_by_height(&self, blockheights: &[u32]) -> Result> { 82 | let mut params_set = Vec::new(); 83 | for height in blockheights { 84 | params_set.push(vec![json!(height), json!(false), json!(false)]); 85 | } 86 | 87 | self.batch("getblockbyheight", ¶ms_set).await 88 | } 89 | 90 | pub async fn get_block_by_height_verbose(&self, blockheight: u32) -> Result { 91 | let params = vec![json!(blockheight), json!(true), json!(false)]; 92 | 93 | self.call("getblockbyheight", ¶ms).await 94 | } 95 | 96 | //Batch 97 | pub async fn get_blocks_by_height_verbose( 98 | &self, 99 | blockheights: &[u32], 100 | ) -> Result> { 101 | let mut params_set = Vec::new(); 102 | for height in blockheights { 103 | params_set.push(vec![json!(height), json!(true), json!(false)]); 104 | } 105 | 106 | self.batch("getblockbyheight", ¶ms_set).await 107 | } 108 | 109 | pub async fn get_block_by_height_detailed(&self, blockheight: u32) -> Result { 110 | let params = vec![json!(blockheight), json!(true), json!(true)]; 111 | 112 | self.call("getblockbyheight", ¶ms).await 113 | } 114 | 115 | //Batch 116 | pub async fn get_blocks_by_height_detailed( 117 | &self, 118 | blockheights: &[u32], 119 | ) -> Result> { 120 | let mut params_set = Vec::new(); 121 | for height in blockheights { 122 | params_set.push(vec![json!(height), json!(true), json!(true)]); 123 | } 124 | 125 | self.batch("getblockbyheight", ¶ms_set).await 126 | } 127 | 128 | pub async fn get_block_hash(&self, height: u32) -> Result { 129 | let params = vec![json!(height)]; 130 | self.call("getblockhash", ¶ms).await 131 | } 132 | 133 | //Returns a hex of the block header 134 | pub async fn get_block_header(&self, blockhash: &str) -> Result { 135 | let params = vec![json!(blockhash), json!(false)]; 136 | self.call("getblockheader", ¶ms).await 137 | } 138 | 139 | pub async fn get_block_header_verbose(&self, blockhash: &str) -> Result { 140 | let params = vec![json!(blockhash), json!(true)]; 141 | self.call("getblockheader", ¶ms).await 142 | } 143 | } 144 | -------------------------------------------------------------------------------- /types/src/lib.rs: -------------------------------------------------------------------------------- 1 | // use extended_primitives::{Buffer, Hash, Uint256}; 2 | use extended_primitives::{Buffer, Hash}; 3 | use handshake_primitives::{Address, Covenant}; 4 | use handshake_types::{amount, Amount, Compact}; 5 | use serde_derive::{Deserialize, Serialize}; 6 | use std::collections::HashMap; 7 | 8 | /// "getinfo" command 9 | #[derive(Debug, Clone, Deserialize, Serialize)] 10 | pub struct GetInfo { 11 | pub version: String, 12 | #[serde(rename = "protocolversion")] 13 | pub protocol_version: u32, 14 | #[serde(rename = "walletversion")] 15 | pub wallet_version: u32, 16 | #[serde(with = "amount::as_doos")] 17 | pub balance: Amount, 18 | pub blocks: u64, 19 | pub timeoffset: i64, 20 | pub connections: u32, 21 | pub proxy: String, 22 | pub difficulty: f64, 23 | pub testnet: bool, 24 | #[serde(rename = "keypoololdest")] 25 | pub key_pool_oldest: u32, 26 | #[serde(rename = "keypoolsize")] 27 | pub key_pool_size: u32, 28 | pub unlocked_until: u32, 29 | #[serde(rename = "paytxfee")] 30 | #[serde(with = "amount::as_hns")] 31 | pub pay_tx_fee: Amount, 32 | #[serde(rename = "relayfee")] 33 | #[serde(with = "amount::as_hns")] 34 | pub relay_fee: Amount, 35 | pub errors: String, 36 | } 37 | 38 | // --- Block Responses --- // 39 | 40 | /// "getblockchaininfo" command 41 | #[derive(Debug, Clone, Deserialize, Serialize)] 42 | pub struct GetBlockchainInfo { 43 | pub chain: String, 44 | pub blocks: u32, 45 | pub headers: u32, 46 | #[serde(rename = "bestblockhash")] 47 | pub best_blockhash: String, 48 | pub difficulty: f64, 49 | pub mediantime: u64, 50 | #[serde(rename = "verificationprogress")] 51 | pub verification_progress: f64, 52 | pub chainwork: String, 53 | pub pruned: bool, 54 | #[serde(rename = "pruneheight")] 55 | pub prune_height: Option, 56 | //Soft forks we need to develop out that struct @todo. 57 | #[serde(skip)] 58 | pub softforks: String, 59 | } 60 | 61 | /// "getblock" and "getblockbyheight" 62 | #[derive(Debug, Clone, Deserialize, Serialize)] 63 | pub struct GetBlock { 64 | pub hash: Hash, 65 | pub confirmations: u32, 66 | #[serde(rename = "strippedsize")] 67 | pub stripped_size: u32, 68 | pub size: u32, 69 | pub weight: u32, 70 | pub height: u32, 71 | pub version: u32, 72 | #[serde(rename = "versionHex")] 73 | pub verion_hex: String, 74 | #[serde(rename = "merkleroot")] 75 | pub merkle_root: Hash, 76 | #[serde(rename = "witnessroot")] 77 | pub witness_root: Hash, 78 | #[serde(rename = "treeroot")] 79 | pub tree_root: Hash, 80 | #[serde(rename = "reservedroot")] 81 | pub reserved_root: Hash, 82 | pub mask: Hash, 83 | pub coinbase: Vec, 84 | pub tx: Vec, 85 | #[serde(rename = "nTx")] 86 | pub num_tx: u32, 87 | pub time: u64, 88 | pub mediantime: u64, 89 | pub nonce: u32, 90 | #[serde(rename = "extranonce")] 91 | pub extra_nonce: Buffer, 92 | pub bits: Compact, 93 | pub difficulty: f64, 94 | pub chainwork: String, 95 | #[serde(rename = "previousblockhash")] 96 | pub previous_blockhash: Option, 97 | #[serde(rename = "nextblockhash")] 98 | pub next_blockhash: Option, 99 | } 100 | 101 | #[derive(Debug, Clone, Deserialize, Serialize)] 102 | pub struct GetBlockDetailed { 103 | pub hash: Hash, 104 | pub confirmations: u32, 105 | #[serde(rename = "strippedsize")] 106 | pub stripped_size: u64, 107 | pub size: u64, 108 | pub weight: u64, 109 | pub height: u32, 110 | pub version: u32, 111 | #[serde(rename = "versionHex")] 112 | pub verion_hex: Buffer, 113 | #[serde(rename = "merkleroot")] 114 | pub merkle_root: Hash, 115 | #[serde(rename = "witnessroot")] 116 | pub witness_root: Hash, 117 | #[serde(rename = "treeroot")] 118 | pub tree_root: Hash, 119 | #[serde(rename = "reservedroot")] 120 | pub reserved_root: Hash, 121 | pub mask: Hash, 122 | pub tx: Vec, 123 | #[serde(rename = "nTx")] 124 | pub num_tx: u32, 125 | pub time: u64, 126 | pub mediantime: u64, 127 | pub nonce: u32, 128 | #[serde(rename = "extranonce")] 129 | pub extra_nonce: Buffer, 130 | pub bits: Compact, 131 | pub difficulty: f64, 132 | pub chainwork: String, 133 | #[serde(rename = "previousblockhash")] 134 | pub previous_blockhash: Option, 135 | #[serde(rename = "nextblockhash")] 136 | pub next_blockhash: Option, 137 | } 138 | 139 | #[derive(Debug, Clone, Deserialize, Serialize)] 140 | pub struct Transaction { 141 | pub txid: Hash, 142 | pub hash: Hash, 143 | pub size: u32, 144 | pub vsize: u32, 145 | pub version: u32, 146 | pub locktime: u32, 147 | pub vin: Vec, 148 | pub vout: Vec, 149 | pub blockhash: Option, 150 | pub confirmations: u32, 151 | pub time: u64, 152 | pub blocktime: u64, 153 | pub hex: Option, 154 | } 155 | 156 | //@todo txid and vout will be Prevout. 157 | #[derive(Debug, Clone, Deserialize, Serialize)] 158 | pub struct VirtualInput { 159 | pub coinbase: bool, 160 | pub txid: Hash, 161 | pub vout: usize, 162 | pub txinwitness: Vec, 163 | pub sequence: u32, 164 | pub link: Option, 165 | } 166 | 167 | #[derive(Debug, Clone, Deserialize, Serialize)] 168 | pub struct VirtualOutput { 169 | #[serde(with = "amount::as_hns")] 170 | pub value: Amount, 171 | pub n: usize, 172 | pub address: Address, 173 | pub covenant: Covenant, 174 | } 175 | 176 | /// "getchaintips" 177 | #[derive(Debug, Clone, Deserialize, Serialize)] 178 | pub struct ChainTip { 179 | pub height: u32, 180 | pub hash: String, 181 | pub branchlen: u32, 182 | pub status: String, 183 | } 184 | 185 | /// "getblockheader" 186 | #[derive(Debug, Clone, Deserialize, Serialize)] 187 | pub struct GetBlockHeader { 188 | pub hash: String, 189 | pub confirmations: u32, 190 | pub height: u32, 191 | pub version: u32, 192 | #[serde(rename = "versionHex")] 193 | pub verion_hex: String, 194 | #[serde(rename = "merkleroot")] 195 | pub merkle_root: String, 196 | #[serde(rename = "witnessroot")] 197 | pub witness_root: String, 198 | #[serde(rename = "treeroot")] 199 | pub tree_root: String, 200 | #[serde(rename = "reservedroot")] 201 | pub reserved_root: String, 202 | pub mask: String, 203 | pub time: u64, 204 | pub mediantime: u64, 205 | pub nonce: u32, 206 | #[serde(rename = "extranonce")] 207 | pub extra_nonce: Buffer, 208 | pub bits: Compact, 209 | pub difficulty: f64, 210 | pub chainwork: String, 211 | #[serde(rename = "previousblockhash")] 212 | pub previous_blockhash: String, 213 | #[serde(rename = "nextblockhash")] 214 | pub next_blockhash: Option, 215 | } 216 | 217 | // --- Mempool Responses --- // 218 | 219 | /// "getmempoolinfo" 220 | #[derive(Debug, Clone, Deserialize, Serialize)] 221 | pub struct GetMempoolInfo { 222 | pub size: u32, 223 | pub bytes: u64, 224 | pub usage: u64, 225 | pub maxmempool: u64, 226 | #[serde(rename = "mempoolminfee")] 227 | #[serde(with = "amount::as_hns")] 228 | pub mempool_min_fee: Amount, 229 | } 230 | 231 | //@todo this is probably be exposed from rsd. 232 | /// "getmempoolentry" 233 | #[derive(Debug, Clone, Deserialize, Serialize)] 234 | pub struct MempoolEntry { 235 | pub size: u32, 236 | #[serde(with = "amount::as_hns")] 237 | pub fee: Amount, 238 | #[serde(rename = "modifiedfee")] 239 | #[serde(with = "amount::as_hns")] 240 | pub modified_fee: Amount, 241 | pub time: u64, 242 | pub height: u32, 243 | //Double check if these should be floats XXX 244 | #[serde(rename = "startingpriority")] 245 | pub starting_priority: f64, 246 | #[serde(rename = "currentpriority")] 247 | pub current_priority: f64, 248 | #[serde(rename = "descendantcount")] 249 | pub descendant_count: u32, 250 | #[serde(rename = "descendantsize")] 251 | pub descendant_size: u32, 252 | #[serde(rename = "descendantfees")] 253 | #[serde(with = "amount::as_doos")] 254 | pub descendant_fees: Amount, 255 | #[serde(rename = "ancestorcount")] 256 | pub ancestor_count: u32, 257 | #[serde(rename = "ancestorsize")] 258 | pub ancestor_size: u32, 259 | #[serde(rename = "ancestorfees")] 260 | #[serde(with = "amount::as_doos")] 261 | pub ancestor_fees: Amount, 262 | pub depends: Vec, 263 | } 264 | 265 | /// "estimatesmartfee" 266 | #[derive(Debug, Clone, Deserialize, Serialize)] 267 | pub struct EstimateSmartFee { 268 | //@todo this can be a -1 so we should almost make a type of Option where -1 = None. 269 | pub fee: f64, 270 | pub blocks: u32, 271 | } 272 | 273 | /// "estimatesmartpriority 274 | #[derive(Debug, Clone, Deserialize, Serialize)] 275 | pub struct EstimateSmartPriority { 276 | pub priority: f64, 277 | pub blocks: u32, 278 | } 279 | 280 | // --- Mining Responses --- // 281 | 282 | /// "getmininginfo" command 283 | #[derive(Debug, Clone, Deserialize, Serialize)] 284 | pub struct GetMiningInfo { 285 | pub blocks: u32, 286 | #[serde(rename = "currentblocksize")] 287 | pub current_block_size: u32, 288 | #[serde(rename = "currentblockweight")] 289 | pub current_block_weight: u32, 290 | #[serde(rename = "currentblocktx")] 291 | pub currrent_block_tx: u32, 292 | pub difficulty: f32, 293 | pub errors: String, 294 | #[serde(rename = "genproclimit")] 295 | pub genproc_limit: u32, 296 | #[serde(rename = "networkhashps")] 297 | pub network_hashps: f32, 298 | #[serde(rename = "pooledtx")] 299 | pub pooled_tx: u32, 300 | pub testnet: bool, 301 | pub chain: String, 302 | pub generate: bool, 303 | } 304 | 305 | /// "getwork" command 306 | #[derive(Debug, Clone, Deserialize, Serialize)] 307 | pub struct GetWork { 308 | pub network: String, 309 | pub data: String, 310 | pub target: String, 311 | pub height: u32, 312 | pub time: u32, 313 | } 314 | 315 | // --- Network Struct --- // 316 | 317 | #[derive(Debug, Clone, Deserialize, Serialize)] 318 | pub struct PeerInfo { 319 | pub id: u32, 320 | pub addr: String, 321 | #[serde(rename = "addrlocal")] 322 | pub addr_local: String, 323 | pub name: Option, 324 | pub services: String, 325 | #[serde(rename = "relaytxes")] 326 | pub relay_txes: bool, 327 | #[serde(rename = "lastsend")] 328 | pub last_send: i64, 329 | #[serde(rename = "lastrecv")] 330 | pub last_recv: i64, 331 | #[serde(rename = "bytessent")] 332 | pub bytes_sent: i64, 333 | #[serde(rename = "bytesrecv")] 334 | pub bytes_recv: i64, 335 | #[serde(rename = "conntime")] 336 | pub conn_time: i64, 337 | #[serde(rename = "timeoffset")] 338 | pub time_offset: i64, 339 | #[serde(rename = "pingtime")] 340 | pub ping_time: f64, 341 | #[serde(rename = "minping")] 342 | pub min_ping: f64, 343 | pub version: u32, 344 | #[serde(rename = "subver")] 345 | pub sub_ver: String, 346 | pub inbound: bool, 347 | #[serde(rename = "startingheight")] 348 | pub starting_height: i32, 349 | #[serde(rename = "besthash")] 350 | pub best_hash: String, 351 | #[serde(rename = "bestheight")] 352 | pub best_height: i32, 353 | #[serde(rename = "banscore")] 354 | pub ban_score: i32, 355 | pub inflight: Vec, 356 | pub whitelisted: bool, 357 | } 358 | 359 | #[derive(Debug, Clone, Deserialize, Serialize)] 360 | pub struct BannedNode { 361 | pub address: String, 362 | pub banned_until: u64, 363 | pub ban_created: u64, 364 | pub ban_reason: String, 365 | } 366 | 367 | #[derive(Debug, Clone, Deserialize, Serialize)] 368 | pub struct NetworkInfo { 369 | pub version: String, 370 | #[serde(rename = "subversion")] 371 | pub sub_version: String, 372 | #[serde(rename = "protocolversion")] 373 | pub protocol_version: u32, 374 | #[serde(rename = "identitykey")] 375 | pub identity_key: String, 376 | #[serde(rename = "localservices")] 377 | pub local_services: String, 378 | #[serde(rename = "localrelay")] 379 | pub local_relay: bool, 380 | #[serde(rename = "timeoffset")] 381 | pub time_offset: u64, 382 | #[serde(rename = "networkactive")] 383 | pub network_active: bool, 384 | pub connections: u32, 385 | pub networks: Vec, 386 | #[serde(rename = "relayfee")] 387 | #[serde(with = "amount::as_hns")] 388 | pub relay_fee: Amount, 389 | #[serde(rename = "incrementalfee")] 390 | #[serde(with = "amount::as_hns")] 391 | pub incremental_fee: Amount, 392 | #[serde(rename = "localaddresses")] 393 | pub local_addresses: Vec, 394 | pub warnings: String, 395 | } 396 | 397 | #[derive(Debug, Clone, Deserialize, Serialize)] 398 | pub struct LocalAddress { 399 | pub address: String, 400 | pub port: u32, 401 | pub score: u32, 402 | } 403 | 404 | #[derive(Debug, Clone, Deserialize, Serialize)] 405 | pub struct NodeAddress { 406 | pub address: String, 407 | pub connected: String, 408 | } 409 | 410 | #[derive(Debug, Clone, Deserialize, Serialize)] 411 | pub struct AddedNodeInfo { 412 | pub addednode: String, 413 | pub connected: bool, 414 | pub addresses: Vec, 415 | } 416 | 417 | #[derive(Debug, Clone, Deserialize, Serialize)] 418 | pub struct NetTotals { 419 | #[serde(rename = "totalbytesrecv")] 420 | pub total_bytes_recv: u64, 421 | #[serde(rename = "totalbytessent")] 422 | pub total_bytes_sent: u64, 423 | #[serde(rename = "timemillis")] 424 | pub time_millis: u64, 425 | } 426 | 427 | /// "createmultisig" command 428 | #[derive(Debug, Clone, Deserialize, Serialize)] 429 | #[serde(rename_all = "camelCase")] 430 | pub struct CreateMultiSig { 431 | pub address: String, 432 | pub redeem_script: String, 433 | } 434 | 435 | /// "validateaddress" command 436 | #[derive(Debug, Clone, Deserialize, Serialize)] 437 | pub struct ValidateAddress { 438 | #[serde(rename = "isvalid")] 439 | pub is_valid: bool, 440 | // TODO transition to hash type 441 | pub address: Option, 442 | #[serde(rename = "ismine")] 443 | pub is_mine: Option, 444 | #[serde(rename = "iswatchonly")] 445 | pub is_watch_only: Option, 446 | } 447 | 448 | /// "getmemoryinfo" command 449 | #[derive(Debug, Clone, Deserialize, Serialize)] 450 | #[serde(rename_all = "camelCase")] 451 | pub struct GetMemoryInfo { 452 | pub total: u32, 453 | pub js_heap: u32, 454 | pub js_heap_total: u32, 455 | pub native_heap: u32, 456 | pub external: u32, 457 | } 458 | 459 | #[derive(Debug, Clone, Deserialize, Serialize)] 460 | pub struct CreateClaim { 461 | pub name: String, 462 | pub target: String, 463 | #[serde(with = "amount::as_doos")] 464 | pub value: Amount, 465 | pub size: u64, 466 | #[serde(with = "amount::as_doos")] 467 | pub fee: Amount, 468 | pub address: String, 469 | pub txt: String, 470 | } 471 | 472 | #[derive(Debug, Clone, Deserialize, Serialize)] 473 | pub struct NameProof { 474 | pub hash: String, 475 | pub height: u32, 476 | pub root: String, 477 | pub name: String, 478 | pub key: String, 479 | pub proof: Proof, 480 | } 481 | 482 | //@todo needs to actually be an enum -> See: https://handshake-org.github.io/api-docs/#getnameproof 483 | #[derive(Debug, Clone, Deserialize, Serialize)] 484 | pub struct Proof { 485 | #[serde(rename = "type")] 486 | pub type_: String, 487 | pub depth: u32, 488 | pub nodes: Vec>, 489 | pub value: String, 490 | } 491 | 492 | //TODO no idea if this works -> Please test 493 | pub type NameResource = HashMap; 494 | 495 | #[derive(Debug, Clone, Deserialize, Serialize)] 496 | #[serde(rename_all = "camelCase")] 497 | pub struct Name { 498 | pub name: String, 499 | pub name_hash: String, 500 | pub state: String, 501 | pub height: u32, 502 | pub renewal: u32, 503 | pub owner: NameOwner, 504 | pub value: u64, 505 | pub highest: u64, 506 | pub data: String, 507 | pub transfer: u32, 508 | pub revoked: u32, 509 | pub claimed: u32, 510 | pub renewals: u32, 511 | pub registered: bool, 512 | pub expired: bool, 513 | pub weak: bool, 514 | pub stats: Option, 515 | } 516 | 517 | #[derive(Debug, Clone, Deserialize, Serialize)] 518 | pub struct NameOwner { 519 | pub hash: String, 520 | pub index: u64, 521 | } 522 | 523 | //TODO make this an Enum for all posibilities 524 | // #[derive(Debug, Clone, Deserialize, Serialize)] 525 | // #[serde(rename_all = "camelCase")] 526 | // pub struct NameStats { 527 | // renewal_period_start: u32, 528 | // renewal_period_end: u32, 529 | // blocks_until_expire: u32, 530 | // days_until_expire: f64, 531 | // } 532 | 533 | #[derive(Debug, Clone, Deserialize, Serialize)] 534 | #[serde(untagged)] 535 | pub enum NameStats { 536 | Open(OpeningStats), 537 | Locked(LockedStats), 538 | Bid(BiddingStats), 539 | Reveal(RevealStats), 540 | Revoke(RevokedStats), 541 | Closed(ClosedStats), 542 | } 543 | 544 | #[derive(Debug, Clone, Deserialize, Serialize)] 545 | #[serde(rename_all = "camelCase")] 546 | pub struct OpeningStats { 547 | pub open_period_start: u32, 548 | pub open_period_end: u32, 549 | pub blocks_until_bidding: u32, 550 | pub hours_until_bidding: f64, 551 | } 552 | 553 | #[derive(Debug, Clone, Deserialize, Serialize)] 554 | #[serde(rename_all = "camelCase")] 555 | pub struct LockedStats { 556 | pub lockup_period_start: u32, 557 | pub lockup_period_end: u32, 558 | pub blocks_until_closed: u32, 559 | pub hours_until_closed: f64, 560 | } 561 | 562 | #[derive(Debug, Clone, Deserialize, Serialize)] 563 | #[serde(rename_all = "camelCase")] 564 | pub struct BiddingStats { 565 | pub bid_period_start: u32, 566 | pub bid_period_end: u32, 567 | pub blocks_until_reveal: u32, 568 | pub hours_until_reveal: f64, 569 | } 570 | 571 | #[derive(Debug, Clone, Deserialize, Serialize)] 572 | #[serde(rename_all = "camelCase")] 573 | pub struct RevealStats { 574 | pub reveal_period_start: u32, 575 | pub reveal_period_end: u32, 576 | pub blocks_until_close: u32, 577 | pub hours_until_close: f64, 578 | } 579 | 580 | #[derive(Debug, Clone, Deserialize, Serialize)] 581 | #[serde(rename_all = "camelCase")] 582 | pub struct RevokedStats { 583 | pub revoke_period_start: u32, 584 | pub revoke_period_end: u32, 585 | pub blocks_until_reopen: u32, 586 | pub hours_until_reopen: f64, 587 | } 588 | 589 | #[derive(Debug, Clone, Deserialize, Serialize)] 590 | #[serde(rename_all = "camelCase")] 591 | pub struct ClosedStats { 592 | pub renewal_period_start: u32, 593 | pub renewal_period_end: u32, 594 | pub blocks_until_expire: u32, 595 | pub days_until_expire: f64, 596 | } 597 | 598 | //TODO check output types 599 | #[derive(Debug, Clone, Deserialize, Serialize)] 600 | pub struct NameInfo { 601 | pub start: NameStart, 602 | pub info: Option, 603 | } 604 | 605 | #[derive(Debug, Clone, Deserialize, Serialize)] 606 | pub struct NameStart { 607 | pub reserved: bool, 608 | pub week: u32, 609 | pub start: u32, 610 | } 611 | 612 | #[derive(Debug, Clone, Deserialize, Serialize)] 613 | pub struct WalletTransaction { 614 | pub account: String, 615 | //Until address supports deserialize string this won't work 616 | pub address: Option, 617 | //@todo probs make this an enum 618 | pub category: String, 619 | pub amount: f64, 620 | pub label: Option, 621 | pub vout: u32, 622 | pub confirmations: i32, 623 | pub blockhash: Option, 624 | pub blockindex: i32, 625 | pub blocktime: u64, 626 | pub blockheight: u32, 627 | pub txid: Hash, 628 | pub walletconflicts: Vec, 629 | pub time: u64, 630 | pub timereceived: u64, 631 | } 632 | --------------------------------------------------------------------------------