chia_sdk_driver/primitives/did/
did_info.rs1use chia_protocol::Bytes32;
2use chia_puzzle_types::{did::DidArgs, singleton::SingletonStruct};
3use clvm_utils::{ToTreeHash, TreeHash};
4use clvmr::Allocator;
5
6use crate::{DidLayer, DriverError, HashedPtr, Layer, Puzzle, SingletonInfo, SingletonLayer};
7
8pub type StandardDidLayers<I> = SingletonLayer<DidLayer<HashedPtr, I>>;
9
10#[derive(Debug, Clone, Copy, PartialEq, Eq)]
15pub struct DidInfo {
16 pub launcher_id: Bytes32,
18
19 pub recovery_list_hash: Option<Bytes32>,
26
27 pub num_verifications_required: u64,
29
30 pub metadata: HashedPtr,
34
35 pub p2_puzzle_hash: Bytes32,
38}
39
40impl DidInfo {
41 pub fn new(
42 launcher_id: Bytes32,
43 recovery_list_hash: Option<Bytes32>,
44 num_verifications_required: u64,
45 metadata: HashedPtr,
46 p2_puzzle_hash: Bytes32,
47 ) -> Self {
48 Self {
49 launcher_id,
50 recovery_list_hash,
51 num_verifications_required,
52 metadata,
53 p2_puzzle_hash,
54 }
55 }
56
57 pub fn parse(
64 allocator: &Allocator,
65 puzzle: Puzzle,
66 ) -> Result<Option<(Self, Puzzle)>, DriverError> {
67 let Some(layers) = StandardDidLayers::<Puzzle>::parse_puzzle(allocator, puzzle)? else {
68 return Ok(None);
69 };
70
71 let p2_puzzle = layers.inner_puzzle.inner_puzzle;
72
73 Ok(Some((Self::from_layers(&layers), p2_puzzle)))
74 }
75
76 pub fn from_layers<I>(layers: &StandardDidLayers<I>) -> Self
77 where
78 I: ToTreeHash,
79 {
80 Self {
81 launcher_id: layers.launcher_id,
82 recovery_list_hash: layers.inner_puzzle.recovery_list_hash,
83 num_verifications_required: layers.inner_puzzle.num_verifications_required,
84 metadata: layers.inner_puzzle.metadata,
85 p2_puzzle_hash: layers.inner_puzzle.inner_puzzle.tree_hash().into(),
86 }
87 }
88
89 #[must_use]
90 pub fn into_layers<I>(self, p2_puzzle: I) -> StandardDidLayers<I> {
91 SingletonLayer::new(
92 self.launcher_id,
93 DidLayer::new(
94 self.launcher_id,
95 self.recovery_list_hash,
96 self.num_verifications_required,
97 self.metadata,
98 p2_puzzle,
99 ),
100 )
101 }
102}
103
104impl SingletonInfo for DidInfo {
105 fn launcher_id(&self) -> Bytes32 {
106 self.launcher_id
107 }
108
109 fn inner_puzzle_hash(&self) -> TreeHash {
110 DidArgs::curry_tree_hash(
111 self.p2_puzzle_hash.into(),
112 self.recovery_list_hash,
113 self.num_verifications_required,
114 SingletonStruct::new(self.launcher_id),
115 self.metadata.tree_hash(),
116 )
117 }
118}
119
120#[cfg(test)]
121mod tests {
122 use chia_sdk_test::Simulator;
123 use chia_sdk_types::Conditions;
124 use clvm_traits::ToClvm;
125
126 use crate::{Launcher, SpendContext, StandardLayer};
127
128 use super::*;
129
130 #[test]
131 fn test_parse_did_info() -> anyhow::Result<()> {
132 let mut sim = Simulator::new();
133 let ctx = &mut SpendContext::new();
134
135 let alice = sim.bls(1);
136 let alice_p2 = StandardLayer::new(alice.pk);
137
138 let custom_metadata = ctx.alloc_hashed(&["Metadata".to_string(), "Example".to_string()])?;
139 let (create_did, did) = Launcher::new(alice.coin.coin_id(), 1).create_did(
140 ctx,
141 None,
142 1,
143 custom_metadata,
144 &alice_p2,
145 )?;
146 alice_p2.spend(ctx, alice.coin, create_did)?;
147
148 let original_did = did;
149 let _did = did.update(ctx, &alice_p2, Conditions::new())?;
150
151 sim.spend_coins(ctx.take(), &[alice.sk])?;
152
153 let puzzle_reveal = sim
154 .puzzle_reveal(original_did.coin.coin_id())
155 .expect("missing did puzzle");
156
157 let mut allocator = Allocator::new();
158 let ptr = puzzle_reveal.to_clvm(&mut allocator)?;
159 let puzzle = Puzzle::parse(&allocator, ptr);
160 let (did_info, p2_puzzle) = DidInfo::parse(&allocator, puzzle)?.expect("not a did");
161
162 assert_eq!(did_info, original_did.info);
163 assert_eq!(p2_puzzle.curried_puzzle_hash(), alice.puzzle_hash.into());
164
165 Ok(())
166 }
167}