mirror of
https://github.com/serai-dex/serai.git
synced 2024-12-23 12:09:37 +00:00
Correct RctPrunable decoding
This commit is contained in:
parent
882d67838e
commit
0c01ad69d8
2 changed files with 52 additions and 36 deletions
|
@ -28,8 +28,10 @@ pub enum RpcError {
|
||||||
TransactionsNotFound(usize, usize),
|
TransactionsNotFound(usize, usize),
|
||||||
#[error("invalid point ({0})")]
|
#[error("invalid point ({0})")]
|
||||||
InvalidPoint(String),
|
InvalidPoint(String),
|
||||||
#[error("invalid transaction")]
|
#[error("pruned transaction")]
|
||||||
InvalidTransaction
|
PrunedTransaction,
|
||||||
|
#[error("invalid transaction ({0:?})")]
|
||||||
|
InvalidTransaction([u8; 32])
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Rpc(String);
|
pub struct Rpc(String);
|
||||||
|
@ -119,24 +121,23 @@ impl Rpc {
|
||||||
Err(RpcError::TransactionsNotFound(txs.txs.len(), hashes.len()))?;
|
Err(RpcError::TransactionsNotFound(txs.txs.len(), hashes.len()))?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(
|
txs.txs.iter().enumerate().map(|(i, res)| {
|
||||||
// Ignores transactions we fail to parse
|
let tx = Transaction::deserialize(
|
||||||
txs.txs.iter().filter_map(
|
&mut std::io::Cursor::new(
|
||||||
|res| rpc_hex(if res.as_hex.len() != 0 { &res.as_hex } else { &res.pruned_as_hex }).ok()
|
rpc_hex(if res.as_hex.len() != 0 { &res.as_hex } else { &res.pruned_as_hex }).unwrap()
|
||||||
.and_then(|bytes| Transaction::deserialize(&mut std::io::Cursor::new(bytes)).ok())
|
)
|
||||||
// https://github.com/monero-project/monero/issues/8311
|
).map_err(|_| RpcError::InvalidTransaction(hashes[i]))?;
|
||||||
.filter(
|
|
||||||
|tx| if res.as_hex.len() == 0 {
|
// https://github.com/monero-project/monero/issues/8311
|
||||||
match tx.prefix.inputs.get(0) {
|
if res.as_hex.len() == 0 {
|
||||||
Some(Input::Gen { .. }) => true,
|
match tx.prefix.inputs.get(0) {
|
||||||
_ => false
|
Some(Input::Gen { .. }) => (),
|
||||||
}
|
_ => Err(RpcError::PrunedTransaction)?
|
||||||
} else {
|
}
|
||||||
true
|
}
|
||||||
}
|
|
||||||
)
|
Ok(tx)
|
||||||
).collect()
|
}).collect::<Result<_, _>>()
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn get_block(&self, height: usize) -> Result<Block, RpcError> {
|
pub async fn get_block(&self, height: usize) -> Result<Block, RpcError> {
|
||||||
|
@ -283,7 +284,7 @@ impl Rpc {
|
||||||
}))).await?;
|
}))).await?;
|
||||||
|
|
||||||
if res.status != "OK" {
|
if res.status != "OK" {
|
||||||
Err(RpcError::InvalidTransaction)?;
|
Err(RpcError::InvalidTransaction(tx.hash()))?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
|
@ -134,23 +134,33 @@ pub struct RctBase {
|
||||||
impl RctBase {
|
impl RctBase {
|
||||||
pub fn serialize<W: std::io::Write>(&self, w: &mut W, rct_type: u8) -> std::io::Result<()> {
|
pub fn serialize<W: std::io::Write>(&self, w: &mut W, rct_type: u8) -> std::io::Result<()> {
|
||||||
w.write_all(&[rct_type])?;
|
w.write_all(&[rct_type])?;
|
||||||
write_varint(&self.fee, w)?;
|
match rct_type {
|
||||||
for ecdh in &self.ecdh_info {
|
0 => Ok(()),
|
||||||
w.write_all(ecdh)?;
|
5 => {
|
||||||
|
write_varint(&self.fee, w)?;
|
||||||
|
for ecdh in &self.ecdh_info {
|
||||||
|
w.write_all(ecdh)?;
|
||||||
|
}
|
||||||
|
write_raw_vec(write_point, &self.commitments, w)
|
||||||
|
},
|
||||||
|
_ => panic!("Serializing unknown RctType's Base")
|
||||||
}
|
}
|
||||||
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)> {
|
pub fn deserialize<R: std::io::Read>(outputs: usize, r: &mut R) -> std::io::Result<(RctBase, u8)> {
|
||||||
let mut rct_type = [0];
|
let mut rct_type = [0];
|
||||||
r.read_exact(&mut rct_type)?;
|
r.read_exact(&mut rct_type)?;
|
||||||
Ok((
|
Ok((
|
||||||
RctBase {
|
if rct_type[0] == 0 {
|
||||||
fee: read_varint(r)?,
|
RctBase { fee: 0, ecdh_info: vec![], commitments: vec![] }
|
||||||
ecdh_info: (0 .. outputs).map(
|
} else {
|
||||||
|_| { let mut ecdh = [0; 8]; r.read_exact(&mut ecdh).map(|_| ecdh) }
|
RctBase {
|
||||||
).collect::<Result<_, _>>()?,
|
fee: read_varint(r)?,
|
||||||
commitments: read_raw_vec(read_point, outputs, 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]
|
rct_type[0]
|
||||||
))
|
))
|
||||||
|
@ -189,7 +199,6 @@ impl RctPrunable {
|
||||||
pub fn deserialize<R: std::io::Read>(
|
pub fn deserialize<R: std::io::Read>(
|
||||||
rct_type: u8,
|
rct_type: u8,
|
||||||
decoys: &[usize],
|
decoys: &[usize],
|
||||||
outputs: usize,
|
|
||||||
r: &mut R
|
r: &mut R
|
||||||
) -> std::io::Result<RctPrunable> {
|
) -> std::io::Result<RctPrunable> {
|
||||||
Ok(
|
Ok(
|
||||||
|
@ -199,7 +208,7 @@ impl RctPrunable {
|
||||||
// TODO: Can the amount of outputs be calculated from the BPs for any validly formed TX?
|
// TODO: Can the amount of outputs be calculated from the BPs for any validly formed TX?
|
||||||
bulletproofs: read_vec(Bulletproofs::deserialize, r)?,
|
bulletproofs: read_vec(Bulletproofs::deserialize, r)?,
|
||||||
clsags: (0 .. decoys.len()).map(|o| Clsag::deserialize(decoys[o], r)).collect::<Result<_, _>>()?,
|
clsags: (0 .. decoys.len()).map(|o| Clsag::deserialize(decoys[o], r)).collect::<Result<_, _>>()?,
|
||||||
pseudo_outs: read_raw_vec(read_point, outputs, r)?
|
pseudo_outs: read_raw_vec(read_point, decoys.len(), r)?
|
||||||
},
|
},
|
||||||
_ => Err(std::io::Error::new(std::io::ErrorKind::Other, "Tried to deserialize unknown RCT type"))?
|
_ => Err(std::io::Error::new(std::io::ErrorKind::Other, "Tried to deserialize unknown RCT type"))?
|
||||||
}
|
}
|
||||||
|
@ -228,7 +237,7 @@ impl RctSignatures {
|
||||||
|
|
||||||
pub fn deserialize<R: std::io::Read>(decoys: Vec<usize>, outputs: usize, r: &mut R) -> std::io::Result<RctSignatures> {
|
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)?;
|
let base = RctBase::deserialize(outputs, r)?;
|
||||||
Ok(RctSignatures { base: base.0, prunable: RctPrunable::deserialize(base.1, &decoys, outputs, r)? })
|
Ok(RctSignatures { base: base.0, prunable: RctPrunable::deserialize(base.1, &decoys, r)? })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -280,8 +289,14 @@ impl Transaction {
|
||||||
sig_hash.extend(hash(&serialized));
|
sig_hash.extend(hash(&serialized));
|
||||||
serialized.clear();
|
serialized.clear();
|
||||||
|
|
||||||
self.rct_signatures.prunable.serialize(&mut serialized).unwrap();
|
match self.rct_signatures.prunable {
|
||||||
sig_hash.extend(hash(&serialized));
|
RctPrunable::Null => serialized.resize(32, 0),
|
||||||
|
_ => {
|
||||||
|
self.rct_signatures.prunable.serialize(&mut serialized).unwrap();
|
||||||
|
serialized = hash(&serialized).to_vec();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sig_hash.extend(&serialized);
|
||||||
|
|
||||||
hash(&sig_hash)
|
hash(&sig_hash)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue