chia_sdk_driver/layers/
bulletin_layer.rs1use chia_sdk_types::{
2 puzzles::{IndexWrapperArgs, INDEX_WRAPPER_HASH},
3 Mod,
4};
5use clvm_traits::{FromClvm, MatchByte};
6use clvm_utils::{ToTreeHash, TreeHash};
7use clvmr::{Allocator, NodePtr};
8
9use crate::{DriverError, Layer, Puzzle, SpendContext};
10
11pub type BulletinNonce = (MatchByte<98>, ());
15
16#[derive(Debug, Clone, Copy, PartialEq, Eq)]
19pub struct BulletinLayer<I> {
20 pub inner_puzzle: I,
22}
23
24impl<I> BulletinLayer<I> {
25 pub fn new(inner_puzzle: I) -> Self {
26 Self { inner_puzzle }
27 }
28}
29
30impl<I> Layer for BulletinLayer<I>
31where
32 I: Layer,
33{
34 type Solution = I::Solution;
35
36 fn parse_puzzle(allocator: &Allocator, puzzle: Puzzle) -> Result<Option<Self>, DriverError> {
37 let Some(puzzle) = puzzle.as_curried() else {
38 return Ok(None);
39 };
40
41 if puzzle.mod_hash != INDEX_WRAPPER_HASH {
42 return Ok(None);
43 }
44
45 let args = IndexWrapperArgs::<NodePtr, NodePtr>::from_clvm(allocator, puzzle.args)?;
46
47 if BulletinNonce::from_clvm(allocator, args.nonce).is_err() {
48 return Err(DriverError::InvalidModHash);
49 }
50
51 let Some(inner_puzzle) =
52 I::parse_puzzle(allocator, Puzzle::parse(allocator, args.inner_puzzle))?
53 else {
54 return Ok(None);
55 };
56
57 Ok(Some(Self { inner_puzzle }))
58 }
59
60 fn parse_solution(
61 allocator: &Allocator,
62 solution: NodePtr,
63 ) -> Result<Self::Solution, DriverError> {
64 I::parse_solution(allocator, solution)
65 }
66
67 fn construct_puzzle(&self, ctx: &mut SpendContext) -> Result<NodePtr, DriverError> {
68 let inner_puzzle = self.inner_puzzle.construct_puzzle(ctx)?;
69 ctx.curry(IndexWrapperArgs::<BulletinNonce, _>::new(
70 (MatchByte, ()),
71 inner_puzzle,
72 ))
73 }
74
75 fn construct_solution(
76 &self,
77 ctx: &mut SpendContext,
78 solution: Self::Solution,
79 ) -> Result<NodePtr, DriverError> {
80 self.inner_puzzle.construct_solution(ctx, solution)
81 }
82}
83
84impl<I> ToTreeHash for BulletinLayer<I>
85where
86 I: ToTreeHash,
87{
88 fn tree_hash(&self) -> TreeHash {
89 let inner_puzzle_hash = self.inner_puzzle.tree_hash();
90 IndexWrapperArgs::<BulletinNonce, _>::new((MatchByte, ()), inner_puzzle_hash)
91 .curry_tree_hash()
92 }
93}