From d7b79c12741f8d521f6edfa5b9dc75ce1a01a3a1 Mon Sep 17 00:00:00 2001 From: Robert Habermeier Date: Thu, 2 Jun 2016 20:34:38 +0200 Subject: [PATCH 1/8] don't return a state in state_at if the db prunes and the block is before guaranteed history --- ethcore/src/client/client.rs | 8 ++++++++ util/src/journaldb/archivedb.rs | 2 ++ util/src/journaldb/traits.rs | 3 +++ 3 files changed, 13 insertions(+) diff --git a/ethcore/src/client/client.rs b/ethcore/src/client/client.rs index 3ddf7018a..ced8c736c 100644 --- a/ethcore/src/client/client.rs +++ b/ethcore/src/client/client.rs @@ -371,6 +371,14 @@ impl Client where V: Verifier { return Some(self.state()) } + let block_number = self.block_number(id.clone()); + + // check that the block is not too old -- blocks within `HISTORY` blocks of the best will + // always be available. + if self.state_db.does_pruning() && self.best_block_number() >= block_number + HISTORY { + return None; + } + self.block_header(id).map(|header| { let db = self.state_db.lock().unwrap().boxed_clone(); State::from_existing(db, HeaderView::new(&header).state_root(), self.engine.account_start_nonce()) diff --git a/util/src/journaldb/archivedb.rs b/util/src/journaldb/archivedb.rs index b554db885..c79bab23e 100644 --- a/util/src/journaldb/archivedb.rs +++ b/util/src/journaldb/archivedb.rs @@ -175,6 +175,8 @@ impl JournalDB for ArchiveDB { fn state(&self, id: &H256) -> Option { self.backing.get_by_prefix(&id.bytes()[0..12]).and_then(|b| Some(b.to_vec())) } + + fn does_pruning(&self) -> bool { false } } #[cfg(test)] diff --git a/util/src/journaldb/traits.rs b/util/src/journaldb/traits.rs index 10212f976..d41077655 100644 --- a/util/src/journaldb/traits.rs +++ b/util/src/journaldb/traits.rs @@ -42,4 +42,7 @@ pub trait JournalDB : HashDB + Send + Sync { fn state(&self, _id: &H256) -> Option { None } + + /// Whether this database does pruning. + fn does_pruning(&self) -> bool { true } } From 6c6229c963260daf991586d3bb5df83fd01515df Mon Sep 17 00:00:00 2001 From: Robert Habermeier Date: Thu, 2 Jun 2016 20:52:21 +0200 Subject: [PATCH 2/8] check if state root is valid for old blocks --- ethcore/src/client/client.rs | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/ethcore/src/client/client.rs b/ethcore/src/client/client.rs index ced8c736c..b9348c997 100644 --- a/ethcore/src/client/client.rs +++ b/ethcore/src/client/client.rs @@ -373,15 +373,18 @@ impl Client where V: Verifier { let block_number = self.block_number(id.clone()); - // check that the block is not too old -- blocks within `HISTORY` blocks of the best will - // always be available. - if self.state_db.does_pruning() && self.best_block_number() >= block_number + HISTORY { - return None; - } + self.block_header(id).and_then(|header| { + let root = HeaderView::new(&header).state_root(); + // check that the block is not too old -- blocks within `HISTORY` blocks of the best will + // always be available. If the block could be too old, check if its state root is valid. + if self.state_db.does_pruning() + && self.best_block_number() >= block_number + HISTORY + && self.state_db.exists(root) { + return None; + } - self.block_header(id).map(|header| { let db = self.state_db.lock().unwrap().boxed_clone(); - State::from_existing(db, HeaderView::new(&header).state_root(), self.engine.account_start_nonce()) + Some(State::from_existing(db, HeaderView::new(&header).state_root(), self.engine.account_start_nonce())) }) } From 1e10445f820fa9158581beece90e1d7b7c3d6206 Mon Sep 17 00:00:00 2001 From: Robert Habermeier Date: Thu, 2 Jun 2016 21:01:47 +0200 Subject: [PATCH 3/8] exists -> contains --- ethcore/src/client/client.rs | 14 +++++++++----- util/src/trie/triedb.rs | 2 +- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/ethcore/src/client/client.rs b/ethcore/src/client/client.rs index b9348c997..9fbe8ae2d 100644 --- a/ethcore/src/client/client.rs +++ b/ethcore/src/client/client.rs @@ -371,19 +371,23 @@ impl Client where V: Verifier { return Some(self.state()) } - let block_number = self.block_number(id.clone()); + let block_number = match self.block_number(id.clone()) { + Some(num) => num, + None => return None, + }; self.block_header(id).and_then(|header| { + let db = self.state_db.lock().unwrap().boxed_clone(); + let root = HeaderView::new(&header).state_root(); // check that the block is not too old -- blocks within `HISTORY` blocks of the best will // always be available. If the block could be too old, check if its state root is valid. - if self.state_db.does_pruning() - && self.best_block_number() >= block_number + HISTORY - && self.state_db.exists(root) { + if db.does_pruning() + && self.chain.best_block_number() >= block_number + HISTORY + && !db.contains(&root) { return None; } - let db = self.state_db.lock().unwrap().boxed_clone(); Some(State::from_existing(db, HeaderView::new(&header).state_root(), self.engine.account_start_nonce())) }) } diff --git a/util/src/trie/triedb.rs b/util/src/trie/triedb.rs index 06076d273..1c6d2236b 100644 --- a/util/src/trie/triedb.rs +++ b/util/src/trie/triedb.rs @@ -59,7 +59,7 @@ impl<'db> TrieDB<'db> { /// Create a new trie with the backing database `db` and `root` /// Panics, if `root` does not exist pub fn new(db: &'db HashDB, root: &'db H256) -> Self { - if !db.exists(root) { + if !db.contains(root) { flushln!("TrieDB::new({}): Trie root not found!", root); panic!("Trie root not found!"); } From 6f850ebdacf6b7b68dac093b558a90d886e91c7e Mon Sep 17 00:00:00 2001 From: Robert Habermeier Date: Fri, 3 Jun 2016 12:10:10 +0200 Subject: [PATCH 4/8] does_pruning -> is_pruned --- ethcore/src/client/client.rs | 2 +- util/src/journaldb/archivedb.rs | 2 +- util/src/journaldb/traits.rs | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/ethcore/src/client/client.rs b/ethcore/src/client/client.rs index 9fbe8ae2d..f74fb33f5 100644 --- a/ethcore/src/client/client.rs +++ b/ethcore/src/client/client.rs @@ -382,7 +382,7 @@ impl Client where V: Verifier { let root = HeaderView::new(&header).state_root(); // check that the block is not too old -- blocks within `HISTORY` blocks of the best will // always be available. If the block could be too old, check if its state root is valid. - if db.does_pruning() + if db.is_pruned() && self.chain.best_block_number() >= block_number + HISTORY && !db.contains(&root) { return None; diff --git a/util/src/journaldb/archivedb.rs b/util/src/journaldb/archivedb.rs index c79bab23e..c6acc1280 100644 --- a/util/src/journaldb/archivedb.rs +++ b/util/src/journaldb/archivedb.rs @@ -176,7 +176,7 @@ impl JournalDB for ArchiveDB { self.backing.get_by_prefix(&id.bytes()[0..12]).and_then(|b| Some(b.to_vec())) } - fn does_pruning(&self) -> bool { false } + fn is_pruned(&self) -> bool { false } } #[cfg(test)] diff --git a/util/src/journaldb/traits.rs b/util/src/journaldb/traits.rs index d41077655..74149b062 100644 --- a/util/src/journaldb/traits.rs +++ b/util/src/journaldb/traits.rs @@ -43,6 +43,6 @@ pub trait JournalDB : HashDB + Send + Sync { None } - /// Whether this database does pruning. - fn does_pruning(&self) -> bool { true } + /// Whether this database is pruned. + fn is_pruned(&self) -> bool { true } } From aa465fa2cdbbeafa899b42ede17e879ad037d8ae Mon Sep 17 00:00:00 2001 From: Robert Habermeier Date: Fri, 3 Jun 2016 12:15:27 +0200 Subject: [PATCH 5/8] conditional style fix --- ethcore/src/client/client.rs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/ethcore/src/client/client.rs b/ethcore/src/client/client.rs index f74fb33f5..83b9e30ef 100644 --- a/ethcore/src/client/client.rs +++ b/ethcore/src/client/client.rs @@ -379,12 +379,11 @@ impl Client where V: Verifier { self.block_header(id).and_then(|header| { let db = self.state_db.lock().unwrap().boxed_clone(); - let root = HeaderView::new(&header).state_root(); // check that the block is not too old -- blocks within `HISTORY` blocks of the best will // always be available. If the block could be too old, check if its state root is valid. - if db.is_pruned() - && self.chain.best_block_number() >= block_number + HISTORY - && !db.contains(&root) { + let root = HeaderView::new(&header).state_root(); + let is_old = self.chain.best_block_number() >= block_number + HISTORY; + if db.is_pruned() && is_old && !db.contains(&root) { return None; } From e6921144dc62fc5f1b81ab7094a12221286b2779 Mon Sep 17 00:00:00 2001 From: Robert Habermeier Date: Sun, 5 Jun 2016 22:05:01 +0200 Subject: [PATCH 6/8] simplify conditional in state_at --- ethcore/src/client/client.rs | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/ethcore/src/client/client.rs b/ethcore/src/client/client.rs index 83b9e30ef..65cb13e4c 100644 --- a/ethcore/src/client/client.rs +++ b/ethcore/src/client/client.rs @@ -379,11 +379,8 @@ impl Client where V: Verifier { self.block_header(id).and_then(|header| { let db = self.state_db.lock().unwrap().boxed_clone(); - // check that the block is not too old -- blocks within `HISTORY` blocks of the best will - // always be available. If the block could be too old, check if its state root is valid. - let root = HeaderView::new(&header).state_root(); - let is_old = self.chain.best_block_number() >= block_number + HISTORY; - if db.is_pruned() && is_old && !db.contains(&root) { + // TODO [rob]: refactor State::from_existing so we avoid doing redundant lookups. + if !db.contains(&root) { return None; } From 3dff5a9f3f8825e859f807a916766bbb4357dfa4 Mon Sep 17 00:00:00 2001 From: Robert Habermeier Date: Sun, 5 Jun 2016 22:14:25 +0200 Subject: [PATCH 7/8] add early exit for pruned blocks --- ethcore/src/client/client.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/ethcore/src/client/client.rs b/ethcore/src/client/client.rs index 65cb13e4c..008ca7860 100644 --- a/ethcore/src/client/client.rs +++ b/ethcore/src/client/client.rs @@ -379,6 +379,11 @@ impl Client where V: Verifier { self.block_header(id).and_then(|header| { let db = self.state_db.lock().unwrap().boxed_clone(); + // early exit for pruned blocks + if db.is_pruned() && self.chain.best_block_number() >= block_number + HISTORY { + return None; + } + // TODO [rob]: refactor State::from_existing so we avoid doing redundant lookups. if !db.contains(&root) { return None; From 64b74eae43628784fc9d6f2ef5d3a39fa57cf25a Mon Sep 17 00:00:00 2001 From: Robert Habermeier Date: Sun, 5 Jun 2016 23:50:27 +0200 Subject: [PATCH 8/8] fix travis build --- ethcore/src/client/client.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/ethcore/src/client/client.rs b/ethcore/src/client/client.rs index 008ca7860..4e834e2f8 100644 --- a/ethcore/src/client/client.rs +++ b/ethcore/src/client/client.rs @@ -384,12 +384,14 @@ impl Client where V: Verifier { return None; } + let root = HeaderView::new(&header).state_root(); + // TODO [rob]: refactor State::from_existing so we avoid doing redundant lookups. if !db.contains(&root) { return None; } - Some(State::from_existing(db, HeaderView::new(&header).state_root(), self.engine.account_start_nonce())) + Some(State::from_existing(db, root, self.engine.account_start_nonce())) }) }