diff --git a/Cargo.lock b/Cargo.lock
index cfa42c4dc35d2d35cbb8a50a14be6780f3aab95f..7e6736743d539c6043a623ef3a02dfb770fa0863 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -3490,6 +3490,7 @@ dependencies = [
 name = "substrate-client-db"
 version = "0.1.0"
 dependencies = [
+ "env_logger 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "hash-db 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "kvdb 0.1.0 (git+https://github.com/paritytech/parity-common?rev=b0317f649ab2c665b7987b8475878fc4d2e1f81d)",
  "kvdb-memorydb 0.1.0 (git+https://github.com/paritytech/parity-common?rev=b0317f649ab2c665b7987b8475878fc4d2e1f81d)",
diff --git a/core/client/db/Cargo.toml b/core/client/db/Cargo.toml
index e3f26e0e2f6c9b205d2bfa3b0470feab2a845832..041440c398769013b4fb11acb9124aa6a048fa63 100644
--- a/core/client/db/Cargo.toml
+++ b/core/client/db/Cargo.toml
@@ -26,3 +26,4 @@ trie = { package = "substrate-trie", path = "../../trie" }
 kvdb-memorydb = { git = "https://github.com/paritytech/parity-common", rev="b0317f649ab2c665b7987b8475878fc4d2e1f81d" }
 substrate-keyring = { path = "../../keyring" }
 test-client = { package = "substrate-test-client", path = "../../test-client" }
+env_logger = { version = "0.6" }
diff --git a/core/client/db/src/lib.rs b/core/client/db/src/lib.rs
index 5e6b336db3043f10d35fb4050a429586e0a19c50..15a71344a5b4a2953a320b82883fdde2e672a0f8 100644
--- a/core/client/db/src/lib.rs
+++ b/core/client/db/src/lib.rs
@@ -612,7 +612,7 @@ impl<Block: BlockT<Hash=H256>> Backend<Block> {
 		if number_u64 > self.canonicalization_delay {
 			let new_canonical = number_u64 - self.canonicalization_delay;
 
-			if new_canonical <= self.storage.state_db.best_canonical() {
+			if new_canonical <= self.storage.state_db.best_canonical().unwrap_or(0) {
 				return Ok(())
 			}
 
@@ -751,7 +751,8 @@ impl<Block: BlockT<Hash=H256>> Backend<Block> {
 				.map_err(|e: state_db::Error<io::Error>| client::error::Error::from(format!("State database error: {:?}", e)))?;
 			apply_state_commit(&mut transaction, commit);
 
-			let finalized = match pending_block.leaf_state {
+			// Check if need to finalize. Genesis is always finalized instantly.
+			let finalized = number_u64 == 0 || match pending_block.leaf_state {
 				NewBlockState::Final => true,
 				_ => false,
 			};
@@ -759,7 +760,6 @@ impl<Block: BlockT<Hash=H256>> Backend<Block> {
 			let header = &pending_block.header;
 			let is_best = pending_block.leaf_state.is_best();
 			let changes_trie_updates = operation.changes_trie_updates;
-
 		
 			self.changes_tries_storage.commit(&mut transaction, changes_trie_updates);
 
@@ -834,7 +834,7 @@ impl<Block: BlockT<Hash=H256>> Backend<Block> {
 	{
 		let f_num = f_header.number().clone();
 
-		if f_num.as_() > self.storage.state_db.best_canonical() {
+		if self.storage.state_db.best_canonical().map(|c| f_num.as_() > c).unwrap_or(true) {
 			let parent_hash = f_header.parent_hash().clone();
 
 			let lookup_key = utils::number_and_hash_to_lookup_key(f_num, f_hash.clone());
@@ -1022,13 +1022,18 @@ impl<Block> client::backend::Backend<Block, Blake2Hasher> for Backend<Block> whe
 		}
 
 		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());
-				let state = DbState::new(self.storage.clone(), root);
-				Ok(CachingState::new(state, self.shared_cache.clone(), Some(hdr.hash())))
+			Ok(Some(ref hdr)) => {
+				let hash = hdr.hash();
+				if !self.storage.state_db.is_pruned(&hash, hdr.number().as_()) {
+					let root = H256::from_slice(hdr.state_root().as_ref());
+					let state = DbState::new(self.storage.clone(), root);
+					Ok(CachingState::new(state, self.shared_cache.clone(), Some(hash)))
+				} else {
+					Err(client::error::ErrorKind::UnknownBlock(format!("State already discarded for {:?}", block)).into())
+				}
 			},
+			Ok(None) => Err(client::error::ErrorKind::UnknownBlock(format!("{:?}", block)).into()),
 			Err(e) => Err(e),
-			_ => Err(client::error::ErrorKind::UnknownBlock(format!("{:?}", block)).into()),
 		}
 	}
 
@@ -1051,7 +1056,6 @@ mod tests {
 	use crate::columns;
 	use client::backend::Backend as BTrait;
 	use client::backend::BlockImportOperation as Op;
-	use client::blockchain::HeaderBackend as BlockchainHeaderBackend;
 	use runtime_primitives::testing::{Header, Block as RawBlock, ExtrinsicWrapper};
 	use runtime_primitives::traits::{Hash, BlakeTwo256};
 	use state_machine::{TrieMut, TrieDBMut, ChangesTrieRootsStorage, ChangesTrieStorage};
@@ -1247,8 +1251,9 @@ mod tests {
 
 	#[test]
 	fn delete_only_when_negative_rc() {
+		let _ = ::env_logger::try_init();
 		let key;
-		let backend = Backend::<Block>::new_test(0, 0);
+		let backend = Backend::<Block>::new_test(1, 0);
 
 		let hash = {
 			let mut op = backend.begin_operation().unwrap();
@@ -1321,7 +1326,7 @@ mod tests {
 			hash
 		};
 
-		{
+		let hash = {
 			let mut op = backend.begin_operation().unwrap();
 			backend.begin_state_operation(&mut op, BlockId::Number(1)).unwrap();
 			let mut header = Header {
@@ -1339,6 +1344,7 @@ mod tests {
 				.cloned()
 				.map(|(x, y)| (x, Some(y)))
 			).0.into();
+			let hash = header.hash();
 
 			op.db_updates.remove(&key);
 			op.set_block_data(
@@ -1350,11 +1356,44 @@ mod tests {
 
 			backend.commit_operation(op).unwrap();
 
+			assert!(backend.storage.db.get(columns::STATE, key.as_bytes()).unwrap().is_some());
+			hash
+		};
+
+		{
+			let mut op = backend.begin_operation().unwrap();
+			backend.begin_state_operation(&mut op, BlockId::Number(2)).unwrap();
+			let mut header = Header {
+				number: 3,
+				parent_hash: hash,
+				state_root: Default::default(),
+				digest: Default::default(),
+				extrinsics_root: Default::default(),
+			};
+
+			let storage: Vec<(_, _)> = vec![];
+
+			header.state_root = op.old_state.storage_root(storage
+				.iter()
+				.cloned()
+				.map(|(x, y)| (x, Some(y)))
+			).0.into();
+
+			op.set_block_data(
+				header,
+				Some(vec![]),
+				None,
+				NewBlockState::Best,
+			).unwrap();
+
+			backend.commit_operation(op).unwrap();
+
 			assert!(backend.storage.db.get(columns::STATE, key.as_bytes()).unwrap().is_none());
 		}
 
 		backend.finalize_block(BlockId::Number(1), None).unwrap();
 		backend.finalize_block(BlockId::Number(2), None).unwrap();
+		backend.finalize_block(BlockId::Number(3), None).unwrap();
 		assert!(backend.storage.db.get(columns::STATE, key.as_bytes()).unwrap().is_none());
 	}
 
@@ -1366,7 +1405,10 @@ mod tests {
 
 		let check_changes = |backend: &Backend<Block>, block: u64, changes: Vec<(Vec<u8>, Vec<u8>)>| {
 			let (changes_root, mut changes_trie_update) = prepare_changes(changes);
-			let anchor = state_machine::ChangesTrieAnchorBlockId { hash: Default::default(), number: block };
+			let anchor = state_machine::ChangesTrieAnchorBlockId {
+				hash: backend.blockchain().header(BlockId::Number(block)).unwrap().unwrap().hash(),
+				number: block
+			};
 			assert_eq!(backend.changes_tries_storage.root(&anchor, block), Ok(Some(changes_root)));
 
 			for (key, (val, _)) in changes_trie_update.drain() {
@@ -1450,7 +1492,6 @@ mod tests {
 	#[test]
 	fn changes_tries_with_digest_are_pruned_on_finalization() {
 		let mut backend = Backend::<Block>::new_test(1000, 100);
-		backend.changes_tries_storage.meta.write().finalized_number = 1000;
 		backend.changes_tries_storage.min_blocks_to_keep = Some(8);
 		let config = ChangesTrieConfiguration {
 			digest_interval: 2,
@@ -1470,10 +1511,12 @@ mod tests {
 		let block9 = insert_header(&backend, 9, block8, vec![(b"key_at_9".to_vec(), b"val_at_9".to_vec())], Default::default());
 		let block10 = insert_header(&backend, 10, block9, vec![(b"key_at_10".to_vec(), b"val_at_10".to_vec())], Default::default());
 		let block11 = insert_header(&backend, 11, block10, vec![(b"key_at_11".to_vec(), b"val_at_11".to_vec())], Default::default());
-		let _ = insert_header(&backend, 12, block11, vec![(b"key_at_12".to_vec(), b"val_at_12".to_vec())], Default::default());
+		let block12 = insert_header(&backend, 12, block11, vec![(b"key_at_12".to_vec(), b"val_at_12".to_vec())], Default::default());
+		let block13 = insert_header(&backend, 13, block12, vec![(b"key_at_13".to_vec(), b"val_at_13".to_vec())], Default::default());
+		backend.changes_tries_storage.meta.write().finalized_number = 13;
 
 		// check that roots of all tries are in the columns::CHANGES_TRIE
-		let anchor = state_machine::ChangesTrieAnchorBlockId { hash: Default::default(), number: 100 };
+		let anchor = state_machine::ChangesTrieAnchorBlockId { hash: block13, number: 13 };
 		fn read_changes_trie_root(backend: &Backend<Block>, num: u64) -> H256 {
 			backend.blockchain().header(BlockId::Number(num)).unwrap().unwrap().digest().logs().iter()
 				.find(|i| i.as_changes_trie_root().is_some()).unwrap().as_changes_trie_root().unwrap().clone()
diff --git a/core/state-db/src/lib.rs b/core/state-db/src/lib.rs
index 9dd693c14eb39a111d39d4db05382aa2feae3dfd..0aedd16a3b2acac2def3ed573c1874938efcc09b 100644
--- a/core/state-db/src/lib.rs
+++ b/core/state-db/src/lib.rs
@@ -190,12 +190,6 @@ impl<BlockHash: Hash, Key: Hash> StateDbSync<BlockHash, Key> {
 	}
 
 	pub fn insert_block<E: fmt::Debug>(&mut self, hash: &BlockHash, number: u64, parent_hash: &BlockHash, mut changeset: ChangeSet<Key>) -> Result<CommitSet<Key>, Error<E>> {
-		if number == 0 {
-			return Ok(CommitSet {
-				data: changeset,
-				meta: Default::default(),
-			})
-		}
 		match self.mode {
 			PruningMode::ArchiveAll => {
 				changeset.deleted.clear();
@@ -232,12 +226,16 @@ impl<BlockHash: Hash, Key: Hash> StateDbSync<BlockHash, Key> {
 		Ok(commit)
 	}
 
-	pub fn best_canonical(&self) -> u64 {
+	pub fn best_canonical(&self) -> Option<u64> {
 		return self.non_canonical.last_canonicalized_block_number()
 	}
 
-	pub fn is_pruned(&self, number: u64) -> bool {
-		self.pruning.as_ref().map_or(false, |pruning| number < pruning.pending())
+	pub fn is_pruned(&self, hash: &BlockHash, number: u64) -> bool {
+		if self.best_canonical().map(|c| number > c).unwrap_or(true) {
+			!self.non_canonical.have_block(hash)
+		} else {
+			self.pruning.as_ref().map_or(false, |pruning| number < pruning.pending() || !pruning.have_block(hash))
+		}
 	}
 
 	fn prune(&mut self, commit: &mut CommitSet<Key>) {
@@ -351,13 +349,13 @@ impl<BlockHash: Hash, Key: Hash> StateDb<BlockHash, Key> {
 	}
 
 	/// Returns last finalized block number.
-	pub fn best_canonical(&self) -> u64 {
+	pub fn best_canonical(&self) -> Option<u64> {
 		return self.db.read().best_canonical()
 	}
 
 	/// Check if block is pruned away.
-	pub fn is_pruned(&self, number: u64) -> bool {
-		return self.db.read().is_pruned(number)
+	pub fn is_pruned(&self, hash: &BlockHash, number: u64) -> bool {
+		return self.db.read().is_pruned(hash, number)
 	}
 
 	/// Apply all pending changes
@@ -471,9 +469,10 @@ mod tests {
 			max_blocks: Some(1),
 			max_mem: None,
 		}));
-		assert!(sdb.is_pruned(0));
-		assert!(sdb.is_pruned(1));
-		assert!(!sdb.is_pruned(2));
+		assert!(sdb.is_pruned(&H256::from_low_u64_be(0), 0));
+		assert!(sdb.is_pruned(&H256::from_low_u64_be(1), 1));
+		assert!(sdb.is_pruned(&H256::from_low_u64_be(21), 2));
+		assert!(sdb.is_pruned(&H256::from_low_u64_be(22), 2));
 		assert!(db.data_eq(&make_db(&[21, 3, 922, 93, 94])));
 	}
 
@@ -483,8 +482,10 @@ mod tests {
 			max_blocks: Some(2),
 			max_mem: None,
 		}));
-		assert!(sdb.is_pruned(0));
-		assert!(!sdb.is_pruned(1));
+		assert!(sdb.is_pruned(&H256::from_low_u64_be(0), 0));
+		assert!(sdb.is_pruned(&H256::from_low_u64_be(1), 1));
+		assert!(!sdb.is_pruned(&H256::from_low_u64_be(21), 2));
+		assert!(sdb.is_pruned(&H256::from_low_u64_be(22), 2));
 		assert!(db.data_eq(&make_db(&[1, 21, 3, 921, 922, 93, 94])));
 	}
 }
diff --git a/core/state-db/src/noncanonical.rs b/core/state-db/src/noncanonical.rs
index 61e720f7773c3b64aca4a6608a301b7c5fe4e23e..847b73f13ac8c7295d5e6421dcc1689a584d7fbc 100644
--- a/core/state-db/src/noncanonical.rs
+++ b/core/state-db/src/noncanonical.rs
@@ -119,10 +119,7 @@ impl<BlockHash: Hash, Key: Hash> NonCanonicalOverlay<BlockHash, Key> {
 	pub fn insert<E: fmt::Debug>(&mut self, hash: &BlockHash, number: u64, parent_hash: &BlockHash, changeset: ChangeSet<Key>) -> Result<CommitSet<Key>, Error<E>> {
 		let mut commit = CommitSet::default();
 		let front_block_number = self.pending_front_block_number();
-		if self.levels.is_empty() && self.last_canonicalized.is_none() {
-			if number < 1 {
-				return Err(Error::InvalidBlockNumber);
-			}
+		if self.levels.is_empty() && self.last_canonicalized.is_none() && number > 0 {
 			// assume that parent was canonicalized
 			let last_canonicalized = (parent_hash.clone(), number - 1);
 			commit.meta.inserted.push((to_meta_key(LAST_CANONICAL, &()), last_canonicalized.encode()));
@@ -224,8 +221,12 @@ impl<BlockHash: Hash, Key: Hash> NonCanonicalOverlay<BlockHash, Key> {
 			.unwrap_or(0)
 	}
 
-	pub fn last_canonicalized_block_number(&self) -> u64 {
-		self.last_canonicalized.as_ref().map(|&(_, n)| n).unwrap_or(0)
+	pub fn last_canonicalized_block_number(&self) -> Option<u64> {
+		match self.last_canonicalized.as_ref().map(|&(_, n)| n) {
+			Some(n) => Some(n + self.pending_canonicalizations.len() as u64),
+			None if !self.pending_canonicalizations.is_empty() => Some(self.pending_canonicalizations.len() as u64),
+			_ => None,
+		}
 	}
 
 	/// Select a top-level root and canonicalized it. Discards all sibling subtrees and the root.
@@ -278,7 +279,7 @@ impl<BlockHash: Hash, Key: Hash> NonCanonicalOverlay<BlockHash, Key> {
 			}
 		}
 		if let Some(hash) = last {
-			let last_canonicalized = (hash, self.last_canonicalized_block_number() + count);
+			let last_canonicalized = (hash, self.last_canonicalized.as_ref().map(|(_, n)| n + count).unwrap_or(count - 1));
 			self.last_canonicalized = Some(last_canonicalized);
 		}
 	}
@@ -295,6 +296,12 @@ impl<BlockHash: Hash, Key: Hash> NonCanonicalOverlay<BlockHash, Key> {
 		None
 	}
 
+	/// Check if the block is in the canonicalization queue. 
+	pub fn have_block(&self, hash: &BlockHash) -> bool {
+		(self.parents.contains_key(hash) || self.pending_insertions.contains(hash))
+			&& !self.pending_canonicalizations.contains(hash)
+	}
+
 	/// Revert a single level. Returns commit set that deletes the journal or `None` if not possible.
 	pub fn revert_one(&mut self) -> Option<CommitSet<Key>> {
 		self.levels.pop_back().map(|level| {
@@ -589,6 +596,10 @@ mod tests {
 		assert!(contains(&overlay, 121));
 		assert!(contains(&overlay, 122));
 		assert!(contains(&overlay, 123));
+		assert!(overlay.have_block(&h_1_2_1));
+		assert!(!overlay.have_block(&h_1_2));
+		assert!(!overlay.have_block(&h_1_1));
+		assert!(!overlay.have_block(&h_1_1_1));
 
 		// canonicalize 1_2_2
 		db.commit(&overlay.canonicalize::<io::Error>(&h_1_2_2).unwrap());
diff --git a/core/state-db/src/pruning.rs b/core/state-db/src/pruning.rs
index f069e18ad668de915ab2beaef59ea8fa04f71ea2..59ced33cc28040e8579114a6c07086e46e77eaff 100644
--- a/core/state-db/src/pruning.rs
+++ b/core/state-db/src/pruning.rs
@@ -130,6 +130,11 @@ impl<BlockHash: Hash, Key: Hash> RefWindow<BlockHash, Key> {
 		self.pending_number + self.pending_prunings as u64
 	}
 
+	pub fn have_block(&self, hash: &BlockHash) -> bool {
+		self.death_rows.iter().skip(self.pending_prunings).any(|r| r.hash == *hash) ||
+			self.pending_records.iter().any(|(_, record)| record.hash == *hash)
+	}
+
 	/// 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>) {
 		if let Some(pruned) = self.death_rows.get(self.pending_prunings) {
@@ -236,7 +241,9 @@ mod tests {
 		let h = H256::random();
 		pruning.note_canonical(&h, &mut commit);
 		db.commit(&commit);
+		assert!(pruning.have_block(&h));
 		pruning.apply_pending();
+		assert!(pruning.have_block(&h));
 		assert!(commit.data.deleted.is_empty());
 		assert_eq!(pruning.death_rows.len(), 1);
 		assert_eq!(pruning.death_index.len(), 2);
@@ -245,8 +252,10 @@ mod tests {
 
 		let mut commit = CommitSet::default();
 		pruning.prune_one(&mut commit);
+		assert!(!pruning.have_block(&h));
 		db.commit(&commit);
 		pruning.apply_pending();
+		assert!(!pruning.have_block(&h));
 		assert!(db.data_eq(&make_db(&[2, 4, 5])));
 		assert!(pruning.death_rows.is_empty());
 		assert!(pruning.death_index.is_empty());