From 8cb427a6ade7087e7440c98945ba0ac6db65c784 Mon Sep 17 00:00:00 2001 From: Ivan Kalinin Date: Sun, 30 Jul 2023 04:27:59 +0200 Subject: [PATCH] Add cell builder commands --- src/error.rs | 2 + src/modules/cell_utils.rs | 132 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 134 insertions(+) diff --git a/src/error.rs b/src/error.rs index d93e5cd..ec36798 100644 --- a/src/error.rs +++ b/src/error.rs @@ -4,6 +4,8 @@ pub type Result = std::result::Result; pub enum Error { #[error("Cell error")] CellError(#[from] everscale_types::error::Error), + #[error("Boc error")] + BocError(#[from] everscale_types::boc::de::Error), #[error("IO error")] IoError(#[from] std::io::Error), diff --git a/src/modules/cell_utils.rs b/src/modules/cell_utils.rs index 9b71500..c8fd674 100644 --- a/src/modules/cell_utils.rs +++ b/src/modules/cell_utils.rs @@ -1,4 +1,5 @@ use everscale_types::prelude::*; +use num_traits::ToPrimitive; use crate::core::*; use crate::error::*; @@ -12,6 +13,96 @@ impl CellUtils { stack.push(CellBuilder::new()) } + #[cmd(name = "i,", stack, args(signed = true))] + #[cmd(name = "u,", stack, args(signed = false))] + fn interpret_store(stack: &mut Stack, signed: bool) -> Result<()> { + let bits = stack.pop_smallint_range(0, 1023)? as u16; + let mut int = stack.pop_int()?; + let mut builder = stack.pop_builder()?; + + if int.bits() > bits as u64 { + return Err(Error::IntegerOverflow); + } + + match int.to_u64() { + Some(value) => builder.store_uint(value, bits)?, + None => { + if bits % 8 != 0 { + let align = 8 - bits % 8; + *int <<= align; + } + + let minimal_bytes = ((bits + 7) / 8) as usize; + + let (prefix, mut bytes) = if signed { + let bytes = int.to_signed_bytes_le(); + ( + bytes + .last() + .map(|first| (first >> 7) * 255) + .unwrap_or_default(), + bytes, + ) + } else { + (0, int.to_bytes_le().1) + }; + bytes.resize(minimal_bytes, prefix); + bytes.reverse(); + + builder.store_raw(&bytes, bits)?; + } + }; + + stack.push_raw(builder) + } + + #[cmd(name = "ref", stack)] + fn interpret_store_ref(stack: &mut Stack) -> Result<()> { + let cell = stack.pop_cell()?; + let mut builder = stack.pop_builder()?; + builder.store_reference(*cell)?; + stack.push_raw(builder) + } + + #[cmd(name = "$,", stack)] + fn interpret_store_str(stack: &mut Stack) -> Result<()> { + let string = stack.pop_string()?; + let mut builder = stack.pop_builder()?; + let bits = len_as_bits(&*string)?; + builder.store_raw(&string.as_bytes(), bits as u16)?; + stack.push_raw(builder) + } + + #[cmd(name = "B,", stack)] + fn interpret_store_bytes(stack: &mut Stack) -> Result<()> { + let bytes = stack.pop_bytes()?; + let mut builder = stack.pop_builder()?; + let bits = len_as_bits(&*bytes)?; + builder.store_raw(bytes.as_slice(), bits as u16)?; + stack.push_raw(builder) + } + + #[cmd(name = "s,", stack)] + fn interpret_store_cellslice(stack: &mut Stack) -> Result<()> { + let slice = stack.pop_slice()?; + let mut builder = stack.pop_builder()?; + builder.store_slice(OwnedCellSlice::as_ref(&slice))?; + stack.push_raw(builder) + } + + #[cmd(name = "sr,", stack)] + fn interpret_store_cellslice_ref(stack: &mut Stack) -> Result<()> { + let slice = stack.pop_slice()?; + let cell = { + let mut builder = CellBuilder::new(); + builder.store_slice(OwnedCellSlice::as_ref(&slice))?; + builder.build()? + }; + let mut builder = stack.pop_builder()?; + builder.store_reference(cell)?; + stack.push_raw(builder) + } + #[cmd(name = "b>", stack, args(is_exotic = false))] #[cmd(name = "b>spec", stack, args(is_exotic = true))] fn interpret_store_end(stack: &mut Stack, is_exotic: bool) -> Result<()> { @@ -21,6 +112,16 @@ impl CellUtils { stack.push(cell) } + #[cmd(name = "$>s", stack)] + fn interpret_string_to_cellslice(stack: &mut Stack) -> Result<()> { + let string = stack.pop_string()?; + let mut builder = CellBuilder::new(); + let bits = len_as_bits(&*string)?; + builder.store_raw(&string.as_bytes(), bits as u16)?; + let slice = OwnedCellSlice::new(builder.build()?)?; + stack.push(slice) + } + #[cmd(name = " Result<()> { let item = stack.pop_cell()?; @@ -37,4 +138,35 @@ impl CellUtils { } Ok(()) } + + #[cmd(name = "B>boc", stack)] + fn interpret_boc_deserialize(stack: &mut Stack) -> Result<()> { + let bytes = stack.pop_bytes()?; + let cell = Boc::decode(*bytes)?; + stack.push(cell) + } + + #[cmd(name = "boc>B", stack)] + fn interpret_boc_serialize(stack: &mut Stack) -> Result<()> { + let cell = stack.pop_cell()?; + let bytes = Boc::encode(*cell); + stack.push(bytes) + } + + #[cmd(name = "boc>base64", stack)] + fn interpret_boc_serialize_base64(stack: &mut Stack) -> Result<()> { + let cell = stack.pop_cell()?; + let string = Boc::encode_base64(*cell); + stack.push(string) + } +} + +fn len_as_bits>(data: T) -> Result { + let bits = data.as_ref().len() * 8; + if bits > everscale_types::cell::MAX_BIT_LEN as usize { + return Err(Error::CellError( + everscale_types::error::Error::CellOverflow, + )); + } + Ok(bits as u16) }