2022-05-25 01:41:14 +00:00
|
|
|
use std::{sync::Mutex, collections::HashMap};
|
2022-05-18 04:53:13 +00:00
|
|
|
|
|
|
|
use lazy_static::lazy_static;
|
|
|
|
|
2022-04-29 00:41:43 +00:00
|
|
|
use rand::rngs::OsRng;
|
|
|
|
|
2022-05-18 04:53:13 +00:00
|
|
|
#[cfg(feature = "multisig")]
|
|
|
|
use blake2::{digest::Update, Digest, Blake2b512};
|
|
|
|
|
2022-04-29 00:41:43 +00:00
|
|
|
use curve25519_dalek::constants::ED25519_BASEPOINT_TABLE;
|
2022-05-18 04:53:13 +00:00
|
|
|
#[cfg(feature = "multisig")]
|
|
|
|
use dalek_ff_group::Scalar;
|
2022-04-29 00:41:43 +00:00
|
|
|
|
|
|
|
use monero::{
|
|
|
|
network::Network,
|
|
|
|
util::{key::PublicKey, address::Address}
|
|
|
|
};
|
|
|
|
|
2022-05-21 19:33:35 +00:00
|
|
|
use monero_serai::{random_scalar, wallet::SignableTransaction};
|
2022-04-29 00:41:43 +00:00
|
|
|
|
|
|
|
mod rpc;
|
2022-05-13 04:05:34 +00:00
|
|
|
use crate::rpc::{rpc, mine_block};
|
2022-04-29 00:41:43 +00:00
|
|
|
|
2022-05-18 04:53:13 +00:00
|
|
|
#[cfg(feature = "multisig")]
|
|
|
|
mod frost;
|
|
|
|
#[cfg(feature = "multisig")]
|
|
|
|
use crate::frost::{THRESHOLD, generate_keys, sign};
|
|
|
|
|
|
|
|
lazy_static! {
|
|
|
|
static ref SEQUENTIAL: Mutex<()> = Mutex::new(());
|
|
|
|
}
|
|
|
|
|
2022-05-21 19:33:35 +00:00
|
|
|
macro_rules! async_sequential {
|
|
|
|
($(async fn $name: ident() $body: block)*) => {
|
|
|
|
$(
|
|
|
|
#[tokio::test]
|
|
|
|
async fn $name() {
|
|
|
|
let guard = SEQUENTIAL.lock().unwrap();
|
|
|
|
let local = tokio::task::LocalSet::new();
|
|
|
|
local.run_until(async move {
|
2022-05-22 02:23:16 +00:00
|
|
|
if let Err(err) = tokio::task::spawn_local(async move { $body }).await {
|
2022-05-21 19:33:35 +00:00
|
|
|
drop(guard);
|
2022-05-22 02:23:16 +00:00
|
|
|
Err(err).unwrap()
|
2022-05-21 19:33:35 +00:00
|
|
|
}
|
|
|
|
}).await;
|
|
|
|
}
|
|
|
|
)*
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
async fn send_core(test: usize, multisig: bool) {
|
2022-05-13 04:05:34 +00:00
|
|
|
let rpc = rpc().await;
|
2022-04-29 00:41:43 +00:00
|
|
|
|
|
|
|
// Generate an address
|
|
|
|
let spend = random_scalar(&mut OsRng);
|
2022-05-18 04:53:13 +00:00
|
|
|
#[allow(unused_mut)]
|
|
|
|
let mut view = random_scalar(&mut OsRng);
|
|
|
|
#[allow(unused_mut)]
|
|
|
|
let mut spend_pub = &spend * &ED25519_BASEPOINT_TABLE;
|
|
|
|
|
|
|
|
#[cfg(feature = "multisig")]
|
|
|
|
let (keys, _) = generate_keys();
|
|
|
|
|
|
|
|
if multisig {
|
|
|
|
#[cfg(not(feature = "multisig"))]
|
|
|
|
panic!("Running a multisig test without the multisig feature");
|
|
|
|
#[cfg(feature = "multisig")]
|
|
|
|
{
|
|
|
|
view = Scalar::from_hash(Blake2b512::new().chain("Monero Serai Transaction Test")).0;
|
2022-05-25 01:41:14 +00:00
|
|
|
spend_pub = keys[&1].group_key().0;
|
2022-05-18 04:53:13 +00:00
|
|
|
}
|
|
|
|
}
|
2022-04-29 00:41:43 +00:00
|
|
|
|
|
|
|
let addr = Address::standard(
|
|
|
|
Network::Mainnet,
|
|
|
|
PublicKey { point: spend_pub.compress() },
|
|
|
|
PublicKey { point: (&view * &ED25519_BASEPOINT_TABLE).compress() }
|
|
|
|
);
|
|
|
|
|
2022-05-18 04:53:13 +00:00
|
|
|
// TODO
|
2022-04-29 00:41:43 +00:00
|
|
|
let fee_per_byte = 50000000;
|
|
|
|
let fee = fee_per_byte * 2000;
|
|
|
|
|
2022-05-18 04:53:13 +00:00
|
|
|
let start = rpc.get_height().await.unwrap();
|
|
|
|
for _ in 0 .. 7 {
|
|
|
|
mine_block(&rpc, &addr.to_string()).await.unwrap();
|
|
|
|
}
|
|
|
|
|
|
|
|
let mut tx = None;
|
|
|
|
// Allow tests to test variable transactions
|
|
|
|
for i in 0 .. [2, 1][test] {
|
|
|
|
let mut outputs = vec![];
|
|
|
|
let mut amount = 0;
|
|
|
|
// Test spending both a miner output and a normal output
|
|
|
|
if test == 0 {
|
|
|
|
if i == 0 {
|
|
|
|
tx = Some(rpc.get_block_transactions(start).await.unwrap().swap_remove(0));
|
|
|
|
}
|
|
|
|
|
2022-05-20 05:03:54 +00:00
|
|
|
// Grab the largest output available
|
|
|
|
let output = {
|
2022-05-21 19:33:35 +00:00
|
|
|
let mut outputs = tx.as_ref().unwrap().scan(view, spend_pub);
|
2022-05-20 05:03:54 +00:00
|
|
|
outputs.sort_by(|x, y| x.commitment.amount.cmp(&y.commitment.amount).reverse());
|
|
|
|
outputs.swap_remove(0)
|
|
|
|
};
|
2022-05-18 04:53:13 +00:00
|
|
|
// Test creating a zero change output and a non-zero change output
|
|
|
|
amount = output.commitment.amount - u64::try_from(i).unwrap();
|
|
|
|
outputs.push(output);
|
|
|
|
|
|
|
|
// Test spending multiple inputs
|
|
|
|
} else if test == 1 {
|
|
|
|
if i != 0 {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
for i in (start + 1) .. (start + 9) {
|
|
|
|
let tx = rpc.get_block_transactions(i).await.unwrap().swap_remove(0);
|
2022-05-21 19:33:35 +00:00
|
|
|
let output = tx.scan(view, spend_pub).swap_remove(0);
|
2022-05-18 04:53:13 +00:00
|
|
|
amount += output.commitment.amount;
|
|
|
|
outputs.push(output);
|
|
|
|
}
|
2022-04-29 00:41:43 +00:00
|
|
|
}
|
|
|
|
|
2022-05-18 04:53:13 +00:00
|
|
|
let mut signable = SignableTransaction::new(
|
|
|
|
outputs, vec![(addr, amount - fee)], addr, fee_per_byte
|
|
|
|
).unwrap();
|
|
|
|
|
|
|
|
if !multisig {
|
|
|
|
tx = Some(signable.sign(&mut OsRng, &rpc, &spend).await.unwrap());
|
|
|
|
} else {
|
|
|
|
#[cfg(feature = "multisig")]
|
|
|
|
{
|
2022-05-25 01:41:14 +00:00
|
|
|
let mut machines = HashMap::new();
|
|
|
|
for i in 1 ..= THRESHOLD {
|
|
|
|
machines.insert(
|
|
|
|
i,
|
2022-05-18 04:53:13 +00:00
|
|
|
signable.clone().multisig(
|
|
|
|
b"Monero Serai Test Transaction".to_vec(),
|
|
|
|
&mut OsRng,
|
|
|
|
&rpc,
|
|
|
|
rpc.get_height().await.unwrap() - 10,
|
2022-05-25 01:41:14 +00:00
|
|
|
keys[&i].clone(),
|
|
|
|
(1 ..= THRESHOLD).collect::<Vec<_>>()
|
2022-05-18 04:53:13 +00:00
|
|
|
).await.unwrap()
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
let mut txs = sign(&mut machines, &vec![]);
|
2022-05-25 01:41:14 +00:00
|
|
|
for s in 1 .. THRESHOLD {
|
|
|
|
assert_eq!(txs[usize::from(s)].hash(), txs[0].hash());
|
2022-05-18 04:53:13 +00:00
|
|
|
}
|
|
|
|
tx = Some(txs.swap_remove(0));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
rpc.publish_transaction(tx.as_ref().unwrap()).await.unwrap();
|
|
|
|
mine_block(&rpc, &addr.to_string()).await.unwrap();
|
2022-04-29 00:41:43 +00:00
|
|
|
}
|
|
|
|
}
|
2022-05-18 04:53:13 +00:00
|
|
|
|
2022-05-21 19:33:35 +00:00
|
|
|
async_sequential! {
|
|
|
|
async fn send_single_input() {
|
|
|
|
send_core(0, false).await;
|
|
|
|
}
|
2022-05-18 04:53:13 +00:00
|
|
|
|
2022-05-21 19:33:35 +00:00
|
|
|
async fn send_multiple_inputs() {
|
|
|
|
send_core(1, false).await;
|
|
|
|
}
|
2022-05-18 04:53:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(feature = "multisig")]
|
2022-05-21 19:33:35 +00:00
|
|
|
async_sequential! {
|
|
|
|
async fn multisig_send_single_input() {
|
|
|
|
send_core(0, true).await;
|
|
|
|
}
|
2022-05-18 04:53:13 +00:00
|
|
|
|
2022-05-21 19:33:35 +00:00
|
|
|
async fn multisig_send_multiple_inputs() {
|
|
|
|
send_core(1, true).await;
|
|
|
|
}
|
2022-05-18 04:53:13 +00:00
|
|
|
}
|