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