Skip to main content

pallas_validate/
utils.rs

1//! Base types used for validating transactions in each era.
2
3pub mod environment;
4pub mod validation;
5
6pub use environment::*;
7use pallas_addresses::{Address, ShelleyAddress, ShelleyPaymentPart};
8use pallas_codec::{
9    minicbor::encode,
10    utils::{Bytes, Nullable},
11};
12use pallas_crypto::key::ed25519::{PublicKey, Signature};
13use pallas_primitives::{
14    alonzo::{Multiasset, NativeScript, Tx as AlonzoTx, VKeyWitness, Value},
15    babbage::Tx as BabbageTx,
16    conway::{Multiasset as ConwayMultiasset, Tx as ConwayTx, Value as ConwayValue},
17    AddrKeyhash, AssetName, Coin, Epoch, GenesisDelegateHash, Genesishash, Hash, NetworkId,
18    NonZeroInt, PlutusScript, PolicyId, PoolKeyhash, PoolMetadata, PositiveCoin, Relay,
19    RewardAccount, StakeCredential, TransactionIndex, UnitInterval, VrfKeyhash,
20};
21
22use pallas_traverse::{time::Slot, Era, MultiEraInput, MultiEraOutput, MultiEraUpdate};
23use serde::{Deserialize, Serialize};
24use std::collections::{HashMap, HashSet};
25use std::ops::Deref;
26pub use validation::*;
27
28pub type TxHash = Hash<32>;
29pub type TxoIdx = u32;
30
31#[derive(Debug, Eq, PartialEq, Clone)]
32pub struct EraCbor(pub Era, pub Vec<u8>);
33
34impl From<(Era, Vec<u8>)> for EraCbor {
35    fn from(value: (Era, Vec<u8>)) -> Self {
36        Self(value.0, value.1)
37    }
38}
39
40impl From<EraCbor> for (Era, Vec<u8>) {
41    fn from(value: EraCbor) -> Self {
42        (value.0, value.1)
43    }
44}
45
46impl From<MultiEraOutput<'_>> for EraCbor {
47    fn from(value: MultiEraOutput<'_>) -> Self {
48        EraCbor(value.era(), value.encode())
49    }
50}
51
52impl<'a> TryFrom<&'a EraCbor> for MultiEraOutput<'a> {
53    type Error = pallas_codec::minicbor::decode::Error;
54
55    fn try_from(value: &'a EraCbor) -> Result<Self, Self::Error> {
56        MultiEraOutput::decode(value.0, &value.1)
57    }
58}
59
60impl TryFrom<EraCbor> for MultiEraUpdate<'_> {
61    type Error = pallas_codec::minicbor::decode::Error;
62
63    fn try_from(value: EraCbor) -> Result<Self, Self::Error> {
64        MultiEraUpdate::decode_for_era(value.0, &value.1)
65    }
66}
67
68pub type UtxoBody<'a> = MultiEraOutput<'a>;
69
70#[derive(Debug, Eq, PartialEq, Hash, Clone, Serialize, Deserialize)]
71pub struct TxoRef(pub TxHash, pub TxoIdx);
72
73impl From<(TxHash, TxoIdx)> for TxoRef {
74    fn from(value: (TxHash, TxoIdx)) -> Self {
75        Self(value.0, value.1)
76    }
77}
78
79impl From<TxoRef> for (TxHash, TxoIdx) {
80    fn from(value: TxoRef) -> Self {
81        (value.0, value.1)
82    }
83}
84
85impl From<&MultiEraInput<'_>> for TxoRef {
86    fn from(value: &MultiEraInput<'_>) -> Self {
87        TxoRef(*value.hash(), value.index() as u32)
88    }
89}
90
91pub type UtxoMap = HashMap<TxoRef, EraCbor>;
92
93pub type UtxoSet = HashSet<TxoRef>;
94
95pub type UTxOs<'b> = HashMap<MultiEraInput<'b>, MultiEraOutput<'b>>;
96
97pub fn get_alonzo_comp_tx_size(mtx: &AlonzoTx) -> u32 {
98    match &mtx.auxiliary_data {
99        Nullable::Some(aux_data) => {
100            (aux_data.raw_cbor().len()
101                + mtx.transaction_body.raw_cbor().len()
102                + mtx.transaction_witness_set.raw_cbor().len()) as u32
103        }
104        _ => {
105            (mtx.transaction_body.raw_cbor().len() + mtx.transaction_witness_set.raw_cbor().len())
106                as u32
107        }
108    }
109}
110
111pub fn get_babbage_tx_size(mtx: &BabbageTx) -> Option<u32> {
112    let mut buff: Vec<u8> = Vec::new();
113    match encode(mtx, &mut buff) {
114        Ok(()) => Some(buff.len() as u32),
115        Err(_) => None,
116    }
117}
118
119pub fn get_conway_tx_size(mtx: &ConwayTx) -> Option<u32> {
120    let mut buff: Vec<u8> = Vec::new();
121    match encode(mtx, &mut buff) {
122        Ok(()) => Some(buff.len() as u32),
123        Err(_) => None,
124    }
125}
126
127pub fn empty_value() -> Value {
128    Value::Multiasset(0, std::collections::BTreeMap::new())
129}
130
131pub fn add_values(
132    first: &Value,
133    second: &Value,
134    err: &ValidationError,
135) -> Result<Value, ValidationError> {
136    match (first, second) {
137        (Value::Coin(f), Value::Coin(s)) => Ok(Value::Coin(f + s)),
138        (Value::Multiasset(f, fma), Value::Coin(s)) => Ok(Value::Multiasset(f + s, fma.clone())),
139        (Value::Coin(f), Value::Multiasset(s, sma)) => Ok(Value::Multiasset(f + s, sma.clone())),
140        (Value::Multiasset(f, fma), Value::Multiasset(s, sma)) => Ok(Value::Multiasset(
141            f + s,
142            coerce_to_coin(
143                &add_multiasset_values(&coerce_to_i64(fma), &coerce_to_i64(sma)),
144                err,
145            )?,
146        )),
147    }
148}
149
150pub fn conway_add_values(
151    first: &ConwayValue,
152    second: &ConwayValue,
153    err: &ValidationError,
154) -> Result<ConwayValue, ValidationError> {
155    match (first, second) {
156        (ConwayValue::Coin(f), ConwayValue::Coin(s)) => Ok(ConwayValue::Coin(f + s)),
157        (ConwayValue::Multiasset(f, fma), ConwayValue::Coin(s)) => {
158            Ok(ConwayValue::Multiasset(f + s, fma.clone()))
159        }
160        (ConwayValue::Coin(f), ConwayValue::Multiasset(s, sma)) => {
161            Ok(ConwayValue::Multiasset(f + s, sma.clone()))
162        }
163        (ConwayValue::Multiasset(f, fma), ConwayValue::Multiasset(s, sma)) => {
164            Ok(ConwayValue::Multiasset(
165                f + s,
166                conway_coerce_to_coin(
167                    &conway_add_multiasset_values(&coerce_to_u64(fma), &coerce_to_u64(sma)),
168                    err,
169                )?,
170            ))
171        }
172    }
173}
174
175pub fn lovelace_diff_or_fail(
176    first: &Value,
177    second: &Value,
178    err: &ValidationError,
179) -> Result<u64, ValidationError> {
180    match (first, second) {
181        (Value::Coin(f), Value::Coin(s)) => {
182            if f >= s {
183                Ok(f - s)
184            } else {
185                Err(err.clone())
186            }
187        }
188        (Value::Coin(_), Value::Multiasset(_, _)) => Err(err.clone()),
189        (Value::Multiasset(f, fma), Value::Coin(s)) => {
190            if f >= s && fma.is_empty() {
191                Ok(f - s)
192            } else {
193                Err(err.clone())
194            }
195        }
196        (Value::Multiasset(f, fma), Value::Multiasset(s, sma)) => {
197            if f >= s && multi_assets_are_equal(fma, sma) {
198                Ok(f - s)
199            } else {
200                Err(err.clone())
201            }
202        }
203    }
204}
205
206pub fn conway_lovelace_diff_or_fail(
207    first: &ConwayValue,
208    second: &ConwayValue,
209    err: &ValidationError,
210) -> Result<u64, ValidationError> {
211    match (first, second) {
212        (ConwayValue::Coin(f), ConwayValue::Coin(s)) => {
213            if f >= s {
214                Ok(f - s)
215            } else {
216                Err(err.clone())
217            }
218        }
219        (ConwayValue::Coin(_), ConwayValue::Multiasset(_, _)) => Err(err.clone()),
220        (ConwayValue::Multiasset(f, fma), ConwayValue::Coin(s)) => {
221            if f >= s && fma.is_empty() {
222                Ok(f - s)
223            } else {
224                Err(err.clone())
225            }
226        }
227        (ConwayValue::Multiasset(f, fma), ConwayValue::Multiasset(s, sma)) => {
228            if f >= s && conway_multi_assets_are_equal(fma, sma) {
229                Ok(f - s)
230            } else {
231                Err(err.clone())
232            }
233        }
234    }
235}
236
237pub fn multi_assets_are_equal(fma: &Multiasset<Coin>, sma: &Multiasset<Coin>) -> bool {
238    multi_asset_included(fma, sma) && multi_asset_included(sma, fma)
239}
240pub fn conway_multi_assets_are_equal(
241    fma: &ConwayMultiasset<PositiveCoin>,
242    sma: &ConwayMultiasset<PositiveCoin>,
243) -> bool {
244    conway_multi_asset_included(fma, sma) && conway_multi_asset_included(sma, fma)
245}
246
247pub fn multi_asset_included(fma: &Multiasset<Coin>, sma: &Multiasset<Coin>) -> bool {
248    for (fpolicy, fassets) in fma.iter() {
249        match find_policy(sma, fpolicy) {
250            Some(sassets) => {
251                for (fasset_name, famount) in fassets.iter() {
252                    // Discard the case where there is 0 of an asset
253                    if *famount != 0 {
254                        match find_assets(&sassets, fasset_name) {
255                            Some(samount) => {
256                                if *famount != samount {
257                                    return false;
258                                }
259                            }
260                            None => return false,
261                        };
262                    }
263                }
264            }
265            None => return false,
266        }
267    }
268    true
269}
270
271pub fn conway_multi_asset_included(
272    fma: &ConwayMultiasset<PositiveCoin>,
273    sma: &ConwayMultiasset<PositiveCoin>,
274) -> bool {
275    for (fpolicy, fassets) in fma.iter() {
276        match conway_find_policy(sma, fpolicy) {
277            Some(sassets) => {
278                for (fasset_name, famount) in fassets.iter() {
279                    // Discard the case where there is 0 of an asset
280                    if *famount >= PositiveCoin::try_from(1).unwrap() {
281                        match conway_find_assets(&sassets, fasset_name) {
282                            Some(samount) => {
283                                if *famount != samount {
284                                    return false;
285                                }
286                            }
287                            None => return false,
288                        };
289                    }
290                }
291            }
292            None => return false,
293        }
294    }
295    true
296}
297
298pub fn add_minted_value(
299    base_value: &Value,
300    minted_value: &Multiasset<i64>,
301    err: &ValidationError,
302) -> Result<Value, ValidationError> {
303    match base_value {
304        Value::Coin(n) => Ok(Value::Multiasset(*n, coerce_to_coin(minted_value, err)?)),
305        Value::Multiasset(n, mary_base_value) => Ok(Value::Multiasset(
306            *n,
307            coerce_to_coin(
308                &add_multiasset_values(&coerce_to_i64(mary_base_value), minted_value),
309                err,
310            )?,
311        )),
312    }
313}
314pub fn conway_add_minted_value(
315    base_value: &ConwayValue,
316    minted_value: &ConwayMultiasset<u64>,
317    err: &ValidationError,
318) -> Result<ConwayValue, ValidationError> {
319    match base_value {
320        ConwayValue::Coin(n) => Ok(ConwayValue::Multiasset(
321            *n,
322            conway_coerce_to_coin(minted_value, err)?,
323        )),
324        ConwayValue::Multiasset(n, mary_base_value) => Ok(ConwayValue::Multiasset(
325            *n,
326            conway_coerce_to_coin(
327                &conway_add_multiasset_values(&coerce_to_u64(mary_base_value), minted_value),
328                err,
329            )?,
330        )),
331    }
332}
333
334pub fn conway_add_minted_non_zero(
335    base_value: &ConwayValue,
336    minted_value: &ConwayMultiasset<NonZeroInt>,
337    err: &ValidationError,
338) -> Result<ConwayValue, ValidationError> {
339    match base_value {
340        ConwayValue::Coin(n) => Ok(ConwayValue::Multiasset(
341            *n,
342            conway_coerce_to_non_zero_coin(minted_value, err)?,
343        )),
344        ConwayValue::Multiasset(n, mary_base_value) => Ok(ConwayValue::Multiasset(
345            *n,
346            conway_coerce_to_coin(
347                &conway_add_multiasset_non_negative_values(
348                    &coerce_to_u64(mary_base_value),
349                    minted_value,
350                )?,
351                err,
352            )?,
353        )),
354    }
355}
356
357fn coerce_to_i64(value: &Multiasset<Coin>) -> Multiasset<i64> {
358    let mut res: Vec<(PolicyId, _)> = Vec::new();
359    for (policy, assets) in value.iter() {
360        let mut aa: Vec<(AssetName, i64)> = Vec::new();
361        for (asset_name, amount) in assets.iter() {
362            aa.push((asset_name.clone(), *amount as i64));
363        }
364        res.push((*policy, aa.into_iter().collect()));
365    }
366    res.into_iter().collect()
367}
368
369fn coerce_to_u64(value: &ConwayMultiasset<PositiveCoin>) -> ConwayMultiasset<u64> {
370    let mut res: Vec<(PolicyId, _)> = Vec::new();
371    for (policy, assets) in value.iter() {
372        let mut aa: Vec<(AssetName, u64)> = Vec::new();
373        for (asset_name, amount) in assets.iter() {
374            aa.push((asset_name.clone(), (*amount).into()));
375        }
376        res.push((*policy, aa.into_iter().collect()));
377    }
378    res.into_iter().collect()
379}
380
381fn coerce_to_coin(
382    value: &Multiasset<i64>,
383    _err: &ValidationError,
384) -> Result<Multiasset<Coin>, ValidationError> {
385    let mut res: Vec<(PolicyId, _)> = Vec::new();
386    for (policy, assets) in value.iter() {
387        let mut aa: Vec<(AssetName, Coin)> = Vec::new();
388        for (asset_name, amount) in assets.iter() {
389            aa.push((asset_name.clone(), *amount as u64));
390        }
391        res.push((*policy, aa.into_iter().collect()));
392    }
393    Ok(res.into_iter().collect())
394}
395
396fn conway_coerce_to_coin(
397    value: &ConwayMultiasset<u64>,
398    _err: &ValidationError,
399) -> Result<ConwayMultiasset<PositiveCoin>, ValidationError> {
400    let mut res: Vec<(PolicyId, _)> = Vec::new();
401    for (policy, assets) in value.iter() {
402        let mut aa: Vec<(AssetName, PositiveCoin)> = Vec::new();
403        for (asset_name, amount) in assets.iter() {
404            aa.push((asset_name.clone(), PositiveCoin::try_from(*amount).unwrap()));
405        }
406        res.push((*policy, aa.into_iter().collect()));
407    }
408    Ok(res.into_iter().collect())
409}
410
411fn conway_coerce_to_non_zero_coin(
412    value: &ConwayMultiasset<NonZeroInt>,
413    _err: &ValidationError,
414) -> Result<ConwayMultiasset<PositiveCoin>, ValidationError> {
415    let mut res: Vec<(PolicyId, _)> = Vec::new();
416    for (policy, assets) in value.iter() {
417        let mut aa: Vec<(AssetName, PositiveCoin)> = Vec::new();
418        for (asset_name, amount) in assets.iter() {
419            aa.push((
420                asset_name.clone(),
421                PositiveCoin::try_from(i64::from(amount) as u64).unwrap(),
422            ));
423        }
424        res.push((*policy, aa.into_iter().collect()));
425    }
426    Ok(res.into_iter().collect())
427}
428
429fn add_multiasset_values(first: &Multiasset<i64>, second: &Multiasset<i64>) -> Multiasset<i64> {
430    let mut res: HashMap<PolicyId, HashMap<AssetName, i64>> = HashMap::new();
431    for (policy, new_assets) in first.iter() {
432        match res.get(policy) {
433            Some(old_assets) => res.insert(*policy, add_same_policy_assets(old_assets, new_assets)),
434            None => res.insert(*policy, add_same_policy_assets(&HashMap::new(), new_assets)),
435        };
436    }
437    for (policy, new_assets) in second.iter() {
438        match res.get(policy) {
439            Some(old_assets) => res.insert(*policy, add_same_policy_assets(old_assets, new_assets)),
440            None => res.insert(*policy, add_same_policy_assets(&HashMap::new(), new_assets)),
441        };
442    }
443    wrap_multiasset(res)
444}
445
446fn conway_add_multiasset_values<T>(
447    first: &ConwayMultiasset<T>,
448    second: &ConwayMultiasset<T>,
449) -> ConwayMultiasset<T>
450where
451    T: std::ops::Add<Output = T> + Copy,
452{
453    let mut res: HashMap<PolicyId, HashMap<AssetName, T>> = HashMap::new();
454
455    for (policy, new_assets) in first.iter() {
456        match res.get(policy) {
457            Some(old_assets) => res.insert(
458                *policy,
459                conway_add_same_policy_assets(old_assets, new_assets),
460            ),
461            None => res.insert(
462                *policy,
463                conway_add_same_policy_assets(&HashMap::new(), new_assets),
464            ),
465        };
466    }
467    for (policy, new_assets) in second.iter() {
468        match res.get(policy) {
469            Some(old_assets) => res.insert(
470                *policy,
471                conway_add_same_policy_assets(old_assets, new_assets),
472            ),
473            None => res.insert(
474                *policy,
475                conway_add_same_policy_assets(&HashMap::new(), new_assets),
476            ),
477        };
478    }
479    conway_wrap_multiasset(res)
480}
481
482fn conway_add_multiasset_non_negative_values(
483    first: &ConwayMultiasset<u64>,
484    second: &ConwayMultiasset<NonZeroInt>,
485) -> Result<ConwayMultiasset<u64>, ValidationError> {
486    let mut res: HashMap<PolicyId, HashMap<AssetName, u64>> = HashMap::new();
487
488    for (policy, new_assets) in first.iter() {
489        match res.get(policy) {
490            Some(old_assets) => res.insert(
491                *policy,
492                conway_add_same_policy_assets(old_assets, new_assets),
493            ),
494            None => res.insert(
495                *policy,
496                conway_add_same_policy_assets(&HashMap::new(), new_assets),
497            ),
498        };
499    }
500
501    for (policy, new_assets) in second.iter() {
502        match res.get(policy) {
503            Some(old_assets) => res.insert(
504                *policy,
505                conway_add_same_non_zero_policy_assets(old_assets, new_assets)?,
506            ),
507            None => res.insert(
508                *policy,
509                conway_add_same_non_zero_policy_assets(&HashMap::new(), new_assets)?,
510            ),
511        };
512    }
513
514    // Remove any asset that has 0 quantity after the addition
515    res.retain(|_, assets| {
516        assets.retain(|_, amount| *amount > 0);
517        !assets.is_empty()
518    });
519
520    Ok(conway_wrap_multiasset(res))
521}
522
523fn add_same_policy_assets(
524    old_assets: &HashMap<AssetName, i64>,
525    new_assets: &std::collections::BTreeMap<AssetName, i64>,
526) -> HashMap<AssetName, i64> {
527    let mut res: HashMap<AssetName, i64> = old_assets.clone();
528    for (asset_name, new_amount) in new_assets.iter() {
529        match res.get(asset_name) {
530            Some(old_amount) => res.insert(asset_name.clone(), old_amount + *new_amount),
531            None => res.insert(asset_name.clone(), *new_amount),
532        };
533    }
534    res
535}
536
537fn conway_add_same_policy_assets<T>(
538    old_assets: &HashMap<AssetName, T>,
539    new_assets: &std::collections::BTreeMap<AssetName, T>,
540) -> HashMap<AssetName, T>
541where
542    T: std::ops::Add<Output = T> + Copy,
543{
544    let mut res: HashMap<AssetName, T> = old_assets.clone();
545
546    for (asset_name, new_amount) in new_assets.iter() {
547        match res.get(asset_name) {
548            Some(old_amount) => res.insert(asset_name.clone(), *old_amount + *new_amount),
549            None => res.insert(asset_name.clone(), *new_amount),
550        };
551    }
552
553    res
554}
555
556fn conway_add_same_non_zero_policy_assets(
557    old_assets: &HashMap<AssetName, u64>,
558    new_assets: &std::collections::BTreeMap<AssetName, NonZeroInt>,
559) -> Result<HashMap<AssetName, u64>, ValidationError> {
560    let mut res: HashMap<AssetName, u64> = old_assets.clone();
561
562    for (asset_name, new_amount) in new_assets.iter() {
563        match res.get(asset_name) {
564            Some(old_amount) => {
565                let result = (*old_amount as i64) + i64::from(new_amount);
566
567                if result < 0 {
568                    return Err(ValidationError::PostAlonzo(PostAlonzoError::NegativeValue));
569                }
570
571                res.insert(asset_name.clone(), result as u64)
572            }
573            None => res.insert(asset_name.clone(), i64::from(new_amount) as u64),
574        };
575    }
576
577    Ok(res)
578}
579
580fn wrap_multiasset(input: HashMap<PolicyId, HashMap<AssetName, i64>>) -> Multiasset<i64> {
581    input
582        .into_iter()
583        .map(|(policy, assets)| (policy, assets.into_iter().collect()))
584        .collect()
585}
586
587fn conway_wrap_multiasset<T>(
588    input: HashMap<PolicyId, HashMap<AssetName, T>>,
589) -> ConwayMultiasset<T> {
590    input
591        .into_iter()
592        .map(|(policy, assets)| (policy, assets.into_iter().collect()))
593        .collect()
594}
595
596pub fn values_are_equal(first: &Value, second: &Value) -> bool {
597    match (first, second) {
598        (Value::Coin(f), Value::Coin(s)) => f == s,
599        (Value::Multiasset(..), Value::Coin(..)) => false,
600        (Value::Coin(..), Value::Multiasset(..)) => false,
601        (Value::Multiasset(f, fma), Value::Multiasset(s, sma)) => {
602            if f != s {
603                false
604            } else {
605                multi_assets_are_equal(fma, sma)
606            }
607        }
608    }
609}
610pub fn conway_values_are_equal(first: &ConwayValue, second: &ConwayValue) -> bool {
611    match (first, second) {
612        (ConwayValue::Coin(f), ConwayValue::Coin(s)) => f == s,
613        (ConwayValue::Multiasset(..), ConwayValue::Coin(..)) => false,
614        (ConwayValue::Coin(..), ConwayValue::Multiasset(..)) => false,
615        (ConwayValue::Multiasset(f, fma), ConwayValue::Multiasset(s, sma)) => {
616            if f != s {
617                false
618            } else {
619                conway_multi_assets_are_equal(fma, sma)
620            }
621        }
622    }
623}
624
625fn find_policy(
626    mary_value: &Multiasset<Coin>,
627    search_policy: &PolicyId,
628) -> Option<std::collections::BTreeMap<AssetName, Coin>> {
629    for (policy, assets) in mary_value.iter() {
630        if policy == search_policy {
631            return Some(assets.clone());
632        }
633    }
634    None
635}
636
637fn conway_find_policy(
638    mary_value: &ConwayMultiasset<PositiveCoin>,
639    search_policy: &PolicyId,
640) -> Option<std::collections::BTreeMap<AssetName, PositiveCoin>> {
641    for (policy, assets) in mary_value.iter() {
642        if policy == search_policy {
643            return Some(assets.clone());
644        }
645    }
646    None
647}
648
649fn find_assets(
650    assets: &std::collections::BTreeMap<AssetName, Coin>,
651    asset_name: &AssetName,
652) -> Option<Coin> {
653    for (an, amount) in assets.iter() {
654        if an == asset_name {
655            return Some(*amount);
656        }
657    }
658    None
659}
660fn conway_find_assets(
661    assets: &std::collections::BTreeMap<AssetName, PositiveCoin>,
662    asset_name: &AssetName,
663) -> Option<PositiveCoin> {
664    for (an, amount) in assets.iter() {
665        if an == asset_name {
666            return Some(*amount);
667        }
668    }
669    None
670}
671
672pub fn get_lovelace_from_alonzo_val(val: &Value) -> Coin {
673    match val {
674        Value::Coin(res) => *res,
675        Value::Multiasset(res, _) => *res,
676    }
677}
678
679pub fn get_lovelace_from_conway_val(val: &ConwayValue) -> Coin {
680    match val {
681        ConwayValue::Coin(res) => *res,
682        ConwayValue::Multiasset(res, _) => *res,
683    }
684}
685
686#[deprecated(since = "0.31.0", note = "use `u8::from(...)` instead")]
687pub fn get_network_id_value(network_id: NetworkId) -> u8 {
688    u8::from(network_id)
689}
690
691pub fn mk_alonzo_vk_wits_check_list(
692    wits: &Option<Vec<VKeyWitness>>,
693    err: ValidationError,
694) -> Result<Vec<(bool, VKeyWitness)>, ValidationError> {
695    Ok(wits
696        .clone()
697        .ok_or(err)?
698        .iter()
699        .map(|x| (false, x.clone()))
700        .collect::<Vec<(bool, VKeyWitness)>>())
701}
702
703pub fn verify_signature(vk_wit: &VKeyWitness, data_to_verify: &[u8]) -> bool {
704    let mut public_key_source: [u8; PublicKey::SIZE] = [0; PublicKey::SIZE];
705    public_key_source.copy_from_slice(vk_wit.vkey.as_slice());
706    let public_key: PublicKey = From::<[u8; PublicKey::SIZE]>::from(public_key_source);
707    let mut signature_source: [u8; Signature::SIZE] = [0; Signature::SIZE];
708    signature_source.copy_from_slice(vk_wit.signature.as_slice());
709    let sig: Signature = From::<[u8; Signature::SIZE]>::from(signature_source);
710    public_key.verify(data_to_verify, &sig)
711}
712
713pub fn get_payment_part(address: &Bytes) -> Option<ShelleyPaymentPart> {
714    let addr: ShelleyAddress = get_shelley_address(Bytes::deref(address))?;
715    Some(addr.payment().clone())
716}
717
718pub fn get_shelley_address(address: &[u8]) -> Option<ShelleyAddress> {
719    match Address::from_bytes(address) {
720        Ok(Address::Shelley(sa)) => Some(sa),
721        _ => None,
722    }
723}
724
725pub fn is_byron_address(address: &[u8]) -> bool {
726    matches!(Address::from_bytes(address), Ok(Address::Byron(_)))
727}
728
729pub fn aux_data_from_alonzo_tx<'a>(mtx: &'a AlonzoTx) -> Option<&'a [u8]> {
730    mtx.auxiliary_data.as_ref().map(|x| x.raw_cbor()).into()
731}
732
733pub fn aux_data_from_babbage_tx<'a>(mtx: &'a BabbageTx) -> Option<&'a [u8]> {
734    mtx.auxiliary_data.as_ref().map(|x| x.raw_cbor()).into()
735}
736
737pub fn aux_data_from_conway_tx<'a>(mtx: &'a ConwayTx) -> Option<&'a [u8]> {
738    mtx.auxiliary_data.as_ref().map(|x| x.raw_cbor()).into()
739}
740
741pub fn get_val_size_in_words(val: &Value) -> u64 {
742    let mut tx_buf: Vec<u8> = Vec::new();
743    let _ = encode(val, &mut tx_buf);
744    (tx_buf.len() as u64).div_ceil(8) // ceiling of the result of dividing
745}
746
747pub fn conway_get_val_size_in_words(val: &ConwayValue) -> u64 {
748    let mut tx_buf: Vec<u8> = Vec::new();
749    let _ = encode(val, &mut tx_buf);
750    (tx_buf.len() as u64).div_ceil(8) // ceiling of the result of dividing
751}
752
753pub fn compute_native_script_hash(script: &NativeScript) -> PolicyId {
754    let mut payload = Vec::new();
755    let _ = encode(script, &mut payload);
756    payload.insert(0, 0);
757    pallas_crypto::hash::Hasher::<224>::hash(&payload)
758}
759
760#[deprecated(since = "0.31.0", note = "use `compute_plutus_v1_script_hash` instead")]
761pub fn compute_plutus_script_hash(script: &PlutusScript<1>) -> PolicyId {
762    compute_plutus_v1_script_hash(script)
763}
764
765pub fn compute_plutus_v1_script_hash(script: &PlutusScript<1>) -> PolicyId {
766    let mut payload: Vec<u8> = Vec::from(script.as_ref());
767    payload.insert(0, 1);
768    pallas_crypto::hash::Hasher::<224>::hash(&payload)
769}
770
771pub fn compute_plutus_v2_script_hash(script: &PlutusScript<2>) -> PolicyId {
772    let mut payload: Vec<u8> = Vec::from(script.as_ref());
773    payload.insert(0, 2);
774    pallas_crypto::hash::Hasher::<224>::hash(&payload)
775}
776
777pub fn compute_plutus_v3_script_hash(script: &PlutusScript<3>) -> PolicyId {
778    let mut payload: Vec<u8> = Vec::from(script.as_ref());
779    payload.insert(0, 3);
780    pallas_crypto::hash::Hasher::<224>::hash(&payload)
781}
782
783pub type CertificateIndex = u32;
784
785#[derive(PartialEq, Eq, Hash, Clone)]
786pub struct CertPointer {
787    pub slot: Slot,
788    pub tx_ix: TransactionIndex,
789    pub cert_ix: CertificateIndex,
790}
791
792pub type GenesisDelegation = HashMap<Genesishash, (GenesisDelegateHash, VrfKeyhash)>;
793pub type FutGenesisDelegation = HashMap<(Slot, Genesishash), (GenesisDelegateHash, VrfKeyhash)>;
794pub type InstantaneousRewards = (
795    HashMap<StakeCredential, Coin>,
796    HashMap<StakeCredential, Coin>,
797);
798
799#[derive(Default, Clone)] // for testing
800pub struct DState {
801    pub rewards: HashMap<StakeCredential, Coin>,
802    pub delegations: HashMap<StakeCredential, PoolKeyhash>,
803    pub ptrs: HashMap<CertPointer, StakeCredential>,
804    pub fut_gen_delegs: FutGenesisDelegation,
805    pub gen_delegs: GenesisDelegation,
806    pub inst_rewards: InstantaneousRewards,
807}
808
809// Essentially part of the `PoolRegistration` component of `Certificate` at
810// alonzo/src/model.rs
811#[derive(Clone, Debug)]
812pub struct PoolParam {
813    pub vrf_keyhash: VrfKeyhash,
814    pub pledge: Coin,
815    pub cost: Coin,
816    pub margin: UnitInterval,
817    pub reward_account: RewardAccount, // FIXME: Should be a `StakeCredential`, or `Hash<_>`???
818    pub pool_owners: Vec<AddrKeyhash>,
819    pub relays: Vec<Relay>,
820    pub pool_metadata: Option<PoolMetadata>,
821}
822
823#[derive(Default, Clone)] // for testing
824pub struct PState {
825    pub pool_params: HashMap<PoolKeyhash, PoolParam>,
826    pub fut_pool_params: HashMap<PoolKeyhash, PoolParam>,
827    pub retiring: HashMap<PoolKeyhash, Epoch>,
828}
829
830// Originally `DPState` in ShelleyMA specs, then updated to
831// `CertState` in Haskell sources at Intersect (#3369).
832#[non_exhaustive]
833#[derive(Default, Clone)] // for testing
834pub struct CertState {
835    pub pstate: PState,
836    pub dstate: DState,
837}