ergotree_interpreter/eval/
spreheader.rs1use std::sync::Arc;
2
3use ergo_chain_types::PreHeader;
4use ergotree_ir::mir::constant::TryExtractInto;
5
6use super::EvalFn;
7
8pub(crate) static VERSION_EVAL_FN: EvalFn = |_env, _ctx, obj, _args| {
9 let preheader = obj.try_extract_into::<PreHeader>()?;
10 Ok((preheader.version as i8).into())
11};
12
13pub(crate) static PARENT_ID_EVAL_FN: EvalFn = |_env, _ctx, obj, _args| {
14 let preheader = obj.try_extract_into::<PreHeader>()?;
15 Ok(Into::<Vec<i8>>::into(preheader.parent_id).into())
16};
17
18pub(crate) static TIMESTAMP_EVAL_FN: EvalFn = |_env, _ctx, obj, _args| {
19 let preheader = obj.try_extract_into::<PreHeader>()?;
20 Ok((preheader.timestamp as i64).into())
21};
22
23pub(crate) static N_BITS_EVAL_FN: EvalFn = |_env, _ctx, obj, _args| {
24 let preheader = obj.try_extract_into::<PreHeader>()?;
25 Ok((preheader.n_bits as i64).into())
26};
27
28pub(crate) static HEIGHT_EVAL_FN: EvalFn = |_env, _ctx, obj, _args| {
29 let preheader = obj.try_extract_into::<PreHeader>()?;
30 Ok((preheader.height as i32).into())
31};
32
33pub(crate) static MINER_PK_EVAL_FN: EvalFn = |_env, _ctx, obj, _args| {
34 let preheader = obj.try_extract_into::<PreHeader>()?;
35 Ok(Arc::new(*preheader.miner_pk).into())
36};
37
38pub(crate) static VOTES_EVAL_FN: EvalFn = |_env, _ctx, obj, _args| {
39 let preheader = obj.try_extract_into::<PreHeader>()?;
40 Ok(Into::<Vec<u8>>::into(preheader.votes).into())
41};
42
43#[cfg(test)]
44#[cfg(feature = "arbitrary")]
45#[allow(clippy::expect_used)]
46mod tests {
47 use std::convert::{TryFrom, TryInto};
48
49 use ergo_chain_types::{BlockId, EcPoint, Votes};
50 use ergotree_ir::{
51 mir::{expr::Expr, property_call::PropertyCall},
52 types::{scontext, smethod::SMethod, spreheader},
53 };
54 use sigma_test_util::force_any_val;
55 use sigma_util::AsVecU8;
56
57 use crate::eval::{
58 context::Context,
59 tests::{eval_out, try_eval_out_wo_ctx},
60 };
61
62 fn create_get_preheader_property_expr(method: SMethod) -> Expr {
63 let get_preheader_expr = create_get_preheader_expr();
64 create_get_preheader_property_expr_impl(get_preheader_expr, method)
65 }
66
67 fn create_get_preheader_expr() -> Expr {
69 PropertyCall::new(Expr::Context, scontext::PRE_HEADER_PROPERTY.clone())
70 .expect("internal error: invalid preheader property call of Context")
71 .into()
72 }
73
74 fn create_get_preheader_property_expr_impl(headers_expr: Expr, method: SMethod) -> Expr {
75 PropertyCall::new(headers_expr, method)
76 .expect("internal error: invalid property call of PreHeader")
77 .into()
78 }
79
80 fn block_id_from_bytes_signed(bytes: Vec<i8>) -> BlockId {
81 let arr32 = bytes
82 .as_vec_u8()
83 .try_into()
84 .expect("internal error: bytes buffer length is not equal to 32");
85 BlockId(arr32)
86 }
87
88 #[test]
89 fn test_eval_version() {
90 let expr = create_get_preheader_property_expr(spreheader::VERSION_PROPERTY.clone());
91 let ctx = force_any_val::<Context>();
92 let expected = ctx.pre_header.version as i8;
93 assert_eq!(expected, eval_out::<i8>(&expr, &ctx));
94 }
95
96 #[test]
97 fn test_eval_parent_id() {
98 let expr = create_get_preheader_property_expr(spreheader::PARENT_ID_PROPERTY.clone());
99 let ctx = force_any_val::<Context>();
100 let expected = ctx.pre_header.parent_id;
101 let actual = {
102 let bs = eval_out::<Vec<i8>>(&expr, &ctx);
103 block_id_from_bytes_signed(bs)
104 };
105 assert_eq!(expected, actual);
106 }
107
108 #[test]
109 fn test_eval_timestamp() {
110 let expr = create_get_preheader_property_expr(spreheader::TIMESTAMP_PROPERTY.clone());
111 let ctx = force_any_val::<Context>();
112 let expected = ctx.pre_header.timestamp as i64;
113 let actual = eval_out::<i64>(&expr, &ctx);
114 assert_eq!(expected, actual);
115 }
116
117 #[test]
118 fn test_eval_n_bits() {
119 let expr = create_get_preheader_property_expr(spreheader::N_BITS_PROPERTY.clone());
120 let ctx = force_any_val::<Context>();
121 let expected = ctx.pre_header.n_bits as i64;
122 let actual = eval_out::<i64>(&expr, &ctx);
123 assert_eq!(expected, actual);
124 }
125
126 #[test]
127 fn test_eval_height() {
128 let expr = create_get_preheader_property_expr(spreheader::HEIGHT_PROPERTY.clone());
129 let ctx = force_any_val::<Context>();
130 let expected = ctx.pre_header.height as i32;
131 let actual = eval_out::<i32>(&expr, &ctx);
132 assert_eq!(expected, actual);
133 }
134
135 #[test]
136 fn test_eval_miner_pk() {
137 let expr = create_get_preheader_property_expr(spreheader::MINER_PK_PROPERTY.clone());
138 let ctx = force_any_val::<Context>();
139 let expected = ctx.pre_header.miner_pk.clone();
140 let actual = {
141 let pk = eval_out::<EcPoint>(&expr, &ctx);
142 Box::new(pk)
143 };
144 assert_eq!(expected, actual);
145 }
146
147 #[test]
148 fn test_eval_votes() {
149 let expr = create_get_preheader_property_expr(spreheader::VOTES_PROPERTY.clone());
150 let ctx = force_any_val::<Context>();
151 let expected = ctx.pre_header.votes.clone();
152 let actual = {
153 let votes_bytes = eval_out::<Vec<i8>>(&expr, &ctx).as_vec_u8();
154 Votes::try_from(votes_bytes)
155 .expect("internal error: votes bytes buffer length isn't equal to 3")
156 };
157 assert_eq!(expected, actual);
158 }
159
160 #[test]
161 fn test_eval_failed_invalid_obj() {
162 let expr: Expr = PropertyCall {
164 obj: Box::new(Expr::Context),
165 method: spreheader::VERSION_PROPERTY.clone(),
166 }
167 .into();
168 assert!(try_eval_out_wo_ctx::<i8>(&expr).is_err());
169 }
170
171 #[test]
172 fn test_eval_failed_unknown_property() {
173 let unknown_property = {
174 use ergotree_ir::types::{
175 smethod::{MethodId, SMethodDesc},
176 stype::SType,
177 stype_companion::STypeCompanion,
178 };
179 let method_desc =
180 SMethodDesc::property(SType::SPreHeader, "unknown", SType::SByte, MethodId(100));
181 SMethod::new(STypeCompanion::PreHeader, method_desc)
182 };
183 let expr = create_get_preheader_property_expr(unknown_property);
184 assert!(try_eval_out_wo_ctx::<i8>(&expr).is_err());
185 }
186}