mirror of
https://github.com/serai-dex/serai.git
synced 2025-01-23 19:15:59 +00:00
Transaction deserialization
This commit is contained in:
parent
aa5d95ef1d
commit
3282b19536
5 changed files with 140 additions and 21 deletions
|
@ -104,8 +104,8 @@ impl Bulletproofs {
|
||||||
T2: read_point(r)?,
|
T2: read_point(r)?,
|
||||||
taux: read_scalar(r)?,
|
taux: read_scalar(r)?,
|
||||||
mu: read_scalar(r)?,
|
mu: read_scalar(r)?,
|
||||||
L: read_vec(r, read_point)?,
|
L: read_vec(read_point, r)?,
|
||||||
R: read_vec(r, read_point)?,
|
R: read_vec(read_point, r)?,
|
||||||
a: read_scalar(r)?,
|
a: read_scalar(r)?,
|
||||||
b: read_scalar(r)?,
|
b: read_scalar(r)?,
|
||||||
t: read_scalar(r)?
|
t: read_scalar(r)?
|
||||||
|
|
|
@ -292,6 +292,16 @@ impl Clsag {
|
||||||
write_point(&self.D, w)
|
write_point(&self.D, w)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn deserialize<R: std::io::Read>(decoys: usize, r: &mut R) -> std::io::Result<Clsag> {
|
||||||
|
Ok(
|
||||||
|
Clsag {
|
||||||
|
s: read_raw_vec(read_scalar, decoys, r)?,
|
||||||
|
c1: read_scalar(r)?,
|
||||||
|
D: read_point(r)?
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn verify(
|
pub fn verify(
|
||||||
&self,
|
&self,
|
||||||
ring: &[[EdwardsPoint; 2]],
|
ring: &[[EdwardsPoint; 2]],
|
||||||
|
|
|
@ -9,7 +9,7 @@ use serde_json::json;
|
||||||
|
|
||||||
use reqwest;
|
use reqwest;
|
||||||
|
|
||||||
use crate::transaction::Transaction;
|
use crate::transaction::{Input, Transaction};
|
||||||
|
|
||||||
#[derive(Deserialize, Debug)]
|
#[derive(Deserialize, Debug)]
|
||||||
pub struct EmptyResponse {}
|
pub struct EmptyResponse {}
|
||||||
|
@ -115,24 +115,24 @@ impl Rpc {
|
||||||
Err(RpcError::TransactionsNotFound(txs.txs.len(), hashes.len()))?;
|
Err(RpcError::TransactionsNotFound(txs.txs.len(), hashes.len()))?;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
Ok(
|
Ok(
|
||||||
|
// Ignores transactions we fail to parse
|
||||||
txs.txs.iter().filter_map(
|
txs.txs.iter().filter_map(
|
||||||
|tx| rpc_hex(if tx.as_hex.len() != 0 { &tx.as_hex } else { &tx.pruned_as_hex }).ok()
|
|res| rpc_hex(if res.as_hex.len() != 0 { &res.as_hex } else { &res.pruned_as_hex }).ok()
|
||||||
.and_then(|mut bytes| Transaction::deserialize(&mut bytes).ok())
|
.and_then(|bytes| Transaction::deserialize(&mut std::io::Cursor::new(bytes)).ok())
|
||||||
// https://github.com/monero-project/monero/issues/8311
|
// https://github.com/monero-project/monero/issues/8311
|
||||||
.filter(
|
.filter(
|
||||||
if tx.as_hex.len() == 0 {
|
|tx| if res.as_hex.len() == 0 {
|
||||||
match res[res.len() - 1].prefix.inputs[0] {
|
match tx.prefix.inputs.get(0) {
|
||||||
Input::Gen { .. } => true,
|
Some(Input::Gen { .. }) => true,
|
||||||
_ => false
|
_ => false
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
true
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
)
|
).collect()
|
||||||
)
|
)
|
||||||
*/
|
|
||||||
Ok(vec![])
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -85,8 +85,7 @@ pub fn read_point<R: io::Read>(r: &mut R) -> io::Result<EdwardsPoint> {
|
||||||
).decompress().filter(|point| point.is_torsion_free()).ok_or(io::Error::new(io::ErrorKind::Other, "invalid point"))
|
).decompress().filter(|point| point.is_torsion_free()).ok_or(io::Error::new(io::ErrorKind::Other, "invalid point"))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn read_vec<R: io::Read, T, F: Fn(&mut R) -> io::Result<T>>(r: &mut R, f: F) -> io::Result<Vec<T>> {
|
pub fn read_raw_vec<R: io::Read, T, F: Fn(&mut R) -> io::Result<T>>(f: F, len: usize, r: &mut R) -> io::Result<Vec<T>> {
|
||||||
let len = read_varint(r)?;
|
|
||||||
let mut res = Vec::with_capacity(
|
let mut res = Vec::with_capacity(
|
||||||
len.try_into().map_err(|_| io::Error::new(io::ErrorKind::Other, "length exceeds usize"))?
|
len.try_into().map_err(|_| io::Error::new(io::ErrorKind::Other, "length exceeds usize"))?
|
||||||
);
|
);
|
||||||
|
@ -95,3 +94,7 @@ pub fn read_vec<R: io::Read, T, F: Fn(&mut R) -> io::Result<T>>(r: &mut R, f: F)
|
||||||
}
|
}
|
||||||
Ok(res)
|
Ok(res)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn read_vec<R: io::Read, T, F: Fn(&mut R) -> io::Result<T>>(f: F, r: &mut R) -> io::Result<Vec<T>> {
|
||||||
|
read_raw_vec(f, read_varint(r)?.try_into().unwrap(), r)
|
||||||
|
}
|
||||||
|
|
|
@ -32,6 +32,22 @@ impl Input {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn deserialize<R: std::io::Read>(r: &mut R) -> std::io::Result<Input> {
|
||||||
|
let mut variant = [0; 1];
|
||||||
|
r.read_exact(&mut variant)?;
|
||||||
|
Ok(
|
||||||
|
match variant[0] {
|
||||||
|
0 => Input::Gen(read_varint(r)?),
|
||||||
|
2 => Input::ToKey {
|
||||||
|
amount: read_varint(r)?,
|
||||||
|
key_offsets: read_vec(read_varint, r)?,
|
||||||
|
key_image: read_point(r)?
|
||||||
|
},
|
||||||
|
_ => Err(std::io::Error::new(std::io::ErrorKind::Other, "Tried to deserialize unknown/unused output type"))?
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Doesn't bother moving to an enum for the unused Script classes
|
// Doesn't bother moving to an enum for the unused Script classes
|
||||||
|
@ -51,6 +67,23 @@ impl Output {
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn deserialize<R: std::io::Read>(r: &mut R) -> std::io::Result<Output> {
|
||||||
|
let amount = read_varint(r)?;
|
||||||
|
let mut tag = [0; 1];
|
||||||
|
r.read_exact(&mut tag)?;
|
||||||
|
if (tag[0] != 2) && (tag[0] != 3) {
|
||||||
|
Err(std::io::Error::new(std::io::ErrorKind::Other, "Tried to deserialize unknown/unused output type"))?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(
|
||||||
|
Output {
|
||||||
|
amount,
|
||||||
|
key: read_point(r)?,
|
||||||
|
tag: if tag[0] == 3 { r.read_exact(&mut tag)?; Some(tag[0]) } else { None }
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct TransactionPrefix {
|
pub struct TransactionPrefix {
|
||||||
|
@ -70,6 +103,22 @@ impl TransactionPrefix {
|
||||||
write_varint(&self.extra.len().try_into().unwrap(), w)?;
|
write_varint(&self.extra.len().try_into().unwrap(), w)?;
|
||||||
w.write_all(&self.extra)
|
w.write_all(&self.extra)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn deserialize<R: std::io::Read>(r: &mut R) -> std::io::Result<TransactionPrefix> {
|
||||||
|
let mut prefix = TransactionPrefix {
|
||||||
|
version: read_varint(r)?,
|
||||||
|
unlock_time: read_varint(r)?,
|
||||||
|
inputs: read_vec(Input::deserialize, r)?,
|
||||||
|
outputs: read_vec(Output::deserialize, r)?,
|
||||||
|
extra: vec![]
|
||||||
|
};
|
||||||
|
|
||||||
|
let len = read_varint(r)?;
|
||||||
|
prefix.extra.resize(len.try_into().unwrap(), 0);
|
||||||
|
r.read_exact(&mut prefix.extra)?;
|
||||||
|
|
||||||
|
Ok(prefix)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct RctBase {
|
pub struct RctBase {
|
||||||
|
@ -87,6 +136,21 @@ impl RctBase {
|
||||||
}
|
}
|
||||||
write_raw_vec(write_point, &self.commitments, w)
|
write_raw_vec(write_point, &self.commitments, w)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn deserialize<R: std::io::Read>(outputs: usize, r: &mut R) -> std::io::Result<(RctBase, u8)> {
|
||||||
|
let mut rct_type = [0];
|
||||||
|
r.read_exact(&mut rct_type)?;
|
||||||
|
Ok((
|
||||||
|
RctBase {
|
||||||
|
fee: read_varint(r)?,
|
||||||
|
ecdh_info: (0 .. outputs).map(
|
||||||
|
|_| { let mut ecdh = [0; 8]; r.read_exact(&mut ecdh).map(|_| ecdh) }
|
||||||
|
).collect::<Result<_, _>>()?,
|
||||||
|
commitments: read_raw_vec(read_point, outputs, r)?
|
||||||
|
},
|
||||||
|
rct_type[0]
|
||||||
|
))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub enum RctPrunable {
|
pub enum RctPrunable {
|
||||||
|
@ -106,13 +170,6 @@ impl RctPrunable {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn signature_serialize<W: std::io::Write>(&self, w: &mut W) -> std::io::Result<()> {
|
|
||||||
match self {
|
|
||||||
RctPrunable::Null => panic!("Serializing RctPrunable::Null for a signature"),
|
|
||||||
RctPrunable::Clsag { bulletproofs, .. } => bulletproofs.iter().map(|bp| bp.signature_serialize(w)).collect(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn serialize<W: std::io::Write>(&self, w: &mut W) -> std::io::Result<()> {
|
pub fn serialize<W: std::io::Write>(&self, w: &mut W) -> std::io::Result<()> {
|
||||||
match self {
|
match self {
|
||||||
RctPrunable::Null => Ok(()),
|
RctPrunable::Null => Ok(()),
|
||||||
|
@ -123,6 +180,33 @@ impl RctPrunable {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn deserialize<R: std::io::Read>(
|
||||||
|
rct_type: u8,
|
||||||
|
decoys: &[usize],
|
||||||
|
outputs: usize,
|
||||||
|
r: &mut R
|
||||||
|
) -> std::io::Result<RctPrunable> {
|
||||||
|
Ok(
|
||||||
|
match rct_type {
|
||||||
|
0 => RctPrunable::Null,
|
||||||
|
5 => RctPrunable::Clsag {
|
||||||
|
// TODO: Can the amount of outputs be calculated from the BPs for any validly formed TX?
|
||||||
|
bulletproofs: read_vec(Bulletproofs::deserialize, r)?,
|
||||||
|
clsags: (0 .. decoys.len()).map(|o| Clsag::deserialize(decoys[o], r)).collect::<Result<_, _>>()?,
|
||||||
|
pseudo_outs: read_raw_vec(read_point, outputs, r)?
|
||||||
|
},
|
||||||
|
_ => Err(std::io::Error::new(std::io::ErrorKind::Other, "Tried to deserialize unknown RCT type"))?
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn signature_serialize<W: std::io::Write>(&self, w: &mut W) -> std::io::Result<()> {
|
||||||
|
match self {
|
||||||
|
RctPrunable::Null => panic!("Serializing RctPrunable::Null for a signature"),
|
||||||
|
RctPrunable::Clsag { bulletproofs, .. } => bulletproofs.iter().map(|bp| bp.signature_serialize(w)).collect(),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct RctSignatures {
|
pub struct RctSignatures {
|
||||||
|
@ -135,6 +219,11 @@ impl RctSignatures {
|
||||||
self.base.serialize(w, self.prunable.rct_type())?;
|
self.base.serialize(w, self.prunable.rct_type())?;
|
||||||
self.prunable.serialize(w)
|
self.prunable.serialize(w)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn deserialize<R: std::io::Read>(decoys: Vec<usize>, outputs: usize, r: &mut R) -> std::io::Result<RctSignatures> {
|
||||||
|
let base = RctBase::deserialize(outputs, r)?;
|
||||||
|
Ok(RctSignatures { base: base.0, prunable: RctPrunable::deserialize(base.1, &decoys, outputs, r)? })
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Transaction {
|
pub struct Transaction {
|
||||||
|
@ -148,6 +237,23 @@ impl Transaction {
|
||||||
self.rct_signatures.serialize(w)
|
self.rct_signatures.serialize(w)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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(
|
||||||
|
prefix.inputs.iter().map(|input| match input {
|
||||||
|
Input::Gen(_) => 0,
|
||||||
|
Input::ToKey { key_offsets, .. } => key_offsets.len()
|
||||||
|
}).collect(),
|
||||||
|
prefix.outputs.len(),
|
||||||
|
r
|
||||||
|
)?,
|
||||||
|
prefix
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn hash(&self) -> [u8; 32] {
|
pub fn hash(&self) -> [u8; 32] {
|
||||||
let mut serialized = Vec::with_capacity(2048);
|
let mut serialized = Vec::with_capacity(2048);
|
||||||
if self.prefix.version == 1 {
|
if self.prefix.version == 1 {
|
||||||
|
|
Loading…
Reference in a new issue