Skip to content

Commit

Permalink
add dependency on clvm-traits. add ToNodePtr and FromNodePtr traits, …
Browse files Browse the repository at this point in the history
…refining ToClvm and FromClvm traits
  • Loading branch information
arvidn committed Dec 6, 2023
1 parent 7e83769 commit a5153c3
Show file tree
Hide file tree
Showing 5 changed files with 303 additions and 1 deletion.
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ lazy_static = "=1.4.0"
num-bigint = "=0.4.3"
num-traits = "=0.2.15"
num-integer = "=0.1.45"
clvm-traits = "0.3.0"
# the experimental feature enables hashing to curves
bls12_381 = { version = "=0.8.0", features = ["experimental"] }
# the newer sha2 crate doesn't implement the digest traits required by HKDF
Expand Down
37 changes: 37 additions & 0 deletions src/allocator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ use crate::err_utils::err;
use crate::number::{node_from_number, number_from_u8, Number};
use crate::reduction::EvalErr;
use bls12_381::{G1Affine, G1Projective, G2Affine, G2Projective};
use clvm_traits::{ClvmDecoder, FromClvmError, ClvmEncoder, ToClvmError};

#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct NodePtr(pub i32);
Expand Down Expand Up @@ -334,6 +335,42 @@ impl Allocator {
}
}

impl ClvmEncoder for Allocator {
type Node = NodePtr;

fn encode_atom(&mut self, bytes: &[u8]) -> Result<Self::Node, ToClvmError> {
self.new_atom(bytes).or(Err(ToClvmError::OutOfMemory))
}

fn encode_pair(
&mut self,
first: Self::Node,
rest: Self::Node,
) -> Result<Self::Node, ToClvmError> {
self.new_pair(first, rest).or(Err(ToClvmError::OutOfMemory))
}
}

impl ClvmDecoder for Allocator {
type Node = NodePtr;

fn decode_atom(&self, node: &Self::Node) -> Result<&[u8], FromClvmError> {
if let SExp::Atom = self.sexp(*node) {
Ok(self.atom(*node))
} else {
Err(FromClvmError::ExpectedAtom)
}
}

fn decode_pair(&self, node: &Self::Node) -> Result<(Self::Node, Self::Node), FromClvmError> {
if let SExp::Pair(first, rest) = self.sexp(*node) {
Ok((first, rest))
} else {
Err(FromClvmError::ExpectedPair)
}
}
}

#[test]
fn test_atom_eq() {
let mut a = Allocator::new();
Expand Down
115 changes: 115 additions & 0 deletions src/from_node_ptr.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
use crate::{allocator::NodePtr, Allocator};

use clvm_traits::{ClvmDecoder, FromClvmError, FromClvm};

pub trait FromNodePtr {
fn from_node_ptr(a: &Allocator, node: NodePtr) -> Result<Self, FromClvmError>
where
Self: Sized;
}

impl<T> FromNodePtr for T
where
T: FromClvm<NodePtr>,
{
fn from_node_ptr(a: &Allocator, node: NodePtr) -> Result<Self, FromClvmError>
where
Self: Sized,
{
T::from_clvm(a, node)
}
}

impl FromClvm<NodePtr> for NodePtr {
fn from_clvm(
_decoder: &impl ClvmDecoder<Node = NodePtr>,
node: NodePtr,
) -> Result<Self, FromClvmError> {
Ok(node)
}
}

#[cfg(test)]
mod tests {
use crate::{allocator::NodePtr, serde::node_from_bytes, Allocator};

use super::*;

fn decode<T>(a: &mut Allocator, hex: &str) -> Result<T, FromClvmError>
where
T: FromClvm<NodePtr>,
{
let bytes = hex::decode(hex).unwrap();
let actual = node_from_bytes(a, &bytes).unwrap();
T::from_clvm(a, actual)
}

#[test]
fn test_nodeptr() {
let a = &mut Allocator::new();
let ptr = a.one();
assert_eq!(NodePtr::from_clvm(a, ptr).unwrap(), ptr);
}

#[test]
fn test_primitives() {
let a = &mut Allocator::new();
assert_eq!(decode(a, "80"), Ok(0u8));
assert_eq!(decode(a, "80"), Ok(0i8));
assert_eq!(decode(a, "05"), Ok(5u8));
assert_eq!(decode(a, "05"), Ok(5u32));
assert_eq!(decode(a, "05"), Ok(5i32));
assert_eq!(decode(a, "81e5"), Ok(-27i32));
assert_eq!(decode(a, "80"), Ok(-0));
assert_eq!(decode(a, "8180"), Ok(-128i8));
}

#[test]
fn test_pair() {
let a = &mut Allocator::new();
assert_eq!(decode(a, "ff0502"), Ok((5, 2)));
assert_eq!(decode(a, "ff81b8ff8301600980"), Ok((-72, (90121, ()))));
assert_eq!(
decode(a, "ffff80ff80ff80ffff80ff80ff80808080"),
Ok((((), ((), ((), (((), ((), ((), ()))), ())))), ()))
);
}

#[test]
fn test_nil() {
let a = &mut Allocator::new();
assert_eq!(decode(a, "80"), Ok(()));
}

#[test]
fn test_array() {
let a = &mut Allocator::new();
assert_eq!(decode(a, "ff01ff02ff03ff0480"), Ok([1, 2, 3, 4]));
assert_eq!(decode(a, "80"), Ok([] as [i32; 0]));
}

#[test]
fn test_vec() {
let a = &mut Allocator::new();
assert_eq!(decode(a, "ff01ff02ff03ff0480"), Ok(vec![1, 2, 3, 4]));
assert_eq!(decode(a, "80"), Ok(Vec::<i32>::new()));
}

#[test]
fn test_option() {
let a = &mut Allocator::new();
assert_eq!(decode(a, "8568656c6c6f"), Ok(Some("hello".to_string())));
assert_eq!(decode(a, "80"), Ok(None::<String>));

// Empty strings get decoded as None instead, since both values are represented by nil bytes.
// This could be considered either intended behavior or not, depending on the way it's used.
assert_ne!(decode(a, "80"), Ok(Some("".to_string())));
}

#[test]
fn test_string() {
let a = &mut Allocator::new();
assert_eq!(decode(a, "8568656c6c6f"), Ok("hello".to_string()));
assert_eq!(decode(a, "80"), Ok("".to_string()));
}
}
8 changes: 7 additions & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,13 @@ pub mod serde;
pub mod sha2;
pub mod traverse_path;

pub use allocator::Allocator;
pub mod from_node_ptr;
pub mod to_node_ptr;

pub use from_node_ptr::FromNodePtr;
pub use to_node_ptr::ToNodePtr;

pub use allocator::{Allocator, NodePtr};
pub use chia_dialect::ChiaDialect;
pub use run_program::run_program;

Expand Down
143 changes: 143 additions & 0 deletions src/to_node_ptr.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
use crate::{allocator::NodePtr, Allocator};

use clvm_traits::{ClvmEncoder, ToClvmError, ToClvm};

pub trait ToNodePtr {
fn to_node_ptr(&self, a: &mut Allocator) -> Result<NodePtr, ToClvmError>;
}

impl<T> ToNodePtr for T
where
T: ToClvm<NodePtr>,
{
fn to_node_ptr(&self, a: &mut Allocator) -> Result<NodePtr, ToClvmError> {
self.to_clvm(a)
}
}

impl ToClvm<NodePtr> for NodePtr {
fn to_clvm(
&self,
_encoder: &mut impl ClvmEncoder<Node = NodePtr>,
) -> Result<NodePtr, ToClvmError> {
Ok(*self)
}
}

#[cfg(test)]
mod tests {
use crate::{serde::node_to_bytes, Allocator};
use hex::ToHex;

use super::*;

fn encode<T>(a: &mut Allocator, value: T) -> Result<String, ToClvmError>
where
T: ToClvm<NodePtr>,
{
let actual = value.to_clvm(a).unwrap();
let actual_bytes = node_to_bytes(a, actual).unwrap();
Ok(actual_bytes.encode_hex())
}

#[test]
fn test_nodeptr() {
let a = &mut Allocator::new();
let ptr = a.one();
assert_eq!(ptr.to_clvm(a).unwrap(), ptr);
}

#[test]
fn test_primitives() {
let a = &mut Allocator::new();
assert_eq!(encode(a, 0u8), Ok("80".to_owned()));
assert_eq!(encode(a, 0i8), Ok("80".to_owned()));
assert_eq!(encode(a, 5u8), Ok("05".to_owned()));
assert_eq!(encode(a, 5u32), Ok("05".to_owned()));
assert_eq!(encode(a, 5i32), Ok("05".to_owned()));
assert_eq!(encode(a, -27i32), Ok("81e5".to_owned()));
assert_eq!(encode(a, -0), Ok("80".to_owned()));
assert_eq!(encode(a, -128i8), Ok("8180".to_owned()));
}

#[test]
fn test_reference() {
let a = &mut Allocator::new();
assert_eq!(encode(a, [1, 2, 3]), encode(a, [1, 2, 3]));
assert_eq!(encode(a, Some(42)), encode(a, Some(42)));
assert_eq!(encode(a, Some(&42)), encode(a, Some(42)));
assert_eq!(encode(a, Some(&42)), encode(a, Some(42)));
}

#[test]
fn test_pair() {
let a = &mut Allocator::new();
assert_eq!(encode(a, (5, 2)), Ok("ff0502".to_owned()));
assert_eq!(
encode(a, (-72, (90121, ()))),
Ok("ff81b8ff8301600980".to_owned())
);
assert_eq!(
encode(a, (((), ((), ((), (((), ((), ((), ()))), ())))), ())),
Ok("ffff80ff80ff80ffff80ff80ff80808080".to_owned())
);
}

#[test]
fn test_nil() {
let a = &mut Allocator::new();
assert_eq!(encode(a, ()), Ok("80".to_owned()));
}

#[test]
fn test_slice() {
let a = &mut Allocator::new();
assert_eq!(
encode(a, [1, 2, 3, 4].as_slice()),
Ok("ff01ff02ff03ff0480".to_owned())
);
assert_eq!(encode(a, [0; 0].as_slice()), Ok("80".to_owned()));
}

#[test]
fn test_array() {
let a = &mut Allocator::new();
assert_eq!(encode(a, [1, 2, 3, 4]), Ok("ff01ff02ff03ff0480".to_owned()));
assert_eq!(encode(a, [0; 0]), Ok("80".to_owned()));
}

#[test]
fn test_vec() {
let a = &mut Allocator::new();
assert_eq!(
encode(a, vec![1, 2, 3, 4]),
Ok("ff01ff02ff03ff0480".to_owned())
);
assert_eq!(encode(a, vec![0; 0]), Ok("80".to_owned()));
}

#[test]
fn test_option() {
let a = &mut Allocator::new();
assert_eq!(encode(a, Some("hello")), Ok("8568656c6c6f".to_owned()));
assert_eq!(encode(a, None::<&str>), Ok("80".to_owned()));
assert_eq!(encode(a, Some("")), Ok("80".to_owned()));
}

#[test]
fn test_str() {
let a = &mut Allocator::new();
assert_eq!(encode(a, "hello"), Ok("8568656c6c6f".to_owned()));
assert_eq!(encode(a, ""), Ok("80".to_owned()));
}

#[test]
fn test_string() {
let a = &mut Allocator::new();
assert_eq!(
encode(a, "hello".to_string()),
Ok("8568656c6c6f".to_owned())
);
assert_eq!(encode(a, "".to_string()), Ok("80".to_owned()));
}
}

0 comments on commit a5153c3

Please sign in to comment.