iota_genesis_builder/stardust/migration/verification/
mod.rs

1// Copyright (c) 2024 IOTA Stiftung
2// SPDX-License-Identifier: Apache-2.0
3
4//! The `verification` module contains the validation logic to make sure that
5//! the stardust outputs are correctly converted to the move objects.
6
7use std::collections::HashMap;
8
9use anyhow::{anyhow, ensure};
10use iota_sdk::types::block::output::{Output, OutputId, TokenId};
11use iota_types::in_memory_storage::InMemoryStorage;
12use tracing::warn;
13use util::{BASE_TOKEN_KEY, TokensAmountCounter};
14
15use self::created_objects::CreatedObjects;
16use crate::stardust::{
17    migration::executor::FoundryLedgerData,
18    types::{address_swap_map::AddressSwapMap, output_header::OutputHeader},
19};
20
21pub mod alias;
22pub mod basic;
23pub mod created_objects;
24pub mod foundry;
25pub mod nft;
26mod util;
27
28pub(crate) fn verify_outputs<'a>(
29    outputs: impl IntoIterator<Item = &'a (OutputHeader, Output)>,
30    output_objects_map: &HashMap<OutputId, CreatedObjects>,
31    foundry_data: &HashMap<TokenId, FoundryLedgerData>,
32    target_milestone_timestamp: u32,
33    total_supply: u64,
34    storage: &InMemoryStorage,
35    address_swap_map: &AddressSwapMap,
36) -> anyhow::Result<()> {
37    let mut tokens_counter = TokensAmountCounter::new(total_supply);
38    for (header, output) in outputs
39        .into_iter()
40        .filter(|(_, output)| !output.is_treasury())
41    {
42        let created_objects = output_objects_map
43            .get(&header.output_id())
44            .ok_or_else(|| anyhow!("missing created objects for output {}", header.output_id()))?;
45        verify_output(
46            header,
47            output,
48            created_objects,
49            foundry_data,
50            target_milestone_timestamp,
51            storage,
52            &mut tokens_counter,
53            address_swap_map,
54        )?;
55    }
56    for (key, (total_value, expected_value)) in tokens_counter.into_inner() {
57        if key == BASE_TOKEN_KEY {
58            ensure!(
59                total_value == expected_value,
60                "base token total supply: found {total_value}, expected {expected_value}"
61            )
62        } else if expected_value != total_value {
63            warn!(
64                "total supply mismatch for {key}: found {total_value}, expected {expected_value}"
65            );
66        }
67    }
68    Ok(())
69}
70
71fn verify_output(
72    header: &OutputHeader,
73    output: &Output,
74    created_objects: &CreatedObjects,
75    foundry_data: &HashMap<TokenId, FoundryLedgerData>,
76    target_milestone_timestamp: u32,
77    storage: &InMemoryStorage,
78    tokens_counter: &mut TokensAmountCounter,
79    address_swap_map: &AddressSwapMap,
80) -> anyhow::Result<()> {
81    match output {
82        Output::Alias(output) => alias::verify_alias_output(
83            header.output_id(),
84            output,
85            created_objects,
86            foundry_data,
87            storage,
88            tokens_counter,
89            address_swap_map,
90        ),
91        Output::Basic(output) => basic::verify_basic_output(
92            header.output_id(),
93            output,
94            created_objects,
95            foundry_data,
96            target_milestone_timestamp,
97            storage,
98            tokens_counter,
99            address_swap_map,
100        ),
101        Output::Foundry(output) => foundry::verify_foundry_output(
102            header.output_id(),
103            output,
104            created_objects,
105            foundry_data,
106            storage,
107            tokens_counter,
108            address_swap_map,
109        ),
110        Output::Nft(output) => nft::verify_nft_output(
111            header.output_id(),
112            output,
113            created_objects,
114            foundry_data,
115            storage,
116            tokens_counter,
117            address_swap_map,
118        ),
119        // Treasury outputs aren't used since Stardust, so no need to verify anything here.
120        Output::Treasury(_) => return Ok(()),
121    }
122    .map_err(|e| anyhow!("error verifying output {}: {}", header.output_id(), e))
123}