mirror of
https://github.com/comit-network/xmr-btc-swap.git
synced 2024-12-24 06:59:36 -05:00
Extend RPC client for monerod with binary requests
This commit is contained in:
parent
1820139786
commit
dd6bfd3bf4
103
Cargo.lock
generated
103
Cargo.lock
generated
@ -129,28 +129,7 @@ dependencies = [
|
||||
"futures-core",
|
||||
"memchr",
|
||||
"pin-project-lite 0.2.6",
|
||||
"tokio 1.5.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "async-stream"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "22068c0c19514942eefcfd4daf8976ef1aad84e61539f95cd200c35202f80af5"
|
||||
dependencies = [
|
||||
"async-stream-impl",
|
||||
"futures-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "async-stream-impl"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "25f9db3b38af870bf7e5cc649167533b493928e50744e2c30ae350230b414670"
|
||||
dependencies = [
|
||||
"proc-macro2 1.0.24",
|
||||
"quote 1.0.9",
|
||||
"syn 1.0.64",
|
||||
"tokio",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -220,7 +199,7 @@ dependencies = [
|
||||
"instant",
|
||||
"pin-project 1.0.5",
|
||||
"rand 0.8.3",
|
||||
"tokio 1.5.0",
|
||||
"tokio",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -237,15 +216,11 @@ checksum = "23ce669cd6c8588f79e15cf450314f9638f967fc5770ff1c7c1deb0925ea7cfa"
|
||||
|
||||
[[package]]
|
||||
name = "base58-monero"
|
||||
version = "0.2.1"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b4b40d07a9459c8d0d60cf7e7935748fae3f401263c38a8a120be6c0a2be566d"
|
||||
checksum = "465ba1f408efdef4d9379bdfa7340899b63e472d50c7fb666480ccfd5a893e53"
|
||||
dependencies = [
|
||||
"async-stream",
|
||||
"futures-util",
|
||||
"thiserror",
|
||||
"tiny-keccak",
|
||||
"tokio 0.2.25",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -296,7 +271,7 @@ dependencies = [
|
||||
"serde",
|
||||
"serde_json",
|
||||
"sled",
|
||||
"tokio 1.5.0",
|
||||
"tokio",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -377,7 +352,7 @@ dependencies = [
|
||||
"serde_json",
|
||||
"testcontainers 0.11.0",
|
||||
"thiserror",
|
||||
"tokio 1.5.0",
|
||||
"tokio",
|
||||
"tracing",
|
||||
"url 2.2.1",
|
||||
]
|
||||
@ -491,7 +466,7 @@ checksum = "c2beb18ef6d59c6aa23181cb6d4ac75e564ce15ed62a66974179a394d386ec27"
|
||||
dependencies = [
|
||||
"futures",
|
||||
"loom",
|
||||
"tokio 1.5.0",
|
||||
"tokio",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -1318,7 +1293,7 @@ dependencies = [
|
||||
"http",
|
||||
"indexmap",
|
||||
"slab",
|
||||
"tokio 1.5.0",
|
||||
"tokio",
|
||||
"tokio-util",
|
||||
"tracing",
|
||||
]
|
||||
@ -1496,7 +1471,7 @@ dependencies = [
|
||||
"itoa",
|
||||
"pin-project 1.0.5",
|
||||
"socket2 0.4.0",
|
||||
"tokio 1.5.0",
|
||||
"tokio",
|
||||
"tower-service",
|
||||
"tracing",
|
||||
"want",
|
||||
@ -1512,7 +1487,7 @@ dependencies = [
|
||||
"hyper 0.14.7",
|
||||
"log 0.4.14",
|
||||
"rustls 0.19.0",
|
||||
"tokio 1.5.0",
|
||||
"tokio",
|
||||
"tokio-rustls",
|
||||
"webpki",
|
||||
]
|
||||
@ -1929,7 +1904,7 @@ dependencies = [
|
||||
"libp2p-core",
|
||||
"log 0.4.14",
|
||||
"socket2 0.4.0",
|
||||
"tokio 1.5.0",
|
||||
"tokio",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -2180,9 +2155,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "monero"
|
||||
version = "0.11.2"
|
||||
version = "0.12.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dad9cdd100bffa1b21e9b1052394dd78246c6977b9e6f801b4acfd53ba62311e"
|
||||
checksum = "2c73108ba5cf025e437600990935234241f95ada3c4621960d50912cde739af6"
|
||||
dependencies = [
|
||||
"base58-monero",
|
||||
"curve25519-dalek",
|
||||
@ -2195,6 +2170,16 @@ dependencies = [
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "monero-epee-bin-serde"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "13be5b525af150f294b98d4291b0ec01e5bc157db740de2822827c17561d3960"
|
||||
dependencies = [
|
||||
"byteorder",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "monero-harness"
|
||||
version = "0.1.0"
|
||||
@ -2205,7 +2190,7 @@ dependencies = [
|
||||
"rand 0.7.3",
|
||||
"spectral",
|
||||
"testcontainers 0.12.0",
|
||||
"tokio 1.5.0",
|
||||
"tokio",
|
||||
"tracing",
|
||||
"tracing-subscriber",
|
||||
]
|
||||
@ -2215,11 +2200,17 @@ name = "monero-rpc"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"curve25519-dalek",
|
||||
"hex 0.4.3",
|
||||
"hex-literal",
|
||||
"jsonrpc_client 0.6.0",
|
||||
"monero",
|
||||
"monero-epee-bin-serde",
|
||||
"rand 0.7.3",
|
||||
"reqwest",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"tokio",
|
||||
"tracing",
|
||||
]
|
||||
|
||||
@ -3079,7 +3070,7 @@ dependencies = [
|
||||
"serde",
|
||||
"serde_json",
|
||||
"serde_urlencoded",
|
||||
"tokio 1.5.0",
|
||||
"tokio",
|
||||
"tokio-rustls",
|
||||
"tokio-socks",
|
||||
"url 2.2.1",
|
||||
@ -3773,7 +3764,7 @@ dependencies = [
|
||||
"testcontainers 0.12.0",
|
||||
"thiserror",
|
||||
"time 0.2.26",
|
||||
"tokio 1.5.0",
|
||||
"tokio",
|
||||
"tokio-socks",
|
||||
"tokio-tar",
|
||||
"tokio-tungstenite",
|
||||
@ -4000,18 +3991,6 @@ version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c"
|
||||
|
||||
[[package]]
|
||||
name = "tokio"
|
||||
version = "0.2.25"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6703a273949a90131b290be1fe7b039d0fc884aa1935860dfcbe056f28cd8092"
|
||||
dependencies = [
|
||||
"bytes 0.5.6",
|
||||
"futures-core",
|
||||
"memchr",
|
||||
"pin-project-lite 0.1.12",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio"
|
||||
version = "1.5.0"
|
||||
@ -4050,7 +4029,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bc6844de72e57df1980054b38be3a9f4702aba4858be64dd700181a8a6d0e1b6"
|
||||
dependencies = [
|
||||
"rustls 0.19.0",
|
||||
"tokio 1.5.0",
|
||||
"tokio",
|
||||
"webpki",
|
||||
]
|
||||
|
||||
@ -4063,7 +4042,7 @@ dependencies = [
|
||||
"either",
|
||||
"futures-util",
|
||||
"thiserror",
|
||||
"tokio 1.5.0",
|
||||
"tokio",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -4074,7 +4053,7 @@ checksum = "c535f53c0cfa1acace62995a8994fc9cc1f12d202420da96ff306ee24d576469"
|
||||
dependencies = [
|
||||
"futures-core",
|
||||
"pin-project-lite 0.2.6",
|
||||
"tokio 1.5.0",
|
||||
"tokio",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -4086,7 +4065,7 @@ dependencies = [
|
||||
"libc",
|
||||
"redox_syscall 0.2.5",
|
||||
"tempfile",
|
||||
"tokio 1.5.0",
|
||||
"tokio",
|
||||
"tokio-stream",
|
||||
"xattr",
|
||||
]
|
||||
@ -4101,7 +4080,7 @@ dependencies = [
|
||||
"log 0.4.14",
|
||||
"pin-project 1.0.5",
|
||||
"rustls 0.19.0",
|
||||
"tokio 1.5.0",
|
||||
"tokio",
|
||||
"tokio-rustls",
|
||||
"tungstenite",
|
||||
"webpki",
|
||||
@ -4119,7 +4098,7 @@ dependencies = [
|
||||
"futures-sink",
|
||||
"log 0.4.14",
|
||||
"pin-project-lite 0.2.6",
|
||||
"tokio 1.5.0",
|
||||
"tokio",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -4145,7 +4124,7 @@ dependencies = [
|
||||
"rand 0.7.3",
|
||||
"sha2 0.8.2",
|
||||
"sha3",
|
||||
"tokio 1.5.0",
|
||||
"tokio",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -4265,7 +4244,7 @@ dependencies = [
|
||||
"smallvec",
|
||||
"thiserror",
|
||||
"tinyvec",
|
||||
"tokio 1.5.0",
|
||||
"tokio",
|
||||
"url 2.2.1",
|
||||
]
|
||||
|
||||
@ -4285,7 +4264,7 @@ dependencies = [
|
||||
"resolv-conf",
|
||||
"smallvec",
|
||||
"thiserror",
|
||||
"tokio 1.5.0",
|
||||
"tokio",
|
||||
"trust-dns-proto",
|
||||
]
|
||||
|
||||
|
@ -6,9 +6,17 @@ edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
anyhow = "1"
|
||||
curve25519-dalek = "3.1"
|
||||
hex = "0.4"
|
||||
jsonrpc_client = { version = "0.6", features = [ "reqwest" ] }
|
||||
monero = "0.11"
|
||||
monero = "0.12"
|
||||
monero-epee-bin-serde = "1"
|
||||
rand = "0.7"
|
||||
reqwest = { version = "0.11", default-features = false, features = [ "json" ] }
|
||||
serde = { version = "1.0", features = [ "derive" ] }
|
||||
serde_json = "1.0"
|
||||
tracing = "0.1"
|
||||
|
||||
[dev-dependencies]
|
||||
hex-literal = "0.3"
|
||||
tokio = { version = "1", features = [ "full" ] }
|
||||
|
@ -1,5 +1,6 @@
|
||||
use anyhow::{Context, Result};
|
||||
use serde::Deserialize;
|
||||
use monero::{cryptonote::hash::Hash, util::ringct, PublicKey};
|
||||
use serde::{de::DeserializeOwned, Deserialize, Serialize, Serializer};
|
||||
|
||||
#[jsonrpc_client::api(version = "2.0")]
|
||||
pub trait MonerodRpc {
|
||||
@ -7,6 +8,7 @@ pub trait MonerodRpc {
|
||||
-> GenerateBlocks;
|
||||
async fn get_block_header_by_height(&self, height: u32) -> BlockHeader;
|
||||
async fn get_block_count(&self) -> BlockCount;
|
||||
async fn get_block(&self, height: u32) -> GetBlockResponse;
|
||||
}
|
||||
|
||||
#[jsonrpc_client::implement(MonerodRpc)]
|
||||
@ -14,33 +16,76 @@ pub trait MonerodRpc {
|
||||
pub struct Client {
|
||||
inner: reqwest::Client,
|
||||
base_url: reqwest::Url,
|
||||
get_o_indexes_bin_url: reqwest::Url,
|
||||
get_outs_bin_url: reqwest::Url,
|
||||
}
|
||||
|
||||
impl Client {
|
||||
/// New local host monerod RPC client.
|
||||
pub fn localhost(port: u16) -> Result<Self> {
|
||||
Self::new("127.0.0.1".to_owned(), port)
|
||||
}
|
||||
|
||||
fn new(host: String, port: u16) -> Result<Self> {
|
||||
Ok(Self {
|
||||
inner: reqwest::ClientBuilder::new()
|
||||
.connection_verbose(true)
|
||||
.build()?,
|
||||
base_url: format!("http://127.0.0.1:{}/json_rpc", port)
|
||||
base_url: format!("http://{}:{}/json_rpc", host, port)
|
||||
.parse()
|
||||
.context("url is well formed")?,
|
||||
get_o_indexes_bin_url: format!("http://{}:{}/get_o_indexes.bin", host, port)
|
||||
.parse()
|
||||
.context("url is well formed")?,
|
||||
get_outs_bin_url: format!("http://{}:{}/get_outs.bin", host, port)
|
||||
.parse()
|
||||
.context("url is well formed")?,
|
||||
})
|
||||
}
|
||||
|
||||
pub async fn get_o_indexes(&self, txid: Hash) -> Result<GetOIndexesResponse> {
|
||||
self.binary_request(self.get_o_indexes_bin_url.clone(), GetOIndexesPayload {
|
||||
txid,
|
||||
})
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn get_outs(&self, outputs: Vec<GetOutputsOut>) -> Result<GetOutsResponse> {
|
||||
self.binary_request(self.get_outs_bin_url.clone(), GetOutsPayload { outputs })
|
||||
.await
|
||||
}
|
||||
|
||||
async fn binary_request<Req, Res>(&self, url: reqwest::Url, request: Req) -> Result<Res>
|
||||
where
|
||||
Req: Serialize,
|
||||
Res: DeserializeOwned,
|
||||
{
|
||||
let response = self
|
||||
.inner
|
||||
.post(url)
|
||||
.body(monero_epee_bin_serde::to_bytes(&request)?)
|
||||
.send()
|
||||
.await?;
|
||||
|
||||
if !response.status().is_success() {
|
||||
anyhow::bail!("Request failed with status code {}", response.status())
|
||||
}
|
||||
|
||||
let body = response.bytes().await?;
|
||||
|
||||
Ok(monero_epee_bin_serde::from_bytes(body)?)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Deserialize)]
|
||||
pub struct GenerateBlocks {
|
||||
pub blocks: Vec<String>,
|
||||
pub height: u32,
|
||||
pub status: String,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Deserialize)]
|
||||
#[derive(Clone, Copy, Debug, Deserialize)]
|
||||
pub struct BlockCount {
|
||||
pub count: u32,
|
||||
pub status: String,
|
||||
}
|
||||
|
||||
// We should be able to use monero-rs for this but it does not include all
|
||||
@ -61,3 +106,147 @@ pub struct BlockHeader {
|
||||
pub reward: u64,
|
||||
pub timestamp: u32,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct GetBlockResponse {
|
||||
#[serde(with = "monero_serde_hex_block")]
|
||||
pub blob: monero::Block,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct GetIndexesResponse {
|
||||
pub o_indexes: Vec<u32>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize)]
|
||||
struct GetOIndexesPayload {
|
||||
#[serde(with = "byte_array")]
|
||||
txid: Hash,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize)]
|
||||
struct GetOutsPayload {
|
||||
outputs: Vec<GetOutputsOut>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Serialize)]
|
||||
pub struct GetOutputsOut {
|
||||
pub amount: u64,
|
||||
pub index: u64,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, PartialEq)]
|
||||
pub struct GetOutsResponse {
|
||||
#[serde(flatten)]
|
||||
pub base: BaseResponse,
|
||||
pub outs: Vec<OutKey>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Deserialize, PartialEq)]
|
||||
pub struct OutKey {
|
||||
pub height: u64,
|
||||
#[serde(with = "byte_array")]
|
||||
pub key: PublicKey,
|
||||
#[serde(with = "byte_array")]
|
||||
pub mask: ringct::Key,
|
||||
#[serde(with = "byte_array")]
|
||||
pub txid: Hash,
|
||||
pub unlocked: bool,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, PartialEq)]
|
||||
pub struct BaseResponse {
|
||||
pub credits: u64,
|
||||
pub status: Status,
|
||||
pub top_hash: String,
|
||||
pub untrusted: bool,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, PartialEq)]
|
||||
pub struct GetOIndexesResponse {
|
||||
#[serde(flatten)]
|
||||
pub base: BaseResponse,
|
||||
#[serde(default)]
|
||||
pub o_indexes: Vec<u64>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Deserialize, PartialEq)]
|
||||
pub enum Status {
|
||||
#[serde(rename = "OK")]
|
||||
Ok,
|
||||
#[serde(rename = "Failed")]
|
||||
Failed,
|
||||
}
|
||||
|
||||
mod monero_serde_hex_block {
|
||||
use super::*;
|
||||
use monero::consensus::Decodable;
|
||||
use serde::{de::Error, Deserialize, Deserializer};
|
||||
use std::io::Cursor;
|
||||
|
||||
pub fn deserialize<'de, D>(deserializer: D) -> Result<monero::Block, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
let hex = String::deserialize(deserializer)?;
|
||||
|
||||
let bytes = hex::decode(&hex).map_err(D::Error::custom)?;
|
||||
let mut cursor = Cursor::new(bytes);
|
||||
|
||||
let block = monero::Block::consensus_decode(&mut cursor).map_err(D::Error::custom)?;
|
||||
|
||||
Ok(block)
|
||||
}
|
||||
}
|
||||
|
||||
mod byte_array {
|
||||
use super::*;
|
||||
use serde::{de::Error, Deserializer};
|
||||
use std::{convert::TryFrom, fmt, marker::PhantomData};
|
||||
|
||||
pub fn serialize<S, B>(bytes: B, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: Serializer,
|
||||
B: AsRef<[u8]>,
|
||||
{
|
||||
serializer.serialize_bytes(bytes.as_ref())
|
||||
}
|
||||
|
||||
pub fn deserialize<'de, D, B, const N: usize>(deserializer: D) -> Result<B, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
B: TryFrom<[u8; N]>,
|
||||
{
|
||||
struct Visitor<T, const N: usize> {
|
||||
phantom: PhantomData<(T, [u8; N])>,
|
||||
}
|
||||
|
||||
impl<'de, T, const N: usize> serde::de::Visitor<'de> for Visitor<T, N>
|
||||
where
|
||||
T: TryFrom<[u8; N]>,
|
||||
{
|
||||
type Value = T;
|
||||
|
||||
fn expecting(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "a byte buffer")
|
||||
}
|
||||
|
||||
fn visit_byte_buf<E>(self, v: Vec<u8>) -> Result<Self::Value, E>
|
||||
where
|
||||
E: Error,
|
||||
{
|
||||
let bytes = <[u8; N]>::try_from(v).map_err(|_| {
|
||||
E::custom(format!("Failed to construct [u8; {}] from buffer", N))
|
||||
})?;
|
||||
let result = T::try_from(bytes)
|
||||
.map_err(|_| E::custom(format!("Failed to construct T from [u8; {}]", N)))?;
|
||||
|
||||
Ok(result)
|
||||
}
|
||||
}
|
||||
|
||||
deserializer.deserialize_byte_buf(Visitor {
|
||||
phantom: PhantomData,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -32,7 +32,7 @@ itertools = "0.10"
|
||||
libp2p = { version = "0.37", default-features = false, features = [ "tcp-tokio", "yamux", "mplex", "dns-tokio", "noise", "request-response", "websocket" ] }
|
||||
libp2p-async-await = { git = "https://github.com/comit-network/rust-libp2p-async-await" }
|
||||
miniscript = { version = "5", features = [ "serde" ] }
|
||||
monero = { version = "0.11", features = [ "serde_support" ] }
|
||||
monero = { version = "0.12", features = [ "serde_support" ] }
|
||||
monero-rpc = { path = "../monero-rpc" }
|
||||
pem = "0.8"
|
||||
prettytable-rs = "0.8"
|
||||
|
Loading…
Reference in New Issue
Block a user