mirror of
https://github.com/serai-dex/serai.git
synced 2025-12-08 12:19:24 +00:00
add scan tests
This commit is contained in:
@@ -1,5 +1,6 @@
|
|||||||
use core::ops::Deref;
|
use core::ops::Deref;
|
||||||
use std::sync::Mutex;
|
use std::sync::Mutex;
|
||||||
|
use std::collections::HashSet;
|
||||||
|
|
||||||
use lazy_static::lazy_static;
|
use lazy_static::lazy_static;
|
||||||
|
|
||||||
@@ -11,8 +12,9 @@ use curve25519_dalek::{constants::ED25519_BASEPOINT_TABLE, scalar::Scalar};
|
|||||||
use monero_serai::{
|
use monero_serai::{
|
||||||
Protocol, random_scalar,
|
Protocol, random_scalar,
|
||||||
wallet::{
|
wallet::{
|
||||||
ViewPair,
|
ViewPair, Scanner,
|
||||||
address::{Network, AddressType, AddressMeta, MoneroAddress},
|
address::{Network, AddressType, AddressMeta, MoneroAddress},
|
||||||
|
SpendableOutput,
|
||||||
},
|
},
|
||||||
rpc::Rpc,
|
rpc::Rpc,
|
||||||
};
|
};
|
||||||
@@ -55,6 +57,18 @@ pub async fn mine_until_unlocked(rpc: &Rpc, addr: &str, tx_hash: [u8; 32]) {
|
|||||||
rpc.generate_blocks(addr, 9).await.unwrap();
|
rpc.generate_blocks(addr, 9).await.unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Mines 60 blocks and returns an unlocked spendable miner tx output.
|
||||||
|
pub async fn get_miner_tx_output(rpc: &Rpc, view: &ViewPair) -> SpendableOutput {
|
||||||
|
let mut scanner = Scanner::from_view(view.clone(), Network::Mainnet, Some(HashSet::new()));
|
||||||
|
|
||||||
|
// mine 60 blocks to unlock a miner tx
|
||||||
|
let start = rpc.get_height().await.unwrap();
|
||||||
|
rpc.generate_blocks(&scanner.address().to_string(), 60).await.unwrap();
|
||||||
|
|
||||||
|
let block = rpc.get_block(start).await.unwrap();
|
||||||
|
scanner.scan(&rpc, &block).await.unwrap().swap_remove(0).ignore_timelock().swap_remove(0)
|
||||||
|
}
|
||||||
|
|
||||||
pub async fn rpc() -> Rpc {
|
pub async fn rpc() -> Rpc {
|
||||||
let rpc = Rpc::new("http://127.0.0.1:18081".to_string()).unwrap();
|
let rpc = Rpc::new("http://127.0.0.1:18081".to_string()).unwrap();
|
||||||
|
|
||||||
@@ -136,12 +150,12 @@ macro_rules! test {
|
|||||||
use monero_serai::{
|
use monero_serai::{
|
||||||
random_scalar,
|
random_scalar,
|
||||||
wallet::{
|
wallet::{
|
||||||
address::Network, ViewPair, Scanner, SignableTransaction,
|
address::{Network, AddressMeta, AddressType}, ViewPair, Scanner, SignableTransaction,
|
||||||
SignableTransactionBuilder,
|
SignableTransactionBuilder,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
use runner::{random_address, rpc, mine_until_unlocked};
|
use runner::{random_address, rpc, mine_until_unlocked, get_miner_tx_output};
|
||||||
|
|
||||||
type Builder = SignableTransactionBuilder;
|
type Builder = SignableTransactionBuilder;
|
||||||
|
|
||||||
@@ -166,28 +180,12 @@ macro_rules! test {
|
|||||||
keys[&1].group_key().0
|
keys[&1].group_key().0
|
||||||
};
|
};
|
||||||
|
|
||||||
let view = ViewPair::new(spend_pub, Zeroizing::new(random_scalar(&mut OsRng)));
|
|
||||||
|
|
||||||
let rpc = rpc().await;
|
let rpc = rpc().await;
|
||||||
|
|
||||||
let (addr, miner_tx) = {
|
let view = ViewPair::new(spend_pub, Zeroizing::new(random_scalar(&mut OsRng)));
|
||||||
let mut scanner =
|
let addr = view.address(AddressMeta::new(Network::Mainnet, AddressType::Standard));
|
||||||
Scanner::from_view(view.clone(), Network::Mainnet, Some(HashSet::new()));
|
|
||||||
let addr = scanner.address();
|
|
||||||
|
|
||||||
// mine 60 blocks to unlock a miner tx
|
let miner_tx = get_miner_tx_output(&rpc, &view).await;
|
||||||
let start = rpc.get_height().await.unwrap();
|
|
||||||
rpc.generate_blocks(&addr.to_string(), 60).await.unwrap();
|
|
||||||
|
|
||||||
let block = rpc.get_block(start).await.unwrap();
|
|
||||||
(
|
|
||||||
addr,
|
|
||||||
scanner.scan(
|
|
||||||
&rpc,
|
|
||||||
&block
|
|
||||||
).await.unwrap().swap_remove(0).ignore_timelock().swap_remove(0)
|
|
||||||
)
|
|
||||||
};
|
|
||||||
|
|
||||||
let builder = SignableTransactionBuilder::new(
|
let builder = SignableTransactionBuilder::new(
|
||||||
rpc.get_protocol().await.unwrap(),
|
rpc.get_protocol().await.unwrap(),
|
||||||
|
|||||||
160
coins/monero/tests/scan.rs
Normal file
160
coins/monero/tests/scan.rs
Normal file
@@ -0,0 +1,160 @@
|
|||||||
|
use std::collections::HashSet;
|
||||||
|
use hex_literal::hex;
|
||||||
|
|
||||||
|
use curve25519_dalek::{constants::ED25519_BASEPOINT_TABLE, scalar::Scalar};
|
||||||
|
use rand_core::OsRng;
|
||||||
|
use zeroize::Zeroizing;
|
||||||
|
|
||||||
|
use monero_serai::{
|
||||||
|
wallet::{
|
||||||
|
address::{Network, MoneroAddress},
|
||||||
|
ViewPair, SignableTransaction, Scanner,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
mod runner;
|
||||||
|
|
||||||
|
const ADDR_SPEND: [u8; 32] =
|
||||||
|
hex!("bf02a79d9e30ea76872e565722517924151793c535832e4353e54dc0be698001");
|
||||||
|
const ADDR_VIEW: [u8; 32] =
|
||||||
|
hex!("c300b798c000f3c5da4ebc5a288418fe9060d623c9830b7abc3d9e7a3152eb08");
|
||||||
|
|
||||||
|
pub struct AddressInfo {
|
||||||
|
address: String,
|
||||||
|
payment_id: Option<[u8; 8]>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn scan_incomings(addr_scanner: &mut Scanner, addresses: &Vec<AddressInfo>) {
|
||||||
|
// get an output to spend
|
||||||
|
let (miner_spend, miner_view, miner_addr) = runner::random_address();
|
||||||
|
let mut miner_scanner =
|
||||||
|
Scanner::from_view(miner_view.clone(), Network::Mainnet, Some(HashSet::new()));
|
||||||
|
let rpc = runner::rpc().await;
|
||||||
|
let mut input = runner::get_miner_tx_output(&rpc, &miner_view).await;
|
||||||
|
|
||||||
|
// chain params
|
||||||
|
let fee = rpc.get_fee().await.unwrap();
|
||||||
|
let start = rpc.get_height().await.unwrap() - 59; // -60 input is already grabbed above
|
||||||
|
let protocol = rpc.get_protocol().await.unwrap();
|
||||||
|
let amount = 1000000;
|
||||||
|
|
||||||
|
for (i, addr) in addresses.iter().enumerate() {
|
||||||
|
let mut tx = SignableTransaction::new(
|
||||||
|
protocol,
|
||||||
|
vec![input],
|
||||||
|
vec![(MoneroAddress::from_str(Network::Mainnet, &addr.address).unwrap(), amount)],
|
||||||
|
Some(miner_addr),
|
||||||
|
vec![],
|
||||||
|
fee,
|
||||||
|
)
|
||||||
|
.unwrap()
|
||||||
|
.sign(&mut OsRng, &rpc, &Zeroizing::new(miner_spend))
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
// submit and unlock tx
|
||||||
|
rpc.publish_transaction(&tx).await.unwrap();
|
||||||
|
runner::mine_until_unlocked(&rpc, &miner_addr.to_string(), tx.hash()).await;
|
||||||
|
|
||||||
|
// get the tx and confirm receipt
|
||||||
|
tx = rpc.get_transaction(tx.hash()).await.unwrap();
|
||||||
|
let output = addr_scanner.scan_transaction(&tx).not_locked().swap_remove(0);
|
||||||
|
assert_eq!(output.commitment().amount, amount);
|
||||||
|
if addr.payment_id.is_some() {
|
||||||
|
assert_eq!(output.metadata.payment_id, addr.payment_id.unwrap());
|
||||||
|
}
|
||||||
|
|
||||||
|
// pick another input to spend for the next address
|
||||||
|
let block = rpc.get_block(start + i).await.unwrap();
|
||||||
|
input = miner_scanner
|
||||||
|
.scan(&rpc, &block)
|
||||||
|
.await
|
||||||
|
.unwrap()
|
||||||
|
.swap_remove(0)
|
||||||
|
.ignore_timelock()
|
||||||
|
.swap_remove(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async_sequential!(
|
||||||
|
async fn scan_all_standard_addresses() {
|
||||||
|
// scanner
|
||||||
|
let spend_pub = &Scalar::from_bits(ADDR_SPEND) * &ED25519_BASEPOINT_TABLE;
|
||||||
|
let mut scanner = Scanner::from_view(
|
||||||
|
ViewPair::new(spend_pub, Zeroizing::new(Scalar::from_bits(ADDR_VIEW))),
|
||||||
|
Network::Mainnet,
|
||||||
|
Some(HashSet::new()),
|
||||||
|
);
|
||||||
|
|
||||||
|
// generate all types of addresses
|
||||||
|
let payment_ids = vec![
|
||||||
|
[46, 48, 134, 34, 245, 148, 243, 195],
|
||||||
|
[153, 176, 98, 204, 151, 27, 197, 168],
|
||||||
|
[88, 37, 149, 111, 171, 108, 120, 181],
|
||||||
|
];
|
||||||
|
let mut addresses = vec![];
|
||||||
|
// standard versions
|
||||||
|
addresses.push(AddressInfo { address: scanner.address().to_string(), payment_id: None });
|
||||||
|
addresses
|
||||||
|
.push(AddressInfo { address: scanner.subaddress((0, 1)).to_string(), payment_id: None });
|
||||||
|
addresses.push(AddressInfo {
|
||||||
|
address: scanner.integrated_address(payment_ids[0]).to_string(),
|
||||||
|
payment_id: Some(payment_ids[0]),
|
||||||
|
});
|
||||||
|
// featured versions
|
||||||
|
addresses.push(AddressInfo {
|
||||||
|
address: scanner.featured_address(Some((0, 2)), Some(payment_ids[1]), false).to_string(),
|
||||||
|
payment_id: Some(payment_ids[1]),
|
||||||
|
});
|
||||||
|
addresses.push(AddressInfo {
|
||||||
|
address: scanner.featured_address(None, None, false).to_string(),
|
||||||
|
payment_id: None,
|
||||||
|
});
|
||||||
|
addresses.push(AddressInfo {
|
||||||
|
address: scanner.featured_address(Some((0, 3)), None, false).to_string(),
|
||||||
|
payment_id: None,
|
||||||
|
});
|
||||||
|
addresses.push(AddressInfo {
|
||||||
|
address: scanner.featured_address(None, Some(payment_ids[2]), false).to_string(),
|
||||||
|
payment_id: Some(payment_ids[2]),
|
||||||
|
});
|
||||||
|
|
||||||
|
// send to & test receive from addresses
|
||||||
|
scan_incomings(&mut scanner, &addresses).await;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
async_sequential!(
|
||||||
|
async fn scan_all_guaranteed_addresses() {
|
||||||
|
// scanner
|
||||||
|
let spend_pub = &Scalar::from_bits(ADDR_SPEND) * &ED25519_BASEPOINT_TABLE;
|
||||||
|
let mut scanner = Scanner::from_view(
|
||||||
|
ViewPair::new(spend_pub, Zeroizing::new(Scalar::from_bits(ADDR_VIEW))),
|
||||||
|
Network::Mainnet,
|
||||||
|
None,
|
||||||
|
);
|
||||||
|
|
||||||
|
// generate all types of addresses
|
||||||
|
let payment_ids =
|
||||||
|
vec![[88, 37, 149, 111, 171, 108, 120, 181], [125, 69, 155, 152, 140, 160, 157, 186]];
|
||||||
|
let mut addresses = vec![];
|
||||||
|
// featured (false, none, true)
|
||||||
|
addresses.push(AddressInfo { address: scanner.address().to_string(), payment_id: None });
|
||||||
|
// featured (false, some, true)
|
||||||
|
addresses.push(AddressInfo {
|
||||||
|
address: scanner.integrated_address(payment_ids[0]).to_string(),
|
||||||
|
payment_id: Some(payment_ids[0]),
|
||||||
|
});
|
||||||
|
// featured (true, none, true)
|
||||||
|
addresses
|
||||||
|
.push(AddressInfo { address: scanner.subaddress((0, 1)).to_string(), payment_id: None });
|
||||||
|
// featured (true, some, true)
|
||||||
|
addresses.push(AddressInfo {
|
||||||
|
address: scanner.featured_address(Some((0, 2)), Some(payment_ids[1]), true).to_string(),
|
||||||
|
payment_id: Some(payment_ids[1]),
|
||||||
|
});
|
||||||
|
|
||||||
|
// send to & test receive from addresses
|
||||||
|
scan_incomings(&mut scanner, &addresses).await;
|
||||||
|
}
|
||||||
|
);
|
||||||
Reference in New Issue
Block a user