Acknowledge Substrate's ordering and move to a multi-key wallet setup

This commit is contained in:
Luke Parker
2022-06-01 03:30:57 -04:00
parent d8e794871c
commit df2876dbd4
5 changed files with 135 additions and 46 deletions

View File

@@ -1,24 +1,30 @@
use async_trait::async_trait;
use rand_core::{RngCore, CryptoRng};
use curve25519_dalek::scalar::Scalar;
use curve25519_dalek::{scalar::Scalar, edwards::CompressedEdwardsY};
use dalek_ff_group as dfg;
use frost::MultisigKeys;
use monero::util::address::Address;
use monero_serai::{frost::Ed25519, rpc::Rpc, wallet::{SpendableOutput, SignableTransaction}};
use monero_serai::{
frost::Ed25519,
transaction::Transaction,
rpc::Rpc,
wallet::{SpendableOutput, SignableTransaction}
};
use crate::{Output as OutputTrait, CoinError, Coin, view_key};
pub struct Output(SpendableOutput);
impl OutputTrait for Output {
// If Monero ever does support more than 255 outputs at once, which it could, this u8 could be a
// u16 which serializes as little endian, dropping the last byte if empty, without conflict
type Id = ([u8; 32], u8);
// While we could use (tx, o), using the key ensures we won't be susceptible to the burning bug.
// While the Monero library offers a variant which allows senders to ensure their TXs have unique
// output keys, Serai can still be targeted using the classic burning bug
type Id = CompressedEdwardsY;
fn id(&self) -> Self::Id {
(self.0.tx, self.0.o.try_into().unwrap())
self.0.key.compress()
}
fn amount(&self) -> u64 {
@@ -59,34 +65,32 @@ impl Coin for Monero {
type Curve = Ed25519;
type Output = Output;
type Block = Vec<Transaction>;
type SignableTransaction = SignableTransaction;
type Address = Address;
fn id() -> &'static [u8] { b"Monero" }
async fn confirmations() -> usize { 10 }
fn confirmations() -> usize { 10 }
// Testnet TX bb4d188a4c571f2f0de70dca9d475abc19078c10ffa8def26dd4f63ce1bcfd79 uses 146 inputs
// while using less than 100kb of space, albeit with just 2 outputs (though outputs share a BP)
// The TX size limit is half the contextual median block weight, where said weight is >= 300,000
// This means any TX which fits into 150kb will be accepted by Monero
// 128, even with 16 outputs, should fit into 100kb. Further efficiency by 192 may be viable
// TODO: Get hard numbers and tune
async fn max_inputs() -> usize { 128 }
async fn max_outputs() -> usize { 16 }
fn max_inputs() -> usize { 128 }
fn max_outputs() -> usize { 16 }
async fn get_height(&self) -> Result<usize, CoinError> {
self.rpc.get_height().await.map_err(|_| CoinError::ConnectionError)
}
async fn get_outputs_in_block(
&self,
height: usize,
key: dfg::EdwardsPoint
) -> Result<Vec<Self::Output>, CoinError> {
Ok(
self.rpc.get_block_transactions_possible(height).await.map_err(|_| CoinError::ConnectionError)?
.iter().flat_map(|tx| tx.scan(self.view, key.0)).map(Output::from).collect()
)
async fn get_block(&self, height: usize) -> Result<Self::Block, CoinError> {
self.rpc.get_block_transactions_possible(height).await.map_err(|_| CoinError::ConnectionError)
}
async fn get_outputs(&self, block: &Self::Block, key: dfg::EdwardsPoint) -> Vec<Self::Output> {
block.iter().flat_map(|tx| tx.scan(self.view, key.0)).map(Output::from).collect()
}
async fn prepare_send<R: RngCore + CryptoRng>(