Correct misc TODOs in monero-serai

This commit is contained in:
Luke Parker
2024-07-05 23:30:02 -04:00
parent 90880cc9c8
commit 1f5e5fc7ac
27 changed files with 266 additions and 111 deletions

View File

@@ -32,6 +32,7 @@ jobs:
-p bitcoin-serai \
-p alloy-simple-request-transport \
-p ethereum-serai \
-p serai-ethereum-relayer \
-p monero-io \
-p monero-generators \
-p monero-primitives \

View File

@@ -37,4 +37,4 @@ jobs:
uses: ./.github/actions/build-dependencies
- name: Run coordinator Docker tests
run: cd tests/coordinator && GITHUB_CI=true RUST_BACKTRACE=1 cargo test --all-features
run: GITHUB_CI=true RUST_BACKTRACE=1 cargo test --all-features -p serai-coordinator-tests

View File

@@ -19,4 +19,4 @@ jobs:
uses: ./.github/actions/build-dependencies
- name: Run Full Stack Docker tests
run: cd tests/full-stack && GITHUB_CI=true RUST_BACKTRACE=1 cargo test --all-features
run: GITHUB_CI=true RUST_BACKTRACE=1 cargo test --all-features -p serai-full-stack-tests

View File

@@ -33,4 +33,4 @@ jobs:
uses: ./.github/actions/build-dependencies
- name: Run message-queue Docker tests
run: cd tests/message-queue && GITHUB_CI=true RUST_BACKTRACE=1 cargo test --all-features
run: GITHUB_CI=true RUST_BACKTRACE=1 cargo test --all-features -p serai-message-queue-tests

View File

@@ -64,6 +64,7 @@ jobs:
- name: Run Integration Tests Without Features
run: |
GITHUB_CI=true RUST_BACKTRACE=1 cargo test --package monero-serai --test '*'
GITHUB_CI=true RUST_BACKTRACE=1 cargo test --package monero-simple-request-rpc --test '*'
GITHUB_CI=true RUST_BACKTRACE=1 cargo test --package monero-wallet --test '*'
GITHUB_CI=true RUST_BACKTRACE=1 cargo test --package monero-wallet-util --test '*'
GITHUB_CI=true RUST_BACKTRACE=1 cargo test --package monero-serai-verify-chain --test '*'
@@ -73,6 +74,7 @@ jobs:
if: ${{ matrix.version != 'v0.18.2.0' }}
run: |
GITHUB_CI=true RUST_BACKTRACE=1 cargo test --package monero-serai --all-features --test '*'
GITHUB_CI=true RUST_BACKTRACE=1 cargo test --package monero-simple-request-rpc --test '*'
GITHUB_CI=true RUST_BACKTRACE=1 cargo test --package monero-wallet --all-features --test '*'
GITHUB_CI=true RUST_BACKTRACE=1 cargo test --package monero-wallet-util --all-features --test '*'
GITHUB_CI=true RUST_BACKTRACE=1 cargo test --package monero-serai-verify-chain --test '*'

View File

@@ -32,4 +32,4 @@ jobs:
run: sudo apt update && sudo apt install -y gcc-riscv64-unknown-elf gcc-multilib && rustup target add riscv32imac-unknown-none-elf
- name: Verify no-std builds
run: cd tests/no-std && CFLAGS=-I/usr/include cargo build --target riscv32imac-unknown-none-elf
run: CFLAGS=-I/usr/include cargo build --target riscv32imac-unknown-none-elf -p serai-no-std-tests

View File

@@ -37,4 +37,4 @@ jobs:
uses: ./.github/actions/build-dependencies
- name: Run processor Docker tests
run: cd tests/processor && GITHUB_CI=true RUST_BACKTRACE=1 cargo test --all-features
run: GITHUB_CI=true RUST_BACKTRACE=1 cargo test --all-features -p serai-processor-tests

View File

@@ -33,4 +33,4 @@ jobs:
uses: ./.github/actions/build-dependencies
- name: Run Reproducible Runtime tests
run: cd tests/reproducible-runtime && GITHUB_CI=true RUST_BACKTRACE=1 cargo test --all-features
run: GITHUB_CI=true RUST_BACKTRACE=1 cargo test --all-features -p serai-reproducible-runtime-tests

2
Cargo.lock generated
View File

@@ -4861,6 +4861,7 @@ dependencies = [
"async-trait",
"curve25519-dalek",
"hex",
"monero-address",
"monero-serai",
"serde",
"serde_json",
@@ -4921,6 +4922,7 @@ dependencies = [
"async-trait",
"digest_auth",
"hex",
"monero-address",
"monero-rpc",
"simple-request",
"tokio",

View File

@@ -74,12 +74,14 @@ members = [
"substrate/coins/primitives",
"substrate/coins/pallet",
"substrate/in-instructions/primitives",
"substrate/in-instructions/pallet",
"substrate/dex/pallet",
"substrate/validator-sets/primitives",
"substrate/validator-sets/pallet",
"substrate/in-instructions/primitives",
"substrate/in-instructions/pallet",
"substrate/signals/primitives",
"substrate/signals/pallet",

View File

@@ -43,10 +43,10 @@ fn generators(prefix: &'static str, path: &str) {
static GENERATORS_CELL: OnceLock<Generators> = OnceLock::new();
pub(crate) fn GENERATORS() -> &'static Generators {{
GENERATORS_CELL.get_or_init(|| Generators {{
G: vec![
G: std_shims::vec![
{G_str}
],
H: vec![
H: std_shims::vec![
{H_str}
],
}})

View File

@@ -1,6 +1,6 @@
#![allow(non_snake_case)]
use std_shims::{sync::OnceLock, vec};
use std_shims::sync::OnceLock;
use curve25519_dalek::{constants::ED25519_BASEPOINT_POINT, scalar::Scalar, edwards::EdwardsPoint};

View File

@@ -113,6 +113,11 @@ struct Interim {
}
/// FROST-inspired algorithm for producing a CLSAG signature.
///
/// Before this has its `process_addendum` called, a mask must be set. Else this will panic.
///
/// The message signed is expected to be a 32-byte value. Per Monero, it's the keccak256 hash of
/// the transaction data which is signed. This will panic if the message is not a 32-byte value.
#[allow(non_snake_case)]
#[derive(Clone, Debug)]
pub struct ClsagMultisig {
@@ -133,8 +138,6 @@ pub struct ClsagMultisig {
impl ClsagMultisig {
/// Construct a new instance of multisignature CLSAG signing.
///
/// Before this has its `process_addendum` called, a mask must be set. Else this will panic.
pub fn new(
transcript: RecommendedTranscript,
context: ClsagContext,
@@ -261,7 +264,6 @@ impl Algorithm<Ed25519> for ClsagMultisig {
// opening of the commitment being re-randomized (and what it's re-randomized to)
let mut rng = ChaCha20Rng::from_seed(self.transcript.rng_seed(b"decoy_responses"));
// TODO: Accept the message preimage and remove this panic
self.msg = Some(msg.try_into().expect("CLSAG message should be 32-bytes"));
let sign_core = Clsag::sign_core(

View File

@@ -29,6 +29,7 @@ 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 }
monero-address = { path = "../wallet/address", default-features = false }
[features]
std = [
@@ -42,5 +43,6 @@ std = [
"serde_json/std",
"monero-serai/std",
"monero-address/std",
]
default = ["std"]

View File

@@ -24,3 +24,8 @@ simple-request = { path = "../../../../common/request", version = "0.1", default
tokio = { version = "1", default-features = false }
monero-rpc = { path = "..", default-features = false, features = ["std"] }
[dev-dependencies]
monero-address = { path = "../../wallet/address", default-features = false, features = ["std"] }
tokio = { version = "1", default-features = false, features = ["macros"] }

View File

@@ -0,0 +1,75 @@
use monero_address::{Network, MoneroAddress};
// monero-rpc doesn't include a transport
// We can't include the simple-request crate there as then we'd have a cyclical dependency
// Accordingly, we test monero-rpc here (implicitly testing the simple-request transport)
use monero_rpc::*;
use monero_simple_request_rpc::*;
const ADDRESS: &str =
"4B33mFPMq6mKi7Eiyd5XuyKRVMGVZz1Rqb9ZTyGApXW5d1aT7UBDZ89ewmnWFkzJ5wPd2SFbn313vCT8a4E2Qf4KQH4pNey";
#[tokio::test]
async fn test_rpc() {
let rpc =
SimpleRequestRpc::new("http://serai:seraidex@127.0.0.1:18081".to_string()).await.unwrap();
{
// Test get_height
let height = rpc.get_height().await.unwrap();
// The height should be the amount of blocks on chain
// The number of a block should be its zero-indexed position
// Accordingly, there should be no block whose number is the height
assert!(rpc.get_block_by_number(height).await.is_err());
let block_number = height - 1;
// There should be a block just prior
let block = rpc.get_block_by_number(block_number).await.unwrap();
// Also test the block RPC routes are consistent
assert_eq!(block.number().unwrap(), block_number);
assert_eq!(rpc.get_block(block.hash()).await.unwrap(), block);
assert_eq!(rpc.get_block_hash(block_number).await.unwrap(), block.hash());
// And finally the hardfork version route
assert_eq!(rpc.get_hardfork_version().await.unwrap(), block.header.hardfork_version);
}
// Test generate_blocks
for amount_of_blocks in [1, 5] {
let (blocks, number) = rpc
.generate_blocks(
&MoneroAddress::from_str(Network::Mainnet, ADDRESS).unwrap(),
amount_of_blocks,
)
.await
.unwrap();
let height = rpc.get_height().await.unwrap();
assert_eq!(number, height - 1);
let mut actual_blocks = Vec::with_capacity(amount_of_blocks);
for i in (height - amount_of_blocks) .. height {
actual_blocks.push(rpc.get_block_by_number(i).await.unwrap().hash());
}
assert_eq!(blocks, actual_blocks);
}
// Test get_output_distribution
// It's documented to take two inclusive block numbers
{
let height = rpc.get_height().await.unwrap();
rpc.get_output_distribution(0 ..= height).await.unwrap_err();
assert_eq!(rpc.get_output_distribution(0 .. height).await.unwrap().len(), height);
assert_eq!(rpc.get_output_distribution(0 .. (height - 1)).await.unwrap().len(), height - 1);
assert_eq!(rpc.get_output_distribution(1 .. height).await.unwrap().len(), height - 1);
assert_eq!(rpc.get_output_distribution(0 ..= 0).await.unwrap().len(), 1);
assert_eq!(rpc.get_output_distribution(0 ..= 1).await.unwrap().len(), 2);
assert_eq!(rpc.get_output_distribution(1 ..= 1).await.unwrap().len(), 1);
rpc.get_output_distribution(0 .. 0).await.unwrap_err();
#[allow(clippy::reversed_empty_ranges)]
rpc.get_output_distribution(1 .. 0).await.unwrap_err();
}
}

View File

@@ -3,7 +3,10 @@
#![deny(missing_docs)]
#![cfg_attr(not(feature = "std"), no_std)]
use core::fmt::Debug;
use core::{
fmt::Debug,
ops::{Bound, RangeBounds},
};
use std_shims::{
alloc::{boxed::Box, format},
vec,
@@ -26,6 +29,7 @@ use monero_serai::{
transaction::{Input, Timelock, Transaction},
block::Block,
};
use monero_address::Address;
// Number of blocks the fee estimate will be valid for
// https://github.com/monero-project/monero/blob/94e67bf96bbc010241f29ada6abc89f49a81759c/
@@ -70,9 +74,9 @@ pub enum RpcError {
#[derive(Clone, Copy, PartialEq, Eq, Debug, Zeroize)]
pub struct FeeRate {
/// The fee per-weight of the transaction.
pub per_weight: u64,
per_weight: u64,
/// The mask to round with.
pub mask: u64,
mask: u64,
}
impl FeeRate {
@@ -108,22 +112,22 @@ impl FeeRate {
/// This is not a Monero protocol defined struct, and this is accordingly not a Monero protocol
/// defined serialization.
pub fn read(r: &mut impl io::Read) -> io::Result<FeeRate> {
Ok(FeeRate { per_weight: read_u64(r)?, mask: read_u64(r)? })
let per_weight = read_u64(r)?;
let mask = read_u64(r)?;
FeeRate::new(per_weight, mask).map_err(io::Error::other)
}
/// Calculate the fee to use from the weight.
///
/// This function may panic if any of the `FeeRate`'s fields are zero.
/// This function may panic upon overflow.
pub fn calculate_fee_from_weight(&self, weight: usize) -> u64 {
let fee = self.per_weight * u64::try_from(weight).unwrap();
let fee = ((fee + self.mask - 1) / self.mask) * self.mask;
let fee = fee.div_ceil(self.mask) * self.mask;
debug_assert_eq!(weight, self.calculate_weight_from_fee(fee), "Miscalculated weight from fee");
fee
}
/// Calculate the weight from the fee.
///
/// This function may panic if any of the `FeeRate`'s fields are zero.
pub fn calculate_weight_from_fee(&self, fee: u64) -> usize {
usize::try_from(fee / self.per_weight).unwrap()
}
@@ -323,7 +327,11 @@ pub trait Rpc: Sync + Clone + Debug {
struct HeightResponse {
height: usize,
}
Ok(self.rpc_call::<Option<()>, HeightResponse>("get_height", None).await?.height)
let res = self.rpc_call::<Option<()>, HeightResponse>("get_height", None).await?.height;
if res == 0 {
Err(RpcError::InvalidNode("node responded with 0 for the height".to_string()))?;
}
Ok(res)
}
/// Get the specified transactions.
@@ -460,7 +468,7 @@ pub trait Rpc: Sync + Clone + Debug {
// Make sure this is actually the block for this number
match block.miner_transaction.prefix().inputs.first() {
Some(Input::Gen(actual)) => {
if usize::try_from(*actual) == Ok(number) {
if *actual == number {
Ok(block)
} else {
Err(RpcError::InvalidNode("different block than requested (number)".to_string()))
@@ -658,8 +666,11 @@ pub trait Rpc: Sync + Clone + Debug {
/// Get the output distribution.
///
/// `from` and `to` are heights, not block numbers, and inclusive.
async fn get_output_distribution(&self, from: usize, to: usize) -> Result<Vec<u64>, RpcError> {
/// `range` is in terms of block numbers.
async fn get_output_distribution(
&self,
range: impl Send + RangeBounds<usize>,
) -> Result<Vec<u64>, RpcError> {
#[derive(Deserialize, Debug)]
struct Distribution {
distribution: Vec<u64>,
@@ -667,10 +678,31 @@ pub trait Rpc: Sync + Clone + Debug {
#[derive(Deserialize, Debug)]
struct Distributions {
distributions: Vec<Distribution>,
distributions: [Distribution; 1],
}
let mut distributions: Distributions = self
let from = match range.start_bound() {
Bound::Included(from) => *from,
Bound::Excluded(from) => from
.checked_add(1)
.ok_or_else(|| RpcError::InternalError("range's from wasn't representable".to_string()))?,
Bound::Unbounded => 0,
};
let to = match range.end_bound() {
Bound::Included(to) => *to,
Bound::Excluded(to) => to
.checked_sub(1)
.ok_or_else(|| RpcError::InternalError("range's to wasn't representable".to_string()))?,
Bound::Unbounded => self.get_height().await? - 1,
};
if from > to {
Err(RpcError::InternalError(format!(
"malformed range: inclusive start {from}, inclusive end {to}"
)))?;
}
let zero_zero_case = (from == 0) && (to == 0);
let distributions: Distributions = self
.json_rpc_call(
"get_output_distribution",
Some(json!({
@@ -678,12 +710,27 @@ pub trait Rpc: Sync + Clone + Debug {
"amounts": [0],
"cumulative": true,
"from_height": from,
"to_height": to,
"to_height": if zero_zero_case { 1 } else { to },
})),
)
.await?;
let mut distributions = distributions.distributions;
let mut distribution = core::mem::take(&mut distributions[0].distribution);
Ok(distributions.distributions.swap_remove(0).distribution)
let expected_len = if zero_zero_case { 2 } else { (to - from) + 1 };
if expected_len != distribution.len() {
Err(RpcError::InvalidNode(format!(
"distribution length ({}) wasn't of the requested length ({})",
distribution.len(),
expected_len
)))?;
}
// Requesting 0, 0 returns the distribution for the entire chain
// We work-around this by requesting 0, 1 (yielding two blocks), then popping the second block
if zero_zero_case {
distribution.pop();
}
Ok(distribution)
}
/// Get the specified outputs from the RingCT (zero-amount) pool.
@@ -763,6 +810,7 @@ pub trait Rpc: Sync + Clone + Debug {
};
Ok(Some([key, rpc_point(&out.mask)?]).filter(|_| {
if fingerprintable_canonical {
// TODO: Are timelock blocks by height or number?
Timelock::Block(height) >= txs[i].prefix().additional_timelock
} else {
out.unlocked
@@ -864,10 +912,9 @@ pub trait Rpc: Sync + Clone + Debug {
/// Generate blocks, with the specified address receiving the block reward.
///
/// Returns the hashes of the generated blocks and the last block's number.
// TODO: Take &Address, not &str?
async fn generate_blocks(
async fn generate_blocks<const ADDR_BYTES: u128>(
&self,
address: &str,
address: &Address<ADDR_BYTES>,
block_count: usize,
) -> Result<(Vec<[u8; 32]>, usize), RpcError> {
#[derive(Debug, Deserialize)]
@@ -880,7 +927,7 @@ pub trait Rpc: Sync + Clone + Debug {
.json_rpc_call::<BlocksResponse>(
"generateblocks",
Some(json!({
"wallet_address": address,
"wallet_address": address.to_string(),
"amount_of_blocks": block_count
})),
)

View File

@@ -83,7 +83,7 @@ impl Block {
///
/// This information comes from the Block's miner transaction. If the miner transaction isn't
/// structed as expected, this will return None.
pub fn number(&self) -> Option<u64> {
pub fn number(&self) -> Option<usize> {
match &self.miner_transaction {
Transaction::V1 { prefix, .. } | Transaction::V2 { prefix, .. } => {
match prefix.inputs.first() {

View File

@@ -20,7 +20,7 @@ use crate::{
#[derive(Clone, PartialEq, Eq, Debug)]
pub enum Input {
/// An input for a miner transaction, which is generating new coins.
Gen(u64),
Gen(usize),
/// An input spending an output on-chain.
ToKey {
/// The pool this input spends an output of.

View File

@@ -155,8 +155,7 @@ async fn select_decoys<R: RngCore + CryptoRng>(
if distribution.len() < height {
// TODO: verify distribution elems are strictly increasing
let extension =
rpc.get_output_distribution(distribution.len(), height.saturating_sub(1)).await?;
let extension = rpc.get_output_distribution(distribution.len() .. height).await?;
distribution.extend(extension);
}
// If asked to use an older height than previously asked, truncate to ensure accuracy

View File

@@ -1,15 +1,12 @@
use std_shims::{vec, vec::Vec};
use rand_core::SeedableRng;
use rand_chacha::ChaCha20Rng;
use curve25519_dalek::{
constants::{ED25519_BASEPOINT_POINT, ED25519_BASEPOINT_TABLE},
Scalar, EdwardsPoint,
};
use crate::{
io::varint_len,
io::{varint_len, write_varint},
primitives::Commitment,
ringct::{
clsag::Clsag, bulletproofs::Bulletproof, EncryptedAmount, RctType, RctBase, RctPrunable,
@@ -138,17 +135,69 @@ impl SignableTransaction {
bp_commitments.push(Commitment::zero());
commitments.push(ED25519_BASEPOINT_POINT);
}
// TODO: Remove this. Deserialize an empty BP?
let bulletproof = (match self.rct_type {
let padded_log2 = {
let mut log2_find = 0;
while (1 << log2_find) < self.payments.len() {
log2_find += 1;
}
log2_find
};
// This is log2 the padded amount of IPA rows
// We have 64 rows per commitment, so we need 64 * c IPA rows
// We rewrite this as 2**6 * c
// By finding the padded log2 of c, we get 2**6 * 2**p
// This declares the log2 to be 6 + p
let lr_len = 6 + padded_log2;
let bulletproof = match self.rct_type {
RctType::ClsagBulletproof => {
Bulletproof::prove(&mut ChaCha20Rng::from_seed([0; 32]), &bp_commitments)
let mut bp = Vec::with_capacity(((9 + (2 * lr_len)) * 32) + 2);
let push_point = |bp: &mut Vec<u8>| {
bp.push(1);
bp.extend([0; 31]);
};
let push_scalar = |bp: &mut Vec<u8>| bp.extend([0; 32]);
for _ in 0 .. 4 {
push_point(&mut bp);
}
for _ in 0 .. 2 {
push_scalar(&mut bp);
}
for _ in 0 .. 2 {
write_varint(&lr_len, &mut bp).unwrap();
for _ in 0 .. lr_len {
push_point(&mut bp);
}
}
for _ in 0 .. 3 {
push_scalar(&mut bp);
}
Bulletproof::read(&mut bp.as_slice()).expect("made an invalid dummy BP")
}
RctType::ClsagBulletproofPlus => {
Bulletproof::prove_plus(&mut ChaCha20Rng::from_seed([0; 32]), bp_commitments)
let mut bp = Vec::with_capacity(((6 + (2 * lr_len)) * 32) + 2);
let push_point = |bp: &mut Vec<u8>| {
bp.push(1);
bp.extend([0; 31]);
};
let push_scalar = |bp: &mut Vec<u8>| bp.extend([0; 32]);
for _ in 0 .. 3 {
push_point(&mut bp);
}
for _ in 0 .. 3 {
push_scalar(&mut bp);
}
for _ in 0 .. 2 {
write_varint(&lr_len, &mut bp).unwrap();
for _ in 0 .. lr_len {
push_point(&mut bp);
}
}
Bulletproof::read_plus(&mut bp.as_slice()).expect("made an invalid dummy BP+")
}
_ => panic!("unsupported RctType"),
})
.expect("couldn't prove BP(+)s for this many payments despite checking in constructor?");
};
// `- 1` to remove the one byte for the 0 fee
Transaction::V2 {

View File

@@ -64,7 +64,11 @@ pub fn random_guaranteed_address() -> (Scalar, GuaranteedViewPair, 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: &SimpleRequestRpc, addr: &str, tx_hash: [u8; 32]) -> Block {
pub async fn mine_until_unlocked(
rpc: &SimpleRequestRpc,
addr: &MoneroAddress,
tx_hash: [u8; 32],
) -> Block {
// mine until tx is in a block
let mut height = rpc.get_height().await.unwrap();
let mut found = false;
@@ -105,7 +109,7 @@ pub async fn get_miner_tx_output(rpc: &SimpleRequestRpc, view: &ViewPair) -> Wal
// Mine 60 blocks to unlock a miner TX
let start = rpc.get_height().await.unwrap();
rpc.generate_blocks(&view.legacy_address(Network::Mainnet).to_string(), 60).await.unwrap();
rpc.generate_blocks(&view.legacy_address(Network::Mainnet), 60).await.unwrap();
let block = rpc.get_block_by_number(start).await.unwrap();
scanner.scan(rpc, &block).await.unwrap().ignore_additional_timelock().swap_remove(0)
@@ -138,8 +142,7 @@ pub async fn rpc() -> SimpleRequestRpc {
AddressType::Legacy,
&Scalar::random(&mut OsRng) * ED25519_BASEPOINT_TABLE,
&Scalar::random(&mut OsRng) * ED25519_BASEPOINT_TABLE,
)
.to_string();
);
// Mine 40 blocks to ensure decoy availability
rpc.generate_blocks(&addr, 40).await.unwrap();
@@ -312,7 +315,7 @@ macro_rules! test {
let signed = sign(tx).await;
rpc.publish_transaction(&signed).await.unwrap();
let block =
mine_until_unlocked(&rpc, &random_address().2.to_string(), signed.hash()).await;
mine_until_unlocked(&rpc, &random_address().2, signed.hash()).await;
let tx = rpc.get_transaction(signed.hash()).await.unwrap();
check_weight_and_fee(&tx, fee_rate);
let scanner = Scanner::new(view.clone());
@@ -333,7 +336,7 @@ macro_rules! test {
let signed = sign(tx).await;
rpc.publish_transaction(&signed).await.unwrap();
let block =
mine_until_unlocked(&rpc, &random_address().2.to_string(), signed.hash()).await;
mine_until_unlocked(&rpc, &random_address().2, signed.hash()).await;
let tx = rpc.get_transaction(signed.hash()).await.unwrap();
if stringify!($name) != "spend_one_input_to_two_outputs_no_change" {
// Skip weight and fee check for the above test because when there is no change,

View File

@@ -41,7 +41,7 @@ async fn make_integrated_address(rpc: &SimpleRequestRpc, payment_id: [u8; 8]) ->
res.integrated_address
}
async fn initialize_rpcs() -> (SimpleRequestRpc, SimpleRequestRpc, String) {
async fn initialize_rpcs() -> (SimpleRequestRpc, SimpleRequestRpc, MoneroAddress) {
let wallet_rpc = SimpleRequestRpc::new("http://127.0.0.1:18082".to_string()).await.unwrap();
let daemon_rpc = runner::rpc().await;
@@ -64,9 +64,10 @@ async fn initialize_rpcs() -> (SimpleRequestRpc, SimpleRequestRpc, String) {
wallet_rpc.json_rpc_call("get_address", Some(json!({ "account_index": 0 }))).await.unwrap();
// Fund the new wallet
daemon_rpc.generate_blocks(&address.address, 70).await.unwrap();
let address = MoneroAddress::from_str(Network::Mainnet, &address.address).unwrap();
daemon_rpc.generate_blocks(&address, 70).await.unwrap();
(wallet_rpc, daemon_rpc, address.address)
(wallet_rpc, daemon_rpc, address)
}
async fn from_wallet_rpc_to_self(spec: AddressSpec) {
@@ -184,8 +185,7 @@ test!(
let (wallet_rpc, _, wallet_rpc_addr) = initialize_rpcs().await;
// add destination
builder
.add_payment(MoneroAddress::from_str(Network::Mainnet, &wallet_rpc_addr).unwrap(), 1000000);
builder.add_payment(wallet_rpc_addr, 1000000);
(builder.build().unwrap(), wallet_rpc)
},
|_, _, tx: Transaction, _, data: SimpleRequestRpc| async move {
@@ -342,8 +342,7 @@ test!(
let (wallet_rpc, _, wallet_rpc_addr) = initialize_rpcs().await;
// add destination
builder
.add_payment(MoneroAddress::from_str(Network::Mainnet, &wallet_rpc_addr).unwrap(), 1000000);
builder.add_payment(wallet_rpc_addr, 1000000);
// Make 2 data that is the full 255 bytes
for _ in 0 .. 2 {

View File

@@ -176,17 +176,17 @@ impl BlockTrait<Monero> for Block {
async fn time(&self, rpc: &Monero) -> u64 {
// Constant from Monero
const BLOCKCHAIN_TIMESTAMP_CHECK_WINDOW: u64 = 60;
const BLOCKCHAIN_TIMESTAMP_CHECK_WINDOW: usize = 60;
// If Monero doesn't have enough blocks to build a window, it doesn't define a network time
if (self.number().unwrap() + 1) < BLOCKCHAIN_TIMESTAMP_CHECK_WINDOW {
// Use the block number as the time
return self.number().unwrap();
return u64::try_from(self.number().unwrap()).unwrap();
}
let mut timestamps = vec![self.header.timestamp];
let mut parent = self.parent();
while u64::try_from(timestamps.len()).unwrap() < BLOCKCHAIN_TIMESTAMP_CHECK_WINDOW {
while timestamps.len() < BLOCKCHAIN_TIMESTAMP_CHECK_WINDOW {
let mut parent_block;
while {
parent_block = rpc.rpc.get_block(parent).await;
@@ -217,7 +217,7 @@ impl BlockTrait<Monero> for Block {
// Monero also solely requires the block's time not be less than the median, it doesn't ensure
// it advances the median forward
// Ensure monotonicity despite both these issues by adding the block number to the median time
res + self.number().unwrap()
res + u64::try_from(self.number().unwrap()).unwrap()
}
}
@@ -553,19 +553,17 @@ impl Network for Monero {
if eventuality.matches(&tx) {
res.insert(
eventualities.map.remove(&tx.prefix().extra).unwrap().0,
(usize::try_from(block.number().unwrap()).unwrap(), tx.id(), tx),
(block.number().unwrap(), tx.id(), tx),
);
}
}
}
eventualities.block_number += 1;
assert_eq!(eventualities.block_number, usize::try_from(block.number().unwrap()).unwrap());
assert_eq!(eventualities.block_number, block.number().unwrap());
}
for block_num in
(eventualities.block_number + 1) .. usize::try_from(block.number().unwrap()).unwrap()
{
for block_num in (eventualities.block_number + 1) .. block.number().unwrap() {
let block = {
let mut block;
while {
@@ -583,7 +581,7 @@ impl Network for Monero {
// Also check the current block
check_block(self, eventualities, block, &mut res).await;
assert_eq!(eventualities.block_number, usize::try_from(block.number().unwrap()).unwrap());
assert_eq!(eventualities.block_number, block.number().unwrap());
res
}
@@ -664,7 +662,7 @@ impl Network for Monero {
#[cfg(test)]
async fn get_block_number(&self, id: &[u8; 32]) -> usize {
self.rpc.get_block(*id).await.unwrap().number().unwrap().try_into().unwrap()
self.rpc.get_block(*id).await.unwrap().number().unwrap()
}
#[cfg(test)]
@@ -696,23 +694,7 @@ impl Network for Monero {
async fn mine_block(&self) {
// https://github.com/serai-dex/serai/issues/198
sleep(std::time::Duration::from_millis(100)).await;
#[derive(Debug, serde::Deserialize)]
struct EmptyResponse {}
let _: EmptyResponse = self
.rpc
.rpc_call(
"json_rpc",
Some(serde_json::json!({
"method": "generateblocks",
"params": {
"wallet_address": Self::test_address().to_string(),
"amount_of_blocks": 1
},
})),
)
.await
.unwrap();
self.rpc.generate_blocks(&Self::test_address().into(), 1).await.unwrap();
}
#[cfg(test)]

View File

@@ -90,8 +90,7 @@ async fn mint_and_burn_test() {
use monero_wallet::{rpc::Rpc, ViewPair, address::Network};
let addr = ViewPair::new(ED25519_BASEPOINT_POINT, Zeroizing::new(Scalar::ONE))
.legacy_address(Network::Mainnet)
.to_string();
.legacy_address(Network::Mainnet);
let rpc = producer_handles.monero(ops).await;
let mut res = Vec::with_capacity(count);

View File

@@ -408,16 +408,11 @@ impl Coordinator {
use monero_wallet::{rpc::Rpc, address::Network, ViewPair};
let rpc = SimpleRequestRpc::new(rpc_url).await.expect("couldn't connect to the Monero RPC");
let _: EmptyResponse = rpc
.json_rpc_call(
"generateblocks",
Some(serde_json::json!({
"wallet_address": ViewPair::new(
ED25519_BASEPOINT_POINT,
Zeroizing::new(Scalar::ONE),
).legacy_address(Network::Mainnet).to_string(),
"amount_of_blocks": 1,
})),
rpc
.generate_blocks(
&ViewPair::new(ED25519_BASEPOINT_POINT, Zeroizing::new(Scalar::ONE))
.legacy_address(Network::Mainnet),
1,
)
.await
.unwrap();

View File

@@ -200,16 +200,7 @@ impl Wallet {
let height = rpc.get_height().await.unwrap();
// Mines 200 blocks so sufficient decoys exist, as only 60 is needed for maturity
let _: EmptyResponse = rpc
.json_rpc_call(
"generateblocks",
Some(serde_json::json!({
"wallet_address": view_pair.legacy_address(Network::Mainnet).to_string(),
"amount_of_blocks": 200,
})),
)
.await
.unwrap();
rpc.generate_blocks(&view_pair.legacy_address(Network::Mainnet), 200).await.unwrap();
let block = rpc.get_block(rpc.get_block_hash(height).await.unwrap()).await.unwrap();
Wallet::Monero {