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

CHIA-886: Redesign ToClvm and FromClvm to be generic over Encoder and Decoder #592

Merged
merged 8 commits into from
Jul 29, 2024
Merged
Show file tree
Hide file tree
Changes from all 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
5 changes: 5 additions & 0 deletions .github/workflows/build-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -344,6 +344,11 @@ jobs:
cd crates/chia-puzzles
cargo +nightly fuzz build
cargo fuzz list | xargs -I "%" sh -c "cargo +nightly fuzz run % -- -max_total_time=20 || exit 255"
- name: cargo fuzz (clvm-traits)
run: |
cd crates/clvm-traits
cargo +nightly fuzz build
cargo fuzz list | xargs -I "%" sh -c "cargo +nightly fuzz run % -- -max_total_time=20 || exit 255"

unit_tests:
runs-on: ${{ matrix.os }}
Expand Down
9 changes: 9 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 3 additions & 3 deletions crates/chia-consensus/fuzz/fuzz_targets/fast-forward.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use chia_protocol::Bytes32;
use chia_protocol::Coin;
use chia_protocol::CoinSpend;
use chia_traits::streamable::Streamable;
use clvm_traits::ToNodePtr;
use clvm_traits::ToClvm;
use clvm_utils::tree_hash;
use clvmr::serde::node_to_bytes;
use clvmr::{Allocator, NodePtr};
Expand All @@ -24,10 +24,10 @@ fuzz_target!(|data: &[u8]| {
hex!("abababababababababababababababababababababababababababababababab");

let mut a = Allocator::new_limited(500_000_000);
let Ok(puzzle) = spend.puzzle_reveal.to_node_ptr(&mut a) else {
let Ok(puzzle) = spend.puzzle_reveal.to_clvm(&mut a) else {
return;
};
let Ok(solution) = spend.solution.to_node_ptr(&mut a) else {
let Ok(solution) = spend.solution.to_clvm(&mut a) else {
return;
};
let puzzle_hash = Bytes32::from(tree_hash(&a, puzzle));
Expand Down
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 @@ -160,7 +160,7 @@ mod tests {
use crate::gen::run_puzzle::run_puzzle;
use chia_protocol::CoinSpend;
use chia_traits::streamable::Streamable;
use clvm_traits::ToNodePtr;
use clvm_traits::ToClvm;
use clvmr::serde::{node_from_bytes, node_to_bytes};
use hex_literal::hex;
use rstest::rstest;
Expand Down Expand Up @@ -189,8 +189,8 @@ mod tests {
let new_parents_parent = hex::decode(new_parents_parent).unwrap();

let mut a = Allocator::new_limited(500_000_000);
let puzzle = spend.puzzle_reveal.to_node_ptr(&mut a).expect("to_clvm");
let solution = spend.solution.to_node_ptr(&mut a).expect("to_clvm");
let puzzle = spend.puzzle_reveal.to_clvm(&mut a).expect("to_clvm");
let solution = spend.solution.to_clvm(&mut a).expect("to_clvm");
let puzzle_hash = Bytes32::from(tree_hash(&a, puzzle));

let new_parent_coin = Coin {
Expand Down Expand Up @@ -265,7 +265,7 @@ mod tests {
&hex!("abababababababababababababababababababababababababababababababab");

let mut a = Allocator::new_limited(500_000_000);
let puzzle = spend.puzzle_reveal.to_node_ptr(&mut a).expect("to_clvm");
let puzzle = spend.puzzle_reveal.to_clvm(&mut a).expect("to_clvm");
let puzzle_hash = Bytes32::from(tree_hash(&a, puzzle));

let mut new_parent_coin = Coin {
Expand Down
21 changes: 11 additions & 10 deletions crates/chia-protocol/src/bytes.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use chia_traits::{chia_error, read_bytes, Streamable};
use clvm_traits::{ClvmDecoder, ClvmEncoder, FromClvm, FromClvmError, ToClvm, ToClvmError};
use clvm_utils::TreeHash;
use clvmr::Atom;
use sha2::{Digest, Sha256};
use std::array::TryFromSliceError;
use std::fmt;
Expand Down Expand Up @@ -109,14 +110,14 @@ impl FromJsonDict for Bytes {
}
}

impl<N> ToClvm<N> for Bytes {
fn to_clvm(&self, encoder: &mut impl ClvmEncoder<Node = N>) -> Result<N, ToClvmError> {
encoder.encode_atom(self.0.as_slice())
impl<N, E: ClvmEncoder<Node = N>> ToClvm<E> for Bytes {
fn to_clvm(&self, encoder: &mut E) -> Result<N, ToClvmError> {
encoder.encode_atom(Atom::Borrowed(self.0.as_slice()))
}
}

impl<N> FromClvm<N> for Bytes {
fn from_clvm(decoder: &impl ClvmDecoder<Node = N>, node: N) -> Result<Self, FromClvmError> {
impl<N, D: ClvmDecoder<Node = N>> FromClvm<D> for Bytes {
fn from_clvm(decoder: &D, node: N) -> Result<Self, FromClvmError> {
let bytes = decoder.decode_atom(&node)?;
Ok(Self(bytes.as_ref().to_vec()))
}
Expand Down Expand Up @@ -256,14 +257,14 @@ impl<const N: usize> FromJsonDict for BytesImpl<N> {
}
}

impl<N, const LEN: usize> ToClvm<N> for BytesImpl<LEN> {
fn to_clvm(&self, encoder: &mut impl ClvmEncoder<Node = N>) -> Result<N, ToClvmError> {
encoder.encode_atom(self.0.as_slice())
impl<N, E: ClvmEncoder<Node = N>, const LEN: usize> ToClvm<E> for BytesImpl<LEN> {
fn to_clvm(&self, encoder: &mut E) -> Result<N, ToClvmError> {
encoder.encode_atom(Atom::Borrowed(self.0.as_slice()))
}
}

impl<N, const LEN: usize> FromClvm<N> for BytesImpl<LEN> {
fn from_clvm(decoder: &impl ClvmDecoder<Node = N>, node: N) -> Result<Self, FromClvmError> {
impl<N, D: ClvmDecoder<Node = N>, const LEN: usize> FromClvm<D> for BytesImpl<LEN> {
fn from_clvm(decoder: &D, node: N) -> Result<Self, FromClvmError> {
let bytes = decoder.decode_atom(&node)?;
if bytes.as_ref().len() != LEN {
return Err(FromClvmError::WrongAtomLength {
Expand Down
8 changes: 4 additions & 4 deletions crates/chia-protocol/src/coin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,14 +55,14 @@ impl Coin {
}
}

impl<N> ToClvm<N> for Coin {
fn to_clvm(&self, encoder: &mut impl ClvmEncoder<Node = N>) -> Result<N, ToClvmError> {
impl<N, E: ClvmEncoder<Node = N>> ToClvm<E> for Coin {
fn to_clvm(&self, encoder: &mut E) -> Result<N, ToClvmError> {
clvm_list!(self.parent_coin_info, self.puzzle_hash, self.amount).to_clvm(encoder)
}
}

impl<N> FromClvm<N> for Coin {
fn from_clvm(decoder: &impl ClvmDecoder<Node = N>, node: N) -> Result<Self, FromClvmError> {
impl<N, D: ClvmDecoder<Node = N>> FromClvm<D> for Coin {
fn from_clvm(decoder: &D, node: N) -> Result<Self, FromClvmError> {
let destructure_list!(parent_coin_info, puzzle_hash, amount) =
<match_list!(BytesImpl<32>, BytesImpl<32>, u64)>::from_clvm(decoder, node)?;
Ok(Coin {
Expand Down
33 changes: 17 additions & 16 deletions crates/chia-protocol/src/program.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use crate::bytes::Bytes;
use chia_traits::chia_error::{Error, Result};
use chia_traits::Streamable;
use clvm_traits::{FromClvmError, FromNodePtr, ToClvmError, ToNodePtr};
use clvm_traits::{FromClvm, FromClvmError, ToClvm, ToClvmError};
use clvmr::allocator::NodePtr;
use clvmr::cost::Cost;
use clvmr::reduction::EvalErr;
Expand Down Expand Up @@ -54,14 +54,14 @@ impl Program {
self.0.into_inner()
}

pub fn run<A: ToNodePtr>(
pub fn run<A: ToClvm<Allocator>>(
&self,
a: &mut Allocator,
flags: u32,
max_cost: Cost,
arg: &A,
) -> std::result::Result<(Cost, NodePtr), EvalErr> {
let arg = arg.to_node_ptr(a).map_err(|_| {
let arg = arg.to_clvm(a).map_err(|_| {
EvalErr(
a.nil(),
"failed to convert argument to CLVM objects".to_string(),
Expand Down Expand Up @@ -316,7 +316,7 @@ impl Program {
fn py_to(args: &Bound<'_, PyAny>) -> PyResult<Program> {
let mut a = Allocator::new_limited(500_000_000);
let clvm = clvm_convert(&mut a, args)?;
Program::from_node_ptr(&a, clvm)
Program::from_clvm(&a, clvm)
.map_err(|error| PyErr::new::<PyTypeError, _>(error.to_string()))
}

Expand Down Expand Up @@ -416,7 +416,7 @@ impl Program {

let mut a = Allocator::new_limited(500_000_000);
let prg = node_from_bytes_backrefs(&mut a, self.0.as_ref())?;
let Ok(uncurried) = CurriedProgram::<NodePtr, NodePtr>::from_node_ptr(&a, prg) else {
let Ok(uncurried) = CurriedProgram::<NodePtr, NodePtr>::from_clvm(&a, prg) else {
let a = Rc::new(a);
let prg = LazyNode::new(a.clone(), prg);
let ret = a.nil();
Expand All @@ -432,11 +432,12 @@ impl Program {
}
// the args of curried puzzles are in the form of:
// (c . ((q . <arg1>) . (<rest> . ())))
let (_, ((_, arg), (rest, ()))) = <(
clvm_traits::MatchByte<4>,
(clvm_traits::match_quote!(NodePtr), (NodePtr, ())),
) as FromNodePtr>::from_node_ptr(&a, args)
.map_err(|error| PyErr::new::<PyTypeError, _>(error.to_string()))?;
let (_, ((_, arg), (rest, ()))) =
<(
clvm_traits::MatchByte<4>,
(clvm_traits::match_quote!(NodePtr), (NodePtr, ())),
) as FromClvm<Allocator>>::from_clvm(&a, args)
.map_err(|error| PyErr::new::<PyTypeError, _>(error.to_string()))?;
curried_args.push(arg);
args = rest;
}
Expand Down Expand Up @@ -501,8 +502,8 @@ impl FromJsonDict for Program {
}
}

impl FromNodePtr for Program {
fn from_node_ptr(a: &Allocator, node: NodePtr) -> std::result::Result<Self, FromClvmError> {
impl FromClvm<Allocator> for Program {
fn from_clvm(a: &Allocator, node: NodePtr) -> std::result::Result<Self, FromClvmError> {
Ok(Self(
node_to_bytes(a, node)
.map_err(|error| FromClvmError::Custom(error.to_string()))?
Expand All @@ -511,8 +512,8 @@ impl FromNodePtr for Program {
}
}

impl ToNodePtr for Program {
fn to_node_ptr(&self, a: &mut Allocator) -> std::result::Result<NodePtr, ToClvmError> {
impl ToClvm<Allocator> for Program {
fn to_clvm(&self, a: &mut Allocator) -> std::result::Result<NodePtr, ToClvmError> {
node_from_bytes(a, self.0.as_ref()).map_err(|error| ToClvmError::Custom(error.to_string()))
}
}
Expand All @@ -528,9 +529,9 @@ mod tests {
let expected_bytes = hex::decode(expected).unwrap();

let ptr = node_from_bytes(a, &expected_bytes).unwrap();
let program = Program::from_node_ptr(a, ptr).unwrap();
let program = Program::from_clvm(a, ptr).unwrap();

let round_trip = program.to_node_ptr(a).unwrap();
let round_trip = program.to_clvm(a).unwrap();
assert_eq!(expected, hex::encode(node_to_bytes(a, round_trip).unwrap()));
}

Expand Down
4 changes: 2 additions & 2 deletions crates/chia-puzzles/fuzz/fuzz_targets/roundtrip.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use std::fmt;

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

Expand All @@ -16,7 +16,7 @@ fuzz_target!(|data: &[u8]| {

fn roundtrip<'a, T>(u: &mut Unstructured<'a>)
where
T: Arbitrary<'a> + ToClvm<NodePtr> + FromClvm<NodePtr> + PartialEq + fmt::Debug,
T: Arbitrary<'a> + ToClvm<Allocator> + FromClvm<Allocator> + PartialEq + fmt::Debug,
{
let obj = T::arbitrary(u).unwrap();
let mut a = Allocator::new();
Expand Down
8 changes: 4 additions & 4 deletions crates/chia-puzzles/src/puzzles/cat.rs
Original file line number Diff line number Diff line change
Expand Up @@ -260,7 +260,7 @@ pub const CAT_PUZZLE_HASH_V1: TreeHash = TreeHash::new(hex!(

#[cfg(test)]
mod tests {
use clvm_traits::ToNodePtr;
use clvm_traits::ToClvm;
use clvm_utils::tree_hash;
use clvmr::{serde::node_from_bytes, Allocator};

Expand Down Expand Up @@ -298,7 +298,7 @@ mod tests {
},
),
}
.to_node_ptr(&mut a)
.to_clvm(&mut a)
.unwrap();

let allocated_tree_hash = hex::encode(tree_hash(&a, curried_ptr));
Expand All @@ -320,7 +320,7 @@ mod tests {
program: mod_ptr,
args: EverythingWithSignatureTailArgs::new(public_key),
}
.to_node_ptr(&mut a)
.to_clvm(&mut a)
.unwrap();

let allocated_tree_hash = hex::encode(tree_hash(&a, curried_ptr));
Expand All @@ -341,7 +341,7 @@ mod tests {
program: mod_ptr,
args: GenesisByCoinIdTailArgs::new(genesis_coin_id),
}
.to_node_ptr(&mut a)
.to_clvm(&mut a)
.unwrap();

let allocated_tree_hash = hex::encode(tree_hash(&a, curried_ptr));
Expand Down
8 changes: 4 additions & 4 deletions crates/chia-puzzles/src/puzzles/nft.rs
Original file line number Diff line number Diff line change
Expand Up @@ -195,8 +195,8 @@ impl Default for NftMetadata {
}
}

impl<N> FromClvm<N> for NftMetadata {
fn from_clvm(decoder: &impl ClvmDecoder<Node = N>, node: N) -> Result<Self, FromClvmError> {
impl<N, D: ClvmDecoder<Node = N>> FromClvm<D> for NftMetadata {
fn from_clvm(decoder: &D, node: N) -> Result<Self, FromClvmError> {
let items: Vec<(String, Raw<N>)> = FromClvm::from_clvm(decoder, node)?;
let mut metadata = Self::default();

Expand All @@ -218,8 +218,8 @@ impl<N> FromClvm<N> for NftMetadata {
}
}

impl<N> ToClvm<N> for NftMetadata {
fn to_clvm(&self, encoder: &mut impl ClvmEncoder<Node = N>) -> Result<N, ToClvmError> {
impl<N, E: ClvmEncoder<Node = N>> ToClvm<E> for NftMetadata {
fn to_clvm(&self, encoder: &mut E) -> Result<N, ToClvmError> {
let mut items: Vec<(&str, Raw<N>)> = Vec::new();

if !self.data_uris.is_empty() {
Expand Down
4 changes: 2 additions & 2 deletions crates/chia-puzzles/src/puzzles/standard.rs
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ pub const DEFAULT_HIDDEN_PUZZLE_HASH: TreeHash = TreeHash::new(hex!(

#[cfg(test)]
mod tests {
use clvm_traits::ToNodePtr;
use clvm_traits::ToClvm;
use clvm_utils::tree_hash;
use clvmr::{serde::node_from_bytes, Allocator};

Expand All @@ -102,7 +102,7 @@ mod tests {
program: mod_ptr,
args: StandardArgs::new(synthetic_key),
}
.to_node_ptr(&mut a)
.to_clvm(&mut a)
.unwrap();

let allocated_tree_hash = hex::encode(tree_hash(&a, curried_ptr));
Expand Down
8 changes: 4 additions & 4 deletions crates/chia-tools/src/bin/fast-forward-spend.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use chia_consensus::fast_forward::fast_forward_singleton;
use chia_protocol::Bytes32;
use chia_protocol::{Coin, CoinSpend, Program};
use chia_traits::streamable::Streamable;
use clvm_traits::{FromNodePtr, ToNodePtr};
use clvm_traits::{FromClvm, ToClvm};
use clvm_utils::tree_hash;
use clvmr::allocator::Allocator;

Expand Down Expand Up @@ -38,8 +38,8 @@ fn main() {
.unwrap();

let mut a = Allocator::new_limited(500_000_000);
let puzzle = spend.puzzle_reveal.to_node_ptr(&mut a).expect("to_clvm");
let solution = spend.solution.to_node_ptr(&mut a).expect("to_clvm");
let puzzle = spend.puzzle_reveal.to_clvm(&mut a).expect("to_clvm");
let solution = spend.solution.to_clvm(&mut a).expect("to_clvm");
let puzzle_hash = Bytes32::from(tree_hash(&a, puzzle));

let new_parent_coin = Coin {
Expand Down Expand Up @@ -67,7 +67,7 @@ fn main() {
let new_spend = CoinSpend {
coin: new_parent_coin,
puzzle_reveal: spend.puzzle_reveal,
solution: Program::from_node_ptr(&a, new_solution).expect("new solution"),
solution: Program::from_clvm(&a, new_solution).expect("new solution"),
};
let mut bytes = Vec::<u8>::new();
new_spend.stream(&mut bytes).expect("stream CoinSpend");
Expand Down
7 changes: 3 additions & 4 deletions crates/chia-tools/src/bin/gen-corpus.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use chia_traits::streamable::Streamable;
use chia_bls::G2Element;
use chia_protocol::{Bytes32, Coin, CoinSpend, Program, SpendBundle};
use chia_puzzles::singleton::SINGLETON_TOP_LAYER_PUZZLE_HASH;
use clvm_traits::{FromClvm, FromNodePtr};
use clvm_traits::FromClvm;
use clvm_utils::{tree_hash, CurriedProgram};
use clvmr::allocator::NodePtr;
use clvmr::Allocator;
Expand Down Expand Up @@ -100,9 +100,8 @@ fn main() {
if !run_puzzle && !fast_forward && !args.spend_bundles {
return;
}
let puzzle_reveal =
Program::from_node_ptr(a, puzzle).expect("puzzle reveal");
let solution = Program::from_node_ptr(a, solution).expect("solution");
let puzzle_reveal = Program::from_clvm(a, puzzle).expect("puzzle reveal");
let solution = Program::from_clvm(a, solution).expect("solution");
let coin = Coin {
parent_coin_info,
puzzle_hash,
Expand Down
Loading
Loading