Skip to content
This repository was archived by the owner on Nov 15, 2023. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
58 commits
Select commit Hold shift + click to select a range
9d58b46
GrandpaLightBlockImport
svyatonik Jan 28, 2019
0b3443b
extract authorities in AuraVerifier
svyatonik Jan 28, 2019
31b183d
Merge branch 'master' into light_grandpa_importer2
svyatonik Jan 29, 2019
da6c11e
post-merge fix
svyatonik Jan 29, 2019
2d8a084
Merge branch 'master' into light_grandpa_importer2
svyatonik Feb 1, 2019
d42315b
restore authorities cache
svyatonik Feb 1, 2019
4cbefb6
license
svyatonik Feb 4, 2019
5344c61
new finality proof draft
svyatonik Feb 8, 2019
c3a8125
generalized PendingJustifications
svyatonik Feb 8, 2019
2c4ae73
finality proof messages
svyatonik Feb 11, 2019
fbf49c6
fixed compilation
svyatonik Feb 11, 2019
ac72a40
pass verifier to import_finality_proof
svyatonik Feb 11, 2019
d4becc1
do not fetch remote proof from light import directly
svyatonik Feb 11, 2019
41c4376
FinalityProofProvider
svyatonik Feb 12, 2019
41a1dba
fixed authorities cache test
svyatonik Feb 12, 2019
2c02eff
restored finality proof tests
svyatonik Feb 12, 2019
527596d
finality_proof docs
svyatonik Feb 12, 2019
7c4c71f
Merge branch 'master' into light_grandpa_importer2
svyatonik Feb 13, 2019
f94d5be
use DB backend in test client
svyatonik Feb 13, 2019
ac63880
justification_is_fetched_by_light_client_when_consensus_data_changes
svyatonik Feb 15, 2019
410d02c
Merge branch 'master' into light_grandpa_importer2
svyatonik Mar 7, 2019
8577c87
restore justification_is_fetched_by_light_client_when_consensus_data_…
svyatonik Mar 7, 2019
8a3ba3d
some more tests
svyatonik Mar 11, 2019
b362518
added authorities-related TODO
svyatonik Mar 11, 2019
4c69880
removed unneeded clear_finality_proof_requests field
svyatonik Mar 11, 2019
0db08a0
truncated some long lines
svyatonik Mar 11, 2019
1315130
more granular light import tests
svyatonik Mar 12, 2019
9e5aabe
only provide finality proof if it is generated by the requested set
svyatonik Mar 14, 2019
a746448
Merge branch 'master' into light_grandpa_importer2
svyatonik Mar 14, 2019
f22ebf1
post-merge fix
svyatonik Mar 14, 2019
c6c128b
finality_proof_is_none_if_first_justification_is_generated_by_unknown…
svyatonik Mar 14, 2019
188ab5a
make light+grandpa test rely on finality proofs (instead of simple ju…
svyatonik Mar 15, 2019
6d3ba01
empty_finality_proof_is_returned_to_light_client_when_authority_set_i…
svyatonik Mar 15, 2019
b99f39d
missing trait method impl
svyatonik Mar 19, 2019
5516ece
Merge branch 'master' into light_grandpa_importer2
svyatonik Mar 19, 2019
d6f01fa
fixed proof-of-finality docs
svyatonik Mar 20, 2019
957139f
one more doc fix
svyatonik Mar 20, 2019
262cdfa
fix docs
svyatonik Mar 20, 2019
7e6e837
Merge branch 'master' into light_grandpa_importer2
svyatonik Mar 22, 2019
271655d
Merge branch 'master' into light_grandpa_importer2
svyatonik Apr 1, 2019
63cde59
initialize authorities cache (post-merge fix)
svyatonik Apr 2, 2019
b8c71b5
fixed cache initialization (post-merge fix)
svyatonik Apr 16, 2019
63b5056
Merge branch 'master' into light_grandpa_importer2
svyatonik Apr 16, 2019
100f4c8
post-fix merge: fix light + GRANDPA tests (bad way)
svyatonik Apr 16, 2019
44d7714
proper fix of empty_finality_proof_is_returned_to_light_client_when_a…
svyatonik Apr 16, 2019
70c8b39
fixed easy grumbles
svyatonik Apr 18, 2019
ff3ceeb
import finality proofs in BlockImportWorker thread
svyatonik Apr 18, 2019
e108f63
allow import of finality proofs for non-requested blocks
svyatonik Apr 18, 2019
e2b5458
limit number of fragments in finality proof
svyatonik Apr 18, 2019
366cb2e
Merge branch 'master' into light_grandpa_importer2
svyatonik Apr 18, 2019
bf1706b
Merge branch 'master' into light_grandpa_importer2
svyatonik Apr 30, 2019
0a5513f
Merge branch 'master' into light_grandpa_importer2
svyatonik May 3, 2019
33d195c
GRANDPA post-merge fix
svyatonik May 3, 2019
d6cbbf3
BABE: pos-merge fix
svyatonik May 3, 2019
b7f2dbc
Merge branch 'master' into light_grandpa_importer2
svyatonik May 7, 2019
d42e730
Merge branch 'master' into light_grandpa_importer2
svyatonik May 10, 2019
fa0e328
Merge branch 'master' into light_grandpa_importer2
svyatonik May 10, 2019
6c80a6e
Merge branch 'master' into light_grandpa_importer2
svyatonik May 13, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 32 additions & 16 deletions core/client/db/src/cache/list_cache.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ use log::warn;
use client::error::{Error as ClientError, Result as ClientResult};
use runtime_primitives::traits::{Block as BlockT, NumberFor, As, Zero};

use crate::cache::{CacheItemT, ComplexBlockId};
use crate::cache::{CacheItemT, ComplexBlockId, EntryType};
use crate::cache::list_entry::{Entry, StorageEntry};
use crate::cache::list_storage::{Storage, StorageTransaction, Metadata};

Expand Down Expand Up @@ -174,17 +174,18 @@ impl<Block: BlockT, T: CacheItemT, S: Storage<Block, T>> ListCache<Block, T, S>
parent: ComplexBlockId<Block>,
block: ComplexBlockId<Block>,
value: Option<T>,
is_final: bool,
entry_type: EntryType,
) -> ClientResult<Option<CommitOperation<Block, T>>> {
// this guarantee is currently provided by LightStorage && we're relying on it here
debug_assert!(!is_final || self.best_finalized_block.hash == parent.hash);
debug_assert!(entry_type != EntryType::Final || self.best_finalized_block.hash == parent.hash);

// we do not store any values behind finalized
if block.number != Zero::zero() && self.best_finalized_block.number >= block.number {
return Ok(None);
}

// if the block is not final, it is possibly appended to/forking from existing unfinalized fork
let is_final = entry_type == EntryType::Final || entry_type == EntryType::Genesis;
if !is_final {
let mut fork_and_action = None;

Expand Down Expand Up @@ -831,12 +832,27 @@ pub mod tests {

#[test]
fn list_on_block_insert_works() {
let nfin = EntryType::NonFinal;
let fin = EntryType::Final;

// when trying to insert block < finalized number
assert!(ListCache::new(DummyStorage::new(), 1024, test_id(100))
.on_block_insert(&mut DummyTransaction::new(), test_id(49), test_id(50), Some(50), false).unwrap().is_none());
.on_block_insert(
&mut DummyTransaction::new(),
test_id(49),
test_id(50),
Some(50),
nfin,
).unwrap().is_none());
// when trying to insert block @ finalized number
assert!(ListCache::new(DummyStorage::new(), 1024, test_id(100))
.on_block_insert(&mut DummyTransaction::new(), test_id(99), test_id(100), Some(100), false).unwrap().is_none());
.on_block_insert(
&mut DummyTransaction::new(),
test_id(99),
test_id(100),
Some(100),
nfin,
).unwrap().is_none());

// when trying to insert non-final block AND it appends to the best block of unfinalized fork
// AND new value is the same as in the fork' best block
Expand All @@ -848,15 +864,15 @@ pub mod tests {
);
cache.unfinalized[0].best_block = Some(test_id(4));
let mut tx = DummyTransaction::new();
assert_eq!(cache.on_block_insert(&mut tx, test_id(4), test_id(5), Some(4), false).unwrap(),
assert_eq!(cache.on_block_insert(&mut tx, test_id(4), test_id(5), Some(4), nfin).unwrap(),
Some(CommitOperation::AppendNewBlock(0, test_id(5))));
assert!(tx.inserted_entries().is_empty());
assert!(tx.removed_entries().is_empty());
assert!(tx.updated_meta().is_none());
// when trying to insert non-final block AND it appends to the best block of unfinalized fork
// AND new value is the same as in the fork' best block
let mut tx = DummyTransaction::new();
assert_eq!(cache.on_block_insert(&mut tx, test_id(4), test_id(5), Some(5), false).unwrap(),
assert_eq!(cache.on_block_insert(&mut tx, test_id(4), test_id(5), Some(5), nfin).unwrap(),
Some(CommitOperation::AppendNewEntry(0, Entry { valid_from: test_id(5), value: Some(5) })));
assert_eq!(*tx.inserted_entries(), vec![test_id(5).hash].into_iter().collect());
assert!(tx.removed_entries().is_empty());
Expand All @@ -872,15 +888,15 @@ pub mod tests {
1024, test_id(2)
);
let mut tx = DummyTransaction::new();
assert_eq!(cache.on_block_insert(&mut tx, correct_id(4), correct_id(5), Some(4), false).unwrap(),
assert_eq!(cache.on_block_insert(&mut tx, correct_id(4), correct_id(5), Some(4), nfin).unwrap(),
Some(CommitOperation::AppendNewBlock(0, correct_id(5))));
assert!(tx.inserted_entries().is_empty());
assert!(tx.removed_entries().is_empty());
assert!(tx.updated_meta().is_none());
// when trying to insert non-final block AND it is the first block that appends to the best block of unfinalized fork
// AND new value is the same as in the fork' best block
let mut tx = DummyTransaction::new();
assert_eq!(cache.on_block_insert(&mut tx, correct_id(4), correct_id(5), Some(5), false).unwrap(),
assert_eq!(cache.on_block_insert(&mut tx, correct_id(4), correct_id(5), Some(5), nfin).unwrap(),
Some(CommitOperation::AppendNewEntry(0, Entry { valid_from: correct_id(5), value: Some(5) })));
assert_eq!(*tx.inserted_entries(), vec![correct_id(5).hash].into_iter().collect());
assert!(tx.removed_entries().is_empty());
Expand All @@ -898,7 +914,7 @@ pub mod tests {
1024, correct_id(2)
);
let mut tx = DummyTransaction::new();
assert_eq!(cache.on_block_insert(&mut tx, correct_id(3), fork_id(0, 3, 4), Some(14), false).unwrap(),
assert_eq!(cache.on_block_insert(&mut tx, correct_id(3), fork_id(0, 3, 4), Some(14), nfin).unwrap(),
Some(CommitOperation::AddNewFork(Entry { valid_from: fork_id(0, 3, 4), value: Some(14) })));
assert_eq!(*tx.inserted_entries(), vec![fork_id(0, 3, 4).hash].into_iter().collect());
assert!(tx.removed_entries().is_empty());
Expand All @@ -913,7 +929,7 @@ pub mod tests {
1024, correct_id(2)
);
let mut tx = DummyTransaction::new();
assert_eq!(cache.on_block_insert(&mut tx, correct_id(2), correct_id(3), Some(2), false).unwrap(), None);
assert_eq!(cache.on_block_insert(&mut tx, correct_id(2), correct_id(3), Some(2), nfin).unwrap(), None);
assert!(tx.inserted_entries().is_empty());
assert!(tx.removed_entries().is_empty());
assert!(tx.updated_meta().is_none());
Expand All @@ -926,7 +942,7 @@ pub mod tests {
1024, correct_id(2)
);
let mut tx = DummyTransaction::new();
assert_eq!(cache.on_block_insert(&mut tx, correct_id(2), correct_id(3), Some(3), false).unwrap(),
assert_eq!(cache.on_block_insert(&mut tx, correct_id(2), correct_id(3), Some(3), nfin).unwrap(),
Some(CommitOperation::AddNewFork(Entry { valid_from: correct_id(3), value: Some(3) })));
assert_eq!(*tx.inserted_entries(), vec![correct_id(3).hash].into_iter().collect());
assert!(tx.removed_entries().is_empty());
Expand All @@ -935,7 +951,7 @@ pub mod tests {
// when inserting finalized entry AND there are no previous finalized entries
let cache = ListCache::new(DummyStorage::new(), 1024, correct_id(2));
let mut tx = DummyTransaction::new();
assert_eq!(cache.on_block_insert(&mut tx, correct_id(2), correct_id(3), Some(3), true).unwrap(),
assert_eq!(cache.on_block_insert(&mut tx, correct_id(2), correct_id(3), Some(3), fin).unwrap(),
Some(CommitOperation::BlockFinalized(correct_id(3), Some(Entry { valid_from: correct_id(3), value: Some(3) }), Default::default())));
assert_eq!(*tx.inserted_entries(), vec![correct_id(3).hash].into_iter().collect());
assert!(tx.removed_entries().is_empty());
Expand All @@ -948,14 +964,14 @@ pub mod tests {
1024, correct_id(2)
);
let mut tx = DummyTransaction::new();
assert_eq!(cache.on_block_insert(&mut tx, correct_id(2), correct_id(3), Some(2), true).unwrap(),
assert_eq!(cache.on_block_insert(&mut tx, correct_id(2), correct_id(3), Some(2), fin).unwrap(),
Some(CommitOperation::BlockFinalized(correct_id(3), None, Default::default())));
assert!(tx.inserted_entries().is_empty());
assert!(tx.removed_entries().is_empty());
assert!(tx.updated_meta().is_none());
// when inserting finalized entry AND value differs from previous finalized
let mut tx = DummyTransaction::new();
assert_eq!(cache.on_block_insert(&mut tx, correct_id(2), correct_id(3), Some(3), true).unwrap(),
assert_eq!(cache.on_block_insert(&mut tx, correct_id(2), correct_id(3), Some(3), fin).unwrap(),
Some(CommitOperation::BlockFinalized(correct_id(3), Some(Entry { valid_from: correct_id(3), value: Some(3) }), Default::default())));
assert_eq!(*tx.inserted_entries(), vec![correct_id(3).hash].into_iter().collect());
assert!(tx.removed_entries().is_empty());
Expand All @@ -970,7 +986,7 @@ pub mod tests {
1024, correct_id(2)
);
let mut tx = DummyTransaction::new();
assert_eq!(cache.on_block_insert(&mut tx, correct_id(2), correct_id(3), Some(2), true).unwrap(),
assert_eq!(cache.on_block_insert(&mut tx, correct_id(2), correct_id(3), Some(2), fin).unwrap(),
Some(CommitOperation::BlockFinalized(correct_id(3), None, vec![0].into_iter().collect())));
}

Expand Down
52 changes: 46 additions & 6 deletions core/client/db/src/cache/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,9 @@ use client::blockchain::Cache as BlockchainCache;
use client::error::Result as ClientResult;
use parity_codec::{Encode, Decode};
use runtime_primitives::generic::BlockId;
use runtime_primitives::traits::{Block as BlockT, Header as HeaderT, NumberFor, As};
use runtime_primitives::traits::{Block as BlockT, Header as HeaderT, NumberFor, As, Zero};
use consensus_common::well_known_cache_keys::Id as CacheKeyId;
use crate::utils::{self, COLUMN_META};
use crate::utils::{self, COLUMN_META, db_err};

use self::list_cache::ListCache;

Expand All @@ -38,6 +38,17 @@ mod list_storage;
/// Minimal post-finalization age age of finalized blocks before they'll pruned.
const PRUNE_DEPTH: u64 = 1024;

/// The type of entry that is inserted to the cache.
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum EntryType {
/// Non-final entry.
NonFinal,
/// Final entry.
Final,
/// Genesis entry (inserted during cache initialization).
Genesis,
}

/// Block identifier that holds both hash and number.
#[derive(Clone, Debug, Encode, Decode, PartialEq)]
pub struct ComplexBlockId<Block: BlockT> {
Expand Down Expand Up @@ -70,6 +81,7 @@ pub struct DbCache<Block: BlockT> {
key_lookup_column: Option<u32>,
header_column: Option<u32>,
authorities_column: Option<u32>,
genesis_hash: Block::Hash,
best_finalized_block: ComplexBlockId<Block>,
}

Expand All @@ -80,6 +92,7 @@ impl<Block: BlockT> DbCache<Block> {
key_lookup_column: Option<u32>,
header_column: Option<u32>,
authorities_column: Option<u32>,
genesis_hash: Block::Hash,
best_finalized_block: ComplexBlockId<Block>,
) -> Self {
Self {
Expand All @@ -88,10 +101,16 @@ impl<Block: BlockT> DbCache<Block> {
key_lookup_column,
header_column,
authorities_column,
genesis_hash,
best_finalized_block,
}
}

/// Set genesis block hash.
pub fn set_genesis_hash(&mut self, genesis_hash: Block::Hash) {
self.genesis_hash = genesis_hash;
}

/// Begin cache transaction.
pub fn transaction<'a>(&'a mut self, tx: &'a mut DBTransaction) -> DbCacheTransaction<'a, Block> {
DbCacheTransaction {
Expand Down Expand Up @@ -182,7 +201,7 @@ impl<'a, Block: BlockT> DbCacheTransaction<'a, Block> {
parent: ComplexBlockId<Block>,
block: ComplexBlockId<Block>,
data_at: HashMap<CacheKeyId, Vec<u8>>,
is_final: bool,
entry_type: EntryType,
) -> ClientResult<Self> {
assert!(self.cache_at_op.is_empty());

Expand All @@ -203,7 +222,7 @@ impl<'a, Block: BlockT> DbCacheTransaction<'a, Block> {
parent.clone(),
block.clone(),
value.or(cache.value_at_block(&parent)?),
is_final,
entry_type,
)?;
if let Some(op) = op {
self.cache_at_op.insert(name, op);
Expand All @@ -214,8 +233,10 @@ impl<'a, Block: BlockT> DbCacheTransaction<'a, Block> {
data_at.into_iter().try_for_each(|(name, data)| insert_op(name, Some(data)))?;
missed_caches.into_iter().try_for_each(|name| insert_op(name, None))?;

if is_final {
self.best_finalized_block = Some(block);
match entry_type {
EntryType::Final | EntryType::Genesis =>
self.best_finalized_block = Some(block),
EntryType::NonFinal => (),
}

Ok(self)
Expand Down Expand Up @@ -254,6 +275,25 @@ impl<'a, Block: BlockT> DbCacheTransaction<'a, Block> {
pub struct DbCacheSync<Block: BlockT>(pub RwLock<DbCache<Block>>);

impl<Block: BlockT> BlockchainCache<Block> for DbCacheSync<Block> {
fn initialize(&self, key: &CacheKeyId, data: Vec<u8>) -> ClientResult<()> {
let mut cache = self.0.write();
let genesis_hash = cache.genesis_hash;
let cache_contents = vec![(*key, data)].into_iter().collect();
let db = cache.db.clone();
let mut dbtx = DBTransaction::new();
let tx = cache.transaction(&mut dbtx);
let tx = tx.on_block_insert(
ComplexBlockId::new(Default::default(), Zero::zero()),
ComplexBlockId::new(genesis_hash, Zero::zero()),
cache_contents,
EntryType::Genesis,
)?;
let tx_ops = tx.into_ops();
db.write(dbtx).map_err(db_err)?;
cache.commit(tx_ops);
Ok(())
}

fn get_at(&self, key: &CacheKeyId, at: &BlockId<Block>) -> Option<Vec<u8>> {
let cache = self.0.read();
let storage = cache.cache_at.get(key)?.storage();
Expand Down
26 changes: 24 additions & 2 deletions core/client/db/src/light.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ use runtime_primitives::generic::BlockId;
use runtime_primitives::traits::{Block as BlockT, Header as HeaderT,
Zero, One, As, NumberFor, Digest, DigestItem};
use consensus_common::well_known_cache_keys;
use crate::cache::{DbCacheSync, DbCache, ComplexBlockId};
use crate::cache::{DbCacheSync, DbCache, ComplexBlockId, EntryType as CacheEntryType};
use crate::utils::{self, meta_keys, Meta, db_err, open_database,
read_db, block_id_to_lookup_key, read_meta};
use crate::DatabaseSettings;
Expand Down Expand Up @@ -91,6 +91,7 @@ impl<Block> LightStorage<Block>
columns::KEY_LOOKUP,
columns::HEADER,
columns::CACHE,
meta.genesis_hash,
ComplexBlockId::new(meta.finalized_hash, meta.finalized_number),
);

Expand Down Expand Up @@ -406,6 +407,7 @@ impl<Block> LightBlockchainStorage<Block> for LightStorage<Block>

let is_genesis = number.is_zero();
if is_genesis {
self.cache.0.write().set_genesis_hash(hash);
transaction.put(columns::META, meta_keys::GENESIS_HASH, hash.as_ref());
}

Expand Down Expand Up @@ -434,7 +436,7 @@ impl<Block> LightBlockchainStorage<Block> for LightStorage<Block>
ComplexBlockId::new(*header.parent_hash(), if number.is_zero() { Zero::zero() } else { number - One::one() }),
ComplexBlockId::new(hash, number),
cache_at,
finalized,
if finalized { CacheEntryType::Final } else { CacheEntryType::NonFinal },
)?
.into_ops();

Expand Down Expand Up @@ -1040,4 +1042,24 @@ pub(crate) mod tests {
// leaves at same height stay. Leaves at lower heights pruned.
assert_eq!(db.leaves.read().hashes(), vec![block2_a, block2_b, block2_c]);
}

#[test]
fn cache_can_be_initialized_after_genesis_inserted() {
let db = LightStorage::<Block>::new_test();

// before cache is initialized => None
assert_eq!(db.cache().get_at(b"test", &BlockId::Number(0)), None);

// insert genesis block (no value for cache is provided)
insert_block(&db, HashMap::new(), || default_header(&Default::default(), 0));

// after genesis is inserted => None
assert_eq!(db.cache().get_at(b"test", &BlockId::Number(0)), None);

// initialize cache
db.cache().initialize(b"test", vec![42]).unwrap();

// after genesis is inserted + cache is initialized => Some
assert_eq!(db.cache().get_at(b"test", &BlockId::Number(0)), Some(vec![42]));
}
}
5 changes: 5 additions & 0 deletions core/client/src/blockchain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,11 @@ pub trait ProvideCache<Block: BlockT> {

/// Blockchain optional data cache.
pub trait Cache<Block: BlockT>: Send + Sync {
/// Initialize genesis value for the given cache.
///
/// The operation should be performed once before anything else is inserted in the cache.
/// Otherwise cache may end up in inconsistent state.
fn initialize(&self, key: &well_known_cache_keys::Id, value_at_genesis: Vec<u8>) -> Result<()>;
/// Returns cached value by the given key.
fn get_at(&self, key: &well_known_cache_keys::Id, block: &BlockId<Block>) -> Option<Vec<u8>>;
}
Expand Down
5 changes: 4 additions & 1 deletion core/client/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,10 @@ pub enum Error {
/// Genesis config is invalid.
#[display(fmt = "Genesis config provided is invalid")]
GenesisInvalid,
/// Bad justification for header.
/// Error decoding header justification.
#[display(fmt = "error decoding justification for header")]
JustificationDecode,
/// Justification for header is correctly encoded, but invalid.
#[display(fmt = "bad justification for header: {}", _0)]
BadJustification(String),
/// Not available on light client.
Expand Down
2 changes: 1 addition & 1 deletion core/client/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ pub use crate::client::{
#[cfg(feature = "std")]
pub use crate::notifications::{StorageEventStream, StorageChangeSet};
#[cfg(feature = "std")]
pub use state_machine::ExecutionStrategy;
pub use state_machine::{ExecutionStrategy, NeverOffchainExt};
#[cfg(feature = "std")]
pub use crate::leaves::LeafSet;

Expand Down
Loading