chik_sdk_test/
announcements.rs1use chik_protocol::{Bytes, Bytes32, CoinSpend};
2use chik_sdk_types::{
3 announcement_id,
4 conditions::{
5 AssertCoinAnnouncement, AssertPuzzleAnnouncement, CreateCoinAnnouncement,
6 CreatePuzzleAnnouncement,
7 },
8};
9use klvm_traits::{FromKlvm, ToKlvm};
10use klvmr::{reduction::Reduction, run_program, Allocator, ChikDialect, NodePtr};
11
12#[derive(Debug, Default, Clone)]
13pub struct Announcements {
14 pub created_coin: Vec<Bytes>,
15 pub asserted_coin: Vec<Bytes32>,
16 pub created_puzzle: Vec<Bytes>,
17 pub asserted_puzzle: Vec<Bytes32>,
18}
19
20pub fn debug_announcements(coin_spends: &[CoinSpend]) {
26 let all_announcements: Vec<Announcements> = coin_spends
27 .iter()
28 .map(|coin_spend| {
29 announcements_for_spend(coin_spend).expect("could not extract announcements")
30 })
31 .collect();
32
33 let mut should_panic = false;
34
35 for (i, announcements) in all_announcements.iter().enumerate() {
36 for &asserted_coin in &announcements.asserted_coin {
37 let Some(created_index) = all_announcements.iter().enumerate().position(|(i, a)| {
38 a.created_coin.iter().any(|message| {
39 asserted_coin == announcement_id(coin_spends[i].coin.coin_id(), message.clone())
40 })
41 }) else {
42 println!(
43 "spend {i} asserted unknown coin announcement {}",
44 hex::encode(&asserted_coin[0..4])
45 );
46 should_panic = true;
47 continue;
48 };
49
50 println!(
51 "spend {i} asserted coin announcement created by spend {created_index}: {}",
52 hex::encode(&asserted_coin[0..4])
53 );
54 }
55
56 for &asserted_puzzle in &announcements.asserted_puzzle {
57 let Some(created_index) = all_announcements.iter().enumerate().position(|(i, a)| {
58 a.created_puzzle.iter().any(|message| {
59 asserted_puzzle
60 == announcement_id(coin_spends[i].coin.puzzle_hash, message.clone())
61 })
62 }) else {
63 println!(
64 "spend {i} asserted unknown puzzle announcement {}",
65 hex::encode(&asserted_puzzle[0..4])
66 );
67 should_panic = true;
68 continue;
69 };
70
71 println!(
72 "spend {i} asserted puzzle announcement created by spend {created_index}: {}",
73 hex::encode(&asserted_puzzle[0..4])
74 );
75 }
76
77 for created_coin in &announcements.created_coin {
78 let asserted = all_announcements.iter().enumerate().any(|(i, a)| {
79 a.asserted_coin.iter().any(|&id| {
80 id == announcement_id(coin_spends[i].coin.coin_id(), created_coin.clone())
81 })
82 });
83
84 if !asserted {
85 println!(
86 "spend {i} created coin announcement {} but it was not asserted",
87 hex::encode(&created_coin[0..4])
88 );
89 should_panic = true;
90 }
91 }
92
93 for created_puzzle in &announcements.created_puzzle {
94 let asserted = all_announcements.iter().enumerate().any(|(i, a)| {
95 a.asserted_puzzle.iter().any(|&id| {
96 id == announcement_id(coin_spends[i].coin.puzzle_hash, created_puzzle.clone())
97 })
98 });
99
100 if !asserted {
101 println!(
102 "spend {i} created puzzle announcement {} but it was not asserted",
103 hex::encode(&created_puzzle[0..4])
104 );
105 should_panic = true;
106 }
107 }
108 }
109
110 assert!(
111 !should_panic,
112 "asserted announcements do not match created announcements"
113 );
114}
115
116pub fn announcements_for_spend(coin_spend: &CoinSpend) -> anyhow::Result<Announcements> {
117 let mut announcements = Announcements::default();
118
119 let allocator = &mut Allocator::new();
120 let puzzle = coin_spend.puzzle_reveal.to_klvm(allocator)?;
121 let solution = coin_spend.solution.to_klvm(allocator)?;
122
123 let Reduction(_cost, output) = run_program(
124 allocator,
125 &ChikDialect::new(0),
126 puzzle,
127 solution,
128 11_000_000_000,
129 )?;
130
131 let conditions = Vec::<NodePtr>::from_klvm(allocator, output)?;
132
133 for condition in conditions {
134 if let Ok(condition) = CreateCoinAnnouncement::from_klvm(allocator, condition) {
135 announcements.created_coin.push(condition.message);
136 } else if let Ok(condition) = CreatePuzzleAnnouncement::from_klvm(allocator, condition) {
137 announcements.created_puzzle.push(condition.message);
138 } else if let Ok(condition) = AssertCoinAnnouncement::from_klvm(allocator, condition) {
139 announcements.asserted_coin.push(condition.announcement_id);
140 } else if let Ok(condition) = AssertPuzzleAnnouncement::from_klvm(allocator, condition) {
141 announcements
142 .asserted_puzzle
143 .push(condition.announcement_id);
144 }
145 }
146
147 Ok(announcements)
148}