mirror of
https://github.com/serai-dex/serai.git
synced 2025-12-08 12:19:24 +00:00
Apply an initial set of rustfmt rules
This commit is contained in:
@@ -12,7 +12,7 @@ pub use self::monero::Monero;
|
||||
#[derive(Clone, Error, Debug)]
|
||||
pub enum CoinError {
|
||||
#[error("failed to connect to coin daemon")]
|
||||
ConnectionError
|
||||
ConnectionError,
|
||||
}
|
||||
|
||||
pub trait Output: Sized + Clone {
|
||||
@@ -52,7 +52,7 @@ pub trait Coin {
|
||||
async fn get_outputs(
|
||||
&self,
|
||||
block: &Self::Block,
|
||||
key: <Self::Curve as Curve>::G
|
||||
key: <Self::Curve as Curve>::G,
|
||||
) -> Vec<Self::Output>;
|
||||
|
||||
async fn prepare_send(
|
||||
@@ -62,18 +62,18 @@ pub trait Coin {
|
||||
height: usize,
|
||||
inputs: Vec<Self::Output>,
|
||||
payments: &[(Self::Address, u64)],
|
||||
fee: Self::Fee
|
||||
fee: Self::Fee,
|
||||
) -> Result<Self::SignableTransaction, CoinError>;
|
||||
|
||||
async fn attempt_send(
|
||||
&self,
|
||||
transaction: Self::SignableTransaction,
|
||||
included: &[u16]
|
||||
included: &[u16],
|
||||
) -> Result<Self::TransactionMachine, CoinError>;
|
||||
|
||||
async fn publish_transaction(
|
||||
&self,
|
||||
tx: &Self::Transaction
|
||||
tx: &Self::Transaction,
|
||||
) -> Result<(Vec<u8>, Vec<<Self::Output as Output>::Id>), CoinError>;
|
||||
|
||||
#[cfg(test)]
|
||||
|
||||
@@ -12,12 +12,16 @@ use monero_serai::{
|
||||
transaction::Transaction,
|
||||
rpc::Rpc,
|
||||
wallet::{
|
||||
ViewPair, address::{Network, AddressType, Address},
|
||||
Fee, SpendableOutput, SignableTransaction as MSignableTransaction, TransactionMachine
|
||||
}
|
||||
ViewPair,
|
||||
address::{Network, AddressType, Address},
|
||||
Fee, SpendableOutput, SignableTransaction as MSignableTransaction, TransactionMachine,
|
||||
},
|
||||
};
|
||||
|
||||
use crate::{coin::{CoinError, Output as OutputTrait, Coin}, view_key};
|
||||
use crate::{
|
||||
coin::{CoinError, Output as OutputTrait, Coin},
|
||||
view_key,
|
||||
};
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Output(SpendableOutput);
|
||||
@@ -55,13 +59,13 @@ pub struct SignableTransaction(
|
||||
Arc<FrostKeys<Ed25519>>,
|
||||
RecommendedTranscript,
|
||||
usize,
|
||||
MSignableTransaction
|
||||
MSignableTransaction,
|
||||
);
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Monero {
|
||||
pub(crate) rpc: Rpc,
|
||||
view: Scalar
|
||||
view: Scalar,
|
||||
}
|
||||
|
||||
impl Monero {
|
||||
@@ -138,47 +142,51 @@ impl Coin for Monero {
|
||||
height: usize,
|
||||
mut inputs: Vec<Output>,
|
||||
payments: &[(Address, u64)],
|
||||
fee: Fee
|
||||
fee: Fee,
|
||||
) -> Result<SignableTransaction, CoinError> {
|
||||
let spend = keys.group_key();
|
||||
Ok(
|
||||
SignableTransaction(
|
||||
keys,
|
||||
transcript,
|
||||
height,
|
||||
MSignableTransaction::new(
|
||||
inputs.drain(..).map(|input| input.0).collect(),
|
||||
payments.to_vec(),
|
||||
Some(self.address(spend)),
|
||||
fee
|
||||
).map_err(|_| CoinError::ConnectionError)?
|
||||
Ok(SignableTransaction(
|
||||
keys,
|
||||
transcript,
|
||||
height,
|
||||
MSignableTransaction::new(
|
||||
inputs.drain(..).map(|input| input.0).collect(),
|
||||
payments.to_vec(),
|
||||
Some(self.address(spend)),
|
||||
fee,
|
||||
)
|
||||
)
|
||||
.map_err(|_| CoinError::ConnectionError)?,
|
||||
))
|
||||
}
|
||||
|
||||
async fn attempt_send(
|
||||
&self,
|
||||
transaction: SignableTransaction,
|
||||
included: &[u16]
|
||||
included: &[u16],
|
||||
) -> Result<Self::TransactionMachine, CoinError> {
|
||||
transaction.3.clone().multisig(
|
||||
&self.rpc,
|
||||
(*transaction.0).clone(),
|
||||
transaction.1.clone(),
|
||||
transaction.2,
|
||||
included.to_vec()
|
||||
).await.map_err(|_| CoinError::ConnectionError)
|
||||
transaction
|
||||
.3
|
||||
.clone()
|
||||
.multisig(
|
||||
&self.rpc,
|
||||
(*transaction.0).clone(),
|
||||
transaction.1.clone(),
|
||||
transaction.2,
|
||||
included.to_vec(),
|
||||
)
|
||||
.await
|
||||
.map_err(|_| CoinError::ConnectionError)
|
||||
}
|
||||
|
||||
async fn publish_transaction(
|
||||
&self,
|
||||
tx: &Self::Transaction
|
||||
tx: &Self::Transaction,
|
||||
) -> Result<(Vec<u8>, Vec<<Self::Output as OutputTrait>::Id>), CoinError> {
|
||||
self.rpc.publish_transaction(&tx).await.map_err(|_| CoinError::ConnectionError)?;
|
||||
|
||||
Ok((
|
||||
tx.hash().to_vec(),
|
||||
tx.prefix.outputs.iter().map(|output| output.key.compress().to_bytes()).collect()
|
||||
tx.prefix.outputs.iter().map(|output| output.key.compress().to_bytes()).collect(),
|
||||
))
|
||||
}
|
||||
|
||||
@@ -186,13 +194,20 @@ impl Coin for Monero {
|
||||
async fn mine_block(&self) {
|
||||
#[derive(serde::Deserialize, Debug)]
|
||||
struct EmptyResponse {}
|
||||
let _: EmptyResponse = self.rpc.rpc_call("json_rpc", Some(serde_json::json!({
|
||||
"method": "generateblocks",
|
||||
"params": {
|
||||
"wallet_address": self.empty_address().to_string(),
|
||||
"amount_of_blocks": 10
|
||||
},
|
||||
}))).await.unwrap();
|
||||
let _: EmptyResponse = self
|
||||
.rpc
|
||||
.rpc_call(
|
||||
"json_rpc",
|
||||
Some(serde_json::json!({
|
||||
"method": "generateblocks",
|
||||
"params": {
|
||||
"wallet_address": self.empty_address().to_string(),
|
||||
"amount_of_blocks": 10
|
||||
},
|
||||
})),
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
@@ -206,9 +221,14 @@ impl Coin for Monero {
|
||||
self.mine_block().await;
|
||||
}
|
||||
|
||||
let outputs = self.rpc
|
||||
.get_block_transactions_possible(height).await.unwrap()
|
||||
.swap_remove(0).scan(self.empty_view_pair(), false).ignore_timelock();
|
||||
let outputs = self
|
||||
.rpc
|
||||
.get_block_transactions_possible(height)
|
||||
.await
|
||||
.unwrap()
|
||||
.swap_remove(0)
|
||||
.scan(self.empty_view_pair(), false)
|
||||
.ignore_timelock();
|
||||
|
||||
let amount = outputs[0].commitment.amount;
|
||||
let fee = 1000000000; // TODO
|
||||
@@ -216,8 +236,12 @@ impl Coin for Monero {
|
||||
outputs,
|
||||
vec![(address, amount - fee)],
|
||||
Some(self.empty_address()),
|
||||
self.rpc.get_fee().await.unwrap()
|
||||
).unwrap().sign(&mut OsRng, &self.rpc, &Scalar::one()).await.unwrap();
|
||||
self.rpc.get_fee().await.unwrap(),
|
||||
)
|
||||
.unwrap()
|
||||
.sign(&mut OsRng, &self.rpc, &Scalar::one())
|
||||
.await
|
||||
.unwrap();
|
||||
self.rpc.publish_transaction(&tx).await.unwrap();
|
||||
self.mine_block().await;
|
||||
}
|
||||
|
||||
@@ -27,7 +27,7 @@ pub enum SignError {
|
||||
#[error("coin had an error {0}")]
|
||||
CoinError(CoinError),
|
||||
#[error("network had an error {0}")]
|
||||
NetworkError(NetworkError)
|
||||
NetworkError(NetworkError),
|
||||
}
|
||||
|
||||
// Generate a static view key for a given chain in a globally consistent manner
|
||||
|
||||
@@ -1,17 +1,25 @@
|
||||
use std::{io::Cursor, sync::{Arc, RwLock}, collections::HashMap};
|
||||
use std::{
|
||||
io::Cursor,
|
||||
sync::{Arc, RwLock},
|
||||
collections::HashMap,
|
||||
};
|
||||
|
||||
use async_trait::async_trait;
|
||||
|
||||
use rand::rngs::OsRng;
|
||||
|
||||
use crate::{NetworkError, Network, coin::{Coin, Monero}, wallet::{WalletKeys, MemCoinDb, Wallet}};
|
||||
use crate::{
|
||||
NetworkError, Network,
|
||||
coin::{Coin, Monero},
|
||||
wallet::{WalletKeys, MemCoinDb, Wallet},
|
||||
};
|
||||
|
||||
#[derive(Clone)]
|
||||
struct LocalNetwork {
|
||||
i: u16,
|
||||
size: u16,
|
||||
round: usize,
|
||||
rounds: Arc<RwLock<Vec<HashMap<u16, Cursor<Vec<u8>>>>>>
|
||||
rounds: Arc<RwLock<Vec<HashMap<u16, Cursor<Vec<u8>>>>>>,
|
||||
}
|
||||
|
||||
impl LocalNetwork {
|
||||
@@ -63,9 +71,7 @@ async fn test_send<C: Coin + Clone>(coin: C, fee: C::Fee) {
|
||||
for i in 1 ..= threshold {
|
||||
let mut wallet = Wallet::new(MemCoinDb::new(), coin.clone());
|
||||
wallet.acknowledge_height(0, height);
|
||||
wallet.add_keys(
|
||||
&WalletKeys::new(Arc::try_unwrap(keys.remove(&i).take().unwrap()).unwrap(), 0)
|
||||
);
|
||||
wallet.add_keys(&WalletKeys::new(Arc::try_unwrap(keys.remove(&i).take().unwrap()).unwrap(), 0));
|
||||
wallets.push(wallet);
|
||||
}
|
||||
|
||||
@@ -87,20 +93,20 @@ async fn test_send<C: Coin + Clone>(coin: C, fee: C::Fee) {
|
||||
|
||||
let height = coin.get_height().await.unwrap();
|
||||
wallet.acknowledge_height(1, height - 10);
|
||||
let signable = wallet.prepare_sends(
|
||||
1,
|
||||
vec![(wallet.address(), 10000000000)],
|
||||
fee
|
||||
).await.unwrap().1.swap_remove(0);
|
||||
futures.push(
|
||||
wallet.attempt_send(network, signable, (1 ..= threshold).into_iter().collect::<Vec<_>>())
|
||||
);
|
||||
let signable = wallet
|
||||
.prepare_sends(1, vec![(wallet.address(), 10000000000)], fee)
|
||||
.await
|
||||
.unwrap()
|
||||
.1
|
||||
.swap_remove(0);
|
||||
futures.push(wallet.attempt_send(
|
||||
network,
|
||||
signable,
|
||||
(1 ..= threshold).into_iter().collect::<Vec<_>>(),
|
||||
));
|
||||
}
|
||||
|
||||
println!(
|
||||
"{:?}",
|
||||
hex::encode(futures::future::join_all(futures).await.swap_remove(0).unwrap().0)
|
||||
);
|
||||
println!("{:?}", hex::encode(futures::future::join_all(futures).await.swap_remove(0).unwrap().0));
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
|
||||
@@ -5,13 +5,20 @@ use rand_core::OsRng;
|
||||
use group::GroupEncoding;
|
||||
|
||||
use transcript::{Transcript, RecommendedTranscript};
|
||||
use frost::{curve::Curve, FrostKeys, sign::{PreprocessMachine, SignMachine, SignatureMachine}};
|
||||
use frost::{
|
||||
curve::Curve,
|
||||
FrostKeys,
|
||||
sign::{PreprocessMachine, SignMachine, SignatureMachine},
|
||||
};
|
||||
|
||||
use crate::{coin::{CoinError, Output, Coin}, SignError, Network};
|
||||
use crate::{
|
||||
coin::{CoinError, Output, Coin},
|
||||
SignError, Network,
|
||||
};
|
||||
|
||||
pub struct WalletKeys<C: Curve> {
|
||||
keys: FrostKeys<C>,
|
||||
creation_height: usize
|
||||
creation_height: usize,
|
||||
}
|
||||
|
||||
impl<C: Curve> WalletKeys<C> {
|
||||
@@ -57,17 +64,12 @@ pub struct MemCoinDb {
|
||||
scanned_height: usize,
|
||||
// Acknowledged height for a given canonical height
|
||||
acknowledged_heights: HashMap<usize, usize>,
|
||||
outputs: HashMap<Vec<u8>, Vec<u8>>
|
||||
outputs: HashMap<Vec<u8>, Vec<u8>>,
|
||||
}
|
||||
|
||||
|
||||
impl MemCoinDb {
|
||||
pub fn new() -> MemCoinDb {
|
||||
MemCoinDb {
|
||||
scanned_height: 0,
|
||||
acknowledged_heights: HashMap::new(),
|
||||
outputs: HashMap::new()
|
||||
}
|
||||
MemCoinDb { scanned_height: 0, acknowledged_heights: HashMap::new(), outputs: HashMap::new() }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -118,7 +120,7 @@ fn select_inputs<C: Coin>(inputs: &mut Vec<C::Output>) -> (Vec<C::Output>, u64)
|
||||
|
||||
fn select_outputs<C: Coin>(
|
||||
payments: &mut Vec<(C::Address, u64)>,
|
||||
value: &mut u64
|
||||
value: &mut u64,
|
||||
) -> Vec<(C::Address, u64)> {
|
||||
// Prioritize large payments which will most efficiently use large inputs
|
||||
payments.sort_by(|a, b| a.1.cmp(&b.1));
|
||||
@@ -144,7 +146,7 @@ fn select_outputs<C: Coin>(
|
||||
fn refine_inputs<C: Coin>(
|
||||
selected: &mut Vec<C::Output>,
|
||||
inputs: &mut Vec<C::Output>,
|
||||
mut remaining: u64
|
||||
mut remaining: u64,
|
||||
) {
|
||||
// Drop unused inputs
|
||||
let mut s = 0;
|
||||
@@ -180,7 +182,7 @@ fn refine_inputs<C: Coin>(
|
||||
|
||||
fn select_inputs_outputs<C: Coin>(
|
||||
inputs: &mut Vec<C::Output>,
|
||||
outputs: &mut Vec<(C::Address, u64)>
|
||||
outputs: &mut Vec<(C::Address, u64)>,
|
||||
) -> (Vec<C::Output>, Vec<(C::Address, u64)>) {
|
||||
if inputs.len() == 0 {
|
||||
return (vec![], vec![]);
|
||||
@@ -202,21 +204,17 @@ pub struct Wallet<D: CoinDb, C: Coin> {
|
||||
db: D,
|
||||
coin: C,
|
||||
keys: Vec<(Arc<FrostKeys<C::Curve>>, Vec<C::Output>)>,
|
||||
pending: Vec<(usize, FrostKeys<C::Curve>)>
|
||||
pending: Vec<(usize, FrostKeys<C::Curve>)>,
|
||||
}
|
||||
|
||||
impl<D: CoinDb, C: Coin> Wallet<D, C> {
|
||||
pub fn new(db: D, coin: C) -> Wallet<D, C> {
|
||||
Wallet {
|
||||
db,
|
||||
coin,
|
||||
|
||||
keys: vec![],
|
||||
pending: vec![]
|
||||
}
|
||||
Wallet { db, coin, keys: vec![], pending: vec![] }
|
||||
}
|
||||
|
||||
pub fn scanned_height(&self) -> usize { self.db.scanned_height() }
|
||||
pub fn scanned_height(&self) -> usize {
|
||||
self.db.scanned_height()
|
||||
}
|
||||
pub fn acknowledge_height(&mut self, canonical: usize, height: usize) {
|
||||
self.db.acknowledge_height(canonical, height);
|
||||
if height > self.db.scanned_height() {
|
||||
@@ -261,9 +259,13 @@ impl<D: CoinDb, C: Coin> Wallet<D, C> {
|
||||
let block = self.coin.get_block(b).await?;
|
||||
for (keys, outputs) in self.keys.iter_mut() {
|
||||
outputs.extend(
|
||||
self.coin.get_outputs(&block, keys.group_key()).await.iter().cloned().filter(
|
||||
|output| self.db.add_output(output)
|
||||
)
|
||||
self
|
||||
.coin
|
||||
.get_outputs(&block, keys.group_key())
|
||||
.await
|
||||
.iter()
|
||||
.cloned()
|
||||
.filter(|output| self.db.add_output(output)),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -283,7 +285,7 @@ impl<D: CoinDb, C: Coin> Wallet<D, C> {
|
||||
&mut self,
|
||||
canonical: usize,
|
||||
payments: Vec<(C::Address, u64)>,
|
||||
fee: C::Fee
|
||||
fee: C::Fee,
|
||||
) -> Result<(Vec<(C::Address, u64)>, Vec<C::SignableTransaction>), CoinError> {
|
||||
if payments.len() == 0 {
|
||||
return Ok((vec![], vec![]));
|
||||
@@ -310,27 +312,18 @@ impl<D: CoinDb, C: Coin> Wallet<D, C> {
|
||||
|
||||
// Create the transcript for this transaction
|
||||
let mut transcript = RecommendedTranscript::new(b"Serai Processor Wallet Send");
|
||||
transcript.append_message(
|
||||
b"canonical_height",
|
||||
&u64::try_from(canonical).unwrap().to_le_bytes()
|
||||
);
|
||||
transcript
|
||||
.append_message(b"canonical_height", &u64::try_from(canonical).unwrap().to_le_bytes());
|
||||
transcript.append_message(
|
||||
b"acknowledged_height",
|
||||
&u64::try_from(acknowledged_height).unwrap().to_le_bytes()
|
||||
);
|
||||
transcript.append_message(
|
||||
b"index",
|
||||
&u64::try_from(txs.len()).unwrap().to_le_bytes()
|
||||
&u64::try_from(acknowledged_height).unwrap().to_le_bytes(),
|
||||
);
|
||||
transcript.append_message(b"index", &u64::try_from(txs.len()).unwrap().to_le_bytes());
|
||||
|
||||
let tx = self.coin.prepare_send(
|
||||
keys.clone(),
|
||||
transcript,
|
||||
acknowledged_height,
|
||||
inputs,
|
||||
&outputs,
|
||||
fee
|
||||
).await?;
|
||||
let tx = self
|
||||
.coin
|
||||
.prepare_send(keys.clone(), transcript, acknowledged_height, inputs, &outputs, fee)
|
||||
.await?;
|
||||
// self.db.save_tx(tx) // TODO
|
||||
txs.push(tx);
|
||||
}
|
||||
@@ -343,12 +336,10 @@ impl<D: CoinDb, C: Coin> Wallet<D, C> {
|
||||
&mut self,
|
||||
network: &mut N,
|
||||
prepared: C::SignableTransaction,
|
||||
included: Vec<u16>
|
||||
included: Vec<u16>,
|
||||
) -> Result<(Vec<u8>, Vec<<C::Output as Output>::Id>), SignError> {
|
||||
let attempt = self.coin.attempt_send(
|
||||
prepared,
|
||||
&included
|
||||
).await.map_err(|e| SignError::CoinError(e))?;
|
||||
let attempt =
|
||||
self.coin.attempt_send(prepared, &included).await.map_err(|e| SignError::CoinError(e))?;
|
||||
|
||||
let (attempt, commitments) = attempt.preprocess(&mut OsRng);
|
||||
let commitments = network.round(commitments).await.map_err(|e| SignError::NetworkError(e))?;
|
||||
|
||||
Reference in New Issue
Block a user