fix: ignore duplicate consumed inputs (#257)
This commit is contained in:
parent
b78a0b3554
commit
a0cc1a5e47
4 changed files with 54 additions and 4 deletions
|
|
@ -138,6 +138,36 @@ mod tests {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_duplicate_consumed_inputs() {
|
||||||
|
let tx_bytecode_hex = include_str!("../../test_data/duplicateinput.tx");
|
||||||
|
let bytecode = hex::decode(tx_bytecode_hex).unwrap();
|
||||||
|
let tx = MultiEraTx::decode(Era::Alonzo, &bytecode).unwrap();
|
||||||
|
|
||||||
|
let expected_inputs = vec![
|
||||||
|
"4d9cb6bf1c2e349f1bcd454a632d2b721d5badcf687220430c316588f39506ab#1",
|
||||||
|
"4d9cb6bf1c2e349f1bcd454a632d2b721d5badcf687220430c316588f39506ab#1",
|
||||||
|
];
|
||||||
|
|
||||||
|
let inputs: Vec<String> = tx
|
||||||
|
.inputs()
|
||||||
|
.into_iter()
|
||||||
|
.map(|x| x.output_ref().to_string())
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
let expected_consumed =
|
||||||
|
vec!["4d9cb6bf1c2e349f1bcd454a632d2b721d5badcf687220430c316588f39506ab#1"];
|
||||||
|
|
||||||
|
let consumed: Vec<String> = tx
|
||||||
|
.consumes()
|
||||||
|
.into_iter()
|
||||||
|
.map(|x| x.output_ref().to_string())
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
assert_eq!(inputs, expected_inputs);
|
||||||
|
assert_eq!(consumed, expected_consumed);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_utxo_ref_parsing() {
|
fn test_utxo_ref_parsing() {
|
||||||
let valid_vectors = [
|
let valid_vectors = [
|
||||||
|
|
|
||||||
|
|
@ -135,7 +135,7 @@ pub enum MultiEraSigners<'b> {
|
||||||
AlonzoCompatible(&'b alonzo::RequiredSigners),
|
AlonzoCompatible(&'b alonzo::RequiredSigners),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone, Hash, PartialEq, Eq)]
|
||||||
pub struct OutputRef(Hash<32>, u64);
|
pub struct OutputRef(Hash<32>, u64);
|
||||||
|
|
||||||
#[derive(Debug, Error)]
|
#[derive(Debug, Error)]
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
use std::{borrow::Cow, ops::Deref};
|
use std::{borrow::Cow, collections::HashSet, ops::Deref};
|
||||||
|
|
||||||
use pallas_codec::{minicbor, utils::KeepRaw};
|
use pallas_codec::{minicbor, utils::KeepRaw};
|
||||||
use pallas_crypto::hash::Hash;
|
use pallas_crypto::hash::Hash;
|
||||||
|
|
@ -114,6 +114,10 @@ impl<'b> MultiEraTx<'b> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Return the transaction inputs
|
||||||
|
///
|
||||||
|
/// NOTE: It is possible for this to return duplicates. See
|
||||||
|
/// https://github.com/input-output-hk/cardano-ledger/commit/a342b74f5db3d3a75eae3e2abe358a169701b1e7
|
||||||
pub fn inputs(&self) -> Vec<MultiEraInput> {
|
pub fn inputs(&self) -> Vec<MultiEraInput> {
|
||||||
match self {
|
match self {
|
||||||
MultiEraTx::AlonzoCompatible(x, _) => x
|
MultiEraTx::AlonzoCompatible(x, _) => x
|
||||||
|
|
@ -137,6 +141,10 @@ impl<'b> MultiEraTx<'b> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Return the transaction reference inputs
|
||||||
|
///
|
||||||
|
/// NOTE: It is possible for this to return duplicates. See
|
||||||
|
/// https://github.com/input-output-hk/cardano-ledger/commit/a342b74f5db3d3a75eae3e2abe358a169701b1e7
|
||||||
pub fn reference_inputs(&self) -> Vec<MultiEraInput> {
|
pub fn reference_inputs(&self) -> Vec<MultiEraInput> {
|
||||||
match self {
|
match self {
|
||||||
MultiEraTx::Babbage(x) => x
|
MultiEraTx::Babbage(x) => x
|
||||||
|
|
@ -192,6 +200,10 @@ impl<'b> MultiEraTx<'b> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Return the transaction collateral inputs
|
||||||
|
///
|
||||||
|
/// NOTE: It is possible for this to return duplicates. See
|
||||||
|
/// https://github.com/input-output-hk/cardano-ledger/commit/a342b74f5db3d3a75eae3e2abe358a169701b1e7
|
||||||
pub fn collateral(&self) -> Vec<MultiEraInput> {
|
pub fn collateral(&self) -> Vec<MultiEraInput> {
|
||||||
match self {
|
match self {
|
||||||
MultiEraTx::AlonzoCompatible(x, _) => x
|
MultiEraTx::AlonzoCompatible(x, _) => x
|
||||||
|
|
@ -230,10 +242,17 @@ impl<'b> MultiEraTx<'b> {
|
||||||
/// will return the list of inputs. If the tx is invalid, it will return the
|
/// will return the list of inputs. If the tx is invalid, it will return the
|
||||||
/// collateral.
|
/// collateral.
|
||||||
pub fn consumes(&self) -> Vec<MultiEraInput> {
|
pub fn consumes(&self) -> Vec<MultiEraInput> {
|
||||||
match self.is_valid() {
|
let consumed = match self.is_valid() {
|
||||||
true => self.inputs(),
|
true => self.inputs(),
|
||||||
false => self.collateral(),
|
false => self.collateral(),
|
||||||
}
|
};
|
||||||
|
|
||||||
|
let mut unique_consumed = HashSet::new();
|
||||||
|
|
||||||
|
consumed
|
||||||
|
.into_iter()
|
||||||
|
.filter(|i| unique_consumed.insert(i.output_ref()))
|
||||||
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns a list of tuples of the outputs produced by the Tx with their
|
/// Returns a list of tuples of the outputs produced by the Tx with their
|
||||||
|
|
|
||||||
1
test_data/duplicateinput.tx
Normal file
1
test_data/duplicateinput.tx
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
84a400828258204d9cb6bf1c2e349f1bcd454a632d2b721d5badcf687220430c316588f39506ab018258204d9cb6bf1c2e349f1bcd454a632d2b721d5badcf687220430c316588f39506ab010182825839018b038a44ef966d2140c923636cea9a2a5a5db4a003c75773d95b3a2562afd01de43f13aadf7a78b27a1b836603906002ebef9963f90fc8ff1a00493e0082583901e25497038dd6d9413e3e43bbe14730130856a2a5b5e08643fc7be1cb62afd01de43f13aadf7a78b27a1b836603906002ebef9963f90fc8ff1a00eaa588021a000f4240031a033dd1fca10081825820565ede44b1980b00a8d02e09887491cb873d691f675a8715e4a0a101154872b958404164058a3e2f5ce9a2582dc8eed0259d29a7cc3bb0ab3d38d1ca219c9a5a5e32a32f798dc59ad680c53e59b04cc60a688b90c30535c93dfae38561da639d710af5f6
|
||||||
Loading…
Add table
Add a link
Reference in a new issue