Files
serai/processor/monero/src/primitives/transaction.rs

138 lines
3.8 KiB
Rust
Raw Normal View History

2024-09-12 18:40:10 -04:00
use std::io;
use rand_core::{RngCore, CryptoRng};
use ciphersuite::Ed25519;
use frost::{dkg::ThresholdKeys, sign::PreprocessMachine};
use monero_wallet::{
transaction::Transaction as MTransaction,
send::{
SignableTransaction as MSignableTransaction, TransactionMachine, Eventuality as MEventuality,
},
};
use crate::output::OutputId;
#[derive(Clone, Debug)]
pub(crate) struct Transaction(pub(crate) MTransaction);
impl From<MTransaction> for Transaction {
fn from(tx: MTransaction) -> Self {
Self(tx)
}
}
impl scheduler::Transaction for Transaction {
fn read(reader: &mut impl io::Read) -> io::Result<Self> {
MTransaction::read(reader).map(Self)
}
fn write(&self, writer: &mut impl io::Write) -> io::Result<()> {
self.0.write(writer)
}
}
#[derive(Clone, Debug)]
pub(crate) struct SignableTransaction {
pub(crate) id: [u8; 32],
pub(crate) signable: MSignableTransaction,
2024-09-12 18:40:10 -04:00
}
#[derive(Clone)]
pub(crate) struct ClonableTransctionMachine(MSignableTransaction, ThresholdKeys<Ed25519>);
impl PreprocessMachine for ClonableTransctionMachine {
type Preprocess = <TransactionMachine as PreprocessMachine>::Preprocess;
type Signature = <TransactionMachine as PreprocessMachine>::Signature;
type SignMachine = <TransactionMachine as PreprocessMachine>::SignMachine;
fn preprocess<R: RngCore + CryptoRng>(
self,
rng: &mut R,
) -> (Self::SignMachine, Self::Preprocess) {
self.0.multisig(self.1).expect("incorrect keys used for SignableTransaction").preprocess(rng)
}
}
impl scheduler::SignableTransaction for SignableTransaction {
type Transaction = Transaction;
type Ciphersuite = Ed25519;
type PreprocessMachine = ClonableTransctionMachine;
fn read(reader: &mut impl io::Read) -> io::Result<Self> {
let mut id = [0; 32];
reader.read_exact(&mut id)?;
let signable = MSignableTransaction::read(reader)?;
Ok(SignableTransaction { id, signable })
}
fn write(&self, writer: &mut impl io::Write) -> io::Result<()> {
writer.write_all(&self.id)?;
self.signable.write(writer)
}
fn id(&self) -> [u8; 32] {
self.id
}
fn sign(self, keys: ThresholdKeys<Self::Ciphersuite>) -> Self::PreprocessMachine {
ClonableTransctionMachine(self.signable, keys)
}
}
#[derive(Clone, PartialEq, Eq, Debug)]
pub(crate) struct Eventuality {
pub(crate) id: [u8; 32],
pub(crate) singular_spent_output: Option<OutputId>,
pub(crate) eventuality: MEventuality,
2024-09-12 18:40:10 -04:00
}
impl primitives::Eventuality for Eventuality {
type OutputId = OutputId;
fn id(&self) -> [u8; 32] {
self.id
}
// We define the lookup as our ID since the resolving transaction only has a singular possible ID
fn lookup(&self) -> Vec<u8> {
self.eventuality.extra()
}
fn singular_spent_output(&self) -> Option<Self::OutputId> {
self.singular_spent_output
}
fn read(reader: &mut impl io::Read) -> io::Result<Self> {
let mut id = [0; 32];
reader.read_exact(&mut id)?;
let singular_spent_output = {
let mut singular_spent_output_opt = [0xff];
reader.read_exact(&mut singular_spent_output_opt)?;
assert!(singular_spent_output_opt[0] <= 1);
(singular_spent_output_opt[0] == 1)
.then(|| -> io::Result<_> {
let mut singular_spent_output = [0; 32];
reader.read_exact(&mut singular_spent_output)?;
Ok(OutputId(singular_spent_output))
})
.transpose()?
};
let eventuality = MEventuality::read(reader)?;
Ok(Self { id, singular_spent_output, eventuality })
}
fn write(&self, writer: &mut impl io::Write) -> io::Result<()> {
writer.write_all(&self.id)?;
if let Some(singular_spent_output) = self.singular_spent_output {
writer.write_all(&[1])?;
writer.write_all(singular_spent_output.as_ref())?;
} else {
writer.write_all(&[0])?;
}
self.eventuality.write(writer)
}
}