Skip to content

Commit

Permalink
fix: fix prune mode sync bug introduced in TariScript (#3082)
Browse files Browse the repository at this point in the history
BREAKING CHANGE: Blockchain will need to be resynced
  • Loading branch information
stringhandler committed Jul 20, 2021
2 parents bbc0b58 + b72182e commit b374e7f
Show file tree
Hide file tree
Showing 11 changed files with 77 additions and 49 deletions.
2 changes: 1 addition & 1 deletion base_layer/core/src/base_node/proto/rpc.proto
Expand Up @@ -74,5 +74,5 @@ message SyncUtxo {

message PrunedOutput {
bytes hash = 1;
bytes rangeproof_hash = 2;
bytes witness_hash = 2;
}
4 changes: 2 additions & 2 deletions base_layer/core/src/base_node/proto/rpc.rs
Expand Up @@ -36,11 +36,11 @@ impl From<PrunedOutput> for proto::SyncUtxo {
match output {
PrunedOutput::Pruned {
output_hash,
range_proof_hash,
witness_hash,
} => proto::SyncUtxo {
utxo: Some(proto::sync_utxo::Utxo::PrunedOutput(proto::PrunedOutput {
hash: output_hash,
rangeproof_hash: range_proof_hash,
witness_hash,
})),
},
PrunedOutput::NotPruned { output } => proto::SyncUtxo {
Expand Down
Expand Up @@ -376,10 +376,10 @@ impl<'a, B: BlockchainBackend + 'static> HorizonStateSynchronization<'a, B> {
);
height_txo_counter += 1;
output_hashes.push(utxo.hash.clone());
witness_hashes.push(utxo.rangeproof_hash.clone());
witness_hashes.push(utxo.witness_hash.clone());
txn.insert_pruned_output_via_horizon_sync(
utxo.hash,
utxo.rangeproof_hash,
utxo.witness_hash,
current_header.hash().clone(),
current_header.height(),
u32::try_from(mmr_position)?,
Expand Down
4 changes: 2 additions & 2 deletions base_layer/core/src/chain_storage/async_db.rs
Expand Up @@ -284,13 +284,13 @@ impl<'a, B: BlockchainBackend + 'static> AsyncDbTransaction<'a, B> {
pub fn insert_pruned_output_via_horizon_sync(
&mut self,
output_hash: HashOutput,
proof_hash: HashOutput,
witness_hash: HashOutput,
header_hash: HashOutput,
header_height: u64,
mmr_position: u32,
) -> &mut Self {
self.transaction
.insert_pruned_utxo(output_hash, proof_hash, header_hash, header_height, mmr_position);
.insert_pruned_utxo(output_hash, witness_hash, header_hash, header_height, mmr_position);
self
}

Expand Down
11 changes: 9 additions & 2 deletions base_layer/core/src/chain_storage/blockchain_database.rs
Expand Up @@ -1138,9 +1138,9 @@ fn fetch_block<T: BlockchainBackend>(db: &T, height: u64) -> Result<HistoricalBl
match output {
PrunedOutput::Pruned {
output_hash,
range_proof_hash,
witness_hash,
} => {
pruned.push((output_hash, range_proof_hash));
pruned.push((output_hash, witness_hash));
},
PrunedOutput::NotPruned { output } => unpruned.push(output),
}
Expand Down Expand Up @@ -1844,6 +1844,13 @@ fn prune_database_if_needed<T: BlockchainBackend>(
let db_height = metadata.height_of_longest_chain();
let abs_pruning_horizon = db_height.saturating_sub(pruning_horizon);

debug!(
target: LOG_TARGET,
"Current pruned height is: {}, pruning horizon is: {}, while the pruning interval is: {}",
metadata.pruned_height(),
abs_pruning_horizon,
pruning_interval,
);
if metadata.pruned_height() < abs_pruning_horizon.saturating_sub(pruning_interval) {
let last_pruned = metadata.pruned_height();
info!(
Expand Down
8 changes: 4 additions & 4 deletions base_layer/core/src/chain_storage/db_transaction.rs
Expand Up @@ -130,7 +130,7 @@ impl DbTransaction {
pub fn insert_pruned_utxo(
&mut self,
output_hash: HashOutput,
proof_hash: HashOutput,
witness_hash: HashOutput,
header_hash: HashOutput,
header_height: u64,
mmr_leaf_index: u32,
Expand All @@ -139,7 +139,7 @@ impl DbTransaction {
header_hash,
header_height,
output_hash,
proof_hash,
witness_hash,
mmr_position: mmr_leaf_index,
});
self
Expand Down Expand Up @@ -297,7 +297,7 @@ pub enum WriteOperation {
header_hash: HashOutput,
header_height: u64,
output_hash: HashOutput,
proof_hash: HashOutput,
witness_hash: HashOutput,
mmr_position: u32,
},
DeleteHeader(u64),
Expand Down Expand Up @@ -410,7 +410,7 @@ impl fmt::Display for WriteOperation {
header_hash: _,
header_height: _,
output_hash: _,
proof_hash: _,
witness_hash: _,
mmr_position: _,
} => write!(f, "Insert pruned output"),
UpdateDeletedBlockAccumulatedDataWithDiff {
Expand Down
81 changes: 51 additions & 30 deletions base_layer/core/src/chain_storage/lmdb_db/lmdb_db.rs
Expand Up @@ -96,6 +96,24 @@ type DatabaseRef = Arc<Database<'static>>;

pub const LOG_TARGET: &str = "c::cs::lmdb_db::lmdb_db";

struct OutputKey {
header_hash: HashOutput,
mmr_position: u32,
}

impl OutputKey {
pub fn new(header_hash: HashOutput, mmr_position: u32) -> OutputKey {
OutputKey {
header_hash,
mmr_position,
}
}

pub fn get_key(&self) -> String {
format!("{}-{:010}", self.header_hash.to_hex(), self.mmr_position)
}
}

/// This is a lmdb-based blockchain database for persistent storage of the chain state.
pub struct LMDBDatabase {
env: Arc<Environment>,
Expand Down Expand Up @@ -196,15 +214,15 @@ impl LMDBDatabase {
header_hash,
header_height,
output_hash,
proof_hash,
witness_hash,
mmr_position,
} => {
self.insert_pruned_output(
&write_txn,
header_hash,
header_height,
output_hash,
proof_hash,
witness_hash,
mmr_position,
)?;
},
Expand Down Expand Up @@ -323,13 +341,18 @@ impl LMDBDatabase {
fn prune_output(
&self,
txn: &WriteTransaction<'_>,
key: &str,
key: &OutputKey,
) -> Result<Option<TransactionOutput>, ChainStorageError> {
let mut output: TransactionOutputRowData =
lmdb_get(txn, &self.utxos_db, key).or_not_found("TransactionOutput", "key", key.to_string())?;
let key = key.get_key();
let key_string = key.as_str();
let mut output: TransactionOutputRowData = lmdb_get(txn, &self.utxos_db, key_string).or_not_found(
"TransactionOutput",
"key",
key_string.to_string(),
)?;
let result = output.output.take();
// output.output is None
lmdb_replace(txn, &self.utxos_db, key, &output)?;
lmdb_replace(txn, &self.utxos_db, key_string, &output)?;
Ok(result)
}

Expand All @@ -342,25 +365,28 @@ impl LMDBDatabase {
mmr_position: u32,
) -> Result<(), ChainStorageError> {
let output_hash = output.hash();
let proof_hash = output.proof.hash();
let key = format!("{}-{:010}", header_hash.to_hex(), mmr_position,);
let witness_hash = output.witness_hash();

let key = OutputKey::new(header_hash.clone(), mmr_position);
let key_string = key.get_key();

lmdb_insert(
txn,
&*self.txos_hash_to_index_db,
output_hash.as_slice(),
&(mmr_position, key.clone()),
&(mmr_position, key_string.clone()),
"txos_hash_to_index_db",
)?;
lmdb_insert(
txn,
&*self.utxos_db,
key.as_str(),
key_string.as_str(),
&TransactionOutputRowData {
output: Some(output),
header_hash,
mmr_position,
hash: output_hash,
range_proof_hash: proof_hash,
witness_hash,
mined_height: header_height,
},
"utxos_db",
Expand All @@ -373,39 +399,34 @@ impl LMDBDatabase {
header_hash: HashOutput,
header_height: u64,
output_hash: HashOutput,
proof_hash: HashOutput,
witness_hash: HashOutput,
mmr_position: u32,
) -> Result<(), ChainStorageError> {
if !lmdb_exists(txn, &self.headers_db, header_hash.as_slice())? {
if !lmdb_exists(txn, &self.block_hashes_db, header_hash.as_slice())? {
return Err(ChainStorageError::InvalidOperation(format!(
"Unable to insert pruned output because header {} does not exist",
header_hash.to_hex()
header_hash.to_hex(),
)));
}
let key = format!(
"{}-{:010}-{}-{}",
header_hash.to_hex(),
mmr_position,
output_hash.to_hex(),
proof_hash.to_hex()
);
let key = OutputKey::new(header_hash.clone(), mmr_position);
let key_string = key.get_key();
lmdb_insert(
txn,
&*self.txos_hash_to_index_db,
output_hash.as_slice(),
&(mmr_position, key.clone()),
&(mmr_position, key_string.clone()),
"txos_hash_to_index_db",
)?;
lmdb_insert(
txn,
&*self.utxos_db,
key.as_str(),
key_string.as_str(),
&TransactionOutputRowData {
output: None,
header_hash,
mmr_position,
hash: output_hash,
range_proof_hash: proof_hash,
witness_hash,
mined_height: header_height,
},
"utxos_db",
Expand Down Expand Up @@ -974,11 +995,11 @@ impl LMDBDatabase {
let (_height, hash) = lmdb_first_after::<_, (u64, Vec<u8>)>(
&write_txn,
&self.output_mmr_size_index,
&(pos as u64).to_be_bytes(),
&((pos + 1) as u64).to_be_bytes(),
)
.or_not_found("BlockHeader", "mmr_position", pos.to_string())?;
let key = format!("{}-{:010}", hash.to_hex(), pos);
debug!(target: LOG_TARGET, "Pruning output: {}", key);
let key = OutputKey::new(hash, pos);
debug!(target: LOG_TARGET, "Pruning output: {}", key.get_key());
self.prune_output(&write_txn, &key)?;
}

Expand Down Expand Up @@ -1538,15 +1559,15 @@ impl BlockchainBackend for LMDBDatabase {
if deleted.contains(row.mmr_position) {
return PrunedOutput::Pruned {
output_hash: row.hash,
range_proof_hash: row.range_proof_hash,
witness_hash: row.witness_hash,
};
}
if let Some(output) = row.output {
PrunedOutput::NotPruned { output }
} else {
PrunedOutput::Pruned {
output_hash: row.hash,
range_proof_hash: row.range_proof_hash,
witness_hash: row.witness_hash,
}
}
}),
Expand Down Expand Up @@ -1625,7 +1646,7 @@ impl BlockchainBackend for LMDBDatabase {
Some(o) => PrunedOutput::NotPruned { output: o },
None => PrunedOutput::Pruned {
output_hash: f.hash,
range_proof_hash: f.range_proof_hash,
witness_hash: f.witness_hash,
},
})
.collect(),
Expand Down
2 changes: 1 addition & 1 deletion base_layer/core/src/chain_storage/lmdb_db/mod.rs
Expand Up @@ -56,7 +56,7 @@ pub(crate) struct TransactionOutputRowData {
pub header_hash: HashOutput,
pub mmr_position: u32,
pub hash: HashOutput,
pub range_proof_hash: HashOutput,
pub witness_hash: HashOutput,
pub mined_height: u64,
}

Expand Down
2 changes: 1 addition & 1 deletion base_layer/core/src/chain_storage/pruned_output.rs
Expand Up @@ -25,7 +25,7 @@ use crate::transactions::{transaction::TransactionOutput, types::HashOutput};
pub enum PrunedOutput {
Pruned {
output_hash: HashOutput,
range_proof_hash: HashOutput,
witness_hash: HashOutput,
},
NotPruned {
output: TransactionOutput,
Expand Down
2 changes: 1 addition & 1 deletion base_layer/core/src/proto/block.proto
Expand Up @@ -72,7 +72,7 @@ message HistoricalBlock {
Block block = 3;
BlockHeaderAccumulatedData accumulated_data = 4;
repeated bytes pruned_output_hashes = 5;
repeated bytes pruned_proof_hashes = 6;
repeated bytes pruned_witness_hash = 6;
uint64 pruned_input_count = 7;
}

Expand Down
6 changes: 3 additions & 3 deletions base_layer/core/src/proto/block.rs
Expand Up @@ -79,7 +79,7 @@ impl TryFrom<proto::HistoricalBlock> for HistoricalBlock {
let pruned = historical_block
.pruned_output_hashes
.into_iter()
.zip(historical_block.pruned_proof_hashes)
.zip(historical_block.pruned_witness_hash)
.collect();

Ok(HistoricalBlock::new(
Expand All @@ -95,14 +95,14 @@ impl TryFrom<proto::HistoricalBlock> for HistoricalBlock {
impl From<HistoricalBlock> for proto::HistoricalBlock {
fn from(block: HistoricalBlock) -> Self {
let pruned_output_hashes = block.pruned_outputs().iter().map(|x| x.0.clone()).collect();
let pruned_proof_hashes = block.pruned_outputs().iter().map(|x| x.1.clone()).collect();
let pruned_witness_hash = block.pruned_outputs().iter().map(|x| x.1.clone()).collect();
let (block, accumulated_data, confirmations, pruned_input_count) = block.dissolve();
Self {
confirmations,
accumulated_data: Some(accumulated_data.into()),
block: Some(block.into()),
pruned_output_hashes,
pruned_proof_hashes,
pruned_witness_hash,
pruned_input_count,
}
}
Expand Down

0 comments on commit b374e7f

Please sign in to comment.