Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Simplify lineage proof and remove chia-consensus singleton types #492

Merged
merged 6 commits into from
Apr 29, 2024
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions crates/chia-consensus/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,9 @@ pub enum Error {
#[error("coin mismatch")]
CoinMismatch,

#[error("expected lineage proof, found eve proof")]
ExpectedLineageProof,

#[error("{0}")]
Custom(String),
}
Expand Down
91 changes: 43 additions & 48 deletions crates/chia-consensus/src/fast_forward.rs
Original file line number Diff line number Diff line change
@@ -1,43 +1,15 @@
use crate::error::{Error, Result};
use chia_protocol::Bytes32;
use chia_protocol::Coin;
use chia_wallet::singleton::SINGLETON_TOP_LAYER_PUZZLE_HASH;
use chia_wallet::singleton::{
SingletonArgs, SingletonSolution, SingletonStruct, SINGLETON_TOP_LAYER_PUZZLE_HASH,
};
use chia_wallet::Proof;
use clvm_traits::{FromClvm, ToClvm};
use clvm_utils::CurriedProgram;
use clvm_utils::{tree_hash, tree_hash_atom, tree_hash_pair};
use clvmr::allocator::{Allocator, NodePtr};

#[derive(FromClvm, ToClvm, Debug)]
#[clvm(tuple)]
pub struct SingletonStruct {
pub mod_hash: Bytes32,
pub launcher_id: Bytes32,
pub launcher_puzzle_hash: Bytes32,
}

#[derive(FromClvm, ToClvm, Debug)]
#[clvm(curry)]
pub struct SingletonArgs<I> {
pub singleton_struct: SingletonStruct,
pub inner_puzzle: I,
}

#[derive(FromClvm, ToClvm, Debug)]
#[clvm(list)]
pub struct LineageProof {
pub parent_parent_coin_id: Bytes32,
pub parent_inner_puzzle_hash: Bytes32,
pub parent_amount: u64,
}

#[derive(FromClvm, ToClvm, Debug)]
#[clvm(list)]
pub struct SingletonSolution<I> {
pub lineage_proof: LineageProof,
pub amount: u64,
pub inner_solution: I,
}

// TODO: replace this with a generic function to compute the hash of curried
// puzzles
const OP_QUOTE: u8 = 1;
Expand Down Expand Up @@ -107,6 +79,11 @@ pub fn fast_forward_singleton(
let singleton = CurriedProgram::<NodePtr, SingletonArgs<NodePtr>>::from_clvm(a, puzzle)?;
let mut new_solution = SingletonSolution::<NodePtr>::from_clvm(a, solution)?;

let lineage_proof = match &mut new_solution.lineage_proof {
Proof::Lineage(proof) => proof,
_ => return Err(Error::ExpectedLineageProof),
};

// this is the tree hash of the singleton top layer puzzle
// the tree hash of singleton_top_layer_v1_1.clsp
if singleton.args.singleton_struct.mod_hash.as_ref() != SINGLETON_TOP_LAYER_PUZZLE_HASH {
Expand All @@ -129,24 +106,24 @@ pub fn fast_forward_singleton(
// given the parent's parent, the parent's inner puzzle and parent's amount,
// we can compute the hash of the curried inner puzzle for our parent coin
let parent_puzzle_hash = curry_and_treehash(
&new_solution.lineage_proof.parent_inner_puzzle_hash,
&lineage_proof.parent_inner_puzzle_hash,
&singleton.args.singleton_struct,
);

// 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: new_solution.lineage_proof.parent_parent_coin_id,
parent_coin_info: lineage_proof.parent_parent_coin_id,
puzzle_hash: parent_puzzle_hash,
amount: new_solution.lineage_proof.parent_amount,
amount: lineage_proof.parent_amount,
};

if parent_coin.coin_id() != coin.parent_coin_info {
return Err(Error::ParentCoinMismatch);
}

let inner_puzzle_hash = tree_hash(a, singleton.args.inner_puzzle);
if inner_puzzle_hash != *new_solution.lineage_proof.parent_inner_puzzle_hash {
if inner_puzzle_hash != *lineage_proof.parent_inner_puzzle_hash {
return Err(Error::InnerPuzzleHashMismatch);
}

Expand All @@ -160,8 +137,8 @@ pub fn fast_forward_singleton(
}

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

let expected_new_parent = new_parent.coin_id();
Expand Down Expand Up @@ -362,7 +339,9 @@ mod tests {

fn parse_solution(a: &mut Allocator, solution: &[u8]) -> SingletonSolution<NodePtr> {
let new_solution = node_from_bytes(a, solution).expect("parse solution");
SingletonSolution::from_clvm(a, new_solution).expect("parse solution")
let solution = SingletonSolution::from_clvm(a, new_solution).expect("parse solution");
assert!(matches!(solution.lineage_proof, Proof::Lineage(_)));
solution
}

fn serialize_solution(a: &mut Allocator, solution: &SingletonSolution<NodePtr>) -> Vec<u8> {
Expand Down Expand Up @@ -392,8 +371,12 @@ mod tests {
|a, _coin, _new_coin, _new_parent, _puzzle, solution| {
let mut new_solution = parse_solution(a, solution);

let Proof::Lineage(lineage_proof) = &mut new_solution.lineage_proof else {
unreachable!();
};

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

Expand All @@ -409,8 +392,12 @@ mod tests {
|a, _coin, _new_coin, _new_parent, _puzzle, solution| {
let mut new_solution = parse_solution(a, solution);

let Proof::Lineage(lineage_proof) = &mut new_solution.lineage_proof else {
unreachable!();
};

// corrupt the lineage proof
new_solution.lineage_proof.parent_amount = 11;
lineage_proof.parent_amount = 11;

*solution = serialize_solution(a, &new_solution);
},
Expand All @@ -424,8 +411,12 @@ mod tests {
|a, _coin, _new_coin, _new_parent, _puzzle, solution| {
let mut new_solution = parse_solution(a, solution);

let Proof::Lineage(lineage_proof) = &mut new_solution.lineage_proof else {
unreachable!();
};

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

Expand All @@ -442,25 +433,29 @@ mod tests {
let mut new_solution = parse_solution(a, solution);
let singleton = parse_singleton(a, puzzle);

let Proof::Lineage(lineage_proof) = &mut new_solution.lineage_proof else {
unreachable!();
};

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

// adjust the coins puzzle hashes to match
let parent_puzzle_hash = curry_and_treehash(
&new_solution.lineage_proof.parent_inner_puzzle_hash,
&lineage_proof.parent_inner_puzzle_hash,
&singleton.args.singleton_struct,
);

*solution = serialize_solution(a, &new_solution);

*new_parent = Coin {
parent_coin_info: new_solution.lineage_proof.parent_parent_coin_id,
parent_coin_info: lineage_proof.parent_parent_coin_id,
puzzle_hash: parent_puzzle_hash,
amount: new_solution.lineage_proof.parent_amount,
amount: lineage_proof.parent_amount,
};

*solution = serialize_solution(a, &new_solution);

new_coin.puzzle_hash = parent_puzzle_hash;

coin.parent_coin_info = new_parent.coin_id();
Expand Down
4 changes: 2 additions & 2 deletions crates/chia-tools/src/bin/run-spend.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use chia_consensus::gen::conditions::Condition;
use chia_traits::Streamable;
use chia_wallet::Proof;
use clap::Parser;
use clvm_traits::{FromClvm, ToNodePtr};
use clvm_utils::tree_hash;
Expand All @@ -10,7 +11,6 @@ use chia_wallet::cat::{CatArgs, CatSolution, CAT_PUZZLE_HASH};
use chia_wallet::did::{DidArgs, DidSolution, DID_INNER_PUZZLE_HASH};
use chia_wallet::singleton::{SingletonArgs, SingletonSolution, SINGLETON_TOP_LAYER_PUZZLE_HASH};
use chia_wallet::standard::{StandardArgs, StandardSolution, STANDARD_PUZZLE_HASH};
use chia_wallet::Proof;

/// Run a puzzle given a solution and print the resulting conditions
#[derive(Parser, Debug)]
Expand Down Expand Up @@ -238,7 +238,7 @@ fn print_puzzle_info(a: &Allocator, puzzle: NodePtr, solution: NodePtr) {
return;
};
println!(" solution");
match sol.proof {
match sol.lineage_proof {
Proof::Lineage(lp) => {
println!(" lineage-proof: {lp:?}");
}
Expand Down
4 changes: 2 additions & 2 deletions crates/chia-wallet/fuzz/fuzz_targets/roundtrip.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,14 @@ fuzz_target!(|data: &[u8]| {
{
use std::fmt;

use chia_wallet::{nft::NftMetadata, Proof};
use chia_wallet::{nft::NftMetadata, MaybeEveProof};
use clvm_traits::{FromClvm, ToClvm};
use clvmr::{allocator::NodePtr, Allocator};
use libfuzzer_sys::arbitrary::{Arbitrary, Unstructured};

let mut u = Unstructured::new(data);
roundtrip::<NftMetadata>(&mut u);
roundtrip::<Proof>(&mut u);
roundtrip::<MaybeEveProof>(&mut u);

fn roundtrip<'a, T>(u: &mut Unstructured<'a>)
where
Expand Down
6 changes: 3 additions & 3 deletions crates/chia-wallet/src/proof.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@ pub enum Proof {
#[cfg_attr(fuzzing, derive(arbitrary::Arbitrary))]
#[clvm(list)]
pub struct LineageProof {
pub parent_coin_info: Bytes32,
pub inner_puzzle_hash: Bytes32,
pub amount: u64,
pub parent_parent_coin_id: Bytes32,
pub parent_inner_puzzle_hash: Bytes32,
pub parent_amount: u64,
}

#[derive(Debug, Clone, PartialEq, Eq, ToClvm, FromClvm)]
Expand Down
2 changes: 1 addition & 1 deletion crates/chia-wallet/src/puzzles/singleton.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ pub struct SingletonStruct {
#[derive(Debug, Clone, PartialEq, Eq, ToClvm, FromClvm)]
#[clvm(list)]
pub struct SingletonSolution<I> {
pub proof: Proof,
pub lineage_proof: Proof,
pub amount: u64,
pub inner_solution: I,
}
Expand Down
Loading