Only read transactions with one Input::Gen or all Input::ToKey

Also adds a helper to fetch a transaction's prefix.
This commit is contained in:
Luke Parker
2024-06-22 15:44:45 -04:00
parent 6fc8b30df2
commit df095f027f
2 changed files with 31 additions and 12 deletions

View File

@@ -84,12 +84,14 @@ impl Block {
/// structed as expected, this will return None. /// structed as expected, this will return None.
pub fn number(&self) -> Option<u64> { pub fn number(&self) -> Option<u64> {
match &self.miner_tx { match &self.miner_tx {
Transaction::V1 { prefix, .. } | Transaction::V2 { prefix, .. } => match prefix.inputs.first() { Transaction::V1 { prefix, .. } | Transaction::V2 { prefix, .. } => {
match prefix.inputs.first() {
Some(Input::Gen(number)) => Some(*number), Some(Input::Gen(number)) => Some(*number),
_ => None, _ => None,
} }
} }
} }
}
/// Write the Block. /// Write the Block.
pub fn write<W: Write>(&self, w: &mut W) -> io::Result<()> { pub fn write<W: Write>(&self, w: &mut W) -> io::Result<()> {

View File

@@ -301,6 +301,13 @@ pub enum Transaction {
} }
impl Transaction { impl Transaction {
/// Get the TransactionPrefix of this transaction.
pub fn prefix(&self) -> &TransactionPrefix {
match self {
Transaction::V1 { prefix, .. } | Transaction::V2 { prefix, .. } => prefix,
}
}
/// The weight of this Transaction, as relevant for fees. /// The weight of this Transaction, as relevant for fees.
// TODO: Replace ring_len, decoy_weights for &[&[usize]], where the inner buf is the decoy // TODO: Replace ring_len, decoy_weights for &[&[usize]], where the inner buf is the decoy
// offsets // offsets
@@ -318,6 +325,9 @@ impl Transaction {
} }
/// Write the Transaction. /// Write the Transaction.
///
/// Some writable transactions may not be readable if they're malformed, per Monero's consensus
/// rules.
pub fn write<W: Write>(&self, w: &mut W) -> io::Result<()> { pub fn write<W: Write>(&self, w: &mut W) -> io::Result<()> {
match self { match self {
Transaction::V1 { prefix, signatures } => { Transaction::V1 { prefix, signatures } => {
@@ -352,15 +362,22 @@ impl Transaction {
let prefix = TransactionPrefix::read(r, version)?; let prefix = TransactionPrefix::read(r, version)?;
if version == 1 { if version == 1 {
let signatures = prefix let signatures = if (prefix.inputs.len() == 1) && matches!(prefix.inputs[0], Input::Gen(_)) {
.inputs vec![]
.iter() } else {
.filter_map(|input| match input { let mut signatures = Vec::with_capacity(prefix.inputs.len());
// TODO: This allows mixing Gen and ToKey, which is likely undefined behavior? for input in &prefix.inputs {
Input::ToKey { key_offsets, .. } => Some(RingSignature::read(key_offsets.len(), r)), match input {
_ => None, Input::ToKey { key_offsets, .. } => {
}) signatures.push(RingSignature::read(key_offsets.len(), r)?)
.collect::<Result<_, _>>()?; }
_ => {
Err(io::Error::other("reading signatures for a transaction with non-ToKey inputs"))?
}
}
}
signatures
};
Ok(Transaction::V1 { prefix, signatures }) Ok(Transaction::V1 { prefix, signatures })
} else if version == 2 { } else if version == 2 {