@@ -2,6 +2,7 @@ use crate::eval::EvalError;
22use alloc:: boxed:: Box ;
33use alloc:: { string:: ToString , sync:: Arc } ;
44
5+ use ergo_chain_types:: autolykos_pow_scheme:: { decode_compact_bits, encode_compact_bits} ;
56use ergotree_ir:: serialization:: sigma_byte_writer:: SigmaByteWrite ;
67use ergotree_ir:: {
78 mir:: {
@@ -14,6 +15,7 @@ use ergotree_ir::{
1415 sigma_byte_writer:: SigmaByteWriter ,
1516 } ,
1617} ;
18+ use num_bigint:: BigInt ;
1719
1820use super :: EvalFn ;
1921use crate :: eval:: Vec ;
@@ -219,6 +221,31 @@ pub(crate) static SGLOBAL_NONE_EVAL_FN: EvalFn = |_mc, _env, _ctx, obj, _args| {
219221 Ok ( Value :: Opt ( None ) )
220222} ;
221223
224+ pub ( crate ) static ENCODE_NBITS_EVAL_FN : EvalFn = |_mc, _env, _ctx, _obj, args| {
225+ let bigint: BigInt = args
226+ . first ( )
227+ . cloned ( )
228+ . ok_or_else ( || EvalError :: NotFound ( "encodeNBits: missing first argument" . into ( ) ) ) ?
229+ . try_extract_into :: < BigInt256 > ( ) ?
230+ . into ( ) ;
231+ Ok ( Value :: Long ( encode_compact_bits ( & bigint) ) )
232+ } ;
233+
234+ pub ( crate ) static DECODE_NBITS_EVAL_FN : EvalFn = |_mc, _env, _ctx, _obj, args| {
235+ let nbits: i64 = args
236+ . first ( )
237+ . cloned ( )
238+ . ok_or_else ( || EvalError :: NotFound ( "decodeNBits: missing first argument" . into ( ) ) ) ?
239+ . try_extract_into ( ) ?;
240+ // truncation is safe here, since only bottom 4 bytes are used in decode.
241+ // nbits is only i64 because Scala doesn't have an unsigned 32-bit type
242+ Ok ( Value :: BigInt (
243+ decode_compact_bits ( nbits as u32 )
244+ . try_into ( )
245+ . map_err ( EvalError :: UnexpectedValue ) ?,
246+ ) )
247+ } ;
248+
222249#[ allow( clippy:: unwrap_used) ]
223250#[ cfg( test) ]
224251#[ cfg( feature = "arbitrary" ) ]
@@ -238,11 +265,14 @@ mod tests {
238265 use ergotree_ir:: types:: sgroup_elem:: GET_ENCODED_METHOD ;
239266 use ergotree_ir:: types:: stype_param:: STypeVar ;
240267 use ergotree_ir:: unsignedbigint256:: UnsignedBigInt ;
268+ use num_traits:: Num ;
241269 use proptest:: proptest;
242270
243271 use crate :: eval:: tests:: { eval_out, eval_out_wo_ctx, try_eval_out_with_version} ;
244272 use ergotree_ir:: chain:: context:: Context ;
245- use ergotree_ir:: types:: sglobal:: { self , DESERIALIZE_METHOD , SERIALIZE_METHOD } ;
273+ use ergotree_ir:: types:: sglobal:: {
274+ self , DECODE_NBITS_METHOD , DESERIALIZE_METHOD , ENCODE_NBITS_METHOD , SERIALIZE_METHOD ,
275+ } ;
246276 use ergotree_ir:: types:: stype:: SType ;
247277 use sigma_test_util:: force_any_val;
248278
@@ -291,6 +321,28 @@ mod tests {
291321 . unwrap ( )
292322 }
293323
324+ fn encode_nbits ( bigint : BigInt256 ) -> i64 {
325+ let mc: Expr = MethodCall :: new (
326+ Expr :: Global ,
327+ ENCODE_NBITS_METHOD . clone ( ) ,
328+ vec ! [ bigint. into( ) ] ,
329+ )
330+ . unwrap ( )
331+ . into ( ) ;
332+ eval_out_wo_ctx ( & mc)
333+ }
334+
335+ fn decode_nbits ( nbits : i64 ) -> BigInt256 {
336+ let mc: Expr = MethodCall :: new (
337+ Expr :: Global ,
338+ DECODE_NBITS_METHOD . clone ( ) ,
339+ vec ! [ nbits. into( ) ] ,
340+ )
341+ . unwrap ( )
342+ . into ( ) ;
343+ eval_out_wo_ctx ( & mc)
344+ }
345+
294346 fn create_some_none_method_call < T > ( value : Option < T > , tpe : SType ) -> Expr
295347 where
296348 T : Into < Constant > ,
@@ -347,6 +399,55 @@ mod tests {
347399 ) ;
348400 }
349401
402+ #[ test]
403+ fn test_eval_encode_nbits ( ) {
404+ assert_eq ! (
405+ encode_nbits(
406+ BigInt256 :: from_str_radix( "1bc330000000000000000000000000000000000000000000" , 16 )
407+ . unwrap( )
408+ ) ,
409+ 0x181bc330
410+ ) ;
411+
412+ assert_eq ! (
413+ encode_nbits( BigInt256 :: from_str_radix( "12345600" , 16 ) . unwrap( ) ) ,
414+ 0x04123456
415+ ) ;
416+ assert_eq ! (
417+ encode_nbits( BigInt256 :: from_str_radix( "-12345600" , 16 ) . unwrap( ) ) ,
418+ -0x1235
419+ ) ;
420+ }
421+
422+ #[ test]
423+ fn test_eval_decode_nbits ( ) {
424+ // Following example taken from https://btcinformation.org/en/developer-reference#target-nbits
425+ let n_bits = 0x181bc330 ;
426+ assert_eq ! (
427+ decode_nbits( n_bits) ,
428+ BigInt256 :: from_str_radix( "1bc330000000000000000000000000000000000000000000" , 16 )
429+ . unwrap( )
430+ ) ;
431+
432+ let n_bits = 0x01003456 ;
433+ assert_eq ! ( decode_nbits( n_bits) , 0x00 . into( ) ) ;
434+
435+ let n_bits = 0x01123456 ;
436+ assert_eq ! ( decode_nbits( n_bits) , 0x12 . into( ) ) ;
437+
438+ let n_bits = 0x04923456 ;
439+ assert_eq ! ( decode_nbits( n_bits) , ( -0x12345600i64 ) . into( ) ) ;
440+
441+ let n_bits = 0x04123456 ;
442+ assert_eq ! ( decode_nbits( n_bits) , 0x12345600 . into( ) ) ;
443+
444+ let n_bits = 0x05123456 ;
445+ assert_eq ! ( decode_nbits( n_bits) , 0x1234560000i64 . into( ) ) ;
446+
447+ let n_bits = 16842752 ;
448+ assert_eq ! ( decode_nbits( n_bits) , BigInt256 :: from( 1_i8 ) ) ;
449+ }
450+
350451 use proptest:: prelude:: * ;
351452
352453 proptest ! {
0 commit comments