// Copyright 2021 The Grin Developers // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. use crate::core::core::hash::DefaultHashable; use crate::core::core::pmmr; use crate::core::core::pmmr::segment::{Segment, SegmentIdentifier}; use crate::core::core::pmmr::{Backend, ReadablePMMR, ReadonlyPMMR, PMMR}; use crate::core::ser::{ BinReader, BinWriter, DeserializationMode, Error, PMMRable, ProtocolVersion, Readable, Reader, Writeable, Writer, }; use crate::store::pmmr::PMMRBackend; use chrono::Utc; use croaring::Bitmap; use grin_core as core; use grin_store as store; use std::fs; use std::io::Cursor; #[test] fn prunable_mmr() { let t = Utc::now(); let data_dir = format!( "./target/tmp/{}.{}-prunable_mmr", t.timestamp(), t.timestamp_subsec_nanos() ); fs::create_dir_all(&data_dir).unwrap(); let n_leaves = 64 + 8 + 4 + 2 + 1; let mut ba = PMMRBackend::new(&data_dir, true, ProtocolVersion(1), None).unwrap(); let mut mmr = PMMR::new(&mut ba); for i in 0..n_leaves { mmr.push(&TestElem([i / 7, i / 5, i / 3, i])).unwrap(); } let last_pos = mmr.unpruned_size(); let root = mmr.root().unwrap(); let mut bitmap = Bitmap::new(); bitmap.add_range(0..n_leaves); let id = SegmentIdentifier { height: 3, idx: 1 }; // Validate a segment before any pruning let mmr = ReadonlyPMMR::at(&mut ba, last_pos); let segment = Segment::from_pmmr(id, &mmr, true).unwrap(); assert_eq!( segment.root(last_pos, Some(&bitmap)).unwrap().unwrap(), mmr.get_hash(29).unwrap() ); segment.validate(last_pos, Some(&bitmap), root).unwrap(); // Prune a few leaves let mut mmr = PMMR::at(&mut ba, last_pos); prune(&mut mmr, &mut bitmap, &[8, 9, 13]); ba.sync().unwrap(); ba.check_compact(last_pos, &Bitmap::new()).unwrap(); ba.sync().unwrap(); // Validate let mmr = ReadonlyPMMR::at(&mut ba, last_pos); let segment = Segment::from_pmmr(id, &mmr, true).unwrap(); assert_eq!( segment.root(last_pos, Some(&bitmap)).unwrap().unwrap(), mmr.get_hash(29).unwrap() ); segment.validate(last_pos, Some(&bitmap), root).unwrap(); // Prune more let mut mmr = PMMR::at(&mut ba, last_pos); prune(&mut mmr, &mut bitmap, &[10, 11]); ba.sync().unwrap(); ba.check_compact(last_pos, &Bitmap::new()).unwrap(); ba.sync().unwrap(); // Validate let mmr = ReadonlyPMMR::at(&mut ba, last_pos); let segment = Segment::from_pmmr(id, &mmr, true).unwrap(); assert_eq!( segment.root(last_pos, Some(&bitmap)).unwrap().unwrap(), mmr.get_hash(29).unwrap() ); segment.validate(last_pos, Some(&bitmap), root).unwrap(); // Prune all but 1 let mut mmr = PMMR::at(&mut ba, last_pos); prune(&mut mmr, &mut bitmap, &[14, 15]); ba.sync().unwrap(); ba.check_compact(last_pos, &Bitmap::new()).unwrap(); ba.sync().unwrap(); // Validate let mmr = ReadonlyPMMR::at(&mut ba, last_pos); let segment = Segment::from_pmmr(id, &mmr, true).unwrap(); assert_eq!( segment.root(last_pos, Some(&bitmap)).unwrap().unwrap(), mmr.get_hash(29).unwrap() ); segment.validate(last_pos, Some(&bitmap), root).unwrap(); // Prune all let mut mmr = PMMR::at(&mut ba, last_pos); prune(&mut mmr, &mut bitmap, &[12]); ba.sync().unwrap(); ba.check_compact(last_pos, &Bitmap::new()).unwrap(); ba.sync().unwrap(); let mmr = ReadonlyPMMR::at(&mut ba, last_pos); assert!(Segment::from_pmmr(id, &mmr, true).is_ok()); // Final segment is not full, test it before pruning let id = SegmentIdentifier { height: 3, idx: 9 }; let mmr = ReadonlyPMMR::at(&mut ba, last_pos); let segment = Segment::from_pmmr(id, &mmr, true).unwrap(); segment.validate(last_pos, Some(&bitmap), root).unwrap(); // Prune second and third to last leaves (a full peak in the MMR) let mut mmr = PMMR::at(&mut ba, last_pos); prune(&mut mmr, &mut bitmap, &[76, 77]); ba.sync().unwrap(); ba.check_compact(last_pos, &Bitmap::new()).unwrap(); ba.sync().unwrap(); // Validate let mmr = ReadonlyPMMR::at(&mut ba, last_pos); let segment = Segment::from_pmmr(id, &mmr, true).unwrap(); segment.validate(last_pos, Some(&bitmap), root).unwrap(); // Prune final element let mut mmr = PMMR::at(&mut ba, last_pos); prune(&mut mmr, &mut bitmap, &[78]); ba.sync().unwrap(); ba.check_compact(last_pos, &Bitmap::new()).unwrap(); ba.sync().unwrap(); // Validate let mmr = ReadonlyPMMR::at(&mut ba, last_pos); let segment = Segment::from_pmmr(id, &mmr, true).unwrap(); segment.validate(last_pos, Some(&bitmap), root).unwrap(); std::mem::drop(ba); fs::remove_dir_all(&data_dir).unwrap(); } #[test] fn pruned_segment() { let t = Utc::now(); let data_dir = format!( "./target/tmp/{}.{}-pruned_segment", t.timestamp(), t.timestamp_subsec_nanos() ); fs::create_dir_all(&data_dir).unwrap(); let n_leaves = 16; let mut ba = PMMRBackend::new(&data_dir, true, ProtocolVersion(1), None).unwrap(); let mut mmr = PMMR::new(&mut ba); for i in 0..n_leaves { mmr.push(&TestElem([i / 7, i / 5, i / 3, i])).unwrap(); } let last_pos = mmr.unpruned_size(); let root = mmr.root().unwrap(); let mut bitmap = Bitmap::new(); bitmap.add_range(0..n_leaves); // Prune all leaves of segment 1 prune(&mut mmr, &mut bitmap, &[4, 5, 6, 7]); ba.sync().unwrap(); ba.check_compact(last_pos, &Bitmap::new()).unwrap(); ba.sync().unwrap(); // Validate the empty segment 1 let id = SegmentIdentifier { height: 2, idx: 1 }; let mmr = ReadonlyPMMR::at(&mut ba, last_pos); let segment = Segment::from_pmmr(id, &mmr, true).unwrap(); assert_eq!(segment.leaf_iter().count(), 0); assert_eq!(segment.hash_iter().count(), 1); assert_eq!( segment .first_unpruned_parent(last_pos, Some(&bitmap)) .unwrap(), (ba.get_hash(13).unwrap(), 14) ); assert!(segment.root(last_pos, Some(&bitmap)).unwrap().is_none()); segment.validate(last_pos, Some(&bitmap), root).unwrap(); // Prune all leaves of segment 0 let mut mmr = PMMR::at(&mut ba, last_pos); prune(&mut mmr, &mut bitmap, &[0, 1, 2, 3]); ba.sync().unwrap(); ba.check_compact(last_pos, &Bitmap::new()).unwrap(); ba.sync().unwrap(); // Validate the empty segment 1 again let mmr = ReadonlyPMMR::at(&mut ba, last_pos); let segment = Segment::from_pmmr(id, &mmr, true).unwrap(); assert_eq!(segment.leaf_iter().count(), 0); assert_eq!(segment.hash_iter().count(), 1); // Since both 7 and 14 are now pruned, the first unpruned hash will be at 15 assert_eq!( segment .first_unpruned_parent(last_pos, Some(&bitmap)) .unwrap(), (ba.get_hash(14).unwrap(), 15) ); assert!(segment.root(last_pos, Some(&bitmap)).unwrap().is_none()); segment.validate(last_pos, Some(&bitmap), root).unwrap(); // Prune all leaves of segment 2 & 3 let mut mmr = PMMR::at(&mut ba, last_pos); prune(&mut mmr, &mut bitmap, &[8, 9, 10, 11, 12, 13, 14, 15]); ba.sync().unwrap(); ba.check_compact(last_pos, &Bitmap::new()).unwrap(); ba.sync().unwrap(); // Validate the empty segment 1 again let mmr = ReadonlyPMMR::at(&mut ba, last_pos); let segment = Segment::from_pmmr(id, &mmr, true).unwrap(); assert_eq!(segment.leaf_iter().count(), 0); assert_eq!(segment.hash_iter().count(), 1); // Since both 15 and 30 are now pruned, the first unpruned hash will be at 31: the mmr root assert_eq!( segment .first_unpruned_parent(last_pos, Some(&bitmap)) .unwrap(), (root, 31) ); assert!(segment.root(last_pos, Some(&bitmap)).unwrap().is_none()); segment.validate(last_pos, Some(&bitmap), root).unwrap(); let n_leaves = n_leaves + 4 + 2 + 1; let mut mmr = PMMR::at(&mut ba, last_pos); for i in 16..n_leaves { mmr.push(&TestElem([i / 7, i / 5, i / 3, i])).unwrap(); } bitmap.add_range(16..n_leaves); let last_pos = mmr.unpruned_size(); let root = mmr.root().unwrap(); // Prune all leaves of segment 4 // The root of this segment is a direct peak of the full MMR prune(&mut mmr, &mut bitmap, &[16, 17, 18, 19]); ba.sync().unwrap(); ba.check_compact(last_pos, &Bitmap::new()).unwrap(); ba.sync().unwrap(); // Validate segment 4 let id = SegmentIdentifier { height: 2, idx: 4 }; let mmr = ReadonlyPMMR::at(&mut ba, last_pos); let segment = Segment::from_pmmr(id, &mmr, true).unwrap(); assert_eq!(segment.leaf_iter().count(), 0); assert_eq!(segment.hash_iter().count(), 1); assert_eq!( segment .first_unpruned_parent(last_pos, Some(&bitmap)) .unwrap(), (ba.get_hash(37).unwrap(), 38) ); assert!(segment.root(last_pos, Some(&bitmap)).unwrap().is_none()); segment.validate(last_pos, Some(&bitmap), root).unwrap(); // Segment 5 has 2 peaks let id = SegmentIdentifier { height: 2, idx: 5 }; let mmr = ReadonlyPMMR::at(&mut ba, last_pos); let segment = Segment::from_pmmr(id, &mmr, true).unwrap(); assert_eq!(segment.leaf_iter().count(), 3); assert_eq!( segment .first_unpruned_parent(last_pos, Some(&bitmap)) .unwrap() .1, 1 + segment.segment_pos_range(last_pos).1 ); assert!(segment.root(last_pos, Some(&bitmap)).unwrap().is_some()); segment.validate(last_pos, Some(&bitmap), root).unwrap(); let prev_segment = segment; // Prune final leaf (a peak) let mut mmr = PMMR::at(&mut ba, last_pos); prune(&mut mmr, &mut bitmap, &[22]); ba.sync().unwrap(); ba.check_compact(last_pos, &Bitmap::new()).unwrap(); ba.sync().unwrap(); // Segment 5 should be unchanged let mmr = ReadonlyPMMR::at(&mut ba, last_pos); let segment = Segment::from_pmmr(id, &mmr, true).unwrap(); assert_eq!(segment, prev_segment); segment.validate(last_pos, Some(&bitmap), root).unwrap(); // Prune other peak of segment 5 let mut mmr = PMMR::at(&mut ba, last_pos); prune(&mut mmr, &mut bitmap, &[20, 21]); ba.sync().unwrap(); ba.check_compact(last_pos, &Bitmap::new()).unwrap(); ba.sync().unwrap(); // Validate segment 5 again let mmr = ReadonlyPMMR::at(&mut ba, last_pos); let segment = Segment::from_pmmr(id, &mmr, true).unwrap(); assert_eq!(segment.leaf_iter().count(), 1); assert_eq!(segment.hash_iter().count(), 1); assert_eq!( segment .first_unpruned_parent(last_pos, Some(&bitmap)) .unwrap() .1, 1 + segment.segment_pos_range(last_pos).1 ); assert!(segment.root(last_pos, Some(&bitmap)).unwrap().is_some()); segment.validate(last_pos, Some(&bitmap), root).unwrap(); std::mem::drop(ba); fs::remove_dir_all(&data_dir).unwrap(); } #[test] fn ser_round_trip() { let t = Utc::now(); let data_dir = format!( "./target/tmp/{}.{}-segment_ser_round_trip", t.timestamp(), t.timestamp_subsec_nanos() ); fs::create_dir_all(&data_dir).unwrap(); let n_leaves = 32; let mut ba = PMMRBackend::new(&data_dir, true, ProtocolVersion(1), None).unwrap(); let mut mmr = pmmr::PMMR::new(&mut ba); for i in 0..n_leaves { mmr.push(&TestElem([i / 7, i / 5, i / 3, i])).unwrap(); } let mut bitmap = Bitmap::new(); bitmap.add_range(0..n_leaves); let last_pos = mmr.unpruned_size(); prune(&mut mmr, &mut bitmap, &[0, 1]); ba.sync().unwrap(); ba.check_compact(last_pos, &Bitmap::new()).unwrap(); ba.sync().unwrap(); let mmr = ReadonlyPMMR::at(&ba, last_pos); let id = SegmentIdentifier { height: 3, idx: 0 }; let segment = Segment::from_pmmr(id, &mmr, true).unwrap(); let mut cursor = Cursor::new(Vec::::new()); let mut writer = BinWriter::new(&mut cursor, ProtocolVersion(1)); Writeable::write(&segment, &mut writer).unwrap(); assert_eq!( cursor.position(), (9) + (8 + 7 * (8 + 32)) + (8 + 6 * (8 + 16)) + (8 + 2 * 32) ); cursor.set_position(0); let mut reader = BinReader::new( &mut cursor, ProtocolVersion(1), DeserializationMode::default(), ); let segment2: Segment = Readable::read(&mut reader).unwrap(); assert_eq!(segment, segment2); std::mem::drop(ba); fs::remove_dir_all(&data_dir).unwrap(); } fn prune(mmr: &mut PMMR, bitmap: &mut Bitmap, leaf_idxs: &[u64]) where T: PMMRable, B: Backend, { for &leaf_idx in leaf_idxs { mmr.prune(pmmr::insertion_to_pmmr_index(leaf_idx)).unwrap(); bitmap.remove(leaf_idx as u32); } } #[derive(Copy, Clone, Debug, PartialEq, Eq)] pub struct TestElem(pub [u32; 4]); impl DefaultHashable for TestElem {} impl PMMRable for TestElem { type E = Self; fn as_elmt(&self) -> Self::E { *self } fn elmt_size() -> Option { Some(16) } } impl Writeable for TestElem { fn write(&self, writer: &mut W) -> Result<(), Error> { writer.write_u32(self.0[0])?; writer.write_u32(self.0[1])?; writer.write_u32(self.0[2])?; writer.write_u32(self.0[3]) } } impl Readable for TestElem { fn read(reader: &mut R) -> Result { Ok(TestElem([ reader.read_u32()?, reader.read_u32()?, reader.read_u32()?, reader.read_u32()?, ])) } }