chia_sdk_driver/layers/
p2_controller_puzzle_layer.rs1use chia_protocol::Bytes32;
2use chia_sdk_types::puzzles::{
3 P2_CONTROLLER_PUZZLE_PUZZLE_HASH, P2ControllerPuzzleArgs, P2ControllerPuzzleSolution,
4};
5use clvm_traits::FromClvm;
6use clvmr::{Allocator, NodePtr};
7
8use crate::{DriverError, Layer, Puzzle, Spend, SpendContext};
9
10#[derive(Debug, Clone, Copy, PartialEq, Eq)]
18pub struct P2ControllerPuzzleLayer {
19 pub controller_puzzle_hash: Bytes32,
20}
21
22impl P2ControllerPuzzleLayer {
23 pub fn new(controller_puzzle_hash: Bytes32) -> Self {
24 Self {
25 controller_puzzle_hash,
26 }
27 }
28
29 pub fn spend(
32 &self,
33 ctx: &mut SpendContext,
34 delegated_spend: Spend,
35 ) -> Result<Spend, DriverError> {
36 self.construct_spend(
37 ctx,
38 P2ControllerPuzzleSolution {
39 delegated_puzzle: delegated_spend.puzzle,
40 delegated_solution: delegated_spend.solution,
41 },
42 )
43 }
44}
45
46impl Layer for P2ControllerPuzzleLayer {
47 type Solution = P2ControllerPuzzleSolution<NodePtr, NodePtr>;
48
49 fn parse_puzzle(allocator: &Allocator, puzzle: Puzzle) -> Result<Option<Self>, DriverError> {
50 let Some(puzzle) = puzzle.as_curried() else {
51 return Ok(None);
52 };
53
54 if puzzle.mod_hash != P2_CONTROLLER_PUZZLE_PUZZLE_HASH {
55 return Ok(None);
56 }
57
58 let args = P2ControllerPuzzleArgs::from_clvm(allocator, puzzle.args)?;
59
60 Ok(Some(Self {
61 controller_puzzle_hash: args.controller_puzzle_hash,
62 }))
63 }
64
65 fn parse_solution(
66 allocator: &Allocator,
67 solution: NodePtr,
68 ) -> Result<Self::Solution, DriverError> {
69 Ok(P2ControllerPuzzleSolution::from_clvm(allocator, solution)?)
70 }
71
72 fn construct_puzzle(&self, ctx: &mut SpendContext) -> Result<NodePtr, DriverError> {
73 ctx.curry(P2ControllerPuzzleArgs {
74 controller_puzzle_hash: self.controller_puzzle_hash,
75 })
76 }
77
78 fn construct_solution(
79 &self,
80 ctx: &mut SpendContext,
81 solution: Self::Solution,
82 ) -> Result<NodePtr, DriverError> {
83 ctx.alloc(&solution)
84 }
85}
86
87#[cfg(test)]
88mod tests {
89 use super::*;
90
91 use chia_protocol::Bytes;
92 use chia_sdk_test::Simulator;
93 use chia_sdk_types::{Conditions, conditions::SendMessage};
94 use clvm_traits::{ToClvm, clvm_quote};
95
96 #[test]
100 fn test_p2_controller_puzzle() -> anyhow::Result<()> {
101 let mut sim = Simulator::new();
102 let mut ctx = SpendContext::new();
103 let ctx = &mut ctx;
104
105 let controller_puzzle = ctx.one();
108 let controller_puzzle_hash: Bytes32 = ctx.tree_hash(controller_puzzle).into();
109
110 let layer = P2ControllerPuzzleLayer::new(controller_puzzle_hash);
111 let coin_puzzle = layer.construct_puzzle(ctx)?;
112 let coin_puzzle_hash = ctx.tree_hash(coin_puzzle);
113
114 let controller_coin = sim.new_coin(controller_puzzle_hash, 42);
115 let coin = sim.new_coin(coin_puzzle_hash.into(), 69);
116
117 let delegated_puzzle =
118 clvm_quote!(Conditions::new().reserve_fee(42 + 69)).to_clvm(&mut **ctx)?;
119 let delegated_solution = ctx.nil();
120
121 let delegated_puzzle_hash: Bytes32 = ctx.tree_hash(delegated_puzzle).into();
122
123 let coin_spend = layer.construct_coin_spend(
124 ctx,
125 coin,
126 P2ControllerPuzzleSolution {
127 delegated_puzzle,
128 delegated_solution,
129 },
130 )?;
131 ctx.insert(coin_spend);
132
133 let coin_id_ptr = ctx.alloc(&coin.coin_id())?;
135 let controller_solution = vec![SendMessage::new(
136 23,
137 Bytes::new(delegated_puzzle_hash.to_vec()),
138 vec![coin_id_ptr],
139 )]
140 .to_clvm(&mut **ctx)?;
141
142 let controller_spend = chia_protocol::CoinSpend::new(
143 controller_coin,
144 chia_protocol::Program::from_clvm(&**ctx, controller_puzzle)?,
145 chia_protocol::Program::from_clvm(&**ctx, controller_solution)?,
146 );
147 ctx.insert(controller_spend);
148
149 sim.spend_coins(ctx.take(), &[])?;
150 Ok(())
151 }
152}