mirror of
https://github.com/serai-dex/serai.git
synced 2025-12-11 21:49:26 +00:00
Smash out RPC, wallet
This commit is contained in:
@@ -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"]
|
||||
|
||||
46
coins/monero/rpc/Cargo.toml
Normal file
46
coins/monero/rpc/Cargo.toml
Normal file
@@ -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 <lukeparker5132@gmail.com>"]
|
||||
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"]
|
||||
21
coins/monero/rpc/LICENSE
Normal file
21
coins/monero/rpc/LICENSE
Normal file
@@ -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.
|
||||
6
coins/monero/rpc/README.md
Normal file
6
coins/monero/rpc/README.md
Normal file
@@ -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.
|
||||
26
coins/monero/rpc/simple-request/Cargo.toml
Normal file
26
coins/monero/rpc/simple-request/Cargo.toml
Normal file
@@ -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 <lukeparker5132@gmail.com>"]
|
||||
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"] }
|
||||
21
coins/monero/rpc/simple-request/LICENSE
Normal file
21
coins/monero/rpc/simple-request/LICENSE
Normal file
@@ -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.
|
||||
3
coins/monero/rpc/simple-request/README.md
Normal file
3
coins/monero/rpc/simple-request/README.md
Normal file
@@ -0,0 +1,3 @@
|
||||
# Monero simple-request RPC
|
||||
|
||||
RPC connection to a Monero daemon via simple-request, built around monero-serai.
|
||||
@@ -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<Option<(WwwAuthenticateHeader, u64)>, 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<Rpc<HttpRpc>, RpcError> {
|
||||
pub async fn new(url: String) -> Result<Rpc<SimpleRequestRpc>, 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<Rpc<HttpRpc>, RpcError> {
|
||||
) -> Result<Rpc<SimpleRequestRpc>, 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<u8>) -> Result<Vec<u8>, 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<u8>) -> Result<Vec<u8>, RpcError> {
|
||||
tokio::time::timeout(self.request_timeout, self.inner_post(route, body))
|
||||
.await
|
||||
@@ -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: RpcConnection>(R);
|
||||
impl<R: RpcConnection> Rpc<R> {
|
||||
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
|
||||
@@ -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<Rpc<HttpRpc>>, block_i: usize) {
|
||||
pub(crate) async fn check_block(rpc: Arc<Rpc<SimpleRequestRpc>>, 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<HttpRpc>,
|
||||
rpc: &Rpc<SimpleRequestRpc>,
|
||||
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() {}
|
||||
|
||||
@@ -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<W: stdio::Write>(&self, w: &mut W) -> stdio::Result<()> {
|
||||
pub fn write<W: stdio::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: stdio::Read>(r: &mut R) -> stdio::Result<Protocol> {
|
||||
pub fn read<R: stdio::Read>(r: &mut R) -> stdio::Result<Protocol> {
|
||||
Ok(match read_byte(r)? {
|
||||
// Monero protocol
|
||||
0 => match read_byte(r)? {
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
88
coins/monero/wallet/Cargo.toml
Normal file
88
coins/monero/wallet/Cargo.toml
Normal file
@@ -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 <lukeparker5132@gmail.com>"]
|
||||
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"]
|
||||
21
coins/monero/wallet/LICENSE
Normal file
21
coins/monero/wallet/LICENSE
Normal file
@@ -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.
|
||||
6
coins/monero/wallet/README.md
Normal file
6
coins/monero/wallet/README.md
Normal file
@@ -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.
|
||||
@@ -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};
|
||||
|
||||
@@ -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<R: RngCore + CryptoRng, RPC: RpcConnection>(
|
||||
Ok(res)
|
||||
}
|
||||
|
||||
pub use monero_primitives::Decoys;
|
||||
pub use monero_serai::primitives::Decoys;
|
||||
|
||||
// TODO: Remove this trait
|
||||
#[cfg(feature = "std")]
|
||||
@@ -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,
|
||||
@@ -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 } => {
|
||||
@@ -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.
|
||||
@@ -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;
|
||||
@@ -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)]
|
||||
@@ -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)
|
||||
}
|
||||
@@ -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 {
|
||||
@@ -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");
|
||||
@@ -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
|
||||
@@ -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,
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
@@ -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<HttpRpc>, addr: &str, tx_hash: [u8; 32]) {
|
||||
pub async fn mine_until_unlocked(rpc: &Rpc<SimpleRequestRpc>, 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<HttpRpc>, 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<HttpRpc>, view: &ViewPair) -> SpendableOutput {
|
||||
pub async fn get_miner_tx_output(rpc: &Rpc<SimpleRequestRpc>, 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<HttpRpc> {
|
||||
let rpc = HttpRpc::new("http://serai:seraidex@127.0.0.1:18081".to_string()).await.unwrap();
|
||||
pub async fn rpc() -> Rpc<SimpleRequestRpc> {
|
||||
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::{
|
||||
@@ -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;
|
||||
|
||||
@@ -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<HttpRpc>,
|
||||
rpc: &Rpc<SimpleRequestRpc>,
|
||||
outputs: Vec<ReceivedOutput>,
|
||||
builder: &mut SignableTransactionBuilder,
|
||||
) {
|
||||
@@ -101,7 +99,7 @@ test!(
|
||||
),
|
||||
(
|
||||
|protocol, rpc: Rpc<_>, _, _, outputs: Vec<ReceivedOutput>| 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<ReceivedOutput>| async move {
|
||||
use monero_serai::wallet::FeePriority;
|
||||
use monero_wallet::FeePriority;
|
||||
|
||||
let mut builder = SignableTransactionBuilder::new(
|
||||
protocol,
|
||||
@@ -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<HttpRpc>, payment_id: [u8; 8]) -> String {
|
||||
async fn make_integrated_address(rpc: &Rpc<SimpleRequestRpc>, payment_id: [u8; 8]) -> String {
|
||||
#[derive(Debug, Deserialize)]
|
||||
struct IntegratedAddressResponse {
|
||||
integrated_address: String,
|
||||
@@ -34,8 +33,8 @@ async fn make_integrated_address(rpc: &Rpc<HttpRpc>, payment_id: [u8; 8]) -> Str
|
||||
res.integrated_address
|
||||
}
|
||||
|
||||
async fn initialize_rpcs() -> (Rpc<HttpRpc>, Rpc<HttpRpc>, String) {
|
||||
let wallet_rpc = HttpRpc::new("http://127.0.0.1:18082".to_string()).await.unwrap();
|
||||
async fn initialize_rpcs() -> (Rpc<SimpleRequestRpc>, Rpc<SimpleRequestRpc>, 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<HttpRpc>| async move {
|
||||
|_, tx: Transaction, _, data: Rpc<SimpleRequestRpc>| 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<HttpRpc>, u32)| async move {
|
||||
|_, tx: Transaction, _, data: (Rpc<SimpleRequestRpc>, 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<HttpRpc>, Rpc<HttpRpc>, u32)| async move {
|
||||
|_, tx: Transaction, _, data: (Rpc<SimpleRequestRpc>, Rpc<SimpleRequestRpc>, 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<HttpRpc>, [u8; 8])| async move {
|
||||
|_, tx: Transaction, _, data: (Rpc<SimpleRequestRpc>, [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<HttpRpc>| async move {
|
||||
|_, tx: Transaction, _, data: Rpc<SimpleRequestRpc>| async move {
|
||||
// confirm receipt
|
||||
let _: EmptyResponse = data.json_rpc_call("refresh", None).await.unwrap();
|
||||
let transfer: TransfersResponse = data
|
||||
Reference in New Issue
Block a user