mirror of
https://github.com/mimblewimble/grin.git
synced 2025-02-01 08:51:08 +03:00
no more conversion to support v2 blocks (#3587)
get_block simply returns None if v2 support required
This commit is contained in:
parent
e023739658
commit
35740204a1
3 changed files with 5 additions and 146 deletions
|
@ -35,15 +35,13 @@ use crate::types::{
|
|||
};
|
||||
use crate::util::secp::pedersen::{Commitment, RangeProof};
|
||||
use crate::util::RwLock;
|
||||
use crate::ChainStore;
|
||||
use grin_core::ser;
|
||||
use grin_store::Error::NotFoundErr;
|
||||
use std::collections::HashMap;
|
||||
use std::fs::{self, File};
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::sync::atomic::{AtomicUsize, Ordering};
|
||||
use std::sync::Arc;
|
||||
use std::time::{Duration, Instant};
|
||||
use std::{collections::HashMap, io::Cursor};
|
||||
|
||||
/// Orphan pool size is limited by MAX_ORPHAN_SIZE
|
||||
pub const MAX_ORPHAN_SIZE: usize = 200;
|
||||
|
@ -173,10 +171,6 @@ impl Chain {
|
|||
) -> Result<Chain, Error> {
|
||||
let store = Arc::new(store::ChainStore::new(&db_root)?);
|
||||
|
||||
// DB migrations to be run prior to the chain being used.
|
||||
// Migrate full blocks to protocol version v3.
|
||||
Chain::migrate_db_v2_v3(&store)?;
|
||||
|
||||
// open the txhashset, creating a new one if necessary
|
||||
let mut txhashset = txhashset::TxHashSet::open(db_root.clone(), store.clone(), None)?;
|
||||
|
||||
|
@ -273,43 +267,6 @@ impl Chain {
|
|||
res
|
||||
}
|
||||
|
||||
/// We plan to support receiving blocks with CommitOnly inputs.
|
||||
/// We also need to support relaying blocks with FeaturesAndCommit inputs to peers.
|
||||
/// So we need a way to convert blocks from CommitOnly to FeaturesAndCommit.
|
||||
/// Validating the inputs against the utxo_view allows us to look the outputs up.
|
||||
pub fn convert_block_v2(&self, block: Block) -> Result<Block, Error> {
|
||||
debug!(
|
||||
"convert_block_v2: {} at {} ({} -> v2)",
|
||||
block.header.hash(),
|
||||
block.header.height,
|
||||
block.inputs().version_str(),
|
||||
);
|
||||
|
||||
if block.inputs().is_empty() {
|
||||
return Ok(Block {
|
||||
header: block.header,
|
||||
body: block.body.replace_inputs(Inputs::FeaturesAndCommit(vec![])),
|
||||
});
|
||||
}
|
||||
|
||||
let mut header_pmmr = self.header_pmmr.write();
|
||||
let mut txhashset = self.txhashset.write();
|
||||
let inputs: Vec<_> =
|
||||
txhashset::extending_readonly(&mut header_pmmr, &mut txhashset, |ext, batch| {
|
||||
let previous_header = batch.get_previous_header(&block.header)?;
|
||||
pipe::rewind_and_apply_fork(&previous_header, ext, batch)?;
|
||||
ext.extension
|
||||
.utxo_view(ext.header_extension)
|
||||
.validate_inputs(&block.inputs(), batch)
|
||||
.map(|outputs| outputs.into_iter().map(|(out, _)| out).collect())
|
||||
})?;
|
||||
let inputs = inputs.as_slice().into();
|
||||
Ok(Block {
|
||||
header: block.header,
|
||||
body: block.body.replace_inputs(inputs),
|
||||
})
|
||||
}
|
||||
|
||||
fn determine_status(
|
||||
&self,
|
||||
head: Option<Tip>,
|
||||
|
@ -401,11 +358,6 @@ impl Chain {
|
|||
// Only do this once we know the header PoW is valid.
|
||||
self.check_orphan(&b, opts)?;
|
||||
|
||||
// We can only reliably convert to "v2" if not an orphan (may spend output from previous block).
|
||||
// We convert from "v3" to "v2" by looking up outputs to be spent.
|
||||
// This conversion also ensures a block received in "v2" has valid input features (prevents malleability).
|
||||
let b = self.convert_block_v2(b)?;
|
||||
|
||||
let (maybe_new_head, prev_head) = {
|
||||
let mut header_pmmr = self.header_pmmr.write();
|
||||
let mut txhashset = self.txhashset.write();
|
||||
|
@ -1367,58 +1319,6 @@ impl Chain {
|
|||
self.header_pmmr.read().get_header_hash_by_height(height)
|
||||
}
|
||||
|
||||
/// Migrate our local db from v2 to v3.
|
||||
/// "commit only" inputs.
|
||||
fn migrate_db_v2_v3(store: &ChainStore) -> Result<(), Error> {
|
||||
if store.batch()?.is_blocks_v3_migrated()? {
|
||||
// Previously migrated so skipping.
|
||||
debug!("migrate_db_v2_v3: previously migrated, skipping");
|
||||
return Ok(());
|
||||
}
|
||||
let mut total = 0;
|
||||
let mut keys_to_migrate = vec![];
|
||||
for (k, v) in store.batch()?.blocks_raw_iter()? {
|
||||
total += 1;
|
||||
|
||||
// We want to migrate all blocks that cannot be read via v3 protocol version.
|
||||
let block_v3: Result<Block, _> =
|
||||
ser::deserialize(&mut Cursor::new(&v), ProtocolVersion(3));
|
||||
if block_v3.is_err() {
|
||||
let block_v2: Result<Block, _> =
|
||||
ser::deserialize(&mut Cursor::new(&v), ProtocolVersion(2));
|
||||
if block_v2.is_ok() {
|
||||
keys_to_migrate.push(k);
|
||||
}
|
||||
}
|
||||
}
|
||||
debug!(
|
||||
"migrate_db_v2_v3: {} (of {}) blocks to migrate",
|
||||
keys_to_migrate.len(),
|
||||
total,
|
||||
);
|
||||
let mut count = 0;
|
||||
keys_to_migrate
|
||||
.chunks(100)
|
||||
.try_for_each(|keys| {
|
||||
let batch = store.batch()?;
|
||||
for key in keys {
|
||||
batch.migrate_block(&key, ProtocolVersion(2), ProtocolVersion(3))?;
|
||||
count += 1;
|
||||
}
|
||||
batch.commit()?;
|
||||
debug!("migrate_db_v2_v3: successfully migrated {} blocks", count);
|
||||
Ok(())
|
||||
})
|
||||
.and_then(|_| {
|
||||
// Set flag to indicate we have migrated all blocks in the db.
|
||||
// We will skip migration in the future.
|
||||
let batch = store.batch()?;
|
||||
batch.set_blocks_v3_migrated(true)?;
|
||||
batch.commit()?;
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
|
||||
/// Gets the block header in which a given output appears in the txhashset.
|
||||
pub fn get_header_for_output(&self, commit: Commitment) -> Result<BlockHeader, Error> {
|
||||
let header_pmmr = self.header_pmmr.read();
|
||||
|
|
|
@ -46,11 +46,6 @@ pub const NRD_KERNEL_ENTRY_PREFIX: u8 = b'k';
|
|||
const BLOCK_SUMS_PREFIX: u8 = b'M';
|
||||
const BLOCK_SPENT_PREFIX: u8 = b'S';
|
||||
|
||||
/// Prefix for various boolean flags stored in the db.
|
||||
const BOOL_FLAG_PREFIX: u8 = b'B';
|
||||
/// Boolean flag for v3 migration.
|
||||
const BLOCKS_V3_MIGRATED: &str = "blocks_v3_migrated";
|
||||
|
||||
/// All chain-related database operations
|
||||
pub struct ChainStore {
|
||||
db: store::Store,
|
||||
|
@ -219,44 +214,6 @@ impl<'a> Batch<'a> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
/// DB flag representing full migration of blocks to v3 version.
|
||||
/// Default to false if flag not present.
|
||||
pub fn is_blocks_v3_migrated(&self) -> Result<bool, Error> {
|
||||
let migrated: Option<BoolFlag> = self
|
||||
.db
|
||||
.get_ser(&to_key(BOOL_FLAG_PREFIX, BLOCKS_V3_MIGRATED))?;
|
||||
match migrated {
|
||||
None => Ok(false),
|
||||
Some(x) => Ok(x.into()),
|
||||
}
|
||||
}
|
||||
|
||||
/// Set DB flag representing full migration of blocks to v3 version.
|
||||
pub fn set_blocks_v3_migrated(&self, migrated: bool) -> Result<(), Error> {
|
||||
self.db.put_ser(
|
||||
&to_key(BOOL_FLAG_PREFIX, BLOCKS_V3_MIGRATED)[..],
|
||||
&BoolFlag(migrated),
|
||||
)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Migrate a block stored in the db reading from one protocol version and writing
|
||||
/// with new protocol version.
|
||||
pub fn migrate_block(
|
||||
&self,
|
||||
key: &[u8],
|
||||
from_version: ProtocolVersion,
|
||||
to_version: ProtocolVersion,
|
||||
) -> Result<(), Error> {
|
||||
let block: Option<Block> = self.db.get_with(key, move |_, mut v| {
|
||||
ser::deserialize(&mut v, from_version).map_err(From::from)
|
||||
})?;
|
||||
if let Some(block) = block {
|
||||
self.db.put_ser_with_version(key, &block, to_version)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Low level function to delete directly by raw key.
|
||||
pub fn delete(&self, key: &[u8]) -> Result<(), Error> {
|
||||
self.db.delete(key)
|
||||
|
|
|
@ -378,12 +378,14 @@ where
|
|||
}
|
||||
|
||||
/// Gets a full block by its hash.
|
||||
/// Will convert to v2 compatibility based on peer protocol version.
|
||||
/// We only support v3 blocks since HF4.
|
||||
/// If a peer is requesting a block and only appears to support v2
|
||||
/// then ignore the request.
|
||||
fn get_block(&self, h: Hash, peer_info: &PeerInfo) -> Option<core::Block> {
|
||||
self.chain()
|
||||
.get_block(&h)
|
||||
.map(|b| match peer_info.version.value() {
|
||||
0..=2 => self.chain().convert_block_v2(b).ok(),
|
||||
0..=2 => None,
|
||||
3..=ProtocolVersion::MAX => Some(b),
|
||||
})
|
||||
.unwrap_or(None)
|
||||
|
|
Loading…
Reference in a new issue