use ergo_chain_types::PreHeader;
use ergotree_ir::mir::constant::TryExtractInto;
use super::EvalFn;
pub(crate) static VERSION_EVAL_FN: EvalFn = |_env, _ctx, obj, _args| {
let preheader = obj.try_extract_into::<PreHeader>()?;
Ok((preheader.version as i8).into())
};
pub(crate) static PARENT_ID_EVAL_FN: EvalFn = |_env, _ctx, obj, _args| {
let preheader = obj.try_extract_into::<PreHeader>()?;
Ok(Into::<Vec<i8>>::into(preheader.parent_id).into())
};
pub(crate) static TIMESTAMP_EVAL_FN: EvalFn = |_env, _ctx, obj, _args| {
let preheader = obj.try_extract_into::<PreHeader>()?;
Ok((preheader.timestamp as i64).into())
};
pub(crate) static N_BITS_EVAL_FN: EvalFn = |_env, _ctx, obj, _args| {
let preheader = obj.try_extract_into::<PreHeader>()?;
Ok((preheader.n_bits as i64).into())
};
pub(crate) static HEIGHT_EVAL_FN: EvalFn = |_env, _ctx, obj, _args| {
let preheader = obj.try_extract_into::<PreHeader>()?;
Ok((preheader.height as i32).into())
};
pub(crate) static MINER_PK_EVAL_FN: EvalFn = |_env, _ctx, obj, _args| {
let preheader = obj.try_extract_into::<PreHeader>()?;
Ok(preheader.miner_pk.into())
};
pub(crate) static VOTES_EVAL_FN: EvalFn = |_env, _ctx, obj, _args| {
let preheader = obj.try_extract_into::<PreHeader>()?;
Ok(Into::<Vec<u8>>::into(preheader.votes).into())
};
#[cfg(test)]
#[cfg(feature = "arbitrary")]
#[allow(clippy::expect_used)]
mod tests {
use std::convert::{TryFrom, TryInto};
use std::rc::Rc;
use ergo_chain_types::{BlockId, EcPoint, Votes};
use ergotree_ir::{
mir::{expr::Expr, property_call::PropertyCall},
types::{scontext, smethod::SMethod, spreheader},
};
use sigma_test_util::force_any_val;
use sigma_util::AsVecU8;
use crate::eval::{
context::Context,
tests::{eval_out, try_eval_out_wo_ctx},
};
fn create_get_preheader_property_expr(method: SMethod) -> Expr {
let get_preheader_expr = create_get_preheader_expr();
create_get_preheader_property_expr_impl(get_preheader_expr, method)
}
fn create_get_preheader_expr() -> Expr {
PropertyCall::new(Expr::Context, scontext::PRE_HEADER_PROPERTY.clone())
.expect("internal error: invalid preheader property call of Context")
.into()
}
fn create_get_preheader_property_expr_impl(headers_expr: Expr, method: SMethod) -> Expr {
PropertyCall::new(headers_expr, method)
.expect("internal error: invalid property call of PreHeader")
.into()
}
fn block_id_from_bytes_signed(bytes: Vec<i8>) -> BlockId {
let arr32 = bytes
.as_vec_u8()
.try_into()
.expect("internal error: bytes buffer length is not equal to 32");
BlockId(arr32)
}
#[test]
fn test_eval_version() {
let expr = create_get_preheader_property_expr(spreheader::VERSION_PROPERTY.clone());
let ctx = Rc::new(force_any_val::<Context>());
let expected = ctx.pre_header.version as i8;
assert_eq!(expected, eval_out::<i8>(&expr, ctx));
}
#[test]
fn test_eval_parent_id() {
let expr = create_get_preheader_property_expr(spreheader::PARENT_ID_PROPERTY.clone());
let ctx = Rc::new(force_any_val::<Context>());
let expected = ctx.pre_header.parent_id;
let actual = {
let bs = eval_out::<Vec<i8>>(&expr, ctx);
block_id_from_bytes_signed(bs)
};
assert_eq!(expected, actual);
}
#[test]
fn test_eval_timestamp() {
let expr = create_get_preheader_property_expr(spreheader::TIMESTAMP_PROPERTY.clone());
let ctx = Rc::new(force_any_val::<Context>());
let expected = ctx.pre_header.timestamp as i64;
let actual = eval_out::<i64>(&expr, ctx);
assert_eq!(expected, actual);
}
#[test]
fn test_eval_n_bits() {
let expr = create_get_preheader_property_expr(spreheader::N_BITS_PROPERTY.clone());
let ctx = Rc::new(force_any_val::<Context>());
let expected = ctx.pre_header.n_bits as i64;
let actual = eval_out::<i64>(&expr, ctx);
assert_eq!(expected as i64, actual);
}
#[test]
fn test_eval_height() {
let expr = create_get_preheader_property_expr(spreheader::HEIGHT_PROPERTY.clone());
let ctx = Rc::new(force_any_val::<Context>());
let expected = ctx.pre_header.height as i32;
let actual = eval_out::<i32>(&expr, ctx);
assert_eq!(expected, actual);
}
#[test]
fn test_eval_miner_pk() {
let expr = create_get_preheader_property_expr(spreheader::MINER_PK_PROPERTY.clone());
let ctx = Rc::new(force_any_val::<Context>());
let expected = ctx.pre_header.miner_pk.clone();
let actual = {
let pk = eval_out::<EcPoint>(&expr, ctx);
Box::new(pk)
};
assert_eq!(expected, actual);
}
#[test]
fn test_eval_votes() {
let expr = create_get_preheader_property_expr(spreheader::VOTES_PROPERTY.clone());
let ctx = Rc::new(force_any_val::<Context>());
let expected = ctx.pre_header.votes.clone();
let actual = {
let votes_bytes = eval_out::<Vec<i8>>(&expr, ctx).as_vec_u8();
Votes::try_from(votes_bytes)
.expect("internal error: votes bytes buffer length isn't equal to 3")
};
assert_eq!(expected, actual);
}
#[test]
fn test_eval_failed_invalid_obj() {
let expr: Expr = PropertyCall {
obj: Box::new(Expr::Context),
method: spreheader::VERSION_PROPERTY.clone(),
}
.into();
assert!(try_eval_out_wo_ctx::<i8>(&expr).is_err());
}
#[test]
fn test_eval_failed_unknown_property() {
let unknown_property = {
use ergotree_ir::types::{
smethod::{MethodId, SMethodDesc},
stype::SType,
stype_companion::STypeCompanion,
};
let method_desc =
SMethodDesc::property(SType::SPreHeader, "unknown", SType::SByte, MethodId(100));
SMethod::new(STypeCompanion::PreHeader, method_desc)
};
let expr = create_get_preheader_property_expr(unknown_property);
assert!(try_eval_out_wo_ctx::<i8>(&expr).is_err());
}
}