Skip to content

Commit 4b60909

Browse files
authored
Merge pull request #59 from Rigidity/test-cov
Improve CAT issuance and CAT tests
2 parents bec96f4 + 1fbda03 commit 4b60909

File tree

7 files changed

+314
-294
lines changed

7 files changed

+314
-294
lines changed

crates/chia-sdk-driver/src/conditions.rs

Lines changed: 32 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -8,34 +8,48 @@ use chia_sdk_types::{
88
Condition, CreateCoin, CreateCoinAnnouncement, CreatePuzzleAnnouncement, ReserveFee,
99
};
1010

11-
use clvm_traits::{ClvmEncoder, ToClvm, ToClvmError};
11+
use clvm_traits::{FromClvm, ToClvm};
1212
use clvm_utils::CurriedProgram;
13-
use clvmr::{sha2::Sha256, NodePtr};
13+
use clvmr::{sha2::Sha256, Allocator, NodePtr};
1414

1515
use crate::{Spend, SpendContext, SpendError};
1616

17-
#[derive(Debug, Default, Clone, PartialEq, Eq)]
1817
#[must_use]
19-
pub struct Conditions {
20-
conditions: Vec<Condition>,
18+
#[derive(Debug, Clone, PartialEq, Eq, ToClvm, FromClvm)]
19+
#[clvm(transparent)]
20+
pub struct Conditions<T = NodePtr> {
21+
conditions: Vec<Condition<T>>,
2122
}
2223

23-
impl Conditions {
24+
impl<T> Default for Conditions<T> {
25+
fn default() -> Self {
26+
Self {
27+
conditions: Vec::new(),
28+
}
29+
}
30+
}
31+
32+
impl Conditions<NodePtr> {
2433
pub fn new() -> Self {
2534
Self::default()
2635
}
36+
}
2737

28-
pub fn condition(mut self, condition: Condition) -> Self {
38+
impl<T> Conditions<T> {
39+
pub fn condition(mut self, condition: Condition<T>) -> Self {
2940
self.conditions.push(condition);
3041
self
3142
}
3243

33-
pub fn conditions(mut self, conditions: &[Condition]) -> Self {
44+
pub fn conditions(mut self, conditions: &[Condition<T>]) -> Self
45+
where
46+
T: Clone,
47+
{
3448
self.conditions.extend_from_slice(conditions);
3549
self
3650
}
3751

38-
pub fn extend(mut self, conditions: impl IntoIterator<Item = Condition>) -> Self {
52+
pub fn extend(mut self, conditions: impl IntoIterator<Item = Condition<T>>) -> Self {
3953
self.conditions.extend(conditions);
4054
self
4155
}
@@ -150,7 +164,10 @@ impl Conditions {
150164
self,
151165
ctx: &mut SpendContext,
152166
synthetic_key: PublicKey,
153-
) -> Result<Spend, SpendError> {
167+
) -> Result<Spend, SpendError>
168+
where
169+
T: ToClvm<Allocator>,
170+
{
154171
let standard_puzzle = ctx.standard_puzzle()?;
155172

156173
let puzzle = ctx.alloc(&CurriedProgram {
@@ -164,31 +181,21 @@ impl Conditions {
164181
}
165182
}
166183

167-
impl AsRef<[Condition]> for Conditions {
168-
fn as_ref(&self) -> &[Condition] {
184+
impl<T> AsRef<[Condition<T>]> for Conditions<T> {
185+
fn as_ref(&self) -> &[Condition<T>] {
169186
&self.conditions
170187
}
171188
}
172189

173-
impl IntoIterator for Conditions {
174-
type Item = Condition;
175-
type IntoIter = std::vec::IntoIter<Condition>;
190+
impl<T> IntoIterator for Conditions<T> {
191+
type Item = Condition<T>;
192+
type IntoIter = std::vec::IntoIter<Condition<T>>;
176193

177194
fn into_iter(self) -> Self::IntoIter {
178195
self.conditions.into_iter()
179196
}
180197
}
181198

182-
impl<E> ToClvm<E> for Conditions
183-
where
184-
E: ClvmEncoder<Node = NodePtr>,
185-
NodePtr: ToClvm<E>,
186-
{
187-
fn to_clvm(&self, encoder: &mut E) -> Result<NodePtr, ToClvmError> {
188-
self.conditions.to_clvm(encoder)
189-
}
190-
}
191-
192199
#[cfg(test)]
193200
mod tests {
194201
use chia_sdk_test::{secret_key, test_transaction, Simulator};

crates/chia-sdk-driver/src/layer.rs

Lines changed: 38 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
1+
use chia_protocol::{Coin, CoinSpend};
2+
use clvm_traits::{FromClvm, ToClvm};
13
use clvmr::{Allocator, NodePtr};
24

3-
use crate::{DriverError, Puzzle, SpendContext};
5+
use crate::{DriverError, Puzzle, Spend, SpendContext};
46

57
/// An individual layer in a puzzle's hierarchy.
68
pub trait Layer {
@@ -32,13 +34,43 @@ pub trait Layer {
3234
ctx: &mut SpendContext,
3335
solution: Self::Solution,
3436
) -> 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+
}
3564
}
3665

37-
impl Layer for NodePtr {
66+
impl<T> Layer for T
67+
where
68+
T: ToClvm<Allocator> + FromClvm<Allocator>,
69+
{
3870
type Solution = NodePtr;
3971

40-
fn parse_puzzle(_allocator: &Allocator, puzzle: Puzzle) -> Result<Option<Self>, DriverError> {
41-
Ok(Some(puzzle.ptr()))
72+
fn parse_puzzle(allocator: &Allocator, puzzle: Puzzle) -> Result<Option<Self>, DriverError> {
73+
Ok(Some(T::from_clvm(allocator, puzzle.ptr())?))
4274
}
4375

4476
fn parse_solution(
@@ -48,8 +80,8 @@ impl Layer for NodePtr {
4880
Ok(solution)
4981
}
5082

51-
fn construct_puzzle(&self, _ctx: &mut SpendContext) -> Result<NodePtr, DriverError> {
52-
Ok(*self)
83+
fn construct_puzzle(&self, ctx: &mut SpendContext) -> Result<NodePtr, DriverError> {
84+
Ok(ctx.alloc(self)?)
5385
}
5486

5587
fn construct_solution(

crates/chia-sdk-driver/src/layers/cat_layer.rs

Lines changed: 64 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use crate::{DriverError, Layer, Puzzle, SpendContext};
88

99
/// The CAT [`Layer`] enforces restrictions on the supply of a token.
1010
/// Specifically, unless the TAIL program is run, the supply cannot change.
11-
#[derive(Debug, Clone, Copy)]
11+
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
1212
pub struct CatLayer<I> {
1313
/// The asset id of the CAT token. This is the tree hash of the TAIL program.
1414
pub asset_id: Bytes32,
@@ -112,3 +112,66 @@ where
112112
CatArgs::curry_tree_hash(self.asset_id, inner_puzzle_hash)
113113
}
114114
}
115+
116+
#[cfg(test)]
117+
mod tests {
118+
119+
use chia_protocol::Coin;
120+
use chia_puzzles::CoinProof;
121+
122+
use super::*;
123+
124+
#[test]
125+
fn test_cat_layer() -> anyhow::Result<()> {
126+
let mut ctx = SpendContext::new();
127+
let asset_id = Bytes32::new([1; 32]);
128+
129+
let layer = CatLayer::new(asset_id, "Hello, world!".to_string());
130+
131+
let ptr = layer.construct_puzzle(&mut ctx)?;
132+
let puzzle = Puzzle::parse(ctx.allocator(), ptr);
133+
let roundtrip =
134+
CatLayer::<String>::parse_puzzle(ctx.allocator(), puzzle)?.expect("invalid CAT layer");
135+
136+
assert_eq!(roundtrip.asset_id, layer.asset_id);
137+
assert_eq!(roundtrip.inner_puzzle, layer.inner_puzzle);
138+
139+
let expected = CatArgs::curry_tree_hash(asset_id, layer.inner_puzzle.tree_hash());
140+
assert_eq!(hex::encode(ctx.tree_hash(ptr)), hex::encode(expected));
141+
142+
Ok(())
143+
}
144+
145+
#[test]
146+
fn test_cat_solution() -> anyhow::Result<()> {
147+
let mut ctx = SpendContext::new();
148+
149+
let layer = CatLayer::new(Bytes32::default(), NodePtr::NIL);
150+
151+
let solution = CatSolution {
152+
inner_puzzle_solution: NodePtr::NIL,
153+
lineage_proof: None,
154+
prev_coin_id: Bytes32::default(),
155+
this_coin_info: Coin::new(Bytes32::default(), Bytes32::default(), 42),
156+
next_coin_proof: CoinProof {
157+
parent_coin_info: Bytes32::default(),
158+
inner_puzzle_hash: Bytes32::default(),
159+
amount: 34,
160+
},
161+
prev_subtotal: 0,
162+
extra_delta: 0,
163+
};
164+
let expected_ptr = ctx.alloc(&solution)?;
165+
let expected_hash = ctx.tree_hash(expected_ptr);
166+
167+
let actual_ptr = layer.construct_solution(&mut ctx, solution)?;
168+
let actual_hash = ctx.tree_hash(actual_ptr);
169+
170+
assert_eq!(hex::encode(actual_hash), hex::encode(expected_hash));
171+
172+
let roundtrip = CatLayer::<NodePtr>::parse_solution(ctx.allocator(), actual_ptr)?;
173+
assert_eq!(roundtrip, solution);
174+
175+
Ok(())
176+
}
177+
}

crates/chia-sdk-driver/src/primitives.rs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ mod did;
55
mod did_info;
66
mod did_launcher;
77
mod intermediate_launcher;
8-
mod issue_cat;
98
mod launcher;
109
mod nft;
1110
mod nft_info;
@@ -17,7 +16,6 @@ pub use debug::*;
1716
pub use did::*;
1817
pub use did_info::*;
1918
pub use intermediate_launcher::*;
20-
pub use issue_cat::*;
2119
pub use launcher::*;
2220
pub use nft::*;
2321
pub use nft_info::*;

0 commit comments

Comments
 (0)