mirror of
https://github.com/mimblewimble/grin.git
synced 2025-02-01 17:01:09 +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::secp::pedersen::{Commitment, RangeProof};
|
||||||
use crate::util::RwLock;
|
use crate::util::RwLock;
|
||||||
use crate::ChainStore;
|
|
||||||
use grin_core::ser;
|
|
||||||
use grin_store::Error::NotFoundErr;
|
use grin_store::Error::NotFoundErr;
|
||||||
|
use std::collections::HashMap;
|
||||||
use std::fs::{self, File};
|
use std::fs::{self, File};
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
use std::sync::atomic::{AtomicUsize, Ordering};
|
use std::sync::atomic::{AtomicUsize, Ordering};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::time::{Duration, Instant};
|
use std::time::{Duration, Instant};
|
||||||
use std::{collections::HashMap, io::Cursor};
|
|
||||||
|
|
||||||
/// Orphan pool size is limited by MAX_ORPHAN_SIZE
|
/// Orphan pool size is limited by MAX_ORPHAN_SIZE
|
||||||
pub const MAX_ORPHAN_SIZE: usize = 200;
|
pub const MAX_ORPHAN_SIZE: usize = 200;
|
||||||
|
@ -173,10 +171,6 @@ impl Chain {
|
||||||
) -> Result<Chain, Error> {
|
) -> Result<Chain, Error> {
|
||||||
let store = Arc::new(store::ChainStore::new(&db_root)?);
|
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
|
// open the txhashset, creating a new one if necessary
|
||||||
let mut txhashset = txhashset::TxHashSet::open(db_root.clone(), store.clone(), None)?;
|
let mut txhashset = txhashset::TxHashSet::open(db_root.clone(), store.clone(), None)?;
|
||||||
|
|
||||||
|
@ -273,43 +267,6 @@ impl Chain {
|
||||||
res
|
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(
|
fn determine_status(
|
||||||
&self,
|
&self,
|
||||||
head: Option<Tip>,
|
head: Option<Tip>,
|
||||||
|
@ -401,11 +358,6 @@ impl Chain {
|
||||||
// Only do this once we know the header PoW is valid.
|
// Only do this once we know the header PoW is valid.
|
||||||
self.check_orphan(&b, opts)?;
|
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 (maybe_new_head, prev_head) = {
|
||||||
let mut header_pmmr = self.header_pmmr.write();
|
let mut header_pmmr = self.header_pmmr.write();
|
||||||
let mut txhashset = self.txhashset.write();
|
let mut txhashset = self.txhashset.write();
|
||||||
|
@ -1367,58 +1319,6 @@ impl Chain {
|
||||||
self.header_pmmr.read().get_header_hash_by_height(height)
|
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.
|
/// 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> {
|
pub fn get_header_for_output(&self, commit: Commitment) -> Result<BlockHeader, Error> {
|
||||||
let header_pmmr = self.header_pmmr.read();
|
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_SUMS_PREFIX: u8 = b'M';
|
||||||
const BLOCK_SPENT_PREFIX: u8 = b'S';
|
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
|
/// All chain-related database operations
|
||||||
pub struct ChainStore {
|
pub struct ChainStore {
|
||||||
db: store::Store,
|
db: store::Store,
|
||||||
|
@ -219,44 +214,6 @@ impl<'a> Batch<'a> {
|
||||||
Ok(())
|
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.
|
/// Low level function to delete directly by raw key.
|
||||||
pub fn delete(&self, key: &[u8]) -> Result<(), Error> {
|
pub fn delete(&self, key: &[u8]) -> Result<(), Error> {
|
||||||
self.db.delete(key)
|
self.db.delete(key)
|
||||||
|
|
|
@ -378,12 +378,14 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Gets a full block by its hash.
|
/// 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> {
|
fn get_block(&self, h: Hash, peer_info: &PeerInfo) -> Option<core::Block> {
|
||||||
self.chain()
|
self.chain()
|
||||||
.get_block(&h)
|
.get_block(&h)
|
||||||
.map(|b| match peer_info.version.value() {
|
.map(|b| match peer_info.version.value() {
|
||||||
0..=2 => self.chain().convert_block_v2(b).ok(),
|
0..=2 => None,
|
||||||
3..=ProtocolVersion::MAX => Some(b),
|
3..=ProtocolVersion::MAX => Some(b),
|
||||||
})
|
})
|
||||||
.unwrap_or(None)
|
.unwrap_or(None)
|
||||||
|
|
Loading…
Reference in a new issue