diff --git a/Cargo.lock b/Cargo.lock index d4551749..58d49d50 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4847,20 +4847,29 @@ dependencies = [ "zeroize", ] +[[package]] +name = "monero-rpc" +version = "0.1.0" +dependencies = [ + "async-trait", + "curve25519-dalek", + "hex", + "monero-serai", + "serde", + "serde_json", + "std-shims", + "thiserror", + "zeroize", +] + [[package]] name = "monero-serai" version = "0.1.4-alpha" dependencies = [ - "async-trait", - "base58-monero", "curve25519-dalek", - "dalek-ff-group", "digest_auth", - "flexible-transcript", - "group", "hex", "hex-literal", - "modular-frost", "monero-borromean", "monero-bulletproofs", "monero-clsag", @@ -4868,6 +4877,43 @@ dependencies = [ "monero-io", "monero-mlsag", "monero-primitives", + "rand_core", + "serde", + "serde_json", + "std-shims", + "thiserror", + "tokio", + "zeroize", +] + +[[package]] +name = "monero-simple-request-rpc" +version = "0.1.0" +dependencies = [ + "async-trait", + "digest_auth", + "hex", + "monero-rpc", + "simple-request", + "tokio", +] + +[[package]] +name = "monero-wallet" +version = "0.1.0" +dependencies = [ + "async-trait", + "base58-monero", + "curve25519-dalek", + "dalek-ff-group", + "flexible-transcript", + "group", + "hex", + "hex-literal", + "modular-frost", + "monero-rpc", + "monero-serai", + "monero-simple-request-rpc", "pbkdf2 0.12.2", "rand", "rand_chacha", @@ -4876,7 +4922,6 @@ dependencies = [ "serde", "serde_json", "sha3", - "simple-request", "std-shims", "subtle", "thiserror", @@ -7867,7 +7912,7 @@ dependencies = [ "frost-schnorrkel", "hex", "modular-frost", - "monero-serai", + "monero-wallet", "multiaddr", "parity-scale-codec", "rand_core", @@ -8025,7 +8070,8 @@ dependencies = [ "curve25519-dalek", "dockertest", "hex", - "monero-serai", + "monero-simple-request-rpc", + "monero-wallet", "parity-scale-codec", "rand_core", "serai-client", @@ -8129,7 +8175,9 @@ dependencies = [ "monero-io", "monero-mlsag", "monero-primitives", + "monero-rpc", "monero-serai", + "monero-wallet", "multiexp", "schnorr-signatures", ] @@ -8230,7 +8278,8 @@ dependencies = [ "k256", "log", "modular-frost", - "monero-serai", + "monero-simple-request-rpc", + "monero-wallet", "parity-scale-codec", "rand_chacha", "rand_core", @@ -8276,7 +8325,8 @@ dependencies = [ "ethereum-serai", "hex", "k256", - "monero-serai", + "monero-simple-request-rpc", + "monero-wallet", "parity-scale-codec", "rand_core", "serai-client", diff --git a/Cargo.toml b/Cargo.toml index 8f4a142f..0e711307 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -51,6 +51,9 @@ members = [ "coins/monero/ringct/borromean", "coins/monero/ringct/bulletproofs", "coins/monero", + "coins/monero/rpc", + "coins/monero/rpc/simple-request", + "coins/monero/wallet", "message-queue", diff --git a/coins/monero/Cargo.toml b/coins/monero/Cargo.toml index f1712a16..f8a14eb3 100644 --- a/coins/monero/Cargo.toml +++ b/coins/monero/Cargo.toml @@ -18,32 +18,13 @@ workspace = true [dependencies] std-shims = { path = "../../common/std-shims", version = "^0.1.1", default-features = false } -async-trait = { version = "0.1", default-features = false } thiserror = { version = "1", default-features = false, optional = true } zeroize = { version = "^1.5", default-features = false, features = ["zeroize_derive"] } -subtle = { version = "^2.4", default-features = false } - rand_core = { version = "0.6", default-features = false } -# Used to send transactions -rand = { version = "0.8", default-features = false } -rand_chacha = { version = "0.3", default-features = false } -# Used to select decoys -rand_distr = { version = "0.4", default-features = false } - -sha3 = { version = "0.10", default-features = false } -pbkdf2 = { version = "0.12", features = ["simple"], default-features = false } curve25519-dalek = { version = "4", default-features = false, features = ["alloc", "zeroize"] } -# Used for the hash to curve, along with the more complicated proofs -group = { version = "0.13", default-features = false } -dalek-ff-group = { path = "../../crypto/dalek-ff-group", version = "0.4", default-features = false } - -# Needed for multisig -transcript = { package = "flexible-transcript", path = "../../crypto/transcript", version = "0.3", default-features = false, features = ["recommended"], optional = true } -frost = { package = "modular-frost", path = "../../crypto/frost", version = "0.8", default-features = false, features = ["ed25519"], optional = true } - monero-io = { path = "io", version = "0.1", default-features = false } monero-generators = { path = "generators", version = "0.4", default-features = false } monero-primitives = { path = "primitives", version = "0.1", default-features = false } @@ -57,22 +38,10 @@ hex = { version = "0.4", default-features = false, features = ["alloc"] } serde = { version = "1", default-features = false, features = ["derive", "alloc"] } serde_json = { version = "1", default-features = false, features = ["alloc"] } -base58-monero = { version = "2", default-features = false, features = ["check"] } - # Used for the provided HTTP RPC digest_auth = { version = "0.3", default-features = false, optional = true } -simple-request = { path = "../../common/request", version = "0.1", default-features = false, features = ["tls"], optional = true } tokio = { version = "1", default-features = false, optional = true } -[build-dependencies] -dalek-ff-group = { path = "../../crypto/dalek-ff-group", version = "0.4", default-features = false } -monero-generators = { path = "generators", version = "0.4", default-features = false } - -[dev-dependencies] -tokio = { version = "1", features = ["sync", "macros"] } - -frost = { package = "modular-frost", path = "../../crypto/frost", features = ["tests"] } - [features] std = [ "std-shims/std", @@ -80,17 +49,8 @@ std = [ "thiserror", "zeroize/std", - "subtle/std", "rand_core/std", - "rand/std", - "rand_chacha/std", - "rand_distr/std", - - "sha3/std", - "pbkdf2/std", - - "transcript/std", "monero-io/std", "monero-generators/std", @@ -102,13 +62,9 @@ std = [ "hex/std", "serde/std", "serde_json/std", - - "base58-monero/std", ] compile-time-generators = ["curve25519-dalek/precomputed-tables", "monero-bulletproofs/compile-time-generators"] -http-rpc = ["digest_auth", "simple-request", "tokio"] -multisig = ["transcript", "frost", "monero-clsag/multisig", "std"] -binaries = ["tokio/rt-multi-thread", "tokio/macros", "http-rpc"] - -default = ["std", "http-rpc"] +multisig = ["monero-clsag/multisig", "std"] +#binaries = ["tokio/rt-multi-thread", "tokio/macros", "http-rpc"] +default = ["std"] diff --git a/coins/monero/rpc/Cargo.toml b/coins/monero/rpc/Cargo.toml new file mode 100644 index 00000000..88e3cdaf --- /dev/null +++ b/coins/monero/rpc/Cargo.toml @@ -0,0 +1,46 @@ +[package] +name = "monero-rpc" +version = "0.1.0" +description = "Trait for an RPC connection to a Monero daemon, built around monero-serai" +license = "MIT" +repository = "https://github.com/serai-dex/serai/tree/develop/coins/monero/rpc" +authors = ["Luke Parker "] +edition = "2021" +rust-version = "1.79" + +[package.metadata.docs.rs] +all-features = true +rustdoc-args = ["--cfg", "docsrs"] + +[lints] +workspace = true + +[dependencies] +std-shims = { path = "../../../common/std-shims", version = "^0.1.1", default-features = false } + +async-trait = { version = "0.1", default-features = false } +thiserror = { version = "1", default-features = false, optional = true } + +zeroize = { version = "^1.5", default-features = false, features = ["zeroize_derive"] } +hex = { version = "0.4", default-features = false, features = ["alloc"] } +serde = { version = "1", default-features = false, features = ["derive", "alloc"] } +serde_json = { version = "1", default-features = false, features = ["alloc"] } + +curve25519-dalek = { version = "4", default-features = false, features = ["alloc", "zeroize"] } + +monero-serai = { path = "..", default-features = false } + +[features] +std = [ + "std-shims/std", + + "thiserror", + + "zeroize/std", + "hex/std", + "serde/std", + "serde_json/std", + + "monero-serai/std", +] +default = ["std"] diff --git a/coins/monero/rpc/LICENSE b/coins/monero/rpc/LICENSE new file mode 100644 index 00000000..91d893c1 --- /dev/null +++ b/coins/monero/rpc/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2022-2024 Luke Parker + +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: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +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. diff --git a/coins/monero/rpc/README.md b/coins/monero/rpc/README.md new file mode 100644 index 00000000..6453e7c6 --- /dev/null +++ b/coins/monero/rpc/README.md @@ -0,0 +1,6 @@ +# Monero RPC + +Trait for an RPC connection to a Monero daemon, built around monero-serai. + +This library is usable under no-std when the `std` feature (on by default) is +disabled. diff --git a/coins/monero/rpc/simple-request/Cargo.toml b/coins/monero/rpc/simple-request/Cargo.toml new file mode 100644 index 00000000..3d0b8bd9 --- /dev/null +++ b/coins/monero/rpc/simple-request/Cargo.toml @@ -0,0 +1,26 @@ +[package] +name = "monero-simple-request-rpc" +version = "0.1.0" +description = "RPC connection to a Monero daemon via simple-request, built around monero-serai" +license = "MIT" +repository = "https://github.com/serai-dex/serai/tree/develop/coins/monero/rpc/simple-request" +authors = ["Luke Parker "] +edition = "2021" +rust-version = "1.79" + +[package.metadata.docs.rs] +all-features = true +rustdoc-args = ["--cfg", "docsrs"] + +[lints] +workspace = true + +[dependencies] +async-trait = { version = "0.1", default-features = false } + +hex = { version = "0.4", default-features = false, features = ["alloc"] } +digest_auth = { version = "0.3", default-features = false } +simple-request = { path = "../../../../common/request", version = "0.1", default-features = false, features = ["tls"] } +tokio = { version = "1", default-features = false } + +monero-rpc = { path = "..", default-features = false, features = ["std"] } diff --git a/coins/monero/rpc/simple-request/LICENSE b/coins/monero/rpc/simple-request/LICENSE new file mode 100644 index 00000000..91d893c1 --- /dev/null +++ b/coins/monero/rpc/simple-request/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2022-2024 Luke Parker + +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: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +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. diff --git a/coins/monero/rpc/simple-request/README.md b/coins/monero/rpc/simple-request/README.md new file mode 100644 index 00000000..947e777e --- /dev/null +++ b/coins/monero/rpc/simple-request/README.md @@ -0,0 +1,3 @@ +# Monero simple-request RPC + +RPC connection to a Monero daemon via simple-request, built around monero-serai. diff --git a/coins/monero/src/rpc/http.rs b/coins/monero/rpc/simple-request/src/lib.rs similarity index 95% rename from coins/monero/src/rpc/http.rs rename to coins/monero/rpc/simple-request/src/lib.rs index 4ed349a5..636852b0 100644 --- a/coins/monero/src/rpc/http.rs +++ b/coins/monero/rpc/simple-request/src/lib.rs @@ -1,3 +1,7 @@ +#![cfg_attr(docsrs, feature(doc_auto_cfg))] +#![doc = include_str!("../README.md")] +// #![deny(missing_docs)] // TODO + use std::{sync::Arc, io::Read, time::Duration}; use async_trait::async_trait; @@ -10,7 +14,7 @@ use simple_request::{ Response, Client, }; -use crate::rpc::{RpcError, RpcConnection, Rpc}; +use monero_rpc::{RpcError, RpcConnection, Rpc}; const DEFAULT_TIMEOUT: Duration = Duration::from_secs(30); @@ -33,13 +37,13 @@ enum Authentication { /// /// Requires tokio. #[derive(Clone, Debug)] -pub struct HttpRpc { +pub struct SimpleRequestRpc { authentication: Authentication, url: String, request_timeout: Duration, } -impl HttpRpc { +impl SimpleRequestRpc { fn digest_auth_challenge( response: &Response, ) -> Result, RpcError> { @@ -60,7 +64,7 @@ impl HttpRpc { /// /// A daemon requiring authentication can be used via including the username and password in the /// URL. - pub async fn new(url: String) -> Result, RpcError> { + pub async fn new(url: String) -> Result, RpcError> { Self::with_custom_timeout(url, DEFAULT_TIMEOUT).await } @@ -71,7 +75,7 @@ impl HttpRpc { pub async fn with_custom_timeout( mut url: String, request_timeout: Duration, - ) -> Result, RpcError> { + ) -> Result, RpcError> { let authentication = if url.contains('@') { // Parse out the username and password let url_clone = url; @@ -119,11 +123,11 @@ impl HttpRpc { Authentication::Unauthenticated(Client::with_connection_pool()) }; - Ok(Rpc(HttpRpc { authentication, url, request_timeout })) + Ok(Rpc::new(SimpleRequestRpc { authentication, url, request_timeout })) } } -impl HttpRpc { +impl SimpleRequestRpc { async fn inner_post(&self, route: &str, body: Vec) -> Result, RpcError> { let request_fn = |uri| { Request::post(uri) @@ -277,7 +281,7 @@ impl HttpRpc { } #[async_trait] -impl RpcConnection for HttpRpc { +impl RpcConnection for SimpleRequestRpc { async fn post(&self, route: &str, body: Vec) -> Result, RpcError> { tokio::time::timeout(self.request_timeout, self.inner_post(route, body)) .await diff --git a/coins/monero/src/rpc/mod.rs b/coins/monero/rpc/src/lib.rs similarity index 93% rename from coins/monero/src/rpc/mod.rs rename to coins/monero/rpc/src/lib.rs index 550abb73..b7726043 100644 --- a/coins/monero/src/rpc/mod.rs +++ b/coins/monero/rpc/src/lib.rs @@ -1,3 +1,8 @@ +#![cfg_attr(docsrs, feature(doc_auto_cfg))] +#![doc = include_str!("../README.md")] +// #![deny(missing_docs)] // TODO +#![cfg_attr(not(feature = "std"), no_std)] + use core::fmt::Debug; #[cfg(not(feature = "std"))] use alloc::boxed::Box; @@ -7,33 +12,72 @@ use std_shims::{ string::{String, ToString}, }; +use zeroize::Zeroize; + use async_trait::async_trait; use curve25519_dalek::edwards::EdwardsPoint; -use monero_io::decompress_point; - use serde::{Serialize, Deserialize, de::DeserializeOwned}; use serde_json::{Value, json}; -use crate::{ +use monero_serai::{ + io::*, Protocol, - serialize::*, transaction::{Input, Timelock, Transaction}, block::Block, - wallet::{FeePriority, Fee}, }; -#[cfg(feature = "http-rpc")] -mod http; -#[cfg(feature = "http-rpc")] -pub use http::*; - // Number of blocks the fee estimate will be valid for // https://github.com/monero-project/monero/blob/94e67bf96bbc010241f29ada6abc89f49a81759c/ // src/wallet/wallet2.cpp#L121 const GRACE_BLOCKS_FOR_FEE_ESTIMATE: u64 = 10; +/// Fee struct, defined as a per-unit cost and a mask for rounding purposes. +#[derive(Clone, Copy, PartialEq, Eq, Debug, Zeroize)] +pub struct Fee { + pub per_weight: u64, + pub mask: u64, +} + +impl Fee { + pub fn calculate_fee_from_weight(&self, weight: usize) -> u64 { + let fee = (((self.per_weight * u64::try_from(weight).unwrap()) + self.mask - 1) / self.mask) * + self.mask; + debug_assert_eq!(weight, self.calculate_weight_from_fee(fee), "Miscalculated weight from fee"); + fee + } + + pub fn calculate_weight_from_fee(&self, fee: u64) -> usize { + usize::try_from(fee / self.per_weight).unwrap() + } +} + +/// Fee priority, determining how quickly a transaction is included in a block. +#[derive(Clone, Copy, PartialEq, Eq, Debug)] +#[allow(non_camel_case_types)] +pub enum FeePriority { + Unimportant, + Normal, + Elevated, + Priority, + Custom { priority: u32 }, +} + +/// https://github.com/monero-project/monero/blob/ac02af92867590ca80b2779a7bbeafa99ff94dcb/ +/// src/simplewallet/simplewallet.cpp#L161 +impl FeePriority { + pub(crate) fn fee_priority(&self) -> u32 { + match self { + FeePriority::Unimportant => 1, + FeePriority::Normal => 2, + FeePriority::Elevated => 3, + FeePriority::Priority => 4, + FeePriority::Custom { priority, .. } => *priority, + } + } +} + #[derive(Deserialize, Debug)] pub struct EmptyResponse {} #[derive(Deserialize, Debug)] @@ -132,6 +176,10 @@ pub trait RpcConnection: Clone + Debug { #[derive(Clone, Debug)] pub struct Rpc(R); impl Rpc { + pub fn new(connection: R) -> Self { + Self(connection) + } + /// Perform a RPC call to the specified route with the provided parameters. /// /// This is NOT a JSON-RPC call. They use a route of "json_rpc" and are available via diff --git a/coins/monero/src/bin/reserialize_chain.rs b/coins/monero/src/bin/reserialize_chain.rs index fcaa78af..93b7a0e3 100644 --- a/coins/monero/src/bin/reserialize_chain.rs +++ b/coins/monero/src/bin/reserialize_chain.rs @@ -1,3 +1,4 @@ +/* TODO #[cfg(feature = "binaries")] mod binaries { pub(crate) use std::sync::Arc; @@ -12,14 +13,14 @@ mod binaries { ringct::{RctPrunable, bulletproofs::BatchVerifier}, transaction::{Input, Transaction}, block::Block, - rpc::{RpcError, Rpc, HttpRpc}, + rpc::{RpcError, Rpc, SimpleRequestRpc}, }; pub(crate) use monero_io::decompress_point; pub(crate) use tokio::task::JoinHandle; - pub(crate) async fn check_block(rpc: Arc>, block_i: usize) { + pub(crate) async fn check_block(rpc: Arc>, block_i: usize) { let hash = loop { match rpc.get_block_hash(block_i).await { Ok(hash) => break hash, @@ -157,7 +158,7 @@ mod binaries { } async fn get_outs( - rpc: &Rpc, + rpc: &Rpc, amount: u64, indexes: &[u64], ) -> Vec<[EdwardsPoint; 2]> { @@ -268,9 +269,9 @@ async fn main() { let nodes = if specified_nodes.is_empty() { default_nodes } else { specified_nodes }; let rpc = |url: String| async move { - HttpRpc::new(url.clone()) + SimpleRequestRpc::new(url.clone()) .await - .unwrap_or_else(|_| panic!("couldn't create HttpRpc connected to {url}")) + .unwrap_or_else(|_| panic!("couldn't create SimpleRequestRpc connected to {url}")) }; let main_rpc = rpc(nodes[0].clone()).await; let mut rpcs = vec![]; @@ -315,3 +316,6 @@ async fn main() { fn main() { panic!("To run binaries, please build with `--feature binaries`."); } +*/ + +fn main() {} diff --git a/coins/monero/src/lib.rs b/coins/monero/src/lib.rs index 76c6cdc4..1b5d37b5 100644 --- a/coins/monero/src/lib.rs +++ b/coins/monero/src/lib.rs @@ -27,14 +27,6 @@ pub mod transaction; /// Block structs. pub mod block; -/// Monero daemon RPC interface. -pub mod rpc; -/// Wallet functionality, enabling scanning and sending transactions. -pub mod wallet; - -#[cfg(test)] -mod tests; - pub const DEFAULT_LOCK_WINDOW: usize = 10; pub const COINBASE_LOCK_WINDOW: usize = 60; pub const BLOCK_TIME: usize = 120; @@ -106,7 +98,7 @@ impl Protocol { } } - pub(crate) fn write(&self, w: &mut W) -> stdio::Result<()> { + pub fn write(&self, w: &mut W) -> stdio::Result<()> { match self { Protocol::v14 => w.write_all(&[0, 14]), Protocol::v16 => w.write_all(&[0, 16]), @@ -122,7 +114,7 @@ impl Protocol { } } - pub(crate) fn read(r: &mut R) -> stdio::Result { + pub fn read(r: &mut R) -> stdio::Result { Ok(match read_byte(r)? { // Monero protocol 0 => match read_byte(r)? { diff --git a/coins/monero/src/ringct.rs b/coins/monero/src/ringct.rs index 8278c4b7..0e61f95d 100644 --- a/coins/monero/src/ringct.rs +++ b/coins/monero/src/ringct.rs @@ -134,7 +134,7 @@ pub struct RctBase { } impl RctBase { - pub(crate) fn fee_weight(outputs: usize, fee: u64) -> usize { + pub fn fee_weight(outputs: usize, fee: u64) -> usize { // 1 byte for the RCT signature type 1 + (outputs * (8 + 32)) + varint_len(fee) } @@ -227,7 +227,7 @@ pub enum RctPrunable { } impl RctPrunable { - pub(crate) fn fee_weight(protocol: Protocol, inputs: usize, outputs: usize) -> usize { + pub fn fee_weight(protocol: Protocol, inputs: usize, outputs: usize) -> usize { // 1 byte for number of BPs (technically a VarInt, yet there's always just zero or one) 1 + Bulletproof::fee_weight(protocol.bp_plus(), outputs) + (inputs * (Clsag::fee_weight(protocol.ring_len()) + 32)) @@ -383,7 +383,7 @@ impl RctSignatures { } } - pub(crate) fn fee_weight(protocol: Protocol, inputs: usize, outputs: usize, fee: u64) -> usize { + pub fn fee_weight(protocol: Protocol, inputs: usize, outputs: usize, fee: u64) -> usize { RctBase::fee_weight(outputs, fee) + RctPrunable::fee_weight(protocol, inputs, outputs) } diff --git a/coins/monero/src/transaction.rs b/coins/monero/src/transaction.rs index 5d27e924..b374c01e 100644 --- a/coins/monero/src/transaction.rs +++ b/coins/monero/src/transaction.rs @@ -23,7 +23,7 @@ pub enum Input { } impl Input { - pub(crate) fn fee_weight(offsets_weight: usize) -> usize { + pub fn fee_weight(offsets_weight: usize) -> usize { // Uses 1 byte for the input type // Uses 1 byte for the VarInt amount due to amount being 0 1 + 1 + offsets_weight + 32 @@ -82,7 +82,7 @@ pub struct Output { } impl Output { - pub(crate) fn fee_weight(view_tags: bool) -> usize { + pub fn fee_weight(view_tags: bool) -> usize { // Uses 1 byte for the output type // Uses 1 byte for the VarInt amount due to amount being 0 1 + 1 + 32 + if view_tags { 1 } else { 0 } @@ -182,7 +182,7 @@ pub struct TransactionPrefix { } impl TransactionPrefix { - pub(crate) fn fee_weight( + pub fn fee_weight( decoy_weights: &[usize], outputs: usize, view_tags: bool, @@ -254,7 +254,7 @@ pub struct Transaction { } impl Transaction { - pub(crate) fn fee_weight( + pub fn fee_weight( protocol: Protocol, decoy_weights: &[usize], outputs: usize, diff --git a/coins/monero/wallet/Cargo.toml b/coins/monero/wallet/Cargo.toml new file mode 100644 index 00000000..dce34ba7 --- /dev/null +++ b/coins/monero/wallet/Cargo.toml @@ -0,0 +1,88 @@ +[package] +name = "monero-wallet" +version = "0.1.0" +description = "Wallet functionality for the Monero protocol, built around monero-serai" +license = "MIT" +repository = "https://github.com/serai-dex/serai/tree/develop/coins/monero/wallet" +authors = ["Luke Parker "] +edition = "2021" +rust-version = "1.79" + +[package.metadata.docs.rs] +all-features = true +rustdoc-args = ["--cfg", "docsrs"] + +[lints] +workspace = true + +[dependencies] +std-shims = { path = "../../../common/std-shims", version = "^0.1.1", default-features = false } + +async-trait = { version = "0.1", default-features = false } +thiserror = { version = "1", default-features = false, optional = true } + +zeroize = { version = "^1.5", default-features = false, features = ["zeroize_derive"] } +subtle = { version = "^2.4", default-features = false } + +rand_core = { version = "0.6", default-features = false } +# Used to send transactions +rand = { version = "0.8", default-features = false } +rand_chacha = { version = "0.3", default-features = false } +# Used to select decoys +rand_distr = { version = "0.4", default-features = false } + +sha3 = { version = "0.10", default-features = false } +pbkdf2 = { version = "0.12", features = ["simple"], default-features = false } + +group = { version = "0.13", default-features = false } +curve25519-dalek = { version = "4", default-features = false, features = ["alloc", "zeroize", "group"] } + +# Multisig dependencies +transcript = { package = "flexible-transcript", path = "../../../crypto/transcript", version = "0.3", default-features = false, features = ["recommended"], optional = true } +dalek-ff-group = { path = "../../../crypto/dalek-ff-group", version = "0.4", default-features = false, optional = true } +frost = { package = "modular-frost", path = "../../../crypto/frost", default-features = false, features = ["ed25519"], optional = true } + +hex = { version = "0.4", default-features = false, features = ["alloc"] } +base58-monero = { version = "2", default-features = false, features = ["check"] } +serde = { version = "1", default-features = false, features = ["derive", "alloc"] } +serde_json = { version = "1", default-features = false, features = ["alloc"] } + +monero-serai = { path = "..", default-features = false } +monero-rpc = { path = "../rpc", default-features = false } + +[dev-dependencies] +hex-literal = "0.4" + +frost = { package = "modular-frost", path = "../../../crypto/frost", default-features = false, features = ["ed25519", "tests"] } + +tokio = { version = "1", features = ["sync", "macros"] } + +monero-simple-request-rpc = { path = "../rpc/simple-request", default-features = false } + +[features] +std = [ + "std-shims/std", + + "thiserror", + + "zeroize/std", + "subtle/std", + + "rand_core/std", + "rand/std", + "rand_chacha/std", + "rand_distr/std", + + "sha3/std", + "pbkdf2/std", + + "hex/std", + "base58-monero/std", + "serde/std", + "serde_json/std", + + "monero-serai/std", + "monero-rpc/std", +] +multisig = ["transcript", "dalek-ff-group", "frost", "monero-serai/multisig", "std"] +default = ["std"] diff --git a/coins/monero/wallet/LICENSE b/coins/monero/wallet/LICENSE new file mode 100644 index 00000000..91d893c1 --- /dev/null +++ b/coins/monero/wallet/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2022-2024 Luke Parker + +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: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +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. diff --git a/coins/monero/wallet/README.md b/coins/monero/wallet/README.md new file mode 100644 index 00000000..e2dd47cc --- /dev/null +++ b/coins/monero/wallet/README.md @@ -0,0 +1,6 @@ +# Monero Wallet + +Wallet functionality for the Monero protocol, built around monero-serai. + +This library is usable under no-std when the `std` feature (on by default) is +disabled. diff --git a/coins/monero/src/wallet/address.rs b/coins/monero/wallet/src/address.rs similarity index 99% rename from coins/monero/src/wallet/address.rs rename to coins/monero/wallet/src/address.rs index 6ceebf05..3111c545 100644 --- a/coins/monero/src/wallet/address.rs +++ b/coins/monero/wallet/src/address.rs @@ -5,7 +5,7 @@ use zeroize::Zeroize; use curve25519_dalek::edwards::EdwardsPoint; -use crate::io::decompress_point; +use monero_serai::io::decompress_point; use base58_monero::base58::{encode_check, decode_check}; diff --git a/coins/monero/src/wallet/decoys.rs b/coins/monero/wallet/src/decoys.rs similarity index 98% rename from coins/monero/src/wallet/decoys.rs rename to coins/monero/wallet/src/decoys.rs index 83762c33..ee4b4695 100644 --- a/coins/monero/src/wallet/decoys.rs +++ b/coins/monero/wallet/src/decoys.rs @@ -9,11 +9,9 @@ use rand_distr::num_traits::Float; use curve25519_dalek::edwards::EdwardsPoint; -use crate::{ - wallet::SpendableOutput, - rpc::{RpcError, RpcConnection, Rpc}, - DEFAULT_LOCK_WINDOW, COINBASE_LOCK_WINDOW, BLOCK_TIME, -}; +use monero_serai::{DEFAULT_LOCK_WINDOW, COINBASE_LOCK_WINDOW, BLOCK_TIME}; +use monero_rpc::{RpcError, RpcConnection, Rpc}; +use crate::SpendableOutput; const RECENT_WINDOW: usize = 15; const BLOCKS_PER_YEAR: usize = 365 * 24 * 60 * 60 / BLOCK_TIME; @@ -274,7 +272,7 @@ async fn select_decoys( Ok(res) } -pub use monero_primitives::Decoys; +pub use monero_serai::primitives::Decoys; // TODO: Remove this trait #[cfg(feature = "std")] diff --git a/coins/monero/src/wallet/extra.rs b/coins/monero/wallet/src/extra.rs similarity index 99% rename from coins/monero/src/wallet/extra.rs rename to coins/monero/wallet/src/extra.rs index e84eb81b..74b0d8c5 100644 --- a/coins/monero/src/wallet/extra.rs +++ b/coins/monero/wallet/src/extra.rs @@ -8,7 +8,7 @@ use zeroize::Zeroize; use curve25519_dalek::edwards::EdwardsPoint; -use crate::io::*; +use monero_serai::io::*; pub const MAX_TX_EXTRA_PADDING_COUNT: usize = 255; pub const MAX_TX_EXTRA_NONCE_SIZE: usize = 255; @@ -209,7 +209,7 @@ impl Extra { } #[rustfmt::skip] - pub(crate) fn fee_weight( + pub fn fee_weight( outputs: usize, additional: bool, payment_id: bool, diff --git a/coins/monero/src/wallet/mod.rs b/coins/monero/wallet/src/lib.rs similarity index 92% rename from coins/monero/src/wallet/mod.rs rename to coins/monero/wallet/src/lib.rs index 3ed56272..e8f2b029 100644 --- a/coins/monero/src/wallet/mod.rs +++ b/coins/monero/wallet/src/lib.rs @@ -1,3 +1,8 @@ +#![cfg_attr(docsrs, feature(doc_auto_cfg))] +#![doc = include_str!("../README.md")] +// #![deny(missing_docs)] // TODO +#![cfg_attr(not(feature = "std"), no_std)] + use core::ops::Deref; use std_shims::collections::{HashSet, HashMap}; @@ -9,12 +14,15 @@ use curve25519_dalek::{ edwards::{EdwardsPoint, CompressedEdwardsY}, }; -use crate::{ +use monero_serai::{ io::write_varint, primitives::{Commitment, keccak256, keccak256_to_scalar}, ringct::EncryptedAmount, transaction::Input, }; +pub use monero_serai as monero; + +pub use monero_rpc as rpc; pub mod extra; pub(crate) use extra::{PaymentId, ExtraField, Extra}; @@ -33,7 +41,7 @@ pub use scan::{ReceivedOutput, SpendableOutput, Timelocked}; pub mod decoys; #[cfg(not(feature = "std"))] pub mod decoys { - pub use monero_primitives::Decoys; + pub use monero_serai::primitives::Decoys; pub trait DecoySelection {} } pub use decoys::{DecoySelection, Decoys}; @@ -47,6 +55,9 @@ pub(crate) use send::InternalPayment; #[cfg(feature = "multisig")] pub use send::TransactionMachine; +#[cfg(test)] +mod tests; + fn key_image_sort(x: &EdwardsPoint, y: &EdwardsPoint) -> core::cmp::Ordering { x.compress().to_bytes().cmp(&y.compress().to_bytes()).reverse() } @@ -109,12 +120,19 @@ pub(crate) fn compact_amount_encryption(amount: u64, key: Scalar) -> [u8; 8] { (amount ^ u64::from_le_bytes(keccak256(amount_mask)[.. 8].try_into().unwrap())).to_le_bytes() } -impl EncryptedAmount { +pub trait EncryptedAmountExt { /// Decrypt an EncryptedAmount into the Commitment it encrypts. /// /// The caller must verify the decrypted Commitment matches with the actual Commitment used /// within in the Monero protocol. - pub fn decrypt(&self, key: Scalar) -> Commitment { + fn decrypt(&self, key: Scalar) -> Commitment; +} +impl EncryptedAmountExt for EncryptedAmount { + /// Decrypt an EncryptedAmount into the Commitment it encrypts. + /// + /// The caller must verify the decrypted Commitment matches with the actual Commitment used + /// within in the Monero protocol. + fn decrypt(&self, key: Scalar) -> Commitment { match self { // TODO: Add a test vector for this EncryptedAmount::Original { mask, amount } => { diff --git a/coins/monero/src/wallet/scan.rs b/coins/monero/wallet/src/scan.rs similarity index 98% rename from coins/monero/src/wallet/scan.rs rename to coins/monero/wallet/src/scan.rs index c0900449..b8fa67e6 100644 --- a/coins/monero/src/wallet/scan.rs +++ b/coins/monero/wallet/src/scan.rs @@ -9,15 +9,15 @@ use zeroize::{Zeroize, ZeroizeOnDrop}; use curve25519_dalek::{constants::ED25519_BASEPOINT_TABLE, scalar::Scalar, edwards::EdwardsPoint}; -use monero_io::decompress_point; - -use crate::{ +use monero_rpc::{RpcError, RpcConnection, Rpc}; +use monero_serai::{ io::*, primitives::Commitment, transaction::{Input, Timelock, Transaction}, block::Block, - rpc::{RpcError, RpcConnection, Rpc}, - wallet::{PaymentId, Extra, address::SubaddressIndex, Scanner, uniqueness, shared_key}, +}; +use crate::{ + PaymentId, Extra, address::SubaddressIndex, Scanner, EncryptedAmountExt, uniqueness, shared_key, }; /// An absolute output ID, defined as its transaction hash and output index. diff --git a/coins/monero/src/wallet/seed/classic.rs b/coins/monero/wallet/src/seed/classic.rs similarity index 99% rename from coins/monero/src/wallet/seed/classic.rs rename to coins/monero/wallet/src/seed/classic.rs index 4acb8991..df9198c8 100644 --- a/coins/monero/src/wallet/seed/classic.rs +++ b/coins/monero/wallet/src/seed/classic.rs @@ -11,7 +11,7 @@ use rand_core::{RngCore, CryptoRng}; use curve25519_dalek::scalar::Scalar; -use crate::wallet::seed::SeedError; +use crate::seed::SeedError; pub(crate) const CLASSIC_SEED_LENGTH: usize = 24; pub(crate) const CLASSIC_SEED_LENGTH_WITH_CHECKSUM: usize = 25; diff --git a/coins/monero/src/wallet/seed/classic/ang.rs b/coins/monero/wallet/src/seed/classic/ang.rs similarity index 100% rename from coins/monero/src/wallet/seed/classic/ang.rs rename to coins/monero/wallet/src/seed/classic/ang.rs diff --git a/coins/monero/src/wallet/seed/classic/de.rs b/coins/monero/wallet/src/seed/classic/de.rs similarity index 100% rename from coins/monero/src/wallet/seed/classic/de.rs rename to coins/monero/wallet/src/seed/classic/de.rs diff --git a/coins/monero/src/wallet/seed/classic/en.rs b/coins/monero/wallet/src/seed/classic/en.rs similarity index 100% rename from coins/monero/src/wallet/seed/classic/en.rs rename to coins/monero/wallet/src/seed/classic/en.rs diff --git a/coins/monero/src/wallet/seed/classic/eo.rs b/coins/monero/wallet/src/seed/classic/eo.rs similarity index 100% rename from coins/monero/src/wallet/seed/classic/eo.rs rename to coins/monero/wallet/src/seed/classic/eo.rs diff --git a/coins/monero/src/wallet/seed/classic/es.rs b/coins/monero/wallet/src/seed/classic/es.rs similarity index 100% rename from coins/monero/src/wallet/seed/classic/es.rs rename to coins/monero/wallet/src/seed/classic/es.rs diff --git a/coins/monero/src/wallet/seed/classic/fr.rs b/coins/monero/wallet/src/seed/classic/fr.rs similarity index 100% rename from coins/monero/src/wallet/seed/classic/fr.rs rename to coins/monero/wallet/src/seed/classic/fr.rs diff --git a/coins/monero/src/wallet/seed/classic/it.rs b/coins/monero/wallet/src/seed/classic/it.rs similarity index 100% rename from coins/monero/src/wallet/seed/classic/it.rs rename to coins/monero/wallet/src/seed/classic/it.rs diff --git a/coins/monero/src/wallet/seed/classic/ja.rs b/coins/monero/wallet/src/seed/classic/ja.rs similarity index 100% rename from coins/monero/src/wallet/seed/classic/ja.rs rename to coins/monero/wallet/src/seed/classic/ja.rs diff --git a/coins/monero/src/wallet/seed/classic/jbo.rs b/coins/monero/wallet/src/seed/classic/jbo.rs similarity index 100% rename from coins/monero/src/wallet/seed/classic/jbo.rs rename to coins/monero/wallet/src/seed/classic/jbo.rs diff --git a/coins/monero/src/wallet/seed/classic/nl.rs b/coins/monero/wallet/src/seed/classic/nl.rs similarity index 100% rename from coins/monero/src/wallet/seed/classic/nl.rs rename to coins/monero/wallet/src/seed/classic/nl.rs diff --git a/coins/monero/src/wallet/seed/classic/pt.rs b/coins/monero/wallet/src/seed/classic/pt.rs similarity index 100% rename from coins/monero/src/wallet/seed/classic/pt.rs rename to coins/monero/wallet/src/seed/classic/pt.rs diff --git a/coins/monero/src/wallet/seed/classic/ru.rs b/coins/monero/wallet/src/seed/classic/ru.rs similarity index 100% rename from coins/monero/src/wallet/seed/classic/ru.rs rename to coins/monero/wallet/src/seed/classic/ru.rs diff --git a/coins/monero/src/wallet/seed/classic/zh.rs b/coins/monero/wallet/src/seed/classic/zh.rs similarity index 100% rename from coins/monero/src/wallet/seed/classic/zh.rs rename to coins/monero/wallet/src/seed/classic/zh.rs diff --git a/coins/monero/src/wallet/seed/mod.rs b/coins/monero/wallet/src/seed/mod.rs similarity index 100% rename from coins/monero/src/wallet/seed/mod.rs rename to coins/monero/wallet/src/seed/mod.rs diff --git a/coins/monero/src/wallet/seed/polyseed.rs b/coins/monero/wallet/src/seed/polyseed.rs similarity index 100% rename from coins/monero/src/wallet/seed/polyseed.rs rename to coins/monero/wallet/src/seed/polyseed.rs diff --git a/coins/monero/src/wallet/seed/polyseed/cs.json b/coins/monero/wallet/src/seed/polyseed/cs.json similarity index 100% rename from coins/monero/src/wallet/seed/polyseed/cs.json rename to coins/monero/wallet/src/seed/polyseed/cs.json diff --git a/coins/monero/src/wallet/seed/polyseed/en.json b/coins/monero/wallet/src/seed/polyseed/en.json similarity index 100% rename from coins/monero/src/wallet/seed/polyseed/en.json rename to coins/monero/wallet/src/seed/polyseed/en.json diff --git a/coins/monero/src/wallet/seed/polyseed/es.json b/coins/monero/wallet/src/seed/polyseed/es.json similarity index 100% rename from coins/monero/src/wallet/seed/polyseed/es.json rename to coins/monero/wallet/src/seed/polyseed/es.json diff --git a/coins/monero/src/wallet/seed/polyseed/fr.json b/coins/monero/wallet/src/seed/polyseed/fr.json similarity index 100% rename from coins/monero/src/wallet/seed/polyseed/fr.json rename to coins/monero/wallet/src/seed/polyseed/fr.json diff --git a/coins/monero/src/wallet/seed/polyseed/it.json b/coins/monero/wallet/src/seed/polyseed/it.json similarity index 100% rename from coins/monero/src/wallet/seed/polyseed/it.json rename to coins/monero/wallet/src/seed/polyseed/it.json diff --git a/coins/monero/src/wallet/seed/polyseed/ja.json b/coins/monero/wallet/src/seed/polyseed/ja.json similarity index 100% rename from coins/monero/src/wallet/seed/polyseed/ja.json rename to coins/monero/wallet/src/seed/polyseed/ja.json diff --git a/coins/monero/src/wallet/seed/polyseed/ko.json b/coins/monero/wallet/src/seed/polyseed/ko.json similarity index 100% rename from coins/monero/src/wallet/seed/polyseed/ko.json rename to coins/monero/wallet/src/seed/polyseed/ko.json diff --git a/coins/monero/src/wallet/seed/polyseed/pt.json b/coins/monero/wallet/src/seed/polyseed/pt.json similarity index 100% rename from coins/monero/src/wallet/seed/polyseed/pt.json rename to coins/monero/wallet/src/seed/polyseed/pt.json diff --git a/coins/monero/src/wallet/seed/polyseed/zh_simplified.json b/coins/monero/wallet/src/seed/polyseed/zh_simplified.json similarity index 100% rename from coins/monero/src/wallet/seed/polyseed/zh_simplified.json rename to coins/monero/wallet/src/seed/polyseed/zh_simplified.json diff --git a/coins/monero/src/wallet/seed/polyseed/zh_traditional.json b/coins/monero/wallet/src/seed/polyseed/zh_traditional.json similarity index 100% rename from coins/monero/src/wallet/seed/polyseed/zh_traditional.json rename to coins/monero/wallet/src/seed/polyseed/zh_traditional.json diff --git a/coins/monero/src/wallet/send/builder.rs b/coins/monero/wallet/src/send/builder.rs similarity index 95% rename from coins/monero/src/wallet/send/builder.rs rename to coins/monero/wallet/src/send/builder.rs index 55d0fc29..d4016a05 100644 --- a/coins/monero/src/wallet/send/builder.rs +++ b/coins/monero/wallet/src/send/builder.rs @@ -2,12 +2,10 @@ use std::sync::{Arc, RwLock}; use zeroize::{Zeroize, ZeroizeOnDrop, Zeroizing}; +use monero_serai::Protocol; use crate::{ - Protocol, - wallet::{ - address::MoneroAddress, Fee, SpendableOutput, Change, Decoys, SignableTransaction, - TransactionError, extra::MAX_ARBITRARY_DATA_SIZE, - }, + address::MoneroAddress, Fee, SpendableOutput, Change, Decoys, SignableTransaction, + TransactionError, extra::MAX_ARBITRARY_DATA_SIZE, }; #[derive(Clone, PartialEq, Eq, Debug, Zeroize, ZeroizeOnDrop)] diff --git a/coins/monero/src/wallet/send/mod.rs b/coins/monero/wallet/src/send/mod.rs similarity index 94% rename from coins/monero/src/wallet/send/mod.rs rename to coins/monero/wallet/src/send/mod.rs index ccf8606b..67709456 100644 --- a/coins/monero/src/wallet/send/mod.rs +++ b/coins/monero/wallet/src/send/mod.rs @@ -17,14 +17,13 @@ use curve25519_dalek::{ scalar::Scalar, edwards::EdwardsPoint, }; -use dalek_ff_group as dfg; #[cfg(feature = "multisig")] use frost::FrostError; -use monero_io::varint_len; - -use crate::{ +use monero_rpc::RpcError; +pub use monero_rpc::{Fee, FeePriority}; +use monero_serai::{ io::*, primitives::{Commitment, keccak256}, Protocol, @@ -35,13 +34,12 @@ use crate::{ RctBase, RctPrunable, RctSignatures, }, transaction::{Input, Output, Timelock, TransactionPrefix, Transaction}, - rpc::RpcError, - wallet::{ - address::{Network, AddressSpec, MoneroAddress}, - ViewPair, SpendableOutput, Decoys, PaymentId, ExtraField, Extra, key_image_sort, uniqueness, - shared_key, commitment_mask, compact_amount_encryption, - extra::{ARBITRARY_DATA_MARKER, MAX_ARBITRARY_DATA_SIZE}, - }, +}; +use crate::{ + address::{Network, AddressSpec, MoneroAddress}, + ViewPair, SpendableOutput, Decoys, PaymentId, ExtraField, Extra, key_image_sort, uniqueness, + shared_key, commitment_mask, compact_amount_encryption, + extra::{ARBITRARY_DATA_MARKER, MAX_ARBITRARY_DATA_SIZE}, }; #[cfg(feature = "std")] @@ -53,7 +51,7 @@ pub use builder::SignableTransactionBuilder; mod multisig; #[cfg(feature = "multisig")] pub use multisig::TransactionMachine; -use crate::ringct::EncryptedAmount; +use monero_serai::ringct::EncryptedAmount; #[allow(non_snake_case)] #[derive(Clone, PartialEq, Eq, Debug, Zeroize, ZeroizeOnDrop)] @@ -264,51 +262,6 @@ fn calculate_weight_and_fee( (weight, fee) } -/// Fee struct, defined as a per-unit cost and a mask for rounding purposes. -#[derive(Clone, Copy, PartialEq, Eq, Debug, Zeroize)] -pub struct Fee { - pub per_weight: u64, - pub mask: u64, -} - -impl Fee { - pub fn calculate_fee_from_weight(&self, weight: usize) -> u64 { - let fee = (((self.per_weight * u64::try_from(weight).unwrap()) + self.mask - 1) / self.mask) * - self.mask; - debug_assert_eq!(weight, self.calculate_weight_from_fee(fee), "Miscalculated weight from fee"); - fee - } - - pub fn calculate_weight_from_fee(&self, fee: u64) -> usize { - usize::try_from(fee / self.per_weight).unwrap() - } -} - -/// Fee priority, determining how quickly a transaction is included in a block. -#[derive(Clone, Copy, PartialEq, Eq, Debug)] -#[allow(non_camel_case_types)] -pub enum FeePriority { - Unimportant, - Normal, - Elevated, - Priority, - Custom { priority: u32 }, -} - -/// https://github.com/monero-project/monero/blob/ac02af92867590ca80b2779a7bbeafa99ff94dcb/ -/// src/simplewallet/simplewallet.cpp#L161 -impl FeePriority { - pub(crate) fn fee_priority(&self) -> u32 { - match self { - FeePriority::Unimportant => 1, - FeePriority::Normal => 2, - FeePriority::Elevated => 3, - FeePriority::Priority => 4, - FeePriority::Custom { priority, .. } => *priority, - } - } -} - #[derive(Clone, PartialEq, Eq, Debug, Zeroize)] pub(crate) enum InternalPayment { Payment((MoneroAddress, u64), bool), @@ -694,7 +647,7 @@ impl SignableTransaction { } else { // If this used tx_key, randomize its R // This is so when extra is created, there's a distinct R for it to use - output.R = dfg::EdwardsPoint::random(&mut rng).0; + output.R = EdwardsPoint::random(&mut rng); } (output, payment_id) } diff --git a/coins/monero/src/wallet/send/multisig.rs b/coins/monero/wallet/src/send/multisig.rs similarity index 99% rename from coins/monero/src/wallet/send/multisig.rs rename to coins/monero/wallet/src/send/multisig.rs index 596e5bb1..3cc8e9bb 100644 --- a/coins/monero/src/wallet/send/multisig.rs +++ b/coins/monero/wallet/src/send/multisig.rs @@ -24,14 +24,14 @@ use frost::{ }, }; -use crate::{ +use monero_serai::{ ringct::{ clsag::{ClsagContext, ClsagMultisigMaskSender, ClsagAddendum, ClsagMultisig}, RctPrunable, }, transaction::{Input, Transaction}, - wallet::{TransactionError, InternalPayment, SignableTransaction, key_image_sort, uniqueness}, }; +use crate::{TransactionError, InternalPayment, SignableTransaction, key_image_sort, uniqueness}; /// FROST signing machine to produce a signed transaction. pub struct TransactionMachine { diff --git a/coins/monero/src/tests/address.rs b/coins/monero/wallet/src/tests/address.rs similarity index 98% rename from coins/monero/src/tests/address.rs rename to coins/monero/wallet/src/tests/address.rs index 3e8ddfc1..06e7f4e9 100644 --- a/coins/monero/src/tests/address.rs +++ b/coins/monero/wallet/src/tests/address.rs @@ -4,9 +4,9 @@ use rand_core::{RngCore, OsRng}; use curve25519_dalek::{constants::ED25519_BASEPOINT_TABLE, scalar::Scalar}; -use monero_io::decompress_point; +use monero_serai::io::decompress_point; -use crate::wallet::address::{Network, AddressType, AddressMeta, MoneroAddress}; +use crate::address::{Network, AddressType, AddressMeta, MoneroAddress}; const SPEND: [u8; 32] = hex!("f8631661f6ab4e6fda310c797330d86e23a682f20d5bc8cc27b18051191f16d7"); const VIEW: [u8; 32] = hex!("4a1535063ad1fee2dabbf909d4fd9a873e29541b401f0944754e17c9a41820ce"); diff --git a/coins/monero/src/tests/extra.rs b/coins/monero/wallet/src/tests/extra.rs similarity index 97% rename from coins/monero/src/tests/extra.rs rename to coins/monero/wallet/src/tests/extra.rs index b727fe9d..650940f7 100644 --- a/coins/monero/src/tests/extra.rs +++ b/coins/monero/wallet/src/tests/extra.rs @@ -1,10 +1,8 @@ -use crate::{ - wallet::{ExtraField, Extra, extra::MAX_TX_EXTRA_PADDING_COUNT}, - serialize::write_varint, -}; - use curve25519_dalek::edwards::{EdwardsPoint, CompressedEdwardsY}; +use monero_serai::io::write_varint; +use crate::{ExtraField, Extra, extra::MAX_TX_EXTRA_PADDING_COUNT}; + // Borrowed tests from // https://github.com/monero-project/monero/blob/ac02af92867590ca80b2779a7bbeafa99ff94dcb/ // tests/unit_tests/test_tx_utils.cpp diff --git a/coins/monero/src/tests/mod.rs b/coins/monero/wallet/src/tests/mod.rs similarity index 100% rename from coins/monero/src/tests/mod.rs rename to coins/monero/wallet/src/tests/mod.rs diff --git a/coins/monero/src/tests/seed.rs b/coins/monero/wallet/src/tests/seed.rs similarity index 99% rename from coins/monero/src/tests/seed.rs rename to coins/monero/wallet/src/tests/seed.rs index d62beac5..9b744ffe 100644 --- a/coins/monero/src/tests/seed.rs +++ b/coins/monero/wallet/src/tests/seed.rs @@ -4,9 +4,9 @@ use rand_core::OsRng; use curve25519_dalek::scalar::Scalar; -use monero_primitives::keccak256; +use monero_serai::primitives::keccak256; -use crate::wallet::seed::{ +use crate::seed::{ Seed, SeedType, SeedError, classic::{self, trim_by_lang}, polyseed, diff --git a/coins/monero/src/tests/vectors/featured_addresses.json b/coins/monero/wallet/src/tests/vectors/featured_addresses.json similarity index 100% rename from coins/monero/src/tests/vectors/featured_addresses.json rename to coins/monero/wallet/src/tests/vectors/featured_addresses.json diff --git a/coins/monero/tests/add_data.rs b/coins/monero/wallet/tests/add_data.rs similarity index 95% rename from coins/monero/tests/add_data.rs rename to coins/monero/wallet/tests/add_data.rs index ab45177b..f1f42f86 100644 --- a/coins/monero/tests/add_data.rs +++ b/coins/monero/wallet/tests/add_data.rs @@ -1,7 +1,5 @@ -use monero_serai::{ - transaction::Transaction, - wallet::{TransactionError, extra::MAX_ARBITRARY_DATA_SIZE}, -}; +use monero_serai::transaction::Transaction; +use monero_wallet::{TransactionError, extra::MAX_ARBITRARY_DATA_SIZE}; mod runner; diff --git a/coins/monero/tests/decoys.rs b/coins/monero/wallet/tests/decoys.rs similarity index 97% rename from coins/monero/tests/decoys.rs rename to coins/monero/wallet/tests/decoys.rs index 1967afde..cb53a06b 100644 --- a/coins/monero/tests/decoys.rs +++ b/coins/monero/wallet/tests/decoys.rs @@ -1,9 +1,6 @@ -use monero_serai::{ - transaction::Transaction, - wallet::SpendableOutput, - rpc::{Rpc, OutputResponse}, - Protocol, DEFAULT_LOCK_WINDOW, -}; +use monero_rpc::{Rpc, OutputResponse}; +use monero_serai::{transaction::Transaction, Protocol, DEFAULT_LOCK_WINDOW}; +use monero_wallet::SpendableOutput; mod runner; diff --git a/coins/monero/tests/eventuality.rs b/coins/monero/wallet/tests/eventuality.rs similarity index 94% rename from coins/monero/tests/eventuality.rs rename to coins/monero/wallet/tests/eventuality.rs index dfbc6f0d..20cb5cbb 100644 --- a/coins/monero/tests/eventuality.rs +++ b/coins/monero/wallet/tests/eventuality.rs @@ -1,11 +1,9 @@ use curve25519_dalek::constants::ED25519_BASEPOINT_POINT; -use monero_serai::{ - transaction::Transaction, - wallet::{ - Eventuality, - address::{AddressType, AddressMeta, MoneroAddress}, - }, +use monero_serai::transaction::Transaction; +use monero_wallet::{ + Eventuality, + address::{AddressType, AddressMeta, MoneroAddress}, }; mod runner; diff --git a/coins/monero/tests/runner.rs b/coins/monero/wallet/tests/runner.rs similarity index 92% rename from coins/monero/tests/runner.rs rename to coins/monero/wallet/tests/runner.rs index fe77f552..12799384 100644 --- a/coins/monero/tests/runner.rs +++ b/coins/monero/wallet/tests/runner.rs @@ -8,15 +8,13 @@ use curve25519_dalek::{constants::ED25519_BASEPOINT_TABLE, scalar::Scalar}; use tokio::sync::Mutex; -use monero_serai::{ - rpc::{HttpRpc, Rpc}, - wallet::{ - ViewPair, Scanner, - address::{Network, AddressType, AddressSpec, AddressMeta, MoneroAddress}, - SpendableOutput, Fee, - }, - transaction::Transaction, - DEFAULT_LOCK_WINDOW, +use monero_rpc::Rpc; +use monero_simple_request_rpc::SimpleRequestRpc; +use monero_serai::{transaction::Transaction, DEFAULT_LOCK_WINDOW}; +use monero_wallet::{ + ViewPair, Scanner, + address::{Network, AddressType, AddressSpec, AddressMeta, MoneroAddress}, + SpendableOutput, Fee, }; pub fn random_address() -> (Scalar, ViewPair, MoneroAddress) { @@ -36,7 +34,7 @@ pub fn random_address() -> (Scalar, ViewPair, MoneroAddress) { // TODO: Support transactions already on-chain // TODO: Don't have a side effect of mining blocks more blocks than needed under race conditions -pub async fn mine_until_unlocked(rpc: &Rpc, addr: &str, tx_hash: [u8; 32]) { +pub async fn mine_until_unlocked(rpc: &Rpc, addr: &str, tx_hash: [u8; 32]) { // mine until tx is in a block let mut height = rpc.get_height().await.unwrap(); let mut found = false; @@ -66,7 +64,7 @@ pub async fn mine_until_unlocked(rpc: &Rpc, addr: &str, tx_hash: [u8; 3 // Mines 60 blocks and returns an unlocked miner TX output. #[allow(dead_code)] -pub async fn get_miner_tx_output(rpc: &Rpc, view: &ViewPair) -> SpendableOutput { +pub async fn get_miner_tx_output(rpc: &Rpc, view: &ViewPair) -> SpendableOutput { let mut scanner = Scanner::from_view(view.clone(), Some(HashSet::new())); // Mine 60 blocks to unlock a miner TX @@ -92,8 +90,9 @@ pub fn check_weight_and_fee(tx: &Transaction, fee_rate: Fee) { assert_eq!(fee, expected_fee); } -pub async fn rpc() -> Rpc { - let rpc = HttpRpc::new("http://serai:seraidex@127.0.0.1:18081".to_string()).await.unwrap(); +pub async fn rpc() -> Rpc { + let rpc = + SimpleRequestRpc::new("http://serai:seraidex@127.0.0.1:18081".to_string()).await.unwrap(); // Only run once if rpc.get_height().await.unwrap() != 1 { @@ -171,12 +170,10 @@ macro_rules! test { tests::{THRESHOLD, key_gen}, }; - use monero_serai::{ - wallet::{ - address::{Network, AddressSpec}, - ViewPair, Scanner, Change, DecoySelection, Decoys, FeePriority, - SignableTransaction, SignableTransactionBuilder, - }, + use monero_wallet::{ + address::{Network, AddressSpec}, + ViewPair, Scanner, Change, DecoySelection, Decoys, FeePriority, + SignableTransaction, SignableTransactionBuilder, }; use runner::{ diff --git a/coins/monero/tests/scan.rs b/coins/monero/wallet/tests/scan.rs similarity index 98% rename from coins/monero/tests/scan.rs rename to coins/monero/wallet/tests/scan.rs index 3e9c9069..51cc4d94 100644 --- a/coins/monero/tests/scan.rs +++ b/coins/monero/wallet/tests/scan.rs @@ -1,9 +1,7 @@ -use rand::RngCore; +use rand_core::RngCore; -use monero_serai::{ - transaction::Transaction, - wallet::{address::SubaddressIndex, extra::PaymentId}, -}; +use monero_serai::transaction::Transaction; +use monero_wallet::{address::SubaddressIndex, extra::PaymentId}; mod runner; diff --git a/coins/monero/tests/send.rs b/coins/monero/wallet/tests/send.rs similarity index 96% rename from coins/monero/tests/send.rs rename to coins/monero/wallet/tests/send.rs index 636912c0..94aa8131 100644 --- a/coins/monero/tests/send.rs +++ b/coins/monero/wallet/tests/send.rs @@ -1,13 +1,11 @@ use rand_core::OsRng; -use monero_serai::{ - transaction::Transaction, - wallet::{ - extra::Extra, address::SubaddressIndex, ReceivedOutput, SpendableOutput, DecoySelection, - Decoys, SignableTransactionBuilder, - }, - rpc::{Rpc, HttpRpc}, - Protocol, +use monero_serai::{transaction::Transaction, Protocol}; +use monero_rpc::Rpc; +use monero_simple_request_rpc::SimpleRequestRpc; +use monero_wallet::{ + extra::Extra, address::SubaddressIndex, ReceivedOutput, SpendableOutput, DecoySelection, Decoys, + SignableTransactionBuilder, }; mod runner; @@ -15,7 +13,7 @@ mod runner; // Set up inputs, select decoys, then add them to the TX builder async fn add_inputs( protocol: Protocol, - rpc: &Rpc, + rpc: &Rpc, outputs: Vec, builder: &mut SignableTransactionBuilder, ) { @@ -101,7 +99,7 @@ test!( ), ( |protocol, rpc: Rpc<_>, _, _, outputs: Vec| async move { - use monero_serai::wallet::FeePriority; + use monero_wallet::FeePriority; let change_view = ViewPair::new( &Scalar::random(&mut OsRng) * ED25519_BASEPOINT_TABLE, @@ -290,7 +288,7 @@ test!( ), ( |protocol, rpc: Rpc<_>, _, addr, outputs: Vec| async move { - use monero_serai::wallet::FeePriority; + use monero_wallet::FeePriority; let mut builder = SignableTransactionBuilder::new( protocol, diff --git a/coins/monero/tests/wallet2_compatibility.rs b/coins/monero/wallet/tests/wallet2_compatibility.rs similarity index 91% rename from coins/monero/tests/wallet2_compatibility.rs rename to coins/monero/wallet/tests/wallet2_compatibility.rs index c6b58978..fa162510 100644 --- a/coins/monero/tests/wallet2_compatibility.rs +++ b/coins/monero/wallet/tests/wallet2_compatibility.rs @@ -5,19 +5,18 @@ use rand_core::{OsRng, RngCore}; use serde::Deserialize; use serde_json::json; -use monero_serai::{ - transaction::Transaction, - rpc::{EmptyResponse, HttpRpc, Rpc}, - wallet::{ - address::{Network, AddressSpec, SubaddressIndex, MoneroAddress}, - extra::{MAX_TX_EXTRA_NONCE_SIZE, Extra, PaymentId}, - Scanner, - }, +use monero_serai::transaction::Transaction; +use monero_rpc::{EmptyResponse, Rpc}; +use monero_simple_request_rpc::SimpleRequestRpc; +use monero_wallet::{ + address::{Network, AddressSpec, SubaddressIndex, MoneroAddress}, + extra::{MAX_TX_EXTRA_NONCE_SIZE, Extra, PaymentId}, + Scanner, }; mod runner; -async fn make_integrated_address(rpc: &Rpc, payment_id: [u8; 8]) -> String { +async fn make_integrated_address(rpc: &Rpc, payment_id: [u8; 8]) -> String { #[derive(Debug, Deserialize)] struct IntegratedAddressResponse { integrated_address: String, @@ -34,8 +33,8 @@ async fn make_integrated_address(rpc: &Rpc, payment_id: [u8; 8]) -> Str res.integrated_address } -async fn initialize_rpcs() -> (Rpc, Rpc, String) { - let wallet_rpc = HttpRpc::new("http://127.0.0.1:18082".to_string()).await.unwrap(); +async fn initialize_rpcs() -> (Rpc, Rpc, String) { + let wallet_rpc = SimpleRequestRpc::new("http://127.0.0.1:18082".to_string()).await.unwrap(); let daemon_rpc = runner::rpc().await; #[derive(Debug, Deserialize)] @@ -174,7 +173,7 @@ test!( .add_payment(MoneroAddress::from_str(Network::Mainnet, &wallet_rpc_addr).unwrap(), 1000000); (builder.build().unwrap(), wallet_rpc) }, - |_, tx: Transaction, _, data: Rpc| async move { + |_, tx: Transaction, _, data: Rpc| async move { // confirm receipt let _: EmptyResponse = data.json_rpc_call("refresh", None).await.unwrap(); let transfer: TransfersResponse = data @@ -208,7 +207,7 @@ test!( .add_payment(MoneroAddress::from_str(Network::Mainnet, &addr.address).unwrap(), 1000000); (builder.build().unwrap(), (wallet_rpc, addr.account_index)) }, - |_, tx: Transaction, _, data: (Rpc, u32)| async move { + |_, tx: Transaction, _, data: (Rpc, u32)| async move { // confirm receipt let _: EmptyResponse = data.0.json_rpc_call("refresh", None).await.unwrap(); let transfer: TransfersResponse = data @@ -260,7 +259,7 @@ test!( ]); (builder.build().unwrap(), (wallet_rpc, daemon_rpc, addrs.address_index)) }, - |_, tx: Transaction, _, data: (Rpc, Rpc, u32)| async move { + |_, tx: Transaction, _, data: (Rpc, Rpc, u32)| async move { // confirm receipt let _: EmptyResponse = data.0.json_rpc_call("refresh", None).await.unwrap(); let transfer: TransfersResponse = data @@ -305,7 +304,7 @@ test!( builder.add_payment(MoneroAddress::from_str(Network::Mainnet, &addr).unwrap(), 1000000); (builder.build().unwrap(), (wallet_rpc, payment_id)) }, - |_, tx: Transaction, _, data: (Rpc, [u8; 8])| async move { + |_, tx: Transaction, _, data: (Rpc, [u8; 8])| async move { // confirm receipt let _: EmptyResponse = data.0.json_rpc_call("refresh", None).await.unwrap(); let transfer: TransfersResponse = data @@ -340,7 +339,7 @@ test!( (builder.build().unwrap(), wallet_rpc) }, - |_, tx: Transaction, _, data: Rpc| async move { + |_, tx: Transaction, _, data: Rpc| async move { // confirm receipt let _: EmptyResponse = data.json_rpc_call("refresh", None).await.unwrap(); let transfer: TransfersResponse = data diff --git a/processor/Cargo.toml b/processor/Cargo.toml index cc010848..ba79402a 100644 --- a/processor/Cargo.toml +++ b/processor/Cargo.toml @@ -53,7 +53,8 @@ ethereum-serai = { path = "../coins/ethereum", default-features = false, optiona # Monero dalek-ff-group = { path = "../crypto/dalek-ff-group", default-features = false, features = ["std"], optional = true } -monero-serai = { path = "../coins/monero", default-features = false, features = ["std", "http-rpc", "multisig"], optional = true } +monero-simple-request-rpc = { path = "../coins/monero/rpc/simple-request", default-features = false, optional = true } +monero-wallet = { path = "../coins/monero/wallet", default-features = false, features = ["std", "multisig"], optional = true } # Application log = { version = "0.4", default-features = false, features = ["std"] } @@ -87,7 +88,7 @@ bitcoin = ["dep:secp256k1", "secp256k1", "bitcoin-serai", "serai-client/bitcoin" ethereum = ["secp256k1", "ethereum-serai/tests"] ed25519 = ["dalek-ff-group", "frost/ed25519"] -monero = ["ed25519", "monero-serai", "serai-client/monero"] +monero = ["ed25519", "monero-simple-request-rpc", "monero-wallet", "serai-client/monero"] binaries = ["env_logger", "serai-env", "message-queue"] parity-db = ["serai-db/parity-db"] diff --git a/processor/src/networks/monero.rs b/processor/src/networks/monero.rs index 2369000c..dd792035 100644 --- a/processor/src/networks/monero.rs +++ b/processor/src/networks/monero.rs @@ -13,18 +13,14 @@ use ciphersuite::group::{ff::Field, Group}; use dalek_ff_group::{Scalar, EdwardsPoint}; use frost::{curve::Ed25519, ThresholdKeys}; -use monero_serai::{ - Protocol, - ringct::RctType, - transaction::Transaction, - block::Block, - rpc::{RpcError, HttpRpc, Rpc}, - wallet::{ - ViewPair, Scanner, - address::{Network as MoneroNetwork, SubaddressIndex, AddressSpec}, - Fee, SpendableOutput, Change, DecoySelection, Decoys, TransactionError, - SignableTransaction as MSignableTransaction, Eventuality, TransactionMachine, - }, +use monero_simple_request_rpc::SimpleRequestRpc; +use monero_wallet::{ + monero::{Protocol, ringct::RctType, transaction::Transaction, block::Block}, + rpc::{RpcError, Rpc}, + ViewPair, Scanner, + address::{Network as MoneroNetwork, SubaddressIndex, AddressSpec}, + Fee, SpendableOutput, Change, DecoySelection, Decoys, TransactionError, + SignableTransaction as MSignableTransaction, Eventuality, TransactionMachine, }; use tokio::time::sleep; @@ -226,7 +222,7 @@ impl BlockTrait for Block { #[derive(Clone, Debug)] pub struct Monero { - rpc: Rpc, + rpc: Rpc, } // Shim required for testing/debugging purposes due to generic arguments also necessitating trait // bounds @@ -249,11 +245,11 @@ fn map_rpc_err(err: RpcError) -> NetworkError { impl Monero { pub async fn new(url: String) -> Monero { - let mut res = HttpRpc::new(url.clone()).await; + let mut res = SimpleRequestRpc::new(url.clone()).await; while let Err(e) = res { log::error!("couldn't connect to Monero node: {e:?}"); tokio::time::sleep(Duration::from_secs(5)).await; - res = HttpRpc::new(url.clone()).await; + res = SimpleRequestRpc::new(url.clone()).await; } Monero { rpc: res.unwrap() } } @@ -760,7 +756,7 @@ impl Network for Monero { async fn test_send(&self, address: Address) -> Block { use zeroize::Zeroizing; use rand_core::OsRng; - use monero_serai::wallet::FeePriority; + use monero_wallet::FeePriority; let new_block = self.get_latest_block_number().await.unwrap() + 1; for _ in 0 .. 80 { diff --git a/substrate/client/Cargo.toml b/substrate/client/Cargo.toml index 0eeb3a2f..c69bf5f5 100644 --- a/substrate/client/Cargo.toml +++ b/substrate/client/Cargo.toml @@ -39,7 +39,7 @@ simple-request = { path = "../../common/request", version = "0.1", optional = tr bitcoin = { version = "0.32", optional = true } ciphersuite = { path = "../../crypto/ciphersuite", version = "0.4", optional = true } -monero-serai = { path = "../../coins/monero", version = "0.1.4-alpha", optional = true } +monero-wallet = { path = "../../coins/monero/wallet", version = "0.1.0", default-features = false, features = ["std"], optional = true } [dev-dependencies] rand_core = "0.6" @@ -62,7 +62,7 @@ borsh = ["serai-abi/borsh"] networks = [] bitcoin = ["networks", "dep:bitcoin"] -monero = ["networks", "ciphersuite/ed25519", "monero-serai"] +monero = ["networks", "ciphersuite/ed25519", "monero-wallet"] # Assumes the default usage is to use Serai as a DEX, which doesn't actually # require connecting to a Serai node diff --git a/substrate/client/src/networks/monero.rs b/substrate/client/src/networks/monero.rs index 5b43860e..7585f5ef 100644 --- a/substrate/client/src/networks/monero.rs +++ b/substrate/client/src/networks/monero.rs @@ -4,7 +4,7 @@ use scale::{Encode, Decode}; use ciphersuite::{Ciphersuite, Ed25519}; -use monero_serai::wallet::address::{AddressError, Network, AddressType, AddressMeta, MoneroAddress}; +use monero_wallet::address::{AddressError, Network, AddressType, AddressMeta, MoneroAddress}; #[derive(Clone, PartialEq, Eq, Debug)] pub struct Address(MoneroAddress); diff --git a/tests/full-stack/Cargo.toml b/tests/full-stack/Cargo.toml index 58e6de28..6a487a34 100644 --- a/tests/full-stack/Cargo.toml +++ b/tests/full-stack/Cargo.toml @@ -27,7 +27,8 @@ rand_core = { version = "0.6", default-features = false } curve25519-dalek = { version = "4", features = ["rand_core"] } bitcoin-serai = { path = "../../coins/bitcoin" } -monero-serai = { path = "../../coins/monero" } +monero-simple-request-rpc = { path = "../../coins/monero/rpc/simple-request" } +monero-wallet = { path = "../../coins/monero/wallet" } scale = { package = "parity-scale-codec", version = "3" } serde = "1" diff --git a/tests/full-stack/src/lib.rs b/tests/full-stack/src/lib.rs index 5e39c70d..e4241b92 100644 --- a/tests/full-stack/src/lib.rs +++ b/tests/full-stack/src/lib.rs @@ -53,8 +53,8 @@ impl Handles { pub async fn monero( &self, ops: &DockerOperations, - ) -> monero_serai::rpc::Rpc { - use monero_serai::rpc::HttpRpc; + ) -> monero_wallet::rpc::Rpc { + use monero_simple_request_rpc::SimpleRequestRpc; let rpc = ops.handle(&self.monero.0).host_port(self.monero.1).unwrap(); let rpc = format!("http://{RPC_USER}:{RPC_PASS}@{}:{}", rpc.0, rpc.1); @@ -62,7 +62,7 @@ impl Handles { // If the RPC server has yet to start, sleep for up to 60s until it does for _ in 0 .. 60 { tokio::time::sleep(Duration::from_secs(1)).await; - let Ok(client) = HttpRpc::new(rpc.clone()).await else { continue }; + let Ok(client) = SimpleRequestRpc::new(rpc.clone()).await else { continue }; if client.get_height().await.is_err() { continue; } diff --git a/tests/full-stack/src/tests/mint_and_burn.rs b/tests/full-stack/src/tests/mint_and_burn.rs index c587b699..ebcc0883 100644 --- a/tests/full-stack/src/tests/mint_and_burn.rs +++ b/tests/full-stack/src/tests/mint_and_burn.rs @@ -88,7 +88,7 @@ async fn mint_and_burn_test() { // Mine a Monero block let monero_blocks = { use curve25519_dalek::{constants::ED25519_BASEPOINT_POINT, scalar::Scalar}; - use monero_serai::wallet::{ + use monero_wallet::{ ViewPair, address::{Network, AddressSpec}, }; @@ -345,14 +345,10 @@ async fn mint_and_burn_test() { // Send in XMR { use curve25519_dalek::{constants::ED25519_BASEPOINT_POINT, scalar::Scalar}; - use monero_serai::{ - Protocol, - transaction::Timelock, - wallet::{ - ViewPair, Scanner, DecoySelection, Decoys, Change, FeePriority, SignableTransaction, - address::{Network, AddressType, AddressMeta, MoneroAddress}, - }, - io::decompress_point, + use monero_wallet::{ + monero::{io::decompress_point, Protocol, transaction::Timelock}, + ViewPair, Scanner, DecoySelection, Decoys, Change, FeePriority, SignableTransaction, + address::{Network, AddressType, AddressMeta, MoneroAddress}, }; // Grab the first output on the chain @@ -473,7 +469,7 @@ async fn mint_and_burn_test() { let spend = ED25519_BASEPOINT_TABLE * &Scalar::random(&mut OsRng); let view = Scalar::random(&mut OsRng); - use monero_serai::wallet::address::{Network, AddressType, AddressMeta, MoneroAddress}; + use monero_wallet::address::{Network, AddressType, AddressMeta, MoneroAddress}; let addr = MoneroAddress::new( AddressMeta::new(Network::Mainnet, AddressType::Standard), spend, @@ -578,7 +574,7 @@ async fn mint_and_burn_test() { // Verify the received Monero TX { - use monero_serai::wallet::{ViewPair, Scanner}; + use monero_wallet::{ViewPair, Scanner}; let rpc = handles[0].monero(&ops).await; let mut scanner = Scanner::from_view( ViewPair::new(monero_spend, Zeroizing::new(monero_view)), diff --git a/tests/no-std/Cargo.toml b/tests/no-std/Cargo.toml index 2c325857..65132244 100644 --- a/tests/no-std/Cargo.toml +++ b/tests/no-std/Cargo.toml @@ -42,3 +42,5 @@ monero-mlsag = { path = "../../coins/monero/ringct/mlsag", default-features = fa monero-clsag = { path = "../../coins/monero/ringct/clsag", default-features = false } monero-bulletproofs = { path = "../../coins/monero/ringct/bulletproofs", default-features = false } monero-serai = { path = "../../coins/monero", default-features = false } +monero-rpc = { path = "../../coins/monero/rpc", default-features = false } +monero-wallet = { path = "../../coins/monero/wallet", default-features = false } diff --git a/tests/no-std/src/lib.rs b/tests/no-std/src/lib.rs index a21189ab..b931e899 100644 --- a/tests/no-std/src/lib.rs +++ b/tests/no-std/src/lib.rs @@ -27,3 +27,4 @@ pub use monero_mlsag; pub use monero_clsag; pub use monero_bulletproofs; pub use monero_serai; +pub use monero_rpc; diff --git a/tests/processor/Cargo.toml b/tests/processor/Cargo.toml index e46312c5..a8245fff 100644 --- a/tests/processor/Cargo.toml +++ b/tests/processor/Cargo.toml @@ -31,7 +31,8 @@ bitcoin-serai = { path = "../../coins/bitcoin" } k256 = "0.13" ethereum-serai = { path = "../../coins/ethereum" } -monero-serai = { path = "../../coins/monero" } +monero-simple-request-rpc = { path = "../../coins/monero/rpc/simple-request" } +monero-wallet = { path = "../../coins/monero/wallet" } messages = { package = "serai-processor-messages", path = "../../processor/messages" } diff --git a/tests/processor/src/lib.rs b/tests/processor/src/lib.rs index 8aa6d48d..e7ff6f14 100644 --- a/tests/processor/src/lib.rs +++ b/tests/processor/src/lib.rs @@ -274,11 +274,11 @@ impl Coordinator { } } NetworkId::Monero => { - use monero_serai::rpc::HttpRpc; + use monero_simple_request_rpc::SimpleRequestRpc; // Monero's won't, so call get_height if handle - .block_on(HttpRpc::new(rpc_url.clone())) + .block_on(SimpleRequestRpc::new(rpc_url.clone())) .ok() .and_then(|rpc| handle.block_on(rpc.get_height()).ok()) .is_some() @@ -403,15 +403,13 @@ impl Coordinator { } NetworkId::Monero => { use curve25519_dalek::{constants::ED25519_BASEPOINT_POINT, scalar::Scalar}; - use monero_serai::{ - wallet::{ - ViewPair, - address::{Network, AddressSpec}, - }, - rpc::HttpRpc, + use monero_simple_request_rpc::SimpleRequestRpc; + use monero_wallet::{ + ViewPair, + address::{Network, AddressSpec}, }; - let rpc = HttpRpc::new(rpc_url).await.expect("couldn't connect to the Monero RPC"); + let rpc = SimpleRequestRpc::new(rpc_url).await.expect("couldn't connect to the Monero RPC"); let _: EmptyResponse = rpc .json_rpc_call( "generateblocks", @@ -517,15 +515,18 @@ impl Coordinator { } } NetworkId::Monero => { - use monero_serai::rpc::HttpRpc; + use monero_simple_request_rpc::SimpleRequestRpc; - let rpc = HttpRpc::new(rpc_url).await.expect("couldn't connect to the Monero RPC"); + let rpc = SimpleRequestRpc::new(rpc_url).await.expect("couldn't connect to the Monero RPC"); let to = rpc.get_height().await.unwrap(); for coordinator in others { - let other_rpc = - HttpRpc::new(network_rpc(coordinator.network, ops, &coordinator.network_handle)) - .await - .expect("couldn't connect to the Monero RPC"); + let other_rpc = SimpleRequestRpc::new(network_rpc( + coordinator.network, + ops, + &coordinator.network_handle, + )) + .await + .expect("couldn't connect to the Monero RPC"); let from = other_rpc.get_height().await.unwrap(); for b in from .. to { @@ -574,10 +575,12 @@ impl Coordinator { let _ = provider.send_raw_transaction(tx).await.unwrap(); } NetworkId::Monero => { - use monero_serai::{transaction::Transaction, rpc::HttpRpc}; + use monero_simple_request_rpc::SimpleRequestRpc; + use monero_wallet::monero::transaction::Transaction; - let rpc = - HttpRpc::new(rpc_url).await.expect("couldn't connect to the coordinator's Monero RPC"); + let rpc = SimpleRequestRpc::new(rpc_url) + .await + .expect("couldn't connect to the coordinator's Monero RPC"); rpc.publish_transaction(&Transaction::read(&mut &*tx).unwrap()).await.unwrap(); } NetworkId::Serai => panic!("processor tests broadcasting block to Serai"), @@ -672,10 +675,11 @@ impl Coordinator { None } NetworkId::Monero => { - use monero_serai::rpc::HttpRpc; + use monero_simple_request_rpc::SimpleRequestRpc; - let rpc = - HttpRpc::new(rpc_url).await.expect("couldn't connect to the coordinator's Monero RPC"); + let rpc = SimpleRequestRpc::new(rpc_url) + .await + .expect("couldn't connect to the coordinator's Monero RPC"); let mut hash = [0; 32]; hash.copy_from_slice(tx); if let Ok(tx) = rpc.get_transaction(hash).await { diff --git a/tests/processor/src/networks.rs b/tests/processor/src/networks.rs index f460fce5..c00dea68 100644 --- a/tests/processor/src/networks.rs +++ b/tests/processor/src/networks.rs @@ -103,8 +103,8 @@ pub enum Wallet { Monero { handle: String, spend_key: Zeroizing, - view_pair: monero_serai::wallet::ViewPair, - inputs: Vec, + view_pair: monero_wallet::ViewPair, + inputs: Vec, }, } @@ -189,12 +189,10 @@ impl Wallet { NetworkId::Monero => { use curve25519_dalek::{constants::ED25519_BASEPOINT_POINT, scalar::Scalar}; - use monero_serai::{ - wallet::{ - ViewPair, Scanner, - address::{Network, AddressSpec}, - }, - rpc::HttpRpc, + use monero_simple_request_rpc::SimpleRequestRpc; + use monero_wallet::{ + ViewPair, Scanner, + address::{Network, AddressSpec}, }; let mut bytes = [0; 64]; @@ -206,7 +204,7 @@ impl Wallet { let view_pair = ViewPair::new(ED25519_BASEPOINT_POINT * spend_key, Zeroizing::new(view_key)); - let rpc = HttpRpc::new(rpc_url).await.expect("couldn't connect to the Monero RPC"); + let rpc = SimpleRequestRpc::new(rpc_url).await.expect("couldn't connect to the Monero RPC"); let height = rpc.get_height().await.unwrap(); // Mines 200 blocks so sufficient decoys exist, as only 60 is needed for maturity @@ -436,20 +434,17 @@ impl Wallet { Wallet::Monero { handle, ref spend_key, ref view_pair, ref mut inputs } => { use curve25519_dalek::constants::ED25519_BASEPOINT_POINT; - use monero_serai::{ - Protocol, - wallet::{ - address::{Network, AddressType, AddressMeta, Address}, - SpendableOutput, DecoySelection, Decoys, Change, FeePriority, Scanner, - SignableTransaction, - }, - rpc::HttpRpc, - io::decompress_point, + use monero_simple_request_rpc::SimpleRequestRpc; + use monero_wallet::{ + monero::{Protocol, io::decompress_point}, + address::{Network, AddressType, AddressMeta, Address}, + SpendableOutput, DecoySelection, Decoys, Change, FeePriority, Scanner, + SignableTransaction, }; use processor::{additional_key, networks::Monero}; let rpc_url = network_rpc(NetworkId::Monero, ops, handle); - let rpc = HttpRpc::new(rpc_url).await.expect("couldn't connect to the Monero RPC"); + let rpc = SimpleRequestRpc::new(rpc_url).await.expect("couldn't connect to the Monero RPC"); // Prepare inputs let outputs = std::mem::take(inputs); @@ -532,7 +527,7 @@ impl Wallet { ) .unwrap(), Wallet::Monero { view_pair, .. } => { - use monero_serai::wallet::address::{Network, AddressSpec}; + use monero_wallet::address::{Network, AddressSpec}; ExternalAddress::new( networks::monero::Address::new( view_pair.address(Network::Mainnet, AddressSpec::Standard),