cardano_sdk/chain/
tx.rs

1use super::address::*;
2use super::certificate::{Certificates, Ed25519KeyHashes, UnitInterval};
3use super::coin::Coin;
4use super::common::*;
5use super::hash::*;
6use super::metadata::Metadata;
7use super::witness::TransactionWitness;
8use cbored::tagged::EncodedCBOR;
9use cbored::CborDataOf;
10use cbored::CborRepr;
11use cryptoxide::hashing::blake2b_256;
12use std::fmt;
13
14/// Fully formed Transaction, with the body and the associated witness
15///
16/// Only used to submit transaction to the nodes, doesn't appear
17/// on the chain format.
18///
19/// TODO: consider moving to the protocol side
20#[derive(Clone, Debug, CborRepr, PartialEq, Eq)]
21#[cborrepr(structure = "array")]
22pub struct Transaction {
23    pub body: SerializedTransactionBody,
24    pub witness: TransactionWitness,
25    pub is_valid: bool,
26    pub auxiliary_data: Nullable<Metadata>,
27}
28
29#[derive(Clone, CborRepr, PartialEq, Eq)]
30#[cborrepr(structure = "flat")]
31pub struct SerializedTransactionBody(CborDataOf<TransactionBody>);
32
33impl SerializedTransactionBody {
34    pub fn hash(&self) -> TxHash {
35        TxHash(blake2b_256(self.0.as_ref()))
36    }
37
38    pub fn unserialize(&self) -> TransactionBody {
39        self.0.unserialize()
40    }
41}
42
43impl AsRef<[u8]> for SerializedTransactionBody {
44    fn as_ref(&self) -> &[u8] {
45        self.0.as_ref()
46    }
47}
48
49impl fmt::Debug for SerializedTransactionBody {
50    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
51        write!(f, "{}", hex::encode(&self.0.as_ref()))
52    }
53}
54
55/// Transaction Body
56#[derive(Clone, Debug, CborRepr, PartialEq, Eq)]
57#[cborrepr(structure = "mapint", skipkey = 10, skipkey = 12)]
58pub struct TransactionBody {
59    #[cborrepr(mandatory)]
60    pub inputs: TransactionInputs,
61    #[cborrepr(mandatory)]
62    pub outputs: TransactionOutputs,
63    #[cborrepr(mandatory)]
64    pub fee: Coin,
65    pub ttl: Option<u64>,
66    pub certs: Option<Certificates>,
67    pub withdrawals: Option<Withdrawals>,
68    pub update: Option<AnyCbor>,
69    pub metadata_hash: Option<MetadataHash>,
70    pub validity_start_interval: Option<u64>,
71    pub mint: Option<Mint>,
72    pub script_data_hash: Option<ScriptDataHash>,
73    pub collateral: Option<TransactionInputs>,
74    pub required_signers: Option<Ed25519KeyHashes>,
75    pub network_id: Option<u8>,
76    pub collateral_return: Option<TransactionOutput>,
77    pub total_collateral: Option<Coin>,
78    pub reference_inputs: Option<TransactionInputs>,
79}
80
81impl TransactionBody {
82    pub fn serialize(&self) -> SerializedTransactionBody {
83        SerializedTransactionBody(CborDataOf::from(self))
84    }
85
86    pub fn hash(&self) -> TxHash {
87        TxHash(blake2b_256(&self.serialize().as_ref()))
88    }
89}
90
91#[derive(Clone, Copy, Debug, CborRepr, PartialEq, Eq, PartialOrd, Ord, Hash)]
92#[cborrepr(structure = "flat")]
93pub struct TxIndex(pub u64);
94
95#[derive(Clone, Debug, CborRepr, PartialEq, Eq)]
96#[cborrepr(structure = "array")]
97pub struct TransactionInput(pub TxHash, pub TxIndex);
98
99#[derive(Clone, Debug, PartialEq, Eq, CborRepr)]
100#[cborrepr(enumtype = "enumtype")]
101pub enum TransactionOutput {
102    #[cborrepr(cbortype = "array")]
103    V1(TransactionOutputV1),
104    #[cborrepr(cbortype = "map")]
105    V2(TransactionOutputV2),
106}
107
108#[derive(Clone, Debug, PartialEq, Eq, CborRepr)]
109#[cborrepr(structure = "array_lastopt")]
110pub struct TransactionOutputV1 {
111    pub address: SerializedAddress,
112    pub amount: TransactionOutputValue,
113    pub data_hash: Option<Bytes>,
114}
115
116#[derive(Clone, Debug, PartialEq, Eq, CborRepr)]
117#[cborrepr(structure = "mapint")]
118pub struct TransactionOutputV2 {
119    #[cborrepr(mandatory)]
120    pub address: SerializedAddress,
121    #[cborrepr(mandatory)]
122    pub amount: TransactionOutputValue,
123    pub datum: Option<Datum>,
124    pub script_ref: Option<EncodedCBOR>,
125}
126
127#[derive(Clone, Debug, CborRepr, PartialEq, Eq)]
128#[cborrepr(enumtype = "tagvariant")]
129pub enum Datum {
130    Hash(Bytes),
131    Inline(EncodedCBOR),
132}
133
134impl TransactionOutput {
135    pub fn value(&self) -> Coin {
136        match self {
137            TransactionOutput::V1(v) => v.value(),
138            TransactionOutput::V2(v) => v.value(),
139        }
140    }
141}
142
143impl TransactionOutputV1 {
144    pub fn value(&self) -> Coin {
145        self.amount.value()
146    }
147}
148
149impl TransactionOutputV2 {
150    pub fn value(&self) -> Coin {
151        self.amount.value()
152    }
153}
154
155#[derive(Clone, Debug, PartialEq, Eq, CborRepr)]
156#[cborrepr(enumtype = "enumtype")]
157pub enum TransactionOutputValue {
158    #[cborrepr(cbortype = "positive")]
159    OnlyCoin(Coin),
160    #[cborrepr(cbortype = "array")]
161    CoinAsset(CoinMultiasset),
162}
163
164impl TransactionOutputValue {
165    pub fn value(&self) -> Coin {
166        match self {
167            TransactionOutputValue::OnlyCoin(coin) => *coin,
168            TransactionOutputValue::CoinAsset(ca) => ca.coin,
169        }
170    }
171}
172
173#[derive(Clone, Debug, PartialEq, Eq, CborRepr)]
174#[cborrepr(structure = "array")]
175pub struct CoinMultiasset {
176    pub coin: Coin,
177    pub multiasset: Multiasset,
178}
179
180crate::map_structure!(Multiasset, Bytes, Assets);
181crate::map_structure!(Assets, Bytes, u64);
182crate::map_structure!(Withdrawals, Bytes, Coin);
183crate::map_structure!(Mint, ScriptHash, MintAssets);
184crate::map_structure!(MintAssets, Bytes, Number64);
185crate::map_structure!(CostModels, Language, Numbers64);
186crate::vec_structure!(TransactionInputs, TransactionInput);
187crate::vec_structure!(TransactionOutputs, TransactionOutput);
188crate::vec_structure!(TransactionBodies, SerializedTransactionBody);
189crate::vec_structure!(TxIndexes, TxIndex);
190crate::vec_structure!(ProtocolVersions, super::header::ProtocolVersion);
191
192#[derive(Clone, Debug, PartialEq, Eq, CborRepr, PartialOrd, Ord)]
193#[cborrepr(enumtype = "enumint")]
194pub enum Language {
195    PlutusV1,
196    PlutusV2,
197}
198
199impl TransactionOutputs {
200    pub fn iter_indexed(&self) -> impl Iterator<Item = (TxIndex, &TransactionOutput)> {
201        self.0
202            .iter()
203            .enumerate()
204            .map(|(idx, txo)| (TxIndex(idx as u64), txo))
205    }
206}
207
208#[derive(Clone, Debug, CborRepr, PartialEq, Eq)]
209#[cborrepr(structure = "mapint")]
210pub struct UpdateProtocolParam {
211    pub minfee_a: Option<Coin>,
212    pub minfee_b: Option<Coin>,
213    pub max_block_body_size: Option<u32>,
214    pub max_tx_size: Option<u32>,
215    pub max_block_header_size: Option<u32>,
216    pub key_deposit: Option<Coin>,
217    pub pool_deposit: Option<Coin>,
218    pub max_epoch: Option<u32>,
219    pub desired_stake_pools: Option<u32>,
220    pub pool_pledge_influence: Option<UnitInterval>,
221    pub expansion_rate: Option<UnitInterval>,
222    pub treasury_growth_rate: Option<UnitInterval>,
223    pub decentralization_d: Option<UnitInterval>,
224    pub extra_entropy: Option<AnyCbor>,
225    pub protocol_version: Option<ProtocolVersions>,
226    pub min_pool_cost: Option<Coin>,
227    pub ada_per_utxo_byte: Option<Coin>,
228    pub cost_models: Option<CostModels>,
229    pub execution_costs: Option<AnyCbor>,
230    pub max_tx_ex_units: Option<AnyCbor>,
231    pub max_block_ex_units: Option<AnyCbor>,
232    pub max_value_size: Option<u32>,
233    pub collateral_percentage: Option<u32>,
234    pub max_collateral_inputs: Option<u32>,
235}