Skip to content

Commit

Permalink
Add Global.deserialize method
Browse files Browse the repository at this point in the history
  • Loading branch information
SethDusek committed Jan 5, 2025
1 parent 2527351 commit 22e2338
Show file tree
Hide file tree
Showing 3 changed files with 138 additions and 9 deletions.
1 change: 1 addition & 0 deletions ergotree-interpreter/src/eval.rs
Original file line number Diff line number Diff line change
Expand Up @@ -345,6 +345,7 @@ fn smethod_eval_fn(method: &SMethod) -> Result<EvalFn, EvalError> {
sglobal::FROM_BIGENDIAN_BYTES_METHOD_ID => {
self::sglobal::SGLOBAL_FROM_BIGENDIAN_BYTES_EVAL_FN
}
sglobal::DESERIALIZE_METHOD_ID => self::sglobal::DESERIALIZE_EVAL_FN,
sglobal::SERIALIZE_METHOD_ID => self::sglobal::SERIALIZE_EVAL_FN,
method_id => {
return Err(EvalError::NotFound(format!(
Expand Down
89 changes: 84 additions & 5 deletions ergotree-interpreter/src/eval/sglobal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,14 @@ use crate::eval::EvalError;

use ergotree_ir::{
mir::{
constant::Constant,
constant::{Constant, TryExtractInto},
value::{CollKind, NativeColl, Value},
},
serialization::{data::DataSerializer, sigma_byte_writer::SigmaByteWriter},
serialization::{
data::DataSerializer,
sigma_byte_reader::{self, SigmaByteRead},
sigma_byte_writer::SigmaByteWriter,
},
};

use super::EvalFn;
Expand Down Expand Up @@ -147,6 +151,27 @@ pub(crate) static SGLOBAL_FROM_BIGENDIAN_BYTES_EVAL_FN: EvalFn = |mc, _env, _ctx
}
};

pub(crate) static DESERIALIZE_EVAL_FN: EvalFn = |mc, _env, ctx, obj, args| {
if obj != Value::Global {
return Err(EvalError::UnexpectedValue(format!(
"sglobal.groupGenerator expected obj to be Value::Global, got {:?}",
obj
)));
}
let output_type = &mc.tpe().t_range;
let bytes = args
.first()
.ok_or_else(|| EvalError::NotFound("deserialize: missing first arg".into()))?
.clone()
.try_extract_into::<Vec<u8>>()?;
let mut reader = sigma_byte_reader::from_bytes(&bytes);
Ok(Value::from(
reader.with_tree_version(ctx.tree_version(), |reader| {
DataSerializer::sigma_parse(output_type, reader)
})?,
))
};

pub(crate) static SERIALIZE_EVAL_FN: EvalFn = |_mc, _env, _ctx, obj, args| {
if obj != Value::Global {
return Err(EvalError::UnexpectedValue(format!(
Expand Down Expand Up @@ -181,14 +206,15 @@ mod tests {
use ergotree_ir::mir::property_call::PropertyCall;
use ergotree_ir::mir::sigma_prop_bytes::SigmaPropBytes;
use ergotree_ir::mir::unary_op::OneArgOpTryBuild;
use ergotree_ir::mir::value::Value;
use ergotree_ir::sigma_protocol::sigma_boolean::SigmaProp;
use ergotree_ir::types::sgroup_elem::GET_ENCODED_METHOD;
use ergotree_ir::types::stype_param::STypeVar;
use proptest::proptest;

use crate::eval::tests::{eval_out, eval_out_wo_ctx, try_eval_out_with_version};
use ergotree_ir::chain::context::Context;
use ergotree_ir::types::sglobal::{self, SERIALIZE_METHOD};
use ergotree_ir::types::sglobal::{self, DESERIALIZE_METHOD, SERIALIZE_METHOD};
use ergotree_ir::types::stype::SType;
use sigma_test_util::force_any_val;

Expand All @@ -198,8 +224,7 @@ mod tests {
Expr::Global,
SERIALIZE_METHOD.clone().with_concrete_types(
&[(STypeVar::t(), constant.tpe.clone())]
.iter()
.cloned()
.into_iter()
.collect(),
),
vec![constant.into()],
Expand All @@ -213,6 +238,30 @@ mod tests {
try_eval_out_with_version(&serialize_node.into(), &ctx, ErgoTreeVersion::V3.into(), 3)
.unwrap()
}
fn deserialize(array: &[u8], return_type: SType) -> Constant {
let type_args = [(STypeVar::t(), return_type)].into_iter().collect();
let deserialize_node = MethodCall::with_type_args(
Expr::Global,
DESERIALIZE_METHOD.clone().with_concrete_types(&type_args),
vec![Constant::from(array.to_owned()).into()],
type_args,
)
.unwrap();
let ctx = force_any_val::<Context>();
assert!((0u8..ErgoTreeVersion::V3.into()).all(|version| {
try_eval_out_with_version::<Vec<u8>>(&deserialize_node.clone().into(), &ctx, version, 3)
.is_err()
}));
try_eval_out_with_version::<Value>(
&deserialize_node.into(),
&ctx,
ErgoTreeVersion::V3.into(),
3,
)
.unwrap()
.try_into()
.unwrap()
}

#[test]
fn eval_group_generator() {
Expand Down Expand Up @@ -424,11 +473,41 @@ mod tests {
);
}

#[test]
fn deserialize_group_element() {
let ec_point = EcPoint::from_base16_str(String::from(
"026930cb9972e01534918a6f6d6b8e35bc398f57140d13eb3623ea31fbd069939b",
))
.unwrap();
let get_encoded = MethodCall::new(
Constant::from(ec_point.clone()).into(),
GET_ENCODED_METHOD.clone(),
vec![],
)
.unwrap();
let encoded = eval_out_wo_ctx::<Vec<u8>>(&get_encoded.into());
assert_eq!(
deserialize(&encoded, SType::SGroupElement),
Constant::from(ec_point)
);
}

proptest! {
#[test]
fn serialize_sigmaprop_eq_prop_bytes(sigma_prop: SigmaProp) {
let prop_bytes = SigmaPropBytes::try_build(Constant::from(sigma_prop.clone()).into()).unwrap();
assert_eq!(serialize(sigma_prop), &eval_out_wo_ctx::<Vec<u8>>(&prop_bytes.into())[2..])
}
#[test]
fn serialize_roundtrip(v in any::<Constant>()) {
let tpe = v.tpe.clone();
let res = std::panic::catch_unwind(|| assert_eq!(deserialize(&serialize(v.clone()), tpe.clone()), v));
if matches!(tpe, SType::SOption(_)) {
assert!(res.is_err());
}
else {
res.unwrap();
}
}
}
}
57 changes: 53 additions & 4 deletions ergotree-ir/src/types/sglobal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ use super::stype::SType;
use crate::types::smethod::SMethod;
use crate::types::stype_companion::STypeCompanion;
use crate::types::stype_param::STypeVar;
use alloc::boxed::Box;
use alloc::vec;
use alloc::vec::Vec;
use lazy_static::lazy_static;
Expand All @@ -21,15 +22,17 @@ pub static TYPE_NAME: &str = "Global";
pub const GROUP_GENERATOR_METHOD_ID: MethodId = MethodId(1);
/// "xor" predefined function
pub const XOR_METHOD_ID: MethodId = MethodId(2);
/// "fromBigEndianBytes" predefined function
pub const FROM_BIGENDIAN_BYTES_METHOD_ID: MethodId = MethodId(5);
/// serialize function added in v6.0
pub const SERIALIZE_METHOD_ID: MethodId = MethodId(3);
/// "fromBigEndianBytes" predefined function
pub const DESERIALIZE_METHOD_ID: MethodId = MethodId(4);
/// "fromBigEndianBytes" predefined function
pub const FROM_BIGENDIAN_BYTES_METHOD_ID: MethodId = MethodId(5);

lazy_static! {
/// Global method descriptors
pub(crate) static ref METHOD_DESC: Vec<&'static SMethodDesc> =
vec![&GROUP_GENERATOR_METHOD_DESC, &XOR_METHOD_DESC, &SERIALIZE_METHOD_DESC, &FROM_BIGENDIAN_BYTES_METHOD_DESC];
vec![&GROUP_GENERATOR_METHOD_DESC, &XOR_METHOD_DESC, &DESERIALIZE_METHOD_DESC, &SERIALIZE_METHOD_DESC, &FROM_BIGENDIAN_BYTES_METHOD_DESC];
}

lazy_static! {
Expand Down Expand Up @@ -84,6 +87,24 @@ lazy_static! {
};
/// GLOBAL.fromBigEndianBytes
pub static ref FROM_BIGENDIAN_BYTES_METHOD: SMethod = SMethod::new(STypeCompanion::Global, FROM_BIGENDIAN_BYTES_METHOD_DESC.clone(),);

static ref DESERIALIZE_METHOD_DESC: SMethodDesc = SMethodDesc {
method_id: DESERIALIZE_METHOD_ID,
name: "deserialize",
tpe: SFunc {
t_dom: vec![
SType::SGlobal,
SType::SColl(SType::SByte.into())
],
t_range: Box::new(STypeVar::t().into()),
tpe_params: vec![],
},
explicit_type_args: vec![STypeVar::t()],
min_version: ErgoTreeVersion::V3
};
/// GLOBAL.deserialize
pub static ref DESERIALIZE_METHOD: SMethod = SMethod::new(STypeCompanion::Global, DESERIALIZE_METHOD_DESC.clone(),);

static ref SERIALIZE_METHOD_DESC: SMethodDesc = SMethodDesc {
method_id: SERIALIZE_METHOD_ID,
name: "serialize",
Expand All @@ -98,6 +119,34 @@ lazy_static! {
explicit_type_args: vec![],
min_version: ErgoTreeVersion::V3
};
/// GLOBAL.serialize
/// GLOBAL.serialize
pub static ref SERIALIZE_METHOD: SMethod = SMethod::new(STypeCompanion::Global, SERIALIZE_METHOD_DESC.clone(),);
}

#[cfg(test)]
#[cfg(feature = "arbitrary")]
#[allow(clippy::unwrap_used)]
mod test {
use proptest::prelude::*;

use crate::{
mir::{expr::Expr, method_call::MethodCall},
serialization::SigmaSerializable,
types::{stype::SType, stype_param::STypeVar},
};

use super::DESERIALIZE_METHOD;
proptest! {
#[test]
fn test_deserialize_method_roundtrip(v in any::<SType>()) {
let type_args = core::iter::once((STypeVar::t(), v)).collect();
let mc = MethodCall::with_type_args(
Expr::Global,
DESERIALIZE_METHOD.clone().with_concrete_types(&type_args),
vec![vec![0i8].into()],
type_args,
).unwrap();
assert_eq!(MethodCall::sigma_parse_bytes(&mc.sigma_serialize_bytes().unwrap()).unwrap(), mc);
}
}
}

0 comments on commit 22e2338

Please sign in to comment.