Skip to content

Commit bec96f4

Browse files
authored
Merge pull request #58 from Rigidity/documentation
Documentation and some structural changes
2 parents 110dc75 + 083bb08 commit bec96f4

21 files changed

+278
-237
lines changed

Cargo.toml

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,12 +21,12 @@ keywords = ["chia", "wallet", "blockchain", "crypto"]
2121
categories = ["cryptography::cryptocurrencies", "development-tools"]
2222

2323
[workspace.lints.rust]
24+
rust_2018_idioms = { level = "deny", priority = -1 }
25+
rust_2021_compatibility = { level = "deny", priority = -1 }
26+
future_incompatible = { level = "deny", priority = -1 }
27+
nonstandard_style = { level = "deny", priority = -1 }
2428
unsafe_code = "deny"
25-
rust_2018_idioms = "deny"
26-
rust_2021_compatibility = "deny"
27-
future_incompatible = "deny"
2829
non_ascii_idents = "deny"
29-
nonstandard_style = "deny"
3030
unused_extern_crates = "deny"
3131
trivial_casts = "deny"
3232
trivial_numeric_casts = "deny"
@@ -44,7 +44,7 @@ all = { level = "deny", priority = -1 }
4444
missing_crate_level_docs = "allow"
4545

4646
[workspace.lints.clippy]
47-
all = "deny"
47+
all = { level = "deny", priority = -1 }
4848
cargo = { level = "warn", priority = -1 }
4949
pedantic = { level = "warn", priority = -1 }
5050
too_many_lines = "allow"

crates/chia-sdk-driver/docs.md

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
## Puzzles
2+
3+
Chia coins have a puzzle, which controls how it can be spent.
4+
The solution is used as the arguments to the puzzle, and the
5+
output is a list of [`Conditions`].
6+
7+
A puzzle consists of multiple layers composed together.
8+
9+
## Layers
10+
11+
A [`Layer`] is a subset of the logic that makes up a smart coin in Chia.
12+
They are also referred to as "inner puzzles", and the solution can be broken
13+
up into "inner solutions" as well.
14+
15+
Generally, you can parse and construct the individual layers separately.
16+
This allows them to be composed together freely. However, there are sometimes
17+
additional restraints which limit the ways they can be mixed. For example,
18+
the [`CatLayer`] cannot have another [`CatLayer`] as its inner puzzle, due to the
19+
way it's written. This would create an error when validating the announcements.
20+
21+
### P2 Puzzles
22+
23+
A p2 puzzle (meaning "pay to") controls the ownership of the coin.
24+
The simplest example of this is [`p2_conditions.clsp`], which requires a signature
25+
from a single public key and outputs a list of conditions from the solution.
26+
27+
The "standard transaction" (which is [`p2_delegated_puzzle_or_hidden_puzzle.clsp`])
28+
is a kind of p2 puzzle that adds additional flexibility. Specifically, support
29+
for an inner puzzle, and usage of a delegated puzzle instead of directly conditions.
30+
31+
Generally, the p2 puzzle is the base layer in a coin's puzzle, and everything
32+
else builds on top of it to restrict the way it can be spent or attach state.
33+
34+
## Primitives
35+
36+
A [`Primitive`] uses one or more [`Layer`] to parse info from a parent's coin spend.
37+
Generally, [`Layer`] has the ability to parse and construct individual puzzles and solutions,
38+
and the composed [`Primitive`] struct can parse all of the information required to spend a coin.
39+
The [`Primitive`] should also provide a way to spend the coin, and other utilities necessary.
40+
41+
[`p2_conditions.clsp`]: https://github.com/Chia-Network/chia-blockchain/blob/bd022b0c9b0d3e0bc13a0efebba9f22417ca64b5/chia/wallet/puzzles/p2_conditions.clsp
42+
[`p2_delegated_puzzle_or_hidden_puzzle.clsp`]: https://github.com/Chia-Network/chia-blockchain/blob/bd022b0c9b0d3e0bc13a0efebba9f22417ca64b5/chia/wallet/puzzles/p2_delegated_puzzle_or_hidden_puzzle.clsp

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

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,13 @@ use clvmr::{Allocator, NodePtr};
66

77
use crate::{DriverError, Layer, Puzzle, SpendContext};
88

9-
#[derive(Debug)]
9+
/// The CAT [`Layer`] enforces restrictions on the supply of a token.
10+
/// Specifically, unless the TAIL program is run, the supply cannot change.
11+
#[derive(Debug, Clone, Copy)]
1012
pub struct CatLayer<I> {
13+
/// The asset id of the CAT token. This is the tree hash of the TAIL program.
1114
pub asset_id: Bytes32,
15+
/// The inner puzzle layer, commonly used for determining ownership.
1216
pub inner_puzzle: I,
1317
}
1418

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

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,41 @@
11
use chia_protocol::Bytes32;
22
use chia_puzzles::{
33
did::{DidArgs, DidSolution, DID_INNER_PUZZLE_HASH},
4-
singleton::SingletonStruct,
4+
singleton::{SingletonStruct, SINGLETON_LAUNCHER_PUZZLE_HASH, SINGLETON_TOP_LAYER_PUZZLE_HASH},
55
};
66
use clvm_traits::{FromClvm, ToClvm};
77
use clvm_utils::{CurriedProgram, ToTreeHash, TreeHash};
88
use clvmr::{Allocator, NodePtr};
99

1010
use crate::{DriverError, Layer, Puzzle, SpendContext};
1111

12+
/// The DID [`Layer`] keeps track of metadata and handles recovery capabilities.
13+
/// It's typically an inner layer of the [`SingletonLayer`](crate::SingletonLayer).
1214
#[derive(Debug)]
1315
pub struct DidLayer<M, I> {
14-
pub singleton_struct: SingletonStruct,
16+
/// The unique launcher id for the DID. Also referred to as the DID id.
17+
pub launcher_id: Bytes32,
18+
/// The tree hash of a list of recovery DIDs.
19+
/// Note that this is currently *not* optional, but will be in the future.
1520
pub recovery_list_hash: Bytes32,
21+
/// The number of verifications required to recover the DID.
1622
pub num_verifications_required: u64,
23+
/// Metadata associated with the DID. This is often just `()` for DIDs without metadata.
1724
pub metadata: M,
25+
/// The inner puzzle layer, commonly used for determining ownership.
1826
pub inner_puzzle: I,
1927
}
2028

2129
impl<M, I> DidLayer<M, I> {
2230
pub fn new(
23-
singleton_struct: SingletonStruct,
31+
launcher_id: Bytes32,
2432
recovery_list_hash: Bytes32,
2533
num_verifications_required: u64,
2634
metadata: M,
2735
inner_puzzle: I,
2836
) -> Self {
2937
Self {
30-
singleton_struct,
38+
launcher_id,
3139
recovery_list_hash,
3240
num_verifications_required,
3341
metadata,
@@ -54,14 +62,20 @@ where
5462

5563
let args = DidArgs::<NodePtr, M>::from_clvm(allocator, puzzle.args)?;
5664

65+
if args.singleton_struct.mod_hash != SINGLETON_TOP_LAYER_PUZZLE_HASH.into()
66+
|| args.singleton_struct.launcher_puzzle_hash != SINGLETON_LAUNCHER_PUZZLE_HASH.into()
67+
{
68+
return Err(DriverError::InvalidSingletonStruct);
69+
}
70+
5771
let Some(inner_puzzle) =
5872
I::parse_puzzle(allocator, Puzzle::parse(allocator, args.inner_puzzle))?
5973
else {
6074
return Ok(None);
6175
};
6276

6377
Ok(Some(Self {
64-
singleton_struct: args.singleton_struct,
78+
launcher_id: args.singleton_struct.launcher_id,
6579
recovery_list_hash: args.recovery_list_hash,
6680
num_verifications_required: args.num_verifications_required,
6781
metadata: args.metadata,
@@ -89,7 +103,7 @@ where
89103
self.inner_puzzle.construct_puzzle(ctx)?,
90104
self.recovery_list_hash,
91105
self.num_verifications_required,
92-
self.singleton_struct,
106+
SingletonStruct::new(self.launcher_id),
93107
&self.metadata,
94108
),
95109
};
@@ -125,7 +139,7 @@ where
125139
inner_puzzle_hash,
126140
self.recovery_list_hash,
127141
self.num_verifications_required,
128-
self.singleton_struct,
142+
SingletonStruct::new(self.launcher_id),
129143
metadata_hash,
130144
)
131145
}

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,11 @@ use crate::{DriverError, Layer, Puzzle, SpendContext};
1010

1111
#[derive(Debug)]
1212
pub struct NftOwnershipLayer<T, I> {
13+
/// The DID owner of this NFT, if it's currently assigned to one.
1314
pub current_owner: Option<Bytes32>,
15+
/// The transfer layer, which is used to transfer ownership of the NFT.
1416
pub transfer_layer: T,
17+
/// The inner puzzle layer, commonly used for determining ownership.
1518
pub inner_puzzle: I,
1619
}
1720

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

Lines changed: 4 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
use chia_protocol::Bytes32;
22
use chia_puzzles::nft::{NftStateLayerArgs, NftStateLayerSolution, NFT_STATE_LAYER_PUZZLE_HASH};
3-
use chia_sdk_types::{run_puzzle, NewMetadataCondition, NewMetadataOutput};
43
use clvm_traits::{FromClvm, ToClvm};
54
use clvm_utils::{CurriedProgram, ToTreeHash, TreeHash};
65
use clvmr::{Allocator, NodePtr};
@@ -9,8 +8,12 @@ use crate::{DriverError, Layer, Puzzle, SpendContext};
98

109
#[derive(Debug)]
1110
pub struct NftStateLayer<M, I> {
11+
/// The NFT metadata. The standard metadata type is [`NftMetadata`](chia_puzzles::nft::NftMetadata).
1212
pub metadata: M,
13+
/// The tree hash of the metadata updater puzzle.
1314
pub metadata_updater_puzzle_hash: Bytes32,
15+
/// The inner puzzle layer. Typically, this is the [`NftOwnershipLayer`](crate::NftOwnershipLayer).
16+
/// However, for the NFT0 standard this can be the p2 layer itself.
1417
pub inner_puzzle: I,
1518
}
1619

@@ -114,40 +117,3 @@ where
114117
.tree_hash()
115118
}
116119
}
117-
118-
impl<M, IP> NftStateLayer<M, IP>
119-
where
120-
M: FromClvm<Allocator>,
121-
{
122-
pub fn new_metadata_and_updater_from_conditions(
123-
allocator: &mut Allocator,
124-
inner_layer_puzzle: NodePtr,
125-
inner_layer_solution: NodePtr,
126-
) -> Result<Option<(M, Bytes32)>, DriverError> {
127-
let output = run_puzzle(allocator, inner_layer_puzzle, inner_layer_solution)?;
128-
129-
let conditions = Vec::<NodePtr>::from_clvm(allocator, output)?;
130-
131-
for condition in conditions {
132-
let condition =
133-
NewMetadataCondition::<NodePtr, NodePtr>::from_clvm(allocator, condition);
134-
135-
if let Ok(condition) = condition {
136-
let output = run_puzzle(
137-
allocator,
138-
condition.metadata_updater_reveal,
139-
condition.metadata_updater_solution,
140-
)?;
141-
142-
let output = NewMetadataOutput::<M, NodePtr>::from_clvm(allocator, output)?;
143-
144-
return Ok(Some((
145-
output.metadata_part.new_metadata,
146-
output.metadata_part.new_metadata_updater_puzhash,
147-
)));
148-
}
149-
}
150-
151-
Ok(None)
152-
}
153-
}

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

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use std::convert::Infallible;
33
use chia_protocol::Bytes32;
44
use chia_puzzles::{
55
nft::{NftRoyaltyTransferPuzzleArgs, NFT_ROYALTY_TRANSFER_PUZZLE_HASH},
6-
singleton::SingletonStruct,
6+
singleton::{SingletonStruct, SINGLETON_LAUNCHER_PUZZLE_HASH, SINGLETON_TOP_LAYER_PUZZLE_HASH},
77
};
88
use clvm_traits::FromClvm;
99
use clvm_utils::CurriedProgram;
@@ -13,19 +13,23 @@ use crate::{DriverError, Layer, Puzzle, SpendContext};
1313

1414
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
1515
pub struct RoyaltyTransferLayer {
16-
pub singleton_struct: SingletonStruct,
16+
/// The launcher id of the NFT this transfer program belongs to.
17+
pub launcher_id: Bytes32,
18+
/// The puzzle hash that receives royalties paid when transferring this NFT.
1719
pub royalty_puzzle_hash: Bytes32,
20+
/// The percentage of the transfer amount that is paid as royalties.
21+
/// This is represented in ten thousandths, so a value of 300 means 3%.
1822
pub royalty_ten_thousandths: u16,
1923
}
2024

2125
impl RoyaltyTransferLayer {
2226
pub fn new(
23-
singleton_struct: SingletonStruct,
27+
launcher_id: Bytes32,
2428
royalty_puzzle_hash: Bytes32,
2529
royalty_ten_thousandths: u16,
2630
) -> Self {
2731
Self {
28-
singleton_struct,
32+
launcher_id,
2933
royalty_puzzle_hash,
3034
royalty_ten_thousandths,
3135
}
@@ -39,7 +43,7 @@ impl Layer for RoyaltyTransferLayer {
3943
let curried = CurriedProgram {
4044
program: ctx.nft_royalty_transfer()?,
4145
args: NftRoyaltyTransferPuzzleArgs {
42-
singleton_struct: self.singleton_struct,
46+
singleton_struct: SingletonStruct::new(self.launcher_id),
4347
royalty_puzzle_hash: self.royalty_puzzle_hash,
4448
royalty_ten_thousandths: self.royalty_ten_thousandths,
4549
},
@@ -58,8 +62,14 @@ impl Layer for RoyaltyTransferLayer {
5862

5963
let args = NftRoyaltyTransferPuzzleArgs::from_clvm(allocator, puzzle.args)?;
6064

65+
if args.singleton_struct.mod_hash != SINGLETON_TOP_LAYER_PUZZLE_HASH.into()
66+
|| args.singleton_struct.launcher_puzzle_hash != SINGLETON_LAUNCHER_PUZZLE_HASH.into()
67+
{
68+
return Err(DriverError::InvalidSingletonStruct);
69+
}
70+
6171
Ok(Some(Self {
62-
singleton_struct: args.singleton_struct,
72+
launcher_id: args.singleton_struct.launcher_id,
6373
royalty_puzzle_hash: args.royalty_puzzle_hash,
6474
royalty_ten_thousandths: args.royalty_ten_thousandths,
6575
}))

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

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use chia_protocol::Bytes32;
12
use chia_puzzles::singleton::{
23
SingletonArgs, SingletonSolution, SingletonStruct, SINGLETON_LAUNCHER_PUZZLE_HASH,
34
SINGLETON_TOP_LAYER_PUZZLE_HASH,
@@ -10,14 +11,16 @@ use crate::{DriverError, Layer, Puzzle, SpendContext};
1011

1112
#[derive(Debug)]
1213
pub struct SingletonLayer<I> {
13-
pub singleton_struct: SingletonStruct,
14+
/// The unique launcher id for the singleton. Also referred to as the singleton id.
15+
pub launcher_id: Bytes32,
16+
/// The inner puzzle layer. For singletons, this determines the actual behavior of the coin.
1417
pub inner_puzzle: I,
1518
}
1619

1720
impl<I> SingletonLayer<I> {
18-
pub fn new(singleton_struct: SingletonStruct, inner_puzzle: I) -> Self {
21+
pub fn new(launcher_id: Bytes32, inner_puzzle: I) -> Self {
1922
Self {
20-
singleton_struct,
23+
launcher_id,
2124
inner_puzzle,
2225
}
2326
}
@@ -53,7 +56,7 @@ where
5356
};
5457

5558
Ok(Some(Self {
56-
singleton_struct: args.singleton_struct,
59+
launcher_id: args.singleton_struct.launcher_id,
5760
inner_puzzle,
5861
}))
5962
}
@@ -75,7 +78,7 @@ where
7578
let curried = CurriedProgram {
7679
program: ctx.singleton_top_layer()?,
7780
args: SingletonArgs {
78-
singleton_struct: self.singleton_struct,
81+
singleton_struct: SingletonStruct::new(self.launcher_id),
7982
inner_puzzle: self.inner_puzzle.construct_puzzle(ctx)?,
8083
},
8184
};
@@ -105,7 +108,7 @@ where
105108
fn tree_hash(&self) -> TreeHash {
106109
let inner_puzzle = self.inner_puzzle.tree_hash();
107110
SingletonArgs {
108-
singleton_struct: self.singleton_struct,
111+
singleton_struct: SingletonStruct::new(self.launcher_id),
109112
inner_puzzle,
110113
}
111114
.tree_hash()

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

Lines changed: 1 addition & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,40 +1,4 @@
1-
//! ## Puzzles
2-
//!
3-
//! Chia coins have a puzzle, which controls how it can be spent.
4-
//! The solution is used as the arguments to the puzzle, and the
5-
//! output is a list of [`Conditions`].
6-
//!
7-
//! A puzzle consists of multiple layers composed together.
8-
//!
9-
//! ## Layers
10-
//!
11-
//! A [`Layer`] is a subset of the logic that makes up a smart coin in Chia.
12-
//! They are also referred to as "inner puzzles", and the solution can be broken
13-
//! up into "inner solutions" as well.
14-
//!
15-
//! Generally, you can parse and construct the individual layers separately.
16-
//! This allows them to be composed together freely. However, there are sometimes
17-
//! additional restraints which limit the ways they can be mixed. For example,
18-
//! the [`CatLayer`] cannot have another [`CatLayer`] as its inner puzzle, due to the
19-
//! way it's written. This would create an error when validating the announcements.
20-
//!
21-
//! ### P2 Layer
22-
//!
23-
//! A p2 puzzle (meaning "pay to") controls the ownership of the coin.
24-
//! The simplest example of this is [`p2_conditions.clsp`], which requires a signature
25-
//! from a single public key and outputs a list of conditions from the solution.
26-
//!
27-
//! The "standard transaction" (which is [`p2_delegated_puzzle_or_hidden_puzzle.clsp`])
28-
//! is a kind of p2 puzzle that adds additional flexibility. Specifically, support
29-
//! for an inner puzzle, and usage of a delegated puzzle instead of directly conditions.
30-
//!
31-
//! Generally, the p2 puzzle is the base layer in a coin's puzzle, and everything
32-
//! else builds on top of it to restrict the way it can be spent or attach state.
33-
//!
34-
//! ## Primitives
35-
//!
36-
//! [`p2_conditions.clsp`]: https://github.com/Chia-Network/chia-blockchain/blob/bd022b0c9b0d3e0bc13a0efebba9f22417ca64b5/chia/wallet/puzzles/p2_conditions.clsp
37-
//! [`p2_delegated_puzzle_or_hidden_puzzle.clsp`]: https://github.com/Chia-Network/chia-blockchain/blob/bd022b0c9b0d3e0bc13a0efebba9f22417ca64b5/chia/wallet/puzzles/p2_delegated_puzzle_or_hidden_puzzle.clsp
1+
#![doc = include_str!("../docs.md")]
382

393
mod conditions;
404
mod driver_error;

0 commit comments

Comments
 (0)