Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

mbuffer from big float with gob encode vm hook impl + tests #1444

Draft
wants to merge 3 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,11 @@ pub trait ManagedBufferFeatures {
ManagedBuffer::new()
}

#[endpoint]
fn mbuffer_from_big_float(&self, big_float: BigFloat) -> ManagedBuffer {
ManagedBuffer::from(big_float)
}

#[endpoint]
fn mbuffer_concat(&self, mb1: ManagedBuffer, mb2: ManagedBuffer) -> ManagedBuffer {
let mut result = mb1;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use multiversx_sc::types::{ManagedAddress, ManagedBuffer};
use multiversx_sc::types::{BigFloat, BigUint, ManagedAddress, ManagedBuffer};
use multiversx_sc_scenario::{api::StaticApi, *};

use basic_features::managed_buffer_features::ManagedBufferFeatures;
Expand All @@ -10,6 +10,14 @@ fn test_managed_buffer_new_empty() {
assert_eq!(ManagedBuffer::new(), result);
}

#[test]
fn test_managed_buffer_from_big_float() {
let bf = basic_features::contract_obj::<StaticApi>();
let big_float = BigFloat::from_big_uint(&BigUint::from(5u64));
let result = bf.mbuffer_from_big_float(big_float);
println!("result is {:#?}", result);
}

#[test]
fn test_managed_address_zero() {
let bf = basic_features::contract_obj::<StaticApi>();
Expand Down
22 changes: 21 additions & 1 deletion framework/base/src/types/managed/basic/managed_buffer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use crate::{
abi::TypeName,
api::{
use_raw_handle, ErrorApiImpl, HandleConstraints, InvalidSliceError, ManagedBufferApiImpl,
ManagedTypeApi, StaticVarApiImpl,
ManagedTypeApi, ManagedTypeApiImpl, StaticVarApiImpl,
},
codec::{
CodecFrom, CodecFromSelf, DecodeErrorHandler, Empty, EncodeErrorHandler, NestedDecode,
Expand All @@ -15,6 +15,8 @@ use crate::{
types::{heap::BoxedBytes, ManagedType, StaticBufferRef},
};

use super::BigFloat;

/// A byte buffer managed by an external API.
#[repr(transparent)]
pub struct ManagedBuffer<M: ManagedTypeApi> {
Expand Down Expand Up @@ -96,6 +98,24 @@ impl<M: ManagedTypeApi> ManagedBuffer<M> {
self.overwrite(result);
});
}

pub fn mb_from_big_float(big_float: BigFloat<M>) -> Self {
let big_float_handle = big_float.get_handle();
let new_handle: M::ManagedBufferHandle =
use_raw_handle(M::static_var_api_impl().next_handle());
M::managed_type_impl().mb_from_big_float(big_float_handle, new_handle.clone());
ManagedBuffer::from_handle(new_handle)
}
}

impl<M> From<BigFloat<M>> for ManagedBuffer<M>
where
M: ManagedTypeApi,
{
#[inline]
fn from(big_float: BigFloat<M>) -> Self {
Self::mb_from_big_float(big_float)
}
}

impl<M> From<&[u8]> for ManagedBuffer<M>
Expand Down
2 changes: 2 additions & 0 deletions vm/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ itertools = "0.12.0"
hex-literal = "=0.4.1"
bitflags = "=2.4.2"
colored = "2.1.0"
gob = "0.1.0"
serde = "1.0.197"

[dependencies.multiversx-chain-vm-executor]
version = "0.2.0"
4 changes: 3 additions & 1 deletion vm/src/vm_hooks/vh_dispatcher.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1413,7 +1413,9 @@ impl VMHooks for VMHooksDispatcher {
}

fn mbuffer_from_big_float(&self, m_buffer_handle: i32, big_float_handle: i32) -> i32 {
panic!("Unavailable: mbuffer_from_big_float")
self.handler
.mb_from_big_float(m_buffer_handle, big_float_handle);
0
}

fn mbuffer_storage_store(&self, key_handle: i32, source_handle: i32) -> i32 {
Expand Down
139 changes: 139 additions & 0 deletions vm/src/vm_hooks/vh_handler/vh_managed_types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@
mod vh_managed_buffer;
mod vh_managed_map;

use gob::{ser::TypeId, Buf, StreamDeserializer, StreamSerializer};

Check failure on line 6 in vm/src/vm_hooks/vh_handler/vh_managed_types.rs

View workflow job for this annotation

GitHub Actions / clippy

[clippy] vm/src/vm_hooks/vh_handler/vh_managed_types.rs#L6

error[E0432]: unresolved import `gob::Buf` --> vm/src/vm_hooks/vh_handler/vh_managed_types.rs:6:24 | 6 | use gob::{ser::TypeId, Buf, StreamDeserializer, StreamSerializer}; | ^^^ no `Buf` in the root
Raw output
vm/src/vm_hooks/vh_handler/vh_managed_types.rs:6:24:e:error[E0432]: unresolved import `gob::Buf`
 --> vm/src/vm_hooks/vh_handler/vh_managed_types.rs:6:24
  |
6 | use gob::{ser::TypeId, Buf, StreamDeserializer, StreamSerializer};
  |                        ^^^ no `Buf` in the root


__END__

Check warning on line 6 in vm/src/vm_hooks/vh_handler/vh_managed_types.rs

View workflow job for this annotation

GitHub Actions / clippy

[clippy] vm/src/vm_hooks/vh_handler/vh_managed_types.rs#L6

warning: unused imports: `StreamDeserializer`, `StreamSerializer`, `ser::TypeId` --> vm/src/vm_hooks/vh_handler/vh_managed_types.rs:6:11 | 6 | use gob::{ser::TypeId, Buf, StreamDeserializer, StreamSerializer}; | ^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^ | = note: `#[warn(unused_imports)]` on by default
Raw output
vm/src/vm_hooks/vh_handler/vh_managed_types.rs:6:11:w:warning: unused imports: `StreamDeserializer`, `StreamSerializer`, `ser::TypeId`
 --> vm/src/vm_hooks/vh_handler/vh_managed_types.rs:6:11
  |
6 | use gob::{ser::TypeId, Buf, StreamDeserializer, StreamSerializer};
  |           ^^^^^^^^^^^       ^^^^^^^^^^^^^^^^^^  ^^^^^^^^^^^^^^^^
  |
  = note: `#[warn(unused_imports)]` on by default


__END__

Check failure on line 6 in vm/src/vm_hooks/vh_handler/vh_managed_types.rs

View workflow job for this annotation

GitHub Actions / Contracts / Rust tests

unresolved import `gob::Buf`

Check warning on line 6 in vm/src/vm_hooks/vh_handler/vh_managed_types.rs

View workflow job for this annotation

GitHub Actions / Contracts / Rust tests

unused imports: `StreamDeserializer`, `StreamSerializer`, `ser::TypeId`

Check failure on line 6 in vm/src/vm_hooks/vh_handler/vh_managed_types.rs

View workflow job for this annotation

GitHub Actions / Test Coverage

unresolved import `gob::Buf`

Check warning on line 6 in vm/src/vm_hooks/vh_handler/vh_managed_types.rs

View workflow job for this annotation

GitHub Actions / Test Coverage

unused imports: `StreamDeserializer`, `StreamSerializer`, `ser::TypeId`

Check failure on line 6 in vm/src/vm_hooks/vh_handler/vh_managed_types.rs

View workflow job for this annotation

GitHub Actions / Template tool test - current (unreleased) templates

unresolved import `gob::Buf`

Check failure on line 6 in vm/src/vm_hooks/vh_handler/vh_managed_types.rs

View workflow job for this annotation

GitHub Actions / Template tool test - current (unreleased) templates

unused imports: `StreamDeserializer`, `StreamSerializer`, `ser::TypeId`

Check failure on line 6 in vm/src/vm_hooks/vh_handler/vh_managed_types.rs

View workflow job for this annotation

GitHub Actions / Template tool test - current (unreleased) templates

unresolved import `gob::Buf`

Check failure on line 6 in vm/src/vm_hooks/vh_handler/vh_managed_types.rs

View workflow job for this annotation

GitHub Actions / Template tool test - current (unreleased) templates

unused imports: `StreamDeserializer`, `StreamSerializer`, `ser::TypeId`

Check failure on line 6 in vm/src/vm_hooks/vh_handler/vh_managed_types.rs

View workflow job for this annotation

GitHub Actions / Contracts / Wasm tests

unresolved import `gob::Buf`

Check warning on line 6 in vm/src/vm_hooks/vh_handler/vh_managed_types.rs

View workflow job for this annotation

GitHub Actions / Contracts / Wasm tests

unused imports: `StreamDeserializer`, `StreamSerializer`, `ser::TypeId`
use num_traits::{float, Signed, ToBytes};

Check warning on line 7 in vm/src/vm_hooks/vh_handler/vh_managed_types.rs

View workflow job for this annotation

GitHub Actions / clippy

[clippy] vm/src/vm_hooks/vh_handler/vh_managed_types.rs#L7

warning: unused imports: `Signed`, `float` --> vm/src/vm_hooks/vh_handler/vh_managed_types.rs:7:18 | 7 | use num_traits::{float, Signed, ToBytes}; | ^^^^^ ^^^^^^
Raw output
vm/src/vm_hooks/vh_handler/vh_managed_types.rs:7:18:w:warning: unused imports: `Signed`, `float`
 --> vm/src/vm_hooks/vh_handler/vh_managed_types.rs:7:18
  |
7 | use num_traits::{float, Signed, ToBytes};
  |                  ^^^^^  ^^^^^^


__END__

Check warning on line 7 in vm/src/vm_hooks/vh_handler/vh_managed_types.rs

View workflow job for this annotation

GitHub Actions / clippy

[clippy] vm/src/vm_hooks/vh_handler/vh_managed_types.rs#L7

warning: unused import: `ToBytes` --> vm/src/vm_hooks/vh_handler/vh_managed_types.rs:7:33 | 7 | use num_traits::{float, Signed, ToBytes}; | ^^^^^^^
Raw output
vm/src/vm_hooks/vh_handler/vh_managed_types.rs:7:33:w:warning: unused import: `ToBytes`
 --> vm/src/vm_hooks/vh_handler/vh_managed_types.rs:7:33
  |
7 | use num_traits::{float, Signed, ToBytes};
  |                                 ^^^^^^^


__END__

Check warning on line 7 in vm/src/vm_hooks/vh_handler/vh_managed_types.rs

View workflow job for this annotation

GitHub Actions / Contracts / Rust tests

unused imports: `Signed`, `float`

Check warning on line 7 in vm/src/vm_hooks/vh_handler/vh_managed_types.rs

View workflow job for this annotation

GitHub Actions / Contracts / Rust tests

unused import: `ToBytes`

Check warning on line 7 in vm/src/vm_hooks/vh_handler/vh_managed_types.rs

View workflow job for this annotation

GitHub Actions / Test Coverage

unused imports: `Signed`, `float`

Check warning on line 7 in vm/src/vm_hooks/vh_handler/vh_managed_types.rs

View workflow job for this annotation

GitHub Actions / Test Coverage

unused import: `ToBytes`

Check failure on line 7 in vm/src/vm_hooks/vh_handler/vh_managed_types.rs

View workflow job for this annotation

GitHub Actions / Template tool test - current (unreleased) templates

unused imports: `Signed`, `float`

Check failure on line 7 in vm/src/vm_hooks/vh_handler/vh_managed_types.rs

View workflow job for this annotation

GitHub Actions / Template tool test - current (unreleased) templates

unused import: `ToBytes`

Check failure on line 7 in vm/src/vm_hooks/vh_handler/vh_managed_types.rs

View workflow job for this annotation

GitHub Actions / Template tool test - current (unreleased) templates

unused imports: `Signed`, `float`

Check failure on line 7 in vm/src/vm_hooks/vh_handler/vh_managed_types.rs

View workflow job for this annotation

GitHub Actions / Template tool test - current (unreleased) templates

unused import: `ToBytes`

Check warning on line 7 in vm/src/vm_hooks/vh_handler/vh_managed_types.rs

View workflow job for this annotation

GitHub Actions / Contracts / Wasm tests

unused imports: `Signed`, `float`

Check warning on line 7 in vm/src/vm_hooks/vh_handler/vh_managed_types.rs

View workflow job for this annotation

GitHub Actions / Contracts / Wasm tests

unused import: `ToBytes`
use serde::ser::Serializer;

Check warning on line 8 in vm/src/vm_hooks/vh_handler/vh_managed_types.rs

View workflow job for this annotation

GitHub Actions / clippy

[clippy] vm/src/vm_hooks/vh_handler/vh_managed_types.rs#L8

warning: unused import: `serde::ser::Serializer` --> vm/src/vm_hooks/vh_handler/vh_managed_types.rs:8:5 | 8 | use serde::ser::Serializer; | ^^^^^^^^^^^^^^^^^^^^^^
Raw output
vm/src/vm_hooks/vh_handler/vh_managed_types.rs:8:5:w:warning: unused import: `serde::ser::Serializer`
 --> vm/src/vm_hooks/vh_handler/vh_managed_types.rs:8:5
  |
8 | use serde::ser::Serializer;
  |     ^^^^^^^^^^^^^^^^^^^^^^


__END__

Check warning on line 8 in vm/src/vm_hooks/vh_handler/vh_managed_types.rs

View workflow job for this annotation

GitHub Actions / Contracts / Rust tests

unused import: `serde::ser::Serializer`

Check warning on line 8 in vm/src/vm_hooks/vh_handler/vh_managed_types.rs

View workflow job for this annotation

GitHub Actions / Test Coverage

unused import: `serde::ser::Serializer`

Check failure on line 8 in vm/src/vm_hooks/vh_handler/vh_managed_types.rs

View workflow job for this annotation

GitHub Actions / Template tool test - current (unreleased) templates

unused import: `serde::ser::Serializer`

Check failure on line 8 in vm/src/vm_hooks/vh_handler/vh_managed_types.rs

View workflow job for this annotation

GitHub Actions / Template tool test - current (unreleased) templates

unused import: `serde::ser::Serializer`

Check warning on line 8 in vm/src/vm_hooks/vh_handler/vh_managed_types.rs

View workflow job for this annotation

GitHub Actions / Contracts / Wasm tests

unused import: `serde::ser::Serializer`
pub use vh_big_float::VMHooksBigFloat;
pub use vh_big_int::VMHooksBigInt;
pub use vh_managed_buffer::VMHooksManagedBuffer;
Expand All @@ -14,6 +17,36 @@

use super::VMHooksError;

const FLOAT_GOB_VERSION: u8 = 1;
const GOB_DEFAULT_PREC: u64 = 53; // can also be 24
const _W: u64 = 64;
const _S: u64 = _W / 8;
// Number of bits in a mantissa word
// 64-bit precision for IEEE-754

#[allow(dead_code)]
pub enum Accuracy {
Below,
Exact,
Above,
}

pub enum Form {
Zero,
Finite,
Infinite,
}

#[allow(dead_code)]
pub enum Mode {
ToNearestEven, // == IEEE 754-2008 roundTiesToEven // default
ToNearestAway, // == IEEE 754-2008 roundTiesToAway
ToZero, // == IEEE 754-2008 roundTowardZero
AwayFromZero, // no IEEE 754-2008 equivalent
ToNegativeInf, // == IEEE 754-2008 roundTowardNegative
ToPositiveInf, // == IEEE 754-2008 roundTowardPositive
}

/// Provides VM hook implementations for methods that deal with more than one type of managed type.
///
/// It is also the trait that unifies all managed type functionality.
Expand Down Expand Up @@ -52,4 +85,110 @@
let bytes = self.random_next_bytes(length);
self.mb_set(dest_handle, bytes.as_slice());
}

// transforms big float into bytes with respect to IEEE-754 gob encode
fn mb_from_big_float(&self, m_buffer_handle: RawHandle, big_float_handle: RawHandle) {
let big_float = self.m_types_lock().bf_get_f64(big_float_handle);
let bytes = gob_encode(
big_float,
Accuracy::Exact,
Mode::ToNearestEven,
GOB_DEFAULT_PREC,
);
println!("encoded bytes {:#?}", bytes);
self.m_types_lock().mb_set(m_buffer_handle, bytes.to_vec());
}

// fn mb_from_big_float(&self, m_buffer_handle: RawHandle, big_float_handle: RawHandle) {
// let big_float = self.m_types_lock().bf_get_f64(big_float_handle);
// println!("big float is {:#?}", big_float.to_bits());

// let mut stream_ser = StreamSerializer::new_with_buffer();

// // serialize the f64 value using the obtained Serializer
// let _ = stream_ser.serialize_with_type_id(TypeId::FLOAT, &big_float);

// // extract the serialized data
// let output_buffer = stream_ser.into_inner();
// let bytes = output_buffer.collect();
// println!("output buffer is {:#?}", bytes);

// self.m_types_lock().mb_set(m_buffer_handle, bytes);
// }
}
fn gob_encode(f: f64, accuracy: Accuracy, mode: Mode, precision: u64) -> Vec<u8> {
let bits = f.to_bits();
let (_sign, exp, mut mant) = extract_float_components(bits);

let mut _n = 0;
let mut _form = Form::Zero;
if f.is_finite() {
let mant_number_of_bits = num_bits(mant) as u64;
_form = Form::Finite;
_n = (GOB_DEFAULT_PREC + (_W - 1)) / _W;
if mant_number_of_bits < _n {
_n = mant_number_of_bits;
}
} else {
_form = Form::Infinite;
}

let mut buf = vec![];
buf.push(FLOAT_GOB_VERSION);

let mode_bits = mode as u8 & 0b111;
let acc_bits = (accuracy as u8 + 1) & 0b11;
let form_bits = _form as u8 & 0b11;

let mut combined_byte = (mode_bits << 5) | (acc_bits << 3) | (form_bits << 1);
if f.is_sign_negative() {
combined_byte |= 1;
}

buf.push(combined_byte);
buf.extend_from_slice(&precision.to_be_bytes());

if f.is_finite() {
buf.extend_from_slice(&exp.to_be_bytes());
mant >>= 64 - _n;
buf.extend_from_slice(&mant.to_be_bytes())
}

buf
}

fn extract_float_components(bits: u64) -> (u64, i64, u64) {
// Define masks for sign, exponent, and mantissa
let sign_mask: u64 = 0x8000000000000000;
let exponent_mask: u64 = 0x7FF0000000000000;
let mantissa_mask: u64 = 0x000FFFFFFFFFFFFF;

// Extract sign
let sign = (bits & sign_mask) >> 63;

// Extract exponent
let mut exponent = ((bits & exponent_mask) >> 52) as i64;
// Adjust for bias
exponent -= 1023;

// Extract mantissa
let mut mantissa = bits & mantissa_mask;

// Add implicit leading bit
mantissa |= 0x0010000000000000;

(sign, exponent, mantissa)
}

fn num_bits(mut n: u64) -> usize {
if n == 0 {
return 1; // Special case for 0
}

let mut bits = 0;
while n > 0 {
bits += 1;
n >>= 1; // Shift right to check the next bit
}
bits
}
Loading