iota_light_client/
construct.rs1use anyhow::{anyhow, bail};
6use iota_types::{
7 effects::TransactionEffectsAPI,
8 full_checkpoint_content::{CheckpointData, CheckpointTransaction},
9};
10
11use crate::proof::{Proof, ProofTarget, TransactionProof};
12
13pub fn construct_proof(targets: ProofTarget, data: &CheckpointData) -> anyhow::Result<Proof> {
20 let checkpoint_summary = data.checkpoint_summary.clone();
21 let mut this_proof = Proof {
22 targets,
23 checkpoint_summary,
24 contents_proof: None,
25 };
26
27 if let Some(committee) = &this_proof.targets.committee {
30 if this_proof.checkpoint_summary.epoch() + 1 != committee.epoch {
32 bail!("Epoch mismatch between checkpoint and committee");
33 }
34
35 if this_proof.checkpoint_summary.end_of_epoch_data.is_none() {
37 bail!("Expected end of epoch checkpoint");
38 }
39 }
40
41 let object_tx = this_proof
45 .targets
46 .objects
47 .iter()
48 .map(|(_, o)| o.previous_transaction);
49 let event_tx = this_proof
50 .targets
51 .events
52 .iter()
53 .map(|(eid, _)| eid.tx_digest);
54 let mut all_tx = object_tx.chain(event_tx);
55
56 let target_tx_id = if let Some(first_tx) = all_tx.next() {
58 first_tx
59 } else {
60 return Ok(this_proof);
62 };
63
64 if !all_tx.all(|tx| tx == target_tx_id) {
66 bail!("All targets must refer to the same transaction");
67 }
68
69 let tx = data
71 .transactions
72 .iter()
73 .find(|t| t.effects.transaction_digest() == &target_tx_id)
74 .ok_or_else(|| anyhow!("Transaction not found in checkpoint data"))?
75 .clone();
76
77 let CheckpointTransaction {
78 transaction,
79 effects,
80 events,
81 ..
82 } = tx;
83
84 this_proof.contents_proof = Some(TransactionProof {
86 checkpoint_contents: data.checkpoint_contents.clone(),
87 transaction,
88 effects,
89 events,
90 });
91
92 Ok(this_proof)
97}