Check for pruned block state (#648)

This commit is contained in:
Arkadiy Paronyan
2018-09-03 16:29:55 +02:00
committed by Gav Wood
parent 73ad673404
commit 146ebceab4
3 changed files with 38 additions and 18 deletions
+13 -9
View File
@@ -300,12 +300,12 @@ impl<Block: BlockT> Backend<Block> {
}
#[cfg(test)]
fn new_test() -> Self {
fn new_test(keep_blocks: u32) -> Self {
use utils::NUM_COLUMNS;
let db = Arc::new(::kvdb_memorydb::create(NUM_COLUMNS));
Backend::from_kvdb(db as Arc<_>, PruningMode::keep_blocks(0), 0).expect("failed to create test-db")
Backend::from_kvdb(db as Arc<_>, PruningMode::keep_blocks(keep_blocks), 0).expect("failed to create test-db")
}
fn from_kvdb(db: Arc<KeyValueDB>, pruning: PruningMode, finalization_window: u64) -> Result<Self, client::error::Error> {
@@ -454,10 +454,14 @@ impl<Block> client::backend::Backend<Block, KeccakHasher, RlpCodec> for Backend<
_ => {}
}
self.blockchain.header(block).and_then(|maybe_hdr| maybe_hdr.map(|hdr| {
let root: H256 = H256::from_slice(hdr.state_root().as_ref());
DbState::with_storage(self.storage.clone(), root)
}).ok_or_else(|| client::error::ErrorKind::UnknownBlock(format!("{:?}", block)).into()))
match self.blockchain.header(block) {
Ok(Some(ref hdr)) if !self.storage.state_db.is_pruned(hdr.number().as_()) => {
let root = H256::from_slice(hdr.state_root().as_ref());
Ok(DbState::with_storage(self.storage.clone(), root))
},
Err(e) => Err(e),
_ => Err(client::error::ErrorKind::UnknownBlock(format!("{:?}", block)).into()),
}
}
}
@@ -477,7 +481,7 @@ mod tests {
#[test]
fn block_hash_inserted_correctly() {
let db = Backend::<Block>::new_test();
let db = Backend::<Block>::new_test(1);
for i in 0..10 {
assert!(db.blockchain().hash(i).unwrap().is_none());
@@ -516,7 +520,7 @@ mod tests {
#[test]
fn set_state_data() {
let db = Backend::<Block>::new_test();
let db = Backend::<Block>::new_test(2);
{
let mut op = db.begin_operation(BlockId::Hash(Default::default())).unwrap();
let mut header = Header {
@@ -595,7 +599,7 @@ mod tests {
#[test]
fn delete_only_when_negative_rc() {
let key;
let backend = Backend::<Block>::new_test();
let backend = Backend::<Block>::new_test(0);
let hash = {
let mut op = backend.begin_operation(BlockId::Hash(Default::default())).unwrap();
+15 -3
View File
@@ -226,6 +226,10 @@ impl<BlockHash: Hash, Key: Hash> StateDbSync<BlockHash, Key> {
return self.unfinalized.last_finalized_block_number()
}
pub fn is_pruned(&self, number: u64) -> bool {
self.pruning.as_ref().map_or(false, |pruning| number < pruning.pending())
}
fn prune(&mut self, commit: &mut CommitSet<Key>) {
if let (&mut Some(ref mut pruning), &PruningMode::Constrained(ref constraints)) = (&mut self.pruning, &self.mode) {
loop {
@@ -241,7 +245,6 @@ impl<BlockHash: Hash, Key: Hash> StateDbSync<BlockHash, Key> {
if pruning.next_hash().map_or(false, |h| pinned.contains(&h)) {
break;
}
pruning.prune_one(commit);
}
}
@@ -328,6 +331,10 @@ impl<BlockHash: Hash, Key: Hash> StateDb<BlockHash, Key> {
return self.db.read().best_finalized()
}
/// Check if block is pruned away.
pub fn is_pruned(&self, number: u64) -> bool {
return self.db.read().is_pruned(number)
}
}
#[cfg(test)]
@@ -375,19 +382,24 @@ mod tests {
#[test]
fn prune_window_1() {
let (db, _) = make_test_db(PruningMode::Constrained(Constraints {
let (db, sdb) = make_test_db(PruningMode::Constrained(Constraints {
max_blocks: Some(1),
max_mem: None,
}));
assert!(sdb.is_pruned(0));
assert!(sdb.is_pruned(1));
assert!(!sdb.is_pruned(2));
assert!(db.data_eq(&make_db(&[21, 3, 922, 93, 94])));
}
#[test]
fn prune_window_2() {
let (db, _) = make_test_db(PruningMode::Constrained(Constraints {
let (db, sdb) = make_test_db(PruningMode::Constrained(Constraints {
max_blocks: Some(2),
max_mem: None,
}));
assert!(sdb.is_pruned(0));
assert!(!sdb.is_pruned(1));
assert!(db.data_eq(&make_db(&[1, 21, 3, 921, 922, 93, 94])));
}
}
+10 -6
View File
@@ -60,7 +60,7 @@ impl<BlockHash: Hash, Key: Hash> RefWindow<BlockHash, Key> {
.map_err(|e| Error::Db(e))?;
let pending_number: u64 = match last_pruned {
Some(buffer) => u64::decode(&mut buffer.as_slice()).ok_or(Error::Decoding)? + 1,
None => 1,
None => 0,
};
let mut block = pending_number;
let mut pruning = RefWindow {
@@ -69,7 +69,7 @@ impl<BlockHash: Hash, Key: Hash> RefWindow<BlockHash, Key> {
pending_number: pending_number,
};
// read the journal
trace!(target: "state-db", "Reading pruning journal. Last pruned #{}", pending_number - 1);
trace!(target: "state-db", "Reading pruning journal. Pending #{}", pending_number);
loop {
let journal_key = to_journal_key(block);
match db.get_meta(&journal_key).map_err(|e| Error::Db(e))? {
@@ -119,6 +119,10 @@ impl<BlockHash: Hash, Key: Hash> RefWindow<BlockHash, Key> {
0
}
pub fn pending(&self) -> u64 {
self.pending_number
}
/// Prune next block. Expects at least one block in the window. Adds changes to `commit`.
pub fn prune_one(&mut self, commit: &mut CommitSet<Key>) {
let pruned = self.death_rows.pop_front().expect("prune_one is only called with a non-empty window");
@@ -168,7 +172,7 @@ mod tests {
fn created_from_empty_db() {
let db = make_db(&[]);
let pruning: RefWindow<H256, H256> = RefWindow::new(&db).unwrap();
assert_eq!(pruning.pending_number, 1);
assert_eq!(pruning.pending_number, 0);
assert!(pruning.death_rows.is_empty());
assert!(pruning.death_index.is_empty());
}
@@ -202,7 +206,7 @@ mod tests {
assert!(db.data_eq(&make_db(&[2, 4, 5])));
assert!(pruning.death_rows.is_empty());
assert!(pruning.death_index.is_empty());
assert_eq!(pruning.pending_number, 2);
assert_eq!(pruning.pending_number, 1);
}
#[test]
@@ -227,7 +231,7 @@ mod tests {
pruning.prune_one(&mut commit);
db.commit(&commit);
assert!(db.data_eq(&make_db(&[3, 4, 5])));
assert_eq!(pruning.pending_number, 3);
assert_eq!(pruning.pending_number, 2);
}
#[test]
@@ -258,6 +262,6 @@ mod tests {
pruning.prune_one(&mut commit);
db.commit(&commit);
assert!(db.data_eq(&make_db(&[1, 3])));
assert_eq!(pruning.pending_number, 4);
assert_eq!(pruning.pending_number, 3);
}
}