iota_genesis_builder/stardust/migration/verification/
mod.rs1use 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 Output::Treasury(_) => return Ok(()),
121 }
122 .map_err(|e| anyhow!("error verifying output {}: {}", header.output_id(), e))
123}