-
Notifications
You must be signed in to change notification settings - Fork 990
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
add segmenter for generating segments from txhashset with consistent …
…rewind (#3482) * add segmenter for generating segments from txhashset with consistent rewind * rework segmenter to take a txhashset wrapped in rwlock rework our rewindable pmmr so we can convert to readonly easily * placeholder code for rewinding readonly txhashset extension to build a rangeproof segment * segment creation for outputs/rangeproofs/kernels/bitmaps * placeholder segment impl * commit * rework segmenter to use a cached bitmap (rewind is expensive) * cache segmenter instance based on current archive header * integrate the real segment and segment identifier with our segmenter * exercise the segmenter code on chain init * wrap accumulator in an arc, no need to clone each time
- Loading branch information
Showing
11 changed files
with
335 additions
and
76 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,149 @@ | ||
// Copyright 2020 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. | ||
|
||
//! Generation of the various necessary segments requested during PIBD. | ||
use std::{sync::Arc, time::Instant}; | ||
|
||
use crate::core::core::hash::Hash; | ||
use crate::core::core::pmmr::ReadablePMMR; | ||
use crate::core::core::{BlockHeader, OutputIdentifier, Segment, SegmentIdentifier, TxKernel}; | ||
use crate::error::{Error, ErrorKind}; | ||
use crate::txhashset::{BitmapAccumulator, BitmapChunk, TxHashSet}; | ||
use crate::util::secp::pedersen::RangeProof; | ||
use crate::util::RwLock; | ||
|
||
/// Segmenter for generating PIBD segments. | ||
#[derive(Clone)] | ||
pub struct Segmenter { | ||
txhashset: Arc<RwLock<TxHashSet>>, | ||
bitmap_snapshot: Arc<BitmapAccumulator>, | ||
header: BlockHeader, | ||
} | ||
|
||
impl Segmenter { | ||
/// Create a new segmenter based on the provided txhashset. | ||
pub fn new( | ||
txhashset: Arc<RwLock<TxHashSet>>, | ||
bitmap_snapshot: Arc<BitmapAccumulator>, | ||
header: BlockHeader, | ||
) -> Segmenter { | ||
Segmenter { | ||
txhashset, | ||
bitmap_snapshot, | ||
header, | ||
} | ||
} | ||
|
||
/// Header associated with this segmenter instance. | ||
/// The bitmap "snapshot" corresponds to rewound state at this header. | ||
pub fn header(&self) -> &BlockHeader { | ||
&self.header | ||
} | ||
|
||
/// Create a kernel segment. | ||
pub fn kernel_segment(&self, id: SegmentIdentifier) -> Result<Segment<TxKernel>, Error> { | ||
let now = Instant::now(); | ||
let txhashset = self.txhashset.read(); | ||
let kernel_pmmr = txhashset.kernel_pmmr_at(&self.header); | ||
let segment = Segment::from_pmmr(id, &kernel_pmmr, false)?; | ||
debug!( | ||
"kernel_segment: id: ({}, {}), leaves: {}, hashes: {}, proof hashes: {}, took {}ms", | ||
segment.id().height, | ||
segment.id().idx, | ||
segment.leaf_iter().count(), | ||
segment.hash_iter().count(), | ||
segment.proof().size(), | ||
now.elapsed().as_millis() | ||
); | ||
Ok(segment) | ||
} | ||
|
||
/// The root of the output PMMR based on size from the header. | ||
fn output_root(&self) -> Result<Hash, Error> { | ||
let txhashset = self.txhashset.read(); | ||
let pmmr = txhashset.output_pmmr_at(&self.header); | ||
let root = pmmr.root().map_err(&ErrorKind::TxHashSetErr)?; | ||
Ok(root) | ||
} | ||
|
||
/// The root of the bitmap snapshot PMMR. | ||
fn bitmap_root(&self) -> Result<Hash, Error> { | ||
let pmmr = self.bitmap_snapshot.readonly_pmmr(); | ||
let root = pmmr.root().map_err(&ErrorKind::TxHashSetErr)?; | ||
Ok(root) | ||
} | ||
|
||
/// Create a utxo bitmap segment based on our bitmap "snapshot" and return it with | ||
/// the corresponding output root. | ||
pub fn bitmap_segment( | ||
&self, | ||
id: SegmentIdentifier, | ||
) -> Result<(Segment<BitmapChunk>, Hash), Error> { | ||
let now = Instant::now(); | ||
let bitmap_pmmr = self.bitmap_snapshot.readonly_pmmr(); | ||
let segment = Segment::from_pmmr(id, &bitmap_pmmr, false)?; | ||
let output_root = self.output_root()?; | ||
debug!( | ||
"bitmap_segment: id: ({}, {}), leaves: {}, hashes: {}, proof hashes: {}, took {}ms", | ||
segment.id().height, | ||
segment.id().idx, | ||
segment.leaf_iter().count(), | ||
segment.hash_iter().count(), | ||
segment.proof().size(), | ||
now.elapsed().as_millis() | ||
); | ||
Ok((segment, output_root)) | ||
} | ||
|
||
/// Create an output segment and return it with the corresponding bitmap root. | ||
pub fn output_segment( | ||
&self, | ||
id: SegmentIdentifier, | ||
) -> Result<(Segment<OutputIdentifier>, Hash), Error> { | ||
let now = Instant::now(); | ||
let txhashset = self.txhashset.read(); | ||
let output_pmmr = txhashset.output_pmmr_at(&self.header); | ||
let segment = Segment::from_pmmr(id, &output_pmmr, true)?; | ||
let bitmap_root = self.bitmap_root()?; | ||
debug!( | ||
"output_segment: id: ({}, {}), leaves: {}, hashes: {}, proof hashes: {}, took {}ms", | ||
segment.id().height, | ||
segment.id().idx, | ||
segment.leaf_iter().count(), | ||
segment.hash_iter().count(), | ||
segment.proof().size(), | ||
now.elapsed().as_millis() | ||
); | ||
Ok((segment, bitmap_root)) | ||
} | ||
|
||
/// Create a rangeproof segment. | ||
pub fn rangeproof_segment(&self, id: SegmentIdentifier) -> Result<Segment<RangeProof>, Error> { | ||
let now = Instant::now(); | ||
let txhashset = self.txhashset.read(); | ||
let pmmr = txhashset.rangeproof_pmmr_at(&self.header); | ||
let segment = Segment::from_pmmr(id, &pmmr, true)?; | ||
debug!( | ||
"rangeproof_segment: id: ({}, {}), leaves: {}, hashes: {}, proof hashes: {}, took {}ms", | ||
segment.id().height, | ||
segment.id().idx, | ||
segment.leaf_iter().count(), | ||
segment.hash_iter().count(), | ||
segment.proof().size(), | ||
now.elapsed().as_millis() | ||
); | ||
Ok(segment) | ||
} | ||
} |
Oops, something went wrong.