Support v1 transactions

Closes https://github.com/serai-dex/serai/issues/117.
This commit is contained in:
Luke Parker 2022-09-28 05:28:42 -04:00
parent 5a4eb0a076
commit f48a48ec3f
No known key found for this signature in database
GPG key ID: F9F1386DB1E119B6
4 changed files with 55 additions and 9 deletions

View file

@ -195,6 +195,10 @@ impl Rpc {
.collect()
}
pub async fn get_transaction(&self, tx: [u8; 32]) -> Result<Transaction, RpcError> {
self.get_transactions(&[tx]).await.map(|mut txs| txs.swap_remove(0))
}
pub async fn get_block(&self, height: usize) -> Result<Block, RpcError> {
#[derive(Deserialize, Debug)]
struct BlockResponse {

View file

@ -94,7 +94,12 @@ pub(crate) fn read_varint<R: io::Read>(r: &mut R) -> io::Result<u64> {
Ok(res)
}
// TODO: https://github.com/serai-dex/serai/issues/25
// All scalar fields supported by monero-serai are checked to be canonical for valid transactions
// While from_bytes_mod_order would be more flexible, it's not currently needed and would be
// inaccurate to include now. While casting a wide net may be preferable, it'd also be inaccurate
// for now. There's also further edge cases as noted by
// https://github.com/monero-project/monero/issues/8438, where some scalars had an archaic
// reduction applied
pub(crate) fn read_scalar<R: io::Read>(r: &mut R) -> io::Result<Scalar> {
Scalar::from_canonical_bytes(read_bytes(r)?)
.ok_or_else(|| io::Error::new(io::ErrorKind::Other, "unreduced scalar"))

View file

@ -2,12 +2,15 @@ use core::cmp::Ordering;
use zeroize::Zeroize;
use curve25519_dalek::edwards::{EdwardsPoint, CompressedEdwardsY};
use curve25519_dalek::{
scalar::Scalar,
edwards::{EdwardsPoint, CompressedEdwardsY},
};
use crate::{
Protocol, hash,
serialize::*,
ringct::{RctPrunable, RctSignatures},
ringct::{RctBase, RctPrunable, RctSignatures},
};
#[derive(Clone, PartialEq, Eq, Debug)]
@ -189,6 +192,7 @@ impl TransactionPrefix {
#[derive(Clone, PartialEq, Eq, Debug)]
pub struct Transaction {
pub prefix: TransactionPrefix,
pub signatures: Vec<(Scalar, Scalar)>,
pub rct_signatures: RctSignatures,
}
@ -205,13 +209,42 @@ impl Transaction {
pub fn serialize<W: std::io::Write>(&self, w: &mut W) -> std::io::Result<()> {
self.prefix.serialize(w)?;
self.rct_signatures.serialize(w)
if self.prefix.version == 1 {
for sig in &self.signatures {
write_scalar(&sig.0, w)?;
write_scalar(&sig.1, w)?;
}
Ok(())
} else if self.prefix.version == 2 {
self.rct_signatures.serialize(w)
} else {
panic!("Serializing a transaction with an unknown version");
}
}
pub fn deserialize<R: std::io::Read>(r: &mut R) -> std::io::Result<Transaction> {
let prefix = TransactionPrefix::deserialize(r)?;
Ok(Transaction {
rct_signatures: RctSignatures::deserialize(
let mut signatures = vec![];
let mut rct_signatures = RctSignatures {
base: RctBase { fee: 0, ecdh_info: vec![], commitments: vec![] },
prunable: RctPrunable::Null,
};
if prefix.version == 1 {
for _ in 0 .. prefix.inputs.len() {
signatures.push((read_scalar(r)?, read_scalar(r)?));
}
rct_signatures.base.fee = prefix
.inputs
.iter()
.map(|input| match input {
Input::Gen(..) => 0,
Input::ToKey { amount, .. } => *amount,
})
.sum::<u64>()
.saturating_sub(prefix.outputs.iter().map(|output| output.amount).sum());
} else if prefix.version == 2 {
rct_signatures = RctSignatures::deserialize(
prefix
.inputs
.iter()
@ -222,9 +255,12 @@ impl Transaction {
.collect(),
prefix.outputs.len(),
r,
)?,
prefix,
})
)?;
} else {
Err(std::io::Error::new(std::io::ErrorKind::Other, "Tried to deserialize unknown version"))?;
}
Ok(Transaction { prefix, signatures, rct_signatures })
}
pub fn hash(&self) -> [u8; 32] {

View file

@ -334,6 +334,7 @@ impl SignableTransaction {
outputs: tx_outputs,
extra,
},
signatures: vec![],
rct_signatures: RctSignatures {
base: RctBase {
fee: self.fee,