Skip to content

Commit

Permalink
Merge branch 'master' into feature/abi
Browse files Browse the repository at this point in the history
  • Loading branch information
Rexagon committed Sep 12, 2023
2 parents 14ebd55 + 749088e commit 6b0198e
Show file tree
Hide file tree
Showing 16 changed files with 780 additions and 144 deletions.
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ name = "everscale-types"
description = "A set of primitive types and utilities for the Everscale blockchain."
authors = ["Ivan Kalinin <[email protected]>"]
repository = "https://github.com/broxus/everscale-types"
version = "0.1.0-rc.3"
version = "0.1.0-rc.4"
edition = "2021"
rust-version = "1.65"
include = ["src/**/*.rs", "benches/**/*.rs", "LICENSE-*", "README.md"]
Expand Down
145 changes: 140 additions & 5 deletions src/cell/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,12 @@ mod __checks {
assert_impl_all!(CellBuilder: Send);
}

/// Marker trait which allows casting lazy-loaded data.
pub trait EquivalentRepr<T> {}

/// All types are equivalent to itself.
impl<T> EquivalentRepr<T> for T {}

/// Cell implementation family.
pub trait CellFamily: Sized {
/// Creates an empty cell.
Expand Down Expand Up @@ -144,6 +150,8 @@ pub trait CellImpl {

/// Returns the sum of all bits and cells of all elements in the cell tree
/// (including this cell).
///
/// NOTE: identical cells are counted each time they occur in the tree.
#[cfg(feature = "stats")]
fn stats(&self) -> CellTreeStats;
}
Expand Down Expand Up @@ -235,6 +243,13 @@ impl DynCell {
CellSlice::new_unchecked(self)
}

/// Recursively computes the count of distinct cells returning
/// the total storage used by this dag taking into account the
/// identification of equal cells.
pub fn compute_unique_stats(&self, limit: usize) -> Option<CellTreeStats> {
StorageStat::compute_for_cell(self, limit)
}

/// Returns an object that implements [`Debug`] for printing only
/// the root cell of the cell tree.
///
Expand Down Expand Up @@ -1062,18 +1077,22 @@ impl Iterator for LevelMaskIter {
}

/// Cell tree storage stats.
///
/// NOTE: identical cells are counted each time they occur in the tree.
#[derive(Default, Debug, Clone, Copy, PartialEq, Eq)]
#[cfg(feature = "stats")]
pub struct CellTreeStats {
/// Total number of bits in tree.
pub bit_count: u64,
/// Total number of cells in tree.
pub cell_count: u64,
}

#[cfg(feature = "stats")]
impl CellTreeStats {
/// The additive identity for this type, i.e. `0`.
pub const ZERO: Self = CellTreeStats {
bit_count: 0,
cell_count: 0,
};
}

impl std::ops::Add for CellTreeStats {
type Output = Self;

Expand All @@ -1086,7 +1105,6 @@ impl std::ops::Add for CellTreeStats {
}
}

#[cfg(feature = "stats")]
impl std::ops::AddAssign for CellTreeStats {
#[inline]
fn add_assign(&mut self, rhs: Self) {
Expand All @@ -1095,6 +1113,123 @@ impl std::ops::AddAssign for CellTreeStats {
}
}

/// A helper to track the size of the unique data in multiple cell trees.
///
/// NOTE: It uses hashes for deduplication, so you can only use it for
/// fully computed and valid trees.
pub struct StorageStat<'a> {
visited: ahash::HashSet<&'a HashBytes>,
stack: Vec<RefsIter<'a>>,
stats: CellTreeStats,
limit: usize,
}

impl<'a> StorageStat<'a> {
/// Recursively computes the count of distinct cells returning
/// the total storage used by this dag taking into account the
/// identification of equal cells.
///
/// Root slice does not count as cell. A slice subrange of
/// cells is used during computation.
pub fn compute_for_slice<'b: 'a>(
slice: &'a CellSlice<'b>,
limit: usize,
) -> Option<CellTreeStats> {
let mut this = Self::with_limit(limit);
if this.add_slice(slice) {
Some(this.stats)
} else {
None
}
}

/// Recursively computes the count of distinct cells returning
/// the total storage used by this dag taking into account the
/// identification of equal cells.
pub fn compute_for_cell(cell: &'a DynCell, limit: usize) -> Option<CellTreeStats> {
let mut this = Self::with_limit(limit);
if this.add_cell(cell) {
Some(this.stats)
} else {
None
}
}

/// Creates a new storage stat state with an explicit limit.
pub fn with_limit(limit: usize) -> Self {
Self {
visited: Default::default(),
stack: Vec::new(),
stats: CellTreeStats::ZERO,
limit,
}
}

/// Creates a new storage stat state without a limit.
pub fn unlimited() -> Self {
Self::with_limit(usize::MAX)
}

/// Returns the current tree stats.
pub fn stats(&self) -> CellTreeStats {
self.stats
}

/// Merges current stats with the stats from the provided cell tree.
///
/// Returns `false` if the limit was reached.
pub fn add_cell(&mut self, cell: &'a DynCell) -> bool {
if !self.visited.insert(cell.repr_hash()) {
return true;
}

self.stats.bit_count += cell.bit_len() as u64;
self.stats.cell_count += 1;

self.stack.clear();
self.stack.push(cell.references());
self.reduce_stack()
}

/// Merges current stats with the stats from the provided slice.
///
/// Returns `false` if the limit was reached.
pub fn add_slice(&mut self, slice: &CellSlice<'a>) -> bool {
self.stats.bit_count += slice.remaining_bits() as u64;

self.stack.clear();
self.stack.push(slice.references());
self.reduce_stack()
}

fn reduce_stack(&mut self) -> bool {
'outer: while let Some(item) = self.stack.last_mut() {
for cell in item.by_ref() {
if !self.visited.insert(cell.repr_hash()) {
continue;
}

if self.stats.cell_count >= self.limit as u64 {
return false;
}

self.stats.bit_count += cell.bit_len() as u64;
self.stats.cell_count += 1;

let next = cell.references();
if next.max > 0 {
self.stack.push(next);
continue 'outer;
}
}

self.stack.pop();
}

true
}
}

/// Helper struct to debug print the root cell.
#[derive(Clone, Copy)]
pub struct DebugCell<'a>(&'a DynCell);
Expand Down
41 changes: 39 additions & 2 deletions src/cell/slice.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,14 @@ use std::num::{NonZeroU16, NonZeroU32, NonZeroU8};
use std::rc::Rc;
use std::sync::Arc;

use crate::cell::{Cell, CellType, DynCell, HashBytes, LevelMask, RefsIter};
use crate::cell::{
Cell, CellTreeStats, CellType, DynCell, HashBytes, LevelMask, RefsIter, StorageStat,
};
use crate::error::Error;
use crate::util::{unlikely, Bitstring};

use super::CellFamily;

/// A data structure that can be deserialized from cells.
pub trait Load<'a>: Sized {
/// Tries to load itself from a cell slice.
Expand Down Expand Up @@ -303,6 +307,15 @@ impl CellSliceRange {
refs_end: std::cmp::min(self.refs_start + refs, self.refs_end),
}
}

/// Returns whether this range has the same size as the cell.
#[inline]
pub fn is_full(&self, cell: &DynCell) -> bool {
self.bits_start == 0
&& self.refs_start == 0
&& self.bits_end == cell.bit_len()
&& self.refs_end == cell.reference_count()
}
}

/// A read-only view for a subrange of a cell.
Expand All @@ -312,6 +325,14 @@ pub struct CellSlice<'a> {
range: CellSliceRange,
}

impl Default for CellSlice<'_> {
#[inline]
fn default() -> Self {
// SAFETY: empty cell is an ordinary cell
unsafe { Cell::empty_cell_ref().as_slice_unchecked() }
}
}

impl<'a> AsRef<CellSlice<'a>> for CellSlice<'a> {
#[inline]
fn as_ref(&self) -> &CellSlice<'a> {
Expand Down Expand Up @@ -460,7 +481,7 @@ impl<'a> CellSlice<'a> {
/// # Ok(()) }
/// ```
#[inline]
pub fn bits_offset(&self) -> u16 {
pub const fn bits_offset(&self) -> u16 {
self.range.bits_offset()
}

Expand Down Expand Up @@ -513,6 +534,22 @@ impl<'a> CellSlice<'a> {
self.range.has_remaining(bits, refs)
}

/// Returns whether this slice is untouched.
#[inline]
pub fn is_full(&self) -> bool {
self.range.is_full(self.cell)
}

/// Recursively computes the count of distinct cells returning
/// the total storage used by this dag taking into account the
/// identification of equal cells.
///
/// Root slice does not count as cell. A slice subrange of
/// cells is used during computation.
pub fn compute_unique_stats(&self, limit: usize) -> Option<CellTreeStats> {
StorageStat::compute_for_slice(self, limit)
}

/// Tries to advance the start of data and refs windows,
/// returns `false` if `bits` or `refs` are greater than the remainder.
pub fn try_advance(&mut self, bits: u16, refs: u8) -> bool {
Expand Down
8 changes: 7 additions & 1 deletion src/dict/raw.rs
Original file line number Diff line number Diff line change
Expand Up @@ -623,7 +623,13 @@ impl<'a> RawIter<'a> {
debug_assert!(
segment.prefix.is_some() && (refs_offset == 1 || refs_offset == 2)
);
let next_bit = (refs_offset != 1) ^ self.reversed;

let next_bit = (refs_offset != 1)
^ self.reversed
^ (self.signed
&& self.segments.len() == 1
&& segment.prefix.unwrap().is_data_empty());

match segment.data.cell().reference_cloned(next_bit as u8) {
Some(cell) => cell,
None => return Some(Err(self.finish(Error::CellUnderflow))),
Expand Down
25 changes: 25 additions & 0 deletions src/dict/typed.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ use super::{
use super::{dict_remove_bound_owned, raw::*};

/// Typed dictionary with fixed length keys.
#[repr(transparent)]
pub struct Dict<K, V> {
pub(crate) root: Option<Cell>,
_key: PhantomData<K>,
Expand Down Expand Up @@ -112,6 +113,30 @@ impl<K, V> Dict<K, V> {
pub const fn root(&self) -> &Option<Cell> {
&self.root
}

/// Converts into a dictionary with an equivalent value type.
#[inline]
pub fn cast_into<Q, T>(self) -> Dict<Q, T>
where
Q: EquivalentRepr<K>,
T: EquivalentRepr<V>,
{
Dict {
root: self.root,
_key: PhantomData,
_value: PhantomData,
}
}

/// Casts itself into a lazy loaded for an equivalent type.
pub fn cast_ref<Q, T>(&self) -> &Dict<Q, T>
where
Q: EquivalentRepr<K>,
T: EquivalentRepr<V>,
{
// SAFETY: Dict is #[repr(transparent)]
unsafe { &*(self as *const Self as *const Dict<Q, T>) }
}
}

impl<K: DictKey, V> Dict<K, V> {
Expand Down
24 changes: 21 additions & 3 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ pub mod error;

#[cfg(test)]
mod tests {
use crate::cell::MAX_BIT_LEN;
use crate::cell::{CellTreeStats, MAX_BIT_LEN};
use crate::prelude::*;
use crate::util::decode_base64;

Expand All @@ -177,7 +177,16 @@ mod tests {
#[test]
fn big_cell_deserialization() {
let data = decode_base64("te6ccgIDAAwAAQAAAACIAAAEBAABAAEAAQABAAEEBAACAAIAAgACAAIEBAADAAMAAwADAAMEBAAEAAQABAAEAAQEBAAFAAUABQAFAAUEBAAGAAYABgAGAAYEBAAHAAcABwAHAAcEBAAIAAgACAAIAAgEBAAJAAkACQAJAAkEBAAKAAoACgAKAAoEBAALAAsACwALAAsABAAA").unwrap();
_ = Boc::decode(data).unwrap();
let cell = Boc::decode(data).unwrap();

let stats = cell.compute_unique_stats(1 << 22).unwrap();
assert_eq!(
stats,
CellTreeStats {
bit_count: 192,
cell_count: 12
}
);
}

#[test]
Expand Down Expand Up @@ -253,6 +262,15 @@ mod tests {

#[test]
fn test_tx() {
Boc::decode_base64("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").unwrap();
let cell = Boc::decode_base64("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").unwrap();

let stats = cell.compute_unique_stats(1 << 22).unwrap();
assert_eq!(
stats,
CellTreeStats {
bit_count: 4681,
cell_count: 266
}
);
}
}
Loading

0 comments on commit 6b0198e

Please sign in to comment.