chia_sdk_driver/
layer.rs

1use chia_protocol::{Coin, CoinSpend};
2use clvm_traits::{FromClvm, ToClvm};
3use clvmr::{Allocator, NodePtr};
4
5use crate::{DriverError, Puzzle, Spend, SpendContext};
6
7/// An individual layer in a puzzle's hierarchy.
8pub trait Layer {
9    /// Most of the time, this is an actual CLVM type representing the solution.
10    /// However, you can also use a helper struct and customize [`Layer::construct_solution`] and [`Layer::parse_solution`].
11    type Solution;
12
13    /// Parses this layer from the given puzzle, returning [`None`] if the puzzle doesn't match.
14    /// An error is returned if the puzzle should have matched but couldn't be parsed.
15    fn parse_puzzle(allocator: &Allocator, puzzle: Puzzle) -> Result<Option<Self>, DriverError>
16    where
17        Self: Sized;
18
19    /// Parses the [`Layer::Solution`] type from a CLVM solution pointer.
20    fn parse_solution(
21        allocator: &Allocator,
22        solution: NodePtr,
23    ) -> Result<Self::Solution, DriverError>;
24
25    /// Constructs the full curried puzzle for this layer.
26    /// Ideally, the puzzle itself should be cached in the [`SpendContext`].
27    fn construct_puzzle(&self, ctx: &mut SpendContext) -> Result<NodePtr, DriverError>;
28
29    /// Constructs the full solution for this layer.
30    /// Can be used to construct the solution from a helper struct, if it's not directly a CLVM type.
31    /// It's also possible to influence the solution based on the puzzle, if needed.
32    fn construct_solution(
33        &self,
34        ctx: &mut SpendContext,
35        solution: Self::Solution,
36    ) -> Result<NodePtr, DriverError>;
37
38    /// Creates a spend for this layer.
39    fn construct_spend(
40        &self,
41        ctx: &mut SpendContext,
42        solution: Self::Solution,
43    ) -> Result<Spend, DriverError> {
44        let solution = self.construct_solution(ctx, solution)?;
45        let puzzle = self.construct_puzzle(ctx)?;
46        Ok(Spend::new(puzzle, solution))
47    }
48
49    /// Creates a coin spend for this layer.
50    fn construct_coin_spend(
51        &self,
52        ctx: &mut SpendContext,
53        coin: Coin,
54        solution: Self::Solution,
55    ) -> Result<CoinSpend, DriverError> {
56        let solution = self.construct_solution(ctx, solution)?;
57        let puzzle = self.construct_puzzle(ctx)?;
58        Ok(CoinSpend::new(
59            coin,
60            ctx.serialize(&puzzle)?,
61            ctx.serialize(&solution)?,
62        ))
63    }
64}
65
66impl<T> Layer for T
67where
68    T: ToClvm<Allocator> + FromClvm<Allocator>,
69{
70    type Solution = NodePtr;
71
72    fn parse_puzzle(allocator: &Allocator, puzzle: Puzzle) -> Result<Option<Self>, DriverError> {
73        Ok(Some(T::from_clvm(allocator, puzzle.ptr())?))
74    }
75
76    fn parse_solution(
77        _allocator: &Allocator,
78        solution: NodePtr,
79    ) -> Result<Self::Solution, DriverError> {
80        Ok(solution)
81    }
82
83    fn construct_puzzle(&self, ctx: &mut SpendContext) -> Result<NodePtr, DriverError> {
84        ctx.alloc(&self)
85    }
86
87    fn construct_solution(
88        &self,
89        _ctx: &mut SpendContext,
90        solution: Self::Solution,
91    ) -> Result<NodePtr, DriverError> {
92        Ok(solution)
93    }
94}