Skip to content

Commit 95addca

Browse files
committed
fix(merkle): only store lower common levels into pruned branch
1 parent 72b2f95 commit 95addca

File tree

2 files changed

+42
-2
lines changed

2 files changed

+42
-2
lines changed

src/cell/mod.rs

+7
Original file line numberDiff line numberDiff line change
@@ -1337,6 +1337,13 @@ impl<'a> arbitrary::Arbitrary<'a> for LevelMask {
13371337
#[derive(Clone)]
13381338
pub struct LevelMaskIter(u8);
13391339

1340+
impl LevelMaskIter {
1341+
/// Returns `true` if all levels were consumed.
1342+
pub fn is_empty(&self) -> bool {
1343+
self.0 == 0
1344+
}
1345+
}
1346+
13401347
impl Iterator for LevelMaskIter {
13411348
type Item = u8;
13421349

src/merkle/pruned_branch.rs

+35-2
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,12 @@ pub fn make_pruned_branch(
88
context: &dyn CellContext,
99
) -> Result<Cell, Error> {
1010
let descriptor = cell.descriptor();
11-
let cell_level_mask = descriptor.level_mask();
11+
let mut cell_level_mask = descriptor.level_mask();
1212

1313
let mut builder = CellBuilder::new();
14-
let level_mask = LevelMask::new(cell_level_mask.to_byte() | (1 << merkle_depth));
14+
15+
let new_level = 1 << merkle_depth;
16+
let level_mask = LevelMask::new(cell_level_mask.to_byte() | new_level);
1517

1618
builder.set_exotic(true);
1719

@@ -20,6 +22,9 @@ pub fn make_pruned_branch(
2022
level_mask.to_byte(),
2123
]));
2224

25+
// Only write levels lower than the new level.
26+
cell_level_mask = LevelMask::new(cell_level_mask.to_byte() & (new_level - 1));
27+
2328
for level in cell_level_mask {
2429
_ = builder.store_u256(cell.hash(level));
2530
}
@@ -33,6 +38,9 @@ pub fn make_pruned_branch(
3338

3439
#[cfg(test)]
3540
mod test {
41+
use crate::boc::Boc;
42+
use crate::merkle::MerkleProof;
43+
3644
use super::*;
3745

3846
#[test]
@@ -56,4 +64,29 @@ mod test {
5664
make_pruned_branch(virtual_cell, 0, Cell::empty_context()).unwrap();
5765
assert_eq!(pruned_branch.as_ref(), virtual_pruned_branch.as_ref());
5866
}
67+
68+
#[test]
69+
fn partial_pruned() -> anyhow::Result<()> {
70+
let cell = CellBuilder::build_from((
71+
CellBuilder::build_from((0xaa_u8, Cell::empty_cell()))?,
72+
CellBuilder::build_from((0xbb_u8, Cell::empty_cell()))?,
73+
))?;
74+
println!("Original: {}", Boc::encode_base64(&cell));
75+
76+
// Prune left cell.
77+
let with_left_pruned = {
78+
let usage_tree = UsageTree::new(UsageTreeMode::OnLoad);
79+
let tracked = usage_tree.track(&cell);
80+
tracked.reference(1).unwrap().touch_recursive();
81+
82+
MerkleProof::create(cell.as_ref(), usage_tree).build_raw_ext(Cell::empty_context())?
83+
};
84+
println!("Left pruned: {}", Boc::encode_base64(&with_left_pruned));
85+
86+
// Full pruned.
87+
let pruned = make_pruned_branch(with_left_pruned.as_ref(), 0, Cell::empty_context())?;
88+
println!("Full pruned: {}", Boc::encode_base64(&pruned));
89+
90+
Ok(())
91+
}
5992
}

0 commit comments

Comments
 (0)