Skip to content

Commit

Permalink
Merge pull request #559 from Chia-Network/rework-puzzle-types
Browse files Browse the repository at this point in the history
  • Loading branch information
Rigidity authored Jun 7, 2024
2 parents 48ac364 + 8c65f79 commit 69e99d5
Show file tree
Hide file tree
Showing 9 changed files with 211 additions and 57 deletions.
8 changes: 4 additions & 4 deletions crates/chia-consensus/src/fast_forward.rs
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ pub fn fast_forward_singleton(
// now that we know the parent coin's puzzle hash, we have all the pieces to
// compute the coin being spent (before the fast-forward).
let parent_coin = Coin {
parent_coin_info: lineage_proof.parent_parent_coin_id,
parent_coin_info: lineage_proof.parent_parent_coin_info,
puzzle_hash: parent_puzzle_hash,
amount: lineage_proof.parent_amount,
};
Expand All @@ -139,7 +139,7 @@ pub fn fast_forward_singleton(
}

// update the solution to use the new parent coin's information
lineage_proof.parent_parent_coin_id = new_parent.parent_coin_info;
lineage_proof.parent_parent_coin_info = new_parent.parent_coin_info;
lineage_proof.parent_amount = new_parent.amount;
new_solution.amount = new_coin.amount;

Expand Down Expand Up @@ -382,7 +382,7 @@ mod tests {
};

// corrupt the lineage proof
lineage_proof.parent_parent_coin_id = Bytes32::from(hex!(
lineage_proof.parent_parent_coin_info = Bytes32::from(hex!(
"fefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefe"
));

Expand Down Expand Up @@ -455,7 +455,7 @@ mod tests {
);

*new_parent = Coin {
parent_coin_info: lineage_proof.parent_parent_coin_id,
parent_coin_info: lineage_proof.parent_parent_coin_info,
puzzle_hash: parent_puzzle_hash,
amount: lineage_proof.parent_amount,
};
Expand Down
11 changes: 10 additions & 1 deletion crates/chia-puzzles/src/proof.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ pub enum Proof {
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
#[clvm(list)]
pub struct LineageProof {
pub parent_parent_coin_id: Bytes32,
pub parent_parent_coin_info: Bytes32,
pub parent_inner_puzzle_hash: Bytes32,
pub parent_amount: u64,
}
Expand All @@ -22,6 +22,15 @@ pub struct LineageProof {
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
#[clvm(list)]
pub struct EveProof {
pub parent_parent_coin_info: Bytes32,
pub parent_amount: u64,
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, ToClvm, FromClvm)]
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
#[clvm(list)]
pub struct CoinProof {
pub parent_coin_info: Bytes32,
pub inner_puzzle_hash: Bytes32,
pub amount: u64,
}
11 changes: 1 addition & 10 deletions crates/chia-puzzles/src/puzzles/cat.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use clvm_traits::{FromClvm, ToClvm};
use clvm_utils::{CurriedProgram, ToTreeHash, TreeHash};
use hex_literal::hex;

use crate::LineageProof;
use crate::{CoinProof, LineageProof};

#[derive(Debug, Clone, Copy, PartialEq, Eq, ToClvm, FromClvm)]
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
Expand Down Expand Up @@ -94,15 +94,6 @@ pub struct CatSolution<I> {
pub extra_delta: i64,
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, ToClvm, FromClvm)]
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
#[clvm(list)]
pub struct CoinProof {
pub parent_coin_info: Bytes32,
pub inner_puzzle_hash: Bytes32,
pub amount: u64,
}

/// This is the puzzle reveal of the [CAT2 standard](https://chialisp.com/cats) puzzle.
pub const CAT_PUZZLE: [u8; 1672] = hex!(
"
Expand Down
132 changes: 97 additions & 35 deletions crates/chia-puzzles/src/puzzles/did.rs
Original file line number Diff line number Diff line change
@@ -1,58 +1,82 @@
use chia_bls::PublicKey;
use chia_protocol::Bytes32;
use clvm_traits::{
clvm_list, match_list, match_tuple, ClvmDecoder, ClvmEncoder, FromClvm, FromClvmError, Raw,
ToClvm, ToClvmError,
};
use clvm_utils::TreeHash;
use clvm_traits::{FromClvm, ToClvm};
use clvm_utils::{CurriedProgram, ToTreeHash, TreeHash};
use hex_literal::hex;

use crate::singleton::SingletonStruct;
use crate::{singleton::SingletonStruct, CoinProof};

#[derive(Debug, Clone, Copy, PartialEq, Eq, ToClvm, FromClvm)]
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
#[clvm(curry)]
pub struct DidArgs<I, M> {
pub inner_puzzle: I,
pub recovery_did_list_hash: Bytes32,
pub recovery_list_hash: Bytes32,
pub num_verifications_required: u64,
pub singleton_struct: SingletonStruct,
pub metadata: M,
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
pub enum DidSolution<I> {
InnerSpend(I),
}

impl<N, I> FromClvm<N> for DidSolution<I>
where
I: FromClvm<N>,
{
fn from_clvm(decoder: &impl ClvmDecoder<Node = N>, node: N) -> Result<Self, FromClvmError> {
let (mode, args) = <match_tuple!(u8, Raw<N>)>::from_clvm(decoder, node)?;
match mode {
1 => Ok(Self::InnerSpend(
<match_list!(I)>::from_clvm(decoder, args.0)?.0,
)),
_ => Err(FromClvmError::Custom(format!(
"unexpected did spend mode {mode}"
))),
impl<I, M> DidArgs<I, M> {
pub fn new(
inner_puzzle: I,
recovery_list_hash: Bytes32,
num_verifications_required: u64,
singleton_struct: SingletonStruct,
metadata: M,
) -> Self {
Self {
inner_puzzle,
recovery_list_hash,
num_verifications_required,
singleton_struct,
metadata,
}
}
}

impl<N, I> ToClvm<N> for DidSolution<I>
where
I: ToClvm<N>,
{
fn to_clvm(&self, encoder: &mut impl ClvmEncoder<Node = N>) -> Result<N, ToClvmError> {
match self {
Self::InnerSpend(solution) => clvm_list!(1, solution).to_clvm(encoder),
impl DidArgs<TreeHash, TreeHash> {
pub fn curry_tree_hash(
inner_puzzle: TreeHash,
recovery_list_hash: Bytes32,
num_verifications_required: u64,
singleton_struct: SingletonStruct,
metadata: TreeHash,
) -> TreeHash {
CurriedProgram {
program: DID_INNER_PUZZLE_HASH,
args: DidArgs {
inner_puzzle,
recovery_list_hash,
num_verifications_required,
singleton_struct,
metadata,
},
}
.tree_hash()
}
}

#[derive(Debug, Clone, PartialEq, Eq, ToClvm, FromClvm)]
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
#[clvm(list)]
#[repr(u8)]
pub enum DidSolution<I> {
Recover(#[clvm(rest)] Box<DidRecoverySolution>) = 0,
Spend(I) = 1,
}

#[derive(Debug, Clone, PartialEq, Eq, ToClvm, FromClvm)]
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
#[clvm(list)]
pub struct DidRecoverySolution {
pub amount: u64,
pub new_inner_puzzle_hash: Bytes32,
pub recovery_coins: Vec<CoinProof>,
pub public_key: PublicKey,
pub recovery_list_reveal: Vec<Bytes32>,
}

/// This is the puzzle reveal of the [DID1 standard](https://chialisp.com/dids) puzzle.
pub const DID_INNER_PUZZLE: [u8; 1012] = hex!(
"
Expand Down Expand Up @@ -100,7 +124,12 @@ pub const DID_INNER_PUZZLE_HASH: TreeHash = TreeHash::new(hex!(

#[cfg(test)]
mod tests {
use clvmr::Allocator;
use clvm_traits::{clvm_list, match_list};
use clvmr::{
run_program,
serde::{node_from_bytes, node_to_bytes},
Allocator, ChiaDialect,
};

use super::*;

Expand All @@ -114,7 +143,40 @@ mod tests {
#[test]
fn did_solution() {
let a = &mut Allocator::new();
let did_solution = DidSolution::InnerSpend(a.nil());

let ptr = clvm_list!(1, clvm_list!(42, "test")).to_clvm(a).unwrap();
let did_solution = DidSolution::<match_list!(i32, String)>::from_clvm(a, ptr).unwrap();
assert_eq!(
did_solution,
DidSolution::Spend(clvm_list!(42, "test".to_string()))
);

let puzzle = node_from_bytes(a, &DID_INNER_PUZZLE).unwrap();
let curried = CurriedProgram {
program: puzzle,
args: DidArgs::new(
1,
Bytes32::default(),
1,
SingletonStruct::new(Bytes32::default()),
(),
),
}
.to_clvm(a)
.unwrap();

let output = run_program(a, &ChiaDialect::new(0), curried, ptr, u64::MAX)
.expect("could not run did puzzle and solution");
assert_eq!(
hex::encode(node_to_bytes(a, output.1).unwrap()),
"ff2aff847465737480"
);
}

#[test]
fn did_solution_roundtrip() {
let a = &mut Allocator::new();
let did_solution = DidSolution::Spend(a.nil());
let ptr = did_solution.to_clvm(a).unwrap();
let roundtrip = DidSolution::from_clvm(a, ptr).unwrap();
assert_eq!(did_solution, roundtrip);
Expand Down
12 changes: 7 additions & 5 deletions crates/chia-puzzles/src/puzzles/nft.rs
Original file line number Diff line number Diff line change
Expand Up @@ -132,33 +132,35 @@ pub struct NftOwnershipLayerSolution<I> {
pub struct NftRoyaltyTransferPuzzleArgs {
pub singleton_struct: SingletonStruct,
pub royalty_puzzle_hash: Bytes32,
pub trade_price_percentage: u16,
/// The royalty percentage expressed as ten-thousandths.
/// For example, 300 represents 3%.
pub royalty_ten_thousandths: u16,
}

impl NftRoyaltyTransferPuzzleArgs {
pub fn new(
launcher_id: Bytes32,
royalty_puzzle_hash: Bytes32,
trade_price_percentage: u16,
royalty_ten_thousandths: u16,
) -> Self {
Self {
singleton_struct: SingletonStruct::new(launcher_id),
royalty_puzzle_hash,
trade_price_percentage,
royalty_ten_thousandths,
}
}

pub fn curry_tree_hash(
launcher_id: Bytes32,
royalty_puzzle_hash: Bytes32,
trade_price_percentage: u16,
royalty_ten_thousandths: u16,
) -> TreeHash {
CurriedProgram {
program: NFT_ROYALTY_TRANSFER_PUZZLE_HASH,
args: NftRoyaltyTransferPuzzleArgs {
singleton_struct: SingletonStruct::new(launcher_id),
royalty_puzzle_hash,
trade_price_percentage,
royalty_ten_thousandths,
},
}
.tree_hash()
Expand Down
14 changes: 14 additions & 0 deletions crates/chia-puzzles/src/puzzles/offer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,20 @@ pub struct Payment {
pub memos: Vec<Bytes>,
}

impl Payment {
pub fn new(puzzle_hash: Bytes32, amount: u64) -> Self {
Self::with_memos(puzzle_hash, amount, Vec::new())
}

pub fn with_memos(puzzle_hash: Bytes32, amount: u64, memos: Vec<Bytes>) -> Self {
Self {
puzzle_hash,
amount,
memos,
}
}
}

/// This is the puzzle reveal of the [offer settlement payments](https://chialisp.com/offers) puzzle.
pub const SETTLEMENT_PAYMENTS_PUZZLE: [u8; 293] = hex!(
"
Expand Down
6 changes: 4 additions & 2 deletions crates/chia-tools/src/bin/run-spend.rs
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,7 @@ fn print_puzzle_info(a: &Allocator, puzzle: NodePtr, solution: NodePtr) {
};
println!(
" recovery_did_list_hash: {:?}",
uncurried.args.recovery_did_list_hash
uncurried.args.recovery_list_hash
);
println!(
" num_verifications_required: {:?}",
Expand All @@ -205,7 +205,9 @@ fn print_puzzle_info(a: &Allocator, puzzle: NodePtr, solution: NodePtr) {
};

println!("\nInner Puzzle\n");
let DidSolution::InnerSpend(inner_sol) = sol;
let DidSolution::Spend(inner_sol) = sol else {
unimplemented!();
};
print_puzzle_info(a, uncurried.args.inner_puzzle, inner_sol);
}
SINGLETON_TOP_LAYER_PUZZLE_HASH => {
Expand Down
37 changes: 37 additions & 0 deletions crates/clvm-traits/src/from_clvm.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
use std::{rc::Rc, sync::Arc};

use num_bigint::{BigInt, Sign};

use crate::{ClvmDecoder, FromClvmError};
Expand Down Expand Up @@ -68,6 +70,33 @@ impl<N> FromClvm<N> for bool {
}
}

impl<N, T> FromClvm<N> for Box<T>
where
T: FromClvm<N>,
{
fn from_clvm(decoder: &impl ClvmDecoder<Node = N>, node: N) -> Result<Self, FromClvmError> {
T::from_clvm(decoder, node).map(Box::new)
}
}

impl<N, T> FromClvm<N> for Rc<T>
where
T: FromClvm<N>,
{
fn from_clvm(decoder: &impl ClvmDecoder<Node = N>, node: N) -> Result<Self, FromClvmError> {
T::from_clvm(decoder, node).map(Rc::new)
}
}

impl<N, T> FromClvm<N> for Arc<T>
where
T: FromClvm<N>,
{
fn from_clvm(decoder: &impl ClvmDecoder<Node = N>, node: N) -> Result<Self, FromClvmError> {
T::from_clvm(decoder, node).map(Arc::new)
}
}

impl<N, A, B> FromClvm<N> for (A, B)
where
A: FromClvm<N>,
Expand Down Expand Up @@ -237,6 +266,14 @@ mod tests {
);
}

#[test]
fn test_smart_pointers() {
let a = &mut Allocator::new();
assert_eq!(decode(a, "80"), Ok(Box::new(0u8)));
assert_eq!(decode(a, "80"), Ok(Rc::new(0u8)));
assert_eq!(decode(a, "80"), Ok(Arc::new(0u8)));
}

#[test]
fn test_pair() {
let a = &mut Allocator::new();
Expand Down
Loading

0 comments on commit 69e99d5

Please sign in to comment.