griffin_core/
checks_interface.rs

1//! Suplementary functions to perform ledger checks on Griffin transactions
2//! by using tools available in Pallas.
3//!
4//! Some of these functions were brought directly from Pallas since they belong
5//! to its test suit.
6use crate::pallas_applying::{utils::ValidationError, UTxOs};
7use crate::pallas_codec::minicbor::encode;
8use crate::pallas_codec::utils::{Bytes, CborWrap};
9use crate::pallas_primitives::{
10    alonzo::Value,
11    babbage::{
12        MintedDatumOption, MintedPostAlonzoTransactionOutput, MintedScriptRef,
13        MintedTransactionBody, MintedTransactionOutput, MintedTx as BabbageMintedTx,
14        PseudoTransactionOutput, Tx as BabbageTx,
15    },
16    conway::MintedTx as ConwayMintedTx,
17};
18use crate::pallas_traverse::{MultiEraInput, MultiEraOutput};
19use crate::types::{
20    value_leq, DispatchResult,
21    UTxOError::{self, *},
22};
23use alloc::{borrow::Cow, boxed::Box, string::String, vec::Vec};
24use core::iter::zip;
25
26/// Every output must contain this many `Coin`s.
27pub const MIN_COIN_PER_OUTPUT: crate::types::Coin = 10;
28
29impl From<ValidationError> for UTxOError {
30    /// Translation of Cardano's Babbage era errors to Griffin's.
31    fn from(err: ValidationError) -> UTxOError {
32        match err {
33            ValidationError::Babbage(err) => UTxOError::Babbage(err),
34            _ => Fail,
35        }
36    }
37}
38
39pub fn babbage_tx_to_cbor(tx: &BabbageTx) -> Vec<u8> {
40    let mut tx_buf: Vec<u8> = Vec::new();
41    let _ = encode(tx, &mut tx_buf);
42
43    tx_buf
44}
45
46pub fn babbage_minted_tx_from_cbor(tx_cbor: &[u8]) -> BabbageMintedTx<'_> {
47    crate::pallas_codec::minicbor::decode::<BabbageMintedTx>(&tx_cbor[..]).unwrap()
48}
49
50pub fn conway_minted_tx_from_cbor(tx_cbor: &[u8]) -> ConwayMintedTx<'_> {
51    crate::pallas_codec::minicbor::decode::<ConwayMintedTx>(&tx_cbor[..]).unwrap()
52}
53
54pub fn mk_utxo_for_babbage_tx<'a>(
55    tx_body: &MintedTransactionBody,
56    tx_outs_info: &'a [(
57        String, // address in string format
58        Value,
59        Option<MintedDatumOption>,
60        Option<CborWrap<MintedScriptRef>>,
61    )],
62) -> UTxOs<'a> {
63    let mut utxos: UTxOs = UTxOs::new();
64    for (tx_in, (addr, val, datum_opt, script_ref)) in zip(tx_body.inputs.clone(), tx_outs_info) {
65        let multi_era_in: MultiEraInput =
66            MultiEraInput::AlonzoCompatible(Box::new(Cow::Owned(tx_in)));
67        let address_bytes: Bytes = match hex::decode(addr) {
68            Ok(bytes_vec) => Bytes::from(bytes_vec),
69            _ => panic!("Unable to decode input address"),
70        };
71        let tx_out: MintedTransactionOutput =
72            PseudoTransactionOutput::PostAlonzo(MintedPostAlonzoTransactionOutput {
73                address: address_bytes,
74                value: val.clone(),
75                datum_option: datum_opt.clone(),
76                script_ref: script_ref.clone(),
77            });
78        let multi_era_out: MultiEraOutput = MultiEraOutput::Babbage(Box::new(Cow::Owned(tx_out)));
79        utxos.insert(multi_era_in, multi_era_out);
80    }
81
82    utxos
83}
84
85pub fn check_min_coin(tx_body: &MintedTransactionBody) -> DispatchResult {
86    use crate::pallas_applying::utils::BabbageError::MinLovelaceUnreached;
87
88    let min_reached: bool = tx_body.outputs.iter().all(|out| {
89        value_leq(
90            &crate::types::Value::Coin(MIN_COIN_PER_OUTPUT),
91            &<_>::from(match out {
92                PseudoTransactionOutput::PostAlonzo(pos) => pos.value.clone(),
93                _ => return false, // Legacy outputs should not be here!
94            }),
95        )
96    });
97    if min_reached {
98        Ok(())
99    } else {
100        Err(UTxOError::Babbage(MinLovelaceUnreached))
101    }
102}