Skip to content

Commit

Permalink
Add totalcsize/totalssize
Browse files Browse the repository at this point in the history
  • Loading branch information
Rexagon committed Jul 31, 2023
1 parent 6adfb1c commit 39f9fe5
Show file tree
Hide file tree
Showing 3 changed files with 96 additions and 2 deletions.
2 changes: 2 additions & 0 deletions src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,8 @@ pub enum Error {
TupleTooLarge,
#[error("Tuple size mismatch")]
TupleSizeMismatch,
#[error("Limit exceeded")]
LimitExceeded,

#[error("Expected interpreter mode")]
ExpectedInterpreterMode,
Expand Down
94 changes: 93 additions & 1 deletion src/modules/cell_utils.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
use std::collections::HashSet;

use everscale_types::cell::{MAX_BIT_LEN, MAX_REF_COUNT};
use everscale_types::prelude::*;
use num_bigint::{BigInt, Sign};
Expand Down Expand Up @@ -375,7 +377,22 @@ impl CellUtils {
Ok(())
}

// TODO: totalcsize/totalssize
#[cmd(name = "totalcsize", stack, args(load_slice = false))]
#[cmd(name = "totalssize", stack, args(load_slice = true))]
fn interpret_cell_datasize(stack: &mut Stack, load_slice: bool) -> Result<()> {
const LIMIT: usize = 1 << 22;
let (cells, bits, refs) = if load_slice {
let slice = stack.pop_slice()?;
StorageStat::compute_for_slice(slice.pin(), LIMIT)
} else {
let cell = stack.pop_cell()?;
StorageStat::compute_for_cell(&**cell, LIMIT)
}
.ok_or(Error::LimitExceeded)?;
stack.push_int(cells)?;
stack.push_int(bits)?;
stack.push_int(refs)
}

// === BOC manipulation ===

Expand Down Expand Up @@ -446,6 +463,81 @@ impl CellUtils {
}
}

struct StorageStat<'a> {
visited: HashSet<&'a HashBytes, ahash::RandomState>,
cells: u64,
bits: u64,
refs: u64,
limit: usize,
}

impl<'a> StorageStat<'a> {
fn with_limit(limit: usize) -> Self {
Self {
visited: Default::default(),
cells: 0,
bits: 0,
refs: 0,
limit,
}
}

fn compute_for_slice<'b: 'a>(
slice: &'a CellSlice<'b>,
limit: usize,
) -> Option<(u64, u64, u64)> {
let mut this = Self::with_limit(limit);
if this.add_slice(slice) {
Some((this.cells, this.bits, this.refs))
} else {
None
}
}

fn compute_for_cell(cell: &'a DynCell, limit: usize) -> Option<(u64, u64, u64)> {
let mut this = Self::with_limit(limit);
if this.add_cell(cell) {
Some((this.cells, this.bits, this.refs))
} else {
None
}
}

fn add_slice<'b: 'a>(&mut self, slice: &'a CellSlice<'b>) -> bool {
self.bits = self.bits.saturating_add(slice.remaining_bits() as u64);
self.refs = self.refs.saturating_add(slice.remaining_refs() as u64);

for cell in slice.references() {
if !self.add_cell(cell) {
return false;
}
}

true
}

fn add_cell(&mut self, cell: &'a DynCell) -> bool {
if !self.visited.insert(cell.repr_hash()) {
return false;
}
if self.cells >= self.limit as u64 {
return false;
}

self.cells += 1;
self.bits = self.bits.saturating_add(cell.bit_len() as u64);
self.refs = self.refs.saturating_add(cell.reference_count() as u64);

for cell in cell.references() {
if !self.add_cell(cell) {
return false;
}
}

true
}
}

fn len_as_bits<T: AsRef<[u8]>>(data: T) -> Result<u16> {
let bits = data.as_ref().len() * 8;
if bits > everscale_types::cell::MAX_BIT_LEN as usize {
Expand Down
2 changes: 1 addition & 1 deletion src/modules/debug_utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ impl DebugUtils {
Ok(())
}

#[cmd(name = "Bx._")]
#[cmd(name = "Bx.")]
fn interpret_bytes_hex_print_raw(ctx: &mut Context) -> Result<()> {
const CHUNK: usize = 16;
let bytes = ctx.stack.pop_bytes()?;
Expand Down

0 comments on commit 39f9fe5

Please sign in to comment.