Skip to content

Commit

Permalink
Merge pull request #592 from Chia-Network/traits-encoder
Browse files Browse the repository at this point in the history
CHIA-886: Redesign ToClvm and FromClvm to be generic over Encoder and Decoder
  • Loading branch information
Rigidity authored Jul 29, 2024
2 parents 74b6db4 + b3d4192 commit 30b23f4
Show file tree
Hide file tree
Showing 29 changed files with 585 additions and 319 deletions.
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

0 comments on commit 30b23f4

Please sign in to comment.