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)] #[cfg(test)]
fn new_test() -> Self { fn new_test(keep_blocks: u32) -> Self {
use utils::NUM_COLUMNS; use utils::NUM_COLUMNS;
let db = Arc::new(::kvdb_memorydb::create(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> { 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| { match self.blockchain.header(block) {
let root: H256 = H256::from_slice(hdr.state_root().as_ref()); Ok(Some(ref hdr)) if !self.storage.state_db.is_pruned(hdr.number().as_()) => {
DbState::with_storage(self.storage.clone(), root) let root = H256::from_slice(hdr.state_root().as_ref());
}).ok_or_else(|| client::error::ErrorKind::UnknownBlock(format!("{:?}", block)).into())) 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] #[test]
fn block_hash_inserted_correctly() { fn block_hash_inserted_correctly() {
let db = Backend::<Block>::new_test(); let db = Backend::<Block>::new_test(1);
for i in 0..10 { for i in 0..10 {
assert!(db.blockchain().hash(i).unwrap().is_none()); assert!(db.blockchain().hash(i).unwrap().is_none());
@@ -516,7 +520,7 @@ mod tests {
#[test] #[test]
fn set_state_data() { 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 op = db.begin_operation(BlockId::Hash(Default::default())).unwrap();
let mut header = Header { let mut header = Header {
@@ -595,7 +599,7 @@ mod tests {
#[test] #[test]
fn delete_only_when_negative_rc() { fn delete_only_when_negative_rc() {
let key; let key;
let backend = Backend::<Block>::new_test(); let backend = Backend::<Block>::new_test(0);
let hash = { let hash = {
let mut op = backend.begin_operation(BlockId::Hash(Default::default())).unwrap(); 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() 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>) { fn prune(&mut self, commit: &mut CommitSet<Key>) {
if let (&mut Some(ref mut pruning), &PruningMode::Constrained(ref constraints)) = (&mut self.pruning, &self.mode) { if let (&mut Some(ref mut pruning), &PruningMode::Constrained(ref constraints)) = (&mut self.pruning, &self.mode) {
loop { loop {
@@ -241,7 +245,6 @@ impl<BlockHash: Hash, Key: Hash> StateDbSync<BlockHash, Key> {
if pruning.next_hash().map_or(false, |h| pinned.contains(&h)) { if pruning.next_hash().map_or(false, |h| pinned.contains(&h)) {
break; break;
} }
pruning.prune_one(commit); pruning.prune_one(commit);
} }
} }
@@ -328,6 +331,10 @@ impl<BlockHash: Hash, Key: Hash> StateDb<BlockHash, Key> {
return self.db.read().best_finalized() 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)] #[cfg(test)]
@@ -375,19 +382,24 @@ mod tests {
#[test] #[test]
fn prune_window_1() { 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_blocks: Some(1),
max_mem: None, 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]))); assert!(db.data_eq(&make_db(&[21, 3, 922, 93, 94])));
} }
#[test] #[test]
fn prune_window_2() { 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_blocks: Some(2),
max_mem: None, 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]))); 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))?; .map_err(|e| Error::Db(e))?;
let pending_number: u64 = match last_pruned { let pending_number: u64 = match last_pruned {
Some(buffer) => u64::decode(&mut buffer.as_slice()).ok_or(Error::Decoding)? + 1, Some(buffer) => u64::decode(&mut buffer.as_slice()).ok_or(Error::Decoding)? + 1,
None => 1, None => 0,
}; };
let mut block = pending_number; let mut block = pending_number;
let mut pruning = RefWindow { let mut pruning = RefWindow {
@@ -69,7 +69,7 @@ impl<BlockHash: Hash, Key: Hash> RefWindow<BlockHash, Key> {
pending_number: pending_number, pending_number: pending_number,
}; };
// read the journal // 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 { loop {
let journal_key = to_journal_key(block); let journal_key = to_journal_key(block);
match db.get_meta(&journal_key).map_err(|e| Error::Db(e))? { 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 0
} }
pub fn pending(&self) -> u64 {
self.pending_number
}
/// Prune next block. Expects at least one block in the window. Adds changes to `commit`. /// 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>) { 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"); 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() { fn created_from_empty_db() {
let db = make_db(&[]); let db = make_db(&[]);
let pruning: RefWindow<H256, H256> = RefWindow::new(&db).unwrap(); 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_rows.is_empty());
assert!(pruning.death_index.is_empty()); assert!(pruning.death_index.is_empty());
} }
@@ -202,7 +206,7 @@ mod tests {
assert!(db.data_eq(&make_db(&[2, 4, 5]))); assert!(db.data_eq(&make_db(&[2, 4, 5])));
assert!(pruning.death_rows.is_empty()); assert!(pruning.death_rows.is_empty());
assert!(pruning.death_index.is_empty()); assert!(pruning.death_index.is_empty());
assert_eq!(pruning.pending_number, 2); assert_eq!(pruning.pending_number, 1);
} }
#[test] #[test]
@@ -227,7 +231,7 @@ mod tests {
pruning.prune_one(&mut commit); pruning.prune_one(&mut commit);
db.commit(&commit); db.commit(&commit);
assert!(db.data_eq(&make_db(&[3, 4, 5]))); assert!(db.data_eq(&make_db(&[3, 4, 5])));
assert_eq!(pruning.pending_number, 3); assert_eq!(pruning.pending_number, 2);
} }
#[test] #[test]
@@ -258,6 +262,6 @@ mod tests {
pruning.prune_one(&mut commit); pruning.prune_one(&mut commit);
db.commit(&commit); db.commit(&commit);
assert!(db.data_eq(&make_db(&[1, 3]))); assert!(db.data_eq(&make_db(&[1, 3])));
assert_eq!(pruning.pending_number, 4); assert_eq!(pruning.pending_number, 3);
} }
} }