use std::cmp::min;
use std::convert::TryFrom;
use std::time::Instant;
use bit_vec::BitVec;
use croaring::Bitmap;
use crate::core::core::hash::{DefaultHashable, Hash};
use crate::core::core::pmmr::segment::{Segment, SegmentIdentifier, SegmentProof};
use crate::core::core::pmmr::{self, Backend, ReadablePMMR, ReadonlyPMMR, VecBackend, PMMR};
use crate::core::ser::{self, PMMRable, Readable, Reader, Writeable, Writer};
use crate::error::Error;
use enum_primitive::FromPrimitive;
#[derive(Clone)]
pub struct BitmapAccumulator {
backend: VecBackend<BitmapChunk>,
}
impl BitmapAccumulator {
const NBITS: u64 = BitmapChunk::LEN_BITS as u64;
pub fn new() -> BitmapAccumulator {
BitmapAccumulator {
backend: VecBackend::new(),
}
}
pub fn init<T: IntoIterator<Item = u64>>(&mut self, idx: T, size: u64) -> Result<(), Error> {
self.apply_from(idx, 0, size)
}
pub fn chunk_start_idx(idx: u64) -> u64 {
idx & !(Self::NBITS - 1)
}
fn chunk_idx(idx: u64) -> u64 {
idx / Self::NBITS
}
fn apply_from<T>(&mut self, idx: T, from_idx: u64, size: u64) -> Result<(), Error>
where
T: IntoIterator<Item = u64>,
{
let now = Instant::now();
let from_chunk_idx = BitmapAccumulator::chunk_idx(from_idx);
let mut chunk_idx = from_chunk_idx;
let mut chunk = BitmapChunk::new();
let mut idx_iter = idx.into_iter().filter(|&x| x < size).peekable();
while let Some(x) = idx_iter.peek() {
if *x < chunk_idx * Self::NBITS {
idx_iter.next();
} else if *x < (chunk_idx + 1) * Self::NBITS {
let idx = idx_iter.next().expect("next after peek");
chunk.set(idx % Self::NBITS, true);
} else {
self.append_chunk(chunk)?;
chunk_idx += 1;
chunk = BitmapChunk::new();
}
}
if chunk.any() {
self.append_chunk(chunk)?;
}
debug!(
"applied {} chunks from idx {} to idx {} ({}ms)",
1 + chunk_idx - from_chunk_idx,
from_chunk_idx,
chunk_idx,
now.elapsed().as_millis(),
);
Ok(())
}
pub fn apply<T, U>(&mut self, invalidated_idx: T, idx: U, size: u64) -> Result<(), Error>
where
T: IntoIterator<Item = u64>,
U: IntoIterator<Item = u64>,
{
if let Some(from_idx) = invalidated_idx.into_iter().next() {
self.rewind_prior(from_idx)?;
self.pad_left(from_idx)?;
self.apply_from(idx, from_idx, size)?;
}
Ok(())
}
fn rewind_prior(&mut self, from_idx: u64) -> Result<(), Error> {
let chunk_idx = BitmapAccumulator::chunk_idx(from_idx);
let last_pos = self.backend.size();
let mut pmmr = PMMR::at(&mut self.backend, last_pos);
let rewind_pos = pmmr::insertion_to_pmmr_index(chunk_idx);
pmmr.rewind(rewind_pos, &Bitmap::new())
.map_err(Error::Other)?;
Ok(())
}
fn pad_left(&mut self, from_idx: u64) -> Result<(), Error> {
let chunk_idx = BitmapAccumulator::chunk_idx(from_idx);
let current_chunk_idx = pmmr::n_leaves(self.backend.size());
for _ in current_chunk_idx..chunk_idx {
self.append_chunk(BitmapChunk::new())?;
}
Ok(())
}
pub fn append_chunk(&mut self, chunk: BitmapChunk) -> Result<u64, Error> {
let last_pos = self.backend.size();
PMMR::at(&mut self.backend, last_pos)
.push(&chunk)
.map_err(Error::Other)
}
pub fn root(&self) -> Hash {
self.readonly_pmmr().root().expect("no root, invalid tree")
}
pub fn readonly_pmmr(&self) -> ReadonlyPMMR<BitmapChunk, VecBackend<BitmapChunk>> {
ReadonlyPMMR::at(&self.backend, self.backend.size())
}
pub fn as_bitmap(&self) -> Result<Bitmap, Error> {
let mut bitmap = Bitmap::new();
for (chunk_index, chunk_pos) in self.backend.leaf_pos_iter().enumerate() {
let chunk = self.backend.get_data(chunk_pos as u64).unwrap();
let additive = chunk.set_iter(chunk_index * 1024).collect::<Vec<u32>>();
bitmap.add_many(&additive);
}
Ok(bitmap)
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct BitmapChunk(BitVec);
impl BitmapChunk {
const LEN_BITS: usize = 1024;
const LEN_BYTES: usize = Self::LEN_BITS / 8;
pub fn new() -> BitmapChunk {
BitmapChunk(BitVec::from_elem(Self::LEN_BITS, false))
}
pub fn set(&mut self, idx: u64, value: bool) {
let idx = usize::try_from(idx).expect("usize from u64");
assert!(idx < Self::LEN_BITS);
self.0.set(idx, value)
}
pub fn any(&self) -> bool {
self.0.any()
}
pub fn set_iter(&self, idx_offset: usize) -> impl Iterator<Item = u32> + '_ {
self.0
.iter()
.enumerate()
.filter(|(_, val)| *val)
.map(move |(idx, _)| (idx as u32 + idx_offset as u32))
}
}
impl PMMRable for BitmapChunk {
type E = Self;
fn as_elmt(&self) -> Self::E {
self.clone()
}
fn elmt_size() -> Option<u16> {
Some(Self::LEN_BYTES as u16)
}
}
impl DefaultHashable for BitmapChunk {}
impl Writeable for BitmapChunk {
fn write<W: Writer>(&self, writer: &mut W) -> Result<(), ser::Error> {
self.0.to_bytes().write(writer)
}
}
impl Readable for BitmapChunk {
fn read<R: Reader>(_reader: &mut R) -> Result<BitmapChunk, ser::Error> {
Ok(BitmapChunk::new())
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct BitmapSegment {
identifier: SegmentIdentifier,
blocks: Vec<BitmapBlock>,
proof: SegmentProof,
}
impl Writeable for BitmapSegment {
fn write<W: Writer>(&self, writer: &mut W) -> Result<(), ser::Error> {
Writeable::write(&self.identifier, writer)?;
writer.write_u16(self.blocks.len() as u16)?;
for block in &self.blocks {
Writeable::write(block, writer)?;
}
Writeable::write(&self.proof, writer)?;
Ok(())
}
}
impl Readable for BitmapSegment {
fn read<R: Reader>(reader: &mut R) -> Result<Self, ser::Error> {
let identifier: SegmentIdentifier = Readable::read(reader)?;
let n_blocks = reader.read_u16()? as usize;
let mut blocks = Vec::<BitmapBlock>::with_capacity(n_blocks);
for _ in 0..n_blocks {
blocks.push(Readable::read(reader)?);
}
let proof = Readable::read(reader)?;
Ok(Self {
identifier,
blocks,
proof,
})
}
}
impl From<Segment<BitmapChunk>> for BitmapSegment {
fn from(segment: Segment<BitmapChunk>) -> Self {
let (identifier, _, _, _, leaf_data, proof) = segment.parts();
let mut chunks_left = leaf_data.len();
let mut blocks =
Vec::with_capacity((chunks_left + BitmapBlock::NCHUNKS - 1) / BitmapBlock::NCHUNKS);
while chunks_left > 0 {
let n_chunks = min(BitmapBlock::NCHUNKS, chunks_left);
chunks_left = chunks_left.saturating_sub(n_chunks);
blocks.push(BitmapBlock::new(n_chunks));
}
for (chunk_idx, chunk) in leaf_data.into_iter().enumerate() {
assert_eq!(chunk.0.len(), BitmapChunk::LEN_BITS);
let block = &mut blocks
.get_mut(chunk_idx / BitmapBlock::NCHUNKS)
.unwrap()
.inner;
let offset = (chunk_idx % BitmapBlock::NCHUNKS) * BitmapChunk::LEN_BITS;
for (i, _) in chunk.0.iter().enumerate().filter(|&(_, v)| v) {
block.set(offset + i, true);
}
}
Self {
identifier,
blocks,
proof,
}
}
}
impl From<BitmapSegment> for Segment<BitmapChunk> {
fn from(segment: BitmapSegment) -> Self {
let BitmapSegment {
identifier,
blocks,
proof,
} = segment;
let n_chunks = (blocks.len() - 1) * BitmapBlock::NCHUNKS
+ blocks.last().map(|b| b.n_chunks()).unwrap_or(0);
let mut leaf_pos = Vec::with_capacity(n_chunks);
let mut chunks = Vec::with_capacity(n_chunks);
let offset = (1 << identifier.height) * identifier.idx;
for i in 0..(n_chunks as u64) {
leaf_pos.push(pmmr::insertion_to_pmmr_index(offset + i));
chunks.push(BitmapChunk::new());
}
for (block_idx, block) in blocks.into_iter().enumerate() {
assert!(block.inner.len() <= BitmapBlock::NBITS as usize);
let offset = block_idx * BitmapBlock::NCHUNKS;
for (i, _) in block.inner.iter().enumerate().filter(|&(_, v)| v) {
chunks
.get_mut(offset + i / BitmapChunk::LEN_BITS)
.unwrap()
.0
.set(i % BitmapChunk::LEN_BITS, true);
}
}
Segment::from_parts(identifier, Vec::new(), Vec::new(), leaf_pos, chunks, proof)
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
struct BitmapBlock {
inner: BitVec,
}
impl BitmapBlock {
const NBITS: u32 = 1 << 16;
const NCHUNKS: usize = Self::NBITS as usize / BitmapChunk::LEN_BITS;
fn new(n_chunks: usize) -> Self {
assert!(n_chunks <= BitmapBlock::NCHUNKS);
Self {
inner: BitVec::from_elem(n_chunks * BitmapChunk::LEN_BITS, false),
}
}
fn n_chunks(&self) -> usize {
let length = self.inner.len();
assert_eq!(length % BitmapChunk::LEN_BITS, 0);
let n_chunks = length / BitmapChunk::LEN_BITS;
assert!(n_chunks <= BitmapBlock::NCHUNKS);
n_chunks
}
}
impl Writeable for BitmapBlock {
fn write<W: Writer>(&self, writer: &mut W) -> Result<(), ser::Error> {
let length = self.inner.len();
assert!(length <= Self::NBITS as usize);
assert_eq!(length % BitmapChunk::LEN_BITS, 0);
writer.write_u8((length / BitmapChunk::LEN_BITS) as u8)?;
let count_pos = self.inner.iter().filter(|&v| v).count() as u32;
let count_neg = length as u32 - count_pos;
let threshold = Self::NBITS / 16;
if count_pos < threshold {
Writeable::write(&BitmapBlockSerialization::Positive, writer)?;
writer.write_u16(count_pos as u16)?;
for (i, _) in self.inner.iter().enumerate().filter(|&(_, v)| v) {
writer.write_u16(i as u16)?;
}
} else if count_neg < threshold {
Writeable::write(&BitmapBlockSerialization::Negative, writer)?;
writer.write_u16(count_neg as u16)?;
for (i, _) in self.inner.iter().enumerate().filter(|&(_, v)| !v) {
writer.write_u16(i as u16)?;
}
} else {
Writeable::write(&BitmapBlockSerialization::Raw, writer)?;
let bytes = self.inner.to_bytes();
assert!(bytes.len() <= Self::NBITS as usize / 8);
writer.write_fixed_bytes(&bytes)?;
}
Ok(())
}
}
impl Readable for BitmapBlock {
fn read<R: Reader>(reader: &mut R) -> Result<Self, ser::Error> {
let n_chunks = reader.read_u8()?;
if n_chunks as usize > BitmapBlock::NCHUNKS {
return Err(ser::Error::TooLargeReadErr);
}
let n_bits = n_chunks as usize * BitmapChunk::LEN_BITS;
let mode = Readable::read(reader)?;
let inner = match mode {
BitmapBlockSerialization::Raw => {
let bytes = reader.read_fixed_bytes(n_bits / 8)?;
BitVec::from_bytes(&bytes)
}
BitmapBlockSerialization::Positive => {
let mut inner = BitVec::from_elem(n_bits, false);
let n = reader.read_u16()?;
for _ in 0..n {
inner.set(reader.read_u16()? as usize, true);
}
inner
}
BitmapBlockSerialization::Negative => {
let mut inner = BitVec::from_elem(n_bits, true);
let n = reader.read_u16()?;
for _ in 0..n {
inner.set(reader.read_u16()? as usize, false);
}
inner
}
};
Ok(BitmapBlock { inner })
}
}
enum_from_primitive! {
#[derive(Debug, Clone, Copy, PartialEq)]
#[repr(u8)]
enum BitmapBlockSerialization {
Raw = 0,
Positive = 1,
Negative = 2,
}
}
impl Writeable for BitmapBlockSerialization {
fn write<W: Writer>(&self, writer: &mut W) -> Result<(), ser::Error> {
writer.write_u8(*self as u8)
}
}
impl Readable for BitmapBlockSerialization {
fn read<R: Reader>(reader: &mut R) -> Result<Self, ser::Error> {
Self::from_u8(reader.read_u8()?).ok_or(ser::Error::CorruptedData)
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::core::ser::{
BinReader, BinWriter, DeserializationMode, ProtocolVersion, Readable, Writeable,
};
use byteorder::ReadBytesExt;
use grin_util::secp::rand::Rng;
use rand::thread_rng;
use std::io::Cursor;
fn test_roundtrip(entries: usize, inverse: bool, encoding: u8, length: usize, n_blocks: usize) {
let mut rng = thread_rng();
let mut block = BitmapBlock::new(n_blocks);
if inverse {
block.inner.negate();
}
let range_size = n_blocks * BitmapChunk::LEN_BITS as usize;
let mut count = 0;
while count < entries {
let idx = rng.gen_range(0, range_size);
if block.inner.get(idx).unwrap() == inverse {
count += 1;
block.inner.set(idx, !inverse);
}
}
let mut cursor = Cursor::new(Vec::<u8>::new());
let mut writer = BinWriter::new(&mut cursor, ProtocolVersion(1));
Writeable::write(&block, &mut writer).unwrap();
cursor.set_position(1);
assert_eq!(cursor.read_u8().unwrap(), encoding);
let actual_length = cursor.get_ref().len();
assert_eq!(actual_length, length);
assert!(actual_length <= 2 + BitmapBlock::NBITS as usize / 8);
cursor.set_position(0);
let mut reader = BinReader::new(
&mut cursor,
ProtocolVersion(1),
DeserializationMode::default(),
);
let block2: BitmapBlock = Readable::read(&mut reader).unwrap();
assert_eq!(block, block2);
}
#[test]
fn block_ser_roundtrip() {
let threshold = BitmapBlock::NBITS as usize / 16;
let entries = thread_rng().gen_range(threshold, 4 * threshold);
test_roundtrip(entries, false, 0, 2 + BitmapBlock::NBITS as usize / 8, 64);
test_roundtrip(entries, true, 0, 2 + BitmapBlock::NBITS as usize / 8, 64);
}
#[test]
fn sparse_block_ser_roundtrip() {
let entries =
thread_rng().gen_range(BitmapChunk::LEN_BITS, BitmapBlock::NBITS as usize / 16);
test_roundtrip(entries, false, 1, 4 + 2 * entries, 64);
}
#[test]
fn sparse_unfull_block_ser_roundtrip() {
let entries =
thread_rng().gen_range(BitmapChunk::LEN_BITS, BitmapBlock::NBITS as usize / 16);
test_roundtrip(entries, false, 1, 4 + 2 * entries, 61);
}
#[test]
fn abdundant_block_ser_roundtrip() {
let entries =
thread_rng().gen_range(BitmapChunk::LEN_BITS, BitmapBlock::NBITS as usize / 16);
test_roundtrip(entries, true, 2, 4 + 2 * entries, 64);
}
#[test]
fn abdundant_unfull_block_ser_roundtrip() {
let entries =
thread_rng().gen_range(BitmapChunk::LEN_BITS, BitmapBlock::NBITS as usize / 16);
test_roundtrip(entries, true, 2, 4 + 2 * entries, 61);
}
}