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
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
18 changes: 18 additions & 0 deletions client/api/src/backend.rs
Original file line number Diff line number Diff line change
Expand Up @@ -536,3 +536,21 @@ pub fn changes_tries_state_at_block<'a, Block: BlockT>(
None => Ok(None),
}
}

/// Provide CHT roots. These are stored on a light client and generated dynamically on a full
/// client.
pub trait ProvideChtRoots<Block: BlockT> {
/// Get headers CHT root for given block. Returns None if the block is not a part of any CHT.
fn header_cht_root(
&self,
cht_size: NumberFor<Block>,
block: NumberFor<Block>,
) -> sp_blockchain::Result<Option<Block::Hash>>;

/// Get changes trie CHT root for given block. Returns None if the block is not a part of any CHT.
fn changes_trie_cht_root(
&self,
cht_size: NumberFor<Block>,
block: NumberFor<Block>,
) -> sp_blockchain::Result<Option<Block::Hash>>;
}
4 changes: 2 additions & 2 deletions client/api/src/in_mem.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ use sp_state_machine::{
use sp_blockchain::{CachedHeaderMetadata, HeaderMetadata};

use crate::{
backend::{self, NewBlockState},
backend::{self, NewBlockState, ProvideChtRoots},
blockchain::{
self, BlockStatus, HeaderBackend, well_known_cache_keys::Id as CacheKeyId
},
Expand Down Expand Up @@ -456,7 +456,7 @@ impl<Block: BlockT> light::Storage<Block> for Blockchain<Block>
}
}

impl<Block: BlockT> light::ChtRootStorage<Block> for Blockchain<Block> {
impl<Block: BlockT> ProvideChtRoots<Block> for Blockchain<Block> {
fn header_cht_root(
&self,
_cht_size: NumberFor<Block>,
Expand Down
21 changes: 2 additions & 19 deletions client/api/src/light.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ use sp_blockchain::{
HeaderMetadata, well_known_cache_keys, HeaderBackend, Cache as BlockchainCache,
Error as ClientError, Result as ClientResult,
};
use crate::{backend::{AuxStore, NewBlockState}, UsageInfo};
use crate::{backend::{AuxStore, NewBlockState}, UsageInfo, ProvideChtRoots};

/// Remote call request.
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
Expand Down Expand Up @@ -233,7 +233,7 @@ pub trait FetchChecker<Block: BlockT>: Send + Sync {

/// Light client blockchain storage.
pub trait Storage<Block: BlockT>: AuxStore + HeaderBackend<Block>
+ HeaderMetadata<Block, Error=ClientError> + ChtRootStorage<Block>
+ HeaderMetadata<Block, Error=ClientError> + ProvideChtRoots<Block>
{
/// Store new header. Should refuse to revert any finalized blocks.
///
Expand Down Expand Up @@ -263,23 +263,6 @@ pub trait Storage<Block: BlockT>: AuxStore + HeaderBackend<Block>
fn usage_info(&self) -> Option<UsageInfo>;
}

/// Light client CHT root storage.
pub trait ChtRootStorage<Block: BlockT> {
/// Get headers CHT root for given block. Returns None if the block is not pruned (not a part of any CHT).
fn header_cht_root(
&self,
cht_size: NumberFor<Block>,
block: NumberFor<Block>,
) -> ClientResult<Option<Block::Hash>>;

/// Get changes trie CHT root for given block. Returns None if the block is not pruned (not a part of any CHT).
fn changes_trie_cht_root(
&self,
cht_size: NumberFor<Block>,
block: NumberFor<Block>,
) -> ClientResult<Option<Block::Hash>>;
}

/// Remote header.
#[derive(Debug)]
pub enum LocalOrRemote<Data, Request> {
Expand Down
91 changes: 88 additions & 3 deletions client/db/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,8 @@ use std::collections::{HashMap, HashSet};

use sc_client_api::{
UsageInfo, MemoryInfo, IoInfo, MemorySize,
backend::{NewBlockState, PrunableStateChangesTrieStorage},
leaves::{LeafSet, FinalizationDisplaced},
backend::{NewBlockState, PrunableStateChangesTrieStorage, ProvideChtRoots},
leaves::{LeafSet, FinalizationDisplaced}, cht,
};
use sp_blockchain::{
Result as ClientResult, Error as ClientError,
Expand All @@ -70,7 +70,7 @@ use sp_core::ChangesTrieConfiguration;
use sp_core::offchain::storage::{OffchainOverlayedChange, OffchainOverlayedChanges};
use sp_core::storage::{well_known_keys, ChildInfo};
use sp_arithmetic::traits::Saturating;
use sp_runtime::{generic::BlockId, Justification, Storage};
use sp_runtime::{generic::{DigestItem, BlockId}, Justification, Storage};
use sp_runtime::traits::{
Block as BlockT, Header as HeaderT, NumberFor, Zero, One, SaturatedConversion, HashFor,
};
Expand Down Expand Up @@ -405,6 +405,14 @@ impl<Block: BlockT> BlockchainDb<Block> {
meta.finalized_hash = hash;
}
}

// Get block changes trie root, if available.
fn changes_trie_root(&self, block: BlockId<Block>) -> ClientResult<Option<Block::Hash>> {
self.header(block)
.map(|header| header.and_then(|header|
header.digest().log(DigestItem::as_changes_trie_root)
.cloned()))
}
}

impl<Block: BlockT> sc_client_api::blockchain::HeaderBackend<Block> for BlockchainDb<Block> {
Expand Down Expand Up @@ -525,6 +533,58 @@ impl<Block: BlockT> HeaderMetadata<Block> for BlockchainDb<Block> {
}
}

impl<Block: BlockT> ProvideChtRoots<Block> for BlockchainDb<Block> {
fn header_cht_root(
&self,
cht_size: NumberFor<Block>,
block: NumberFor<Block>,
) -> sp_blockchain::Result<Option<Block::Hash>> {
let cht_number = match cht::block_to_cht_number(cht_size, block) {
Some(number) => number,
None => return Ok(None),
};

let cht_start: NumberFor<Block> = cht::start_number(cht::size(), cht_number);

let mut current_num = cht_start;
let cht_range = ::std::iter::from_fn(|| {
let old_current_num = current_num;
current_num = current_num + One::one();
Some(old_current_num)
});

cht::compute_root::<Block::Header, HashFor<Block>, _>(
cht::size(), cht_number, cht_range.map(|num| self.hash(num))
).map(Some)
}

fn changes_trie_cht_root(
&self,
cht_size: NumberFor<Block>,
block: NumberFor<Block>,
) -> sp_blockchain::Result<Option<Block::Hash>> {
let cht_number = match cht::block_to_cht_number(cht_size, block) {
Some(number) => number,
None => return Ok(None),
};

let cht_start: NumberFor<Block> = cht::start_number(cht::size(), cht_number);

let mut current_num = cht_start;
let cht_range = ::std::iter::from_fn(|| {
let old_current_num = current_num;
current_num = current_num + One::one();
Some(old_current_num)
});

cht::compute_root::<Block::Header, HashFor<Block>, _>(
cht::size(),
cht_number,
cht_range.map(|num| self.changes_trie_root(BlockId::Number(num))),
).map(Some)
}
}

/// Database transaction
pub struct BlockImportOperation<Block: BlockT> {
old_state: SyncingCachingState<RefTrackingState<Block>, Block>,
Expand Down Expand Up @@ -2329,4 +2389,29 @@ pub(crate) mod tests {
backend.commit_operation(op).unwrap_err();
}
}

#[test]
fn header_cht_root_works() {
use sc_client_api::ProvideChtRoots;

let backend = Backend::<Block>::new_test(10, 10);

// insert 1 + SIZE + SIZE + 1 blocks so that CHT#0 is created
let mut prev_hash = insert_header(&backend, 0, Default::default(), None, Default::default());
let cht_size: u64 = cht::size();
for i in 1..1 + cht_size + cht_size + 1 {
prev_hash = insert_header(&backend, i, prev_hash, None, Default::default());
}

let blockchain = backend.blockchain();

let cht_root_1 = blockchain.header_cht_root(cht_size, cht::start_number(cht_size, 0))
.unwrap().unwrap();
let cht_root_2 = blockchain.header_cht_root(cht_size, cht::start_number(cht_size, 0) + cht_size / 2)
.unwrap().unwrap();
let cht_root_3 = blockchain.header_cht_root(cht_size, cht::end_number(cht_size, 0))
.unwrap().unwrap();
assert_eq!(cht_root_1, cht_root_2);
assert_eq!(cht_root_2, cht_root_3);
}
}
6 changes: 3 additions & 3 deletions client/db/src/light.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,11 @@ use std::convert::TryInto;
use parking_lot::RwLock;

use sc_client_api::{
cht, backend::{AuxStore, NewBlockState}, UsageInfo,
cht, backend::{AuxStore, NewBlockState, ProvideChtRoots}, UsageInfo,
blockchain::{
BlockStatus, Cache as BlockchainCache, Info as BlockchainInfo,
},
Storage, ChtRootStorage,
Storage,
};
use sp_blockchain::{
CachedHeaderMetadata, HeaderMetadata, HeaderMetadataCache,
Expand Down Expand Up @@ -596,7 +596,7 @@ impl<Block> Storage<Block> for LightStorage<Block>
}
}

impl<Block> ChtRootStorage<Block> for LightStorage<Block>
impl<Block> ProvideChtRoots<Block> for LightStorage<Block>
where Block: BlockT,
{
fn header_cht_root(
Expand Down
20 changes: 19 additions & 1 deletion client/light/src/blockchain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ use sp_blockchain::{
};
pub use sc_client_api::{
backend::{
AuxStore, NewBlockState
AuxStore, NewBlockState, ProvideChtRoots,
},
blockchain::{
Backend as BlockchainBackend, BlockStatus, Cache as BlockchainCache,
Expand Down Expand Up @@ -173,3 +173,21 @@ impl<S, Block: BlockT> RemoteBlockchain<Block> for Blockchain<S>
}))
}
}

impl<S: Storage<Block>, Block: BlockT> ProvideChtRoots<Block> for Blockchain<S> {
fn header_cht_root(
&self,
cht_size: NumberFor<Block>,
block: NumberFor<Block>,
) -> sp_blockchain::Result<Option<Block::Hash>> {
self.storage().header_cht_root(cht_size, block)
}

fn changes_trie_cht_root(
&self,
cht_size: NumberFor<Block>,
block: NumberFor<Block>,
) -> sp_blockchain::Result<Option<Block::Hash>> {
self.storage().changes_trie_cht_root(cht_size, block)
}
}
31 changes: 5 additions & 26 deletions client/service/src/chain_ops/build_spec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,31 +16,9 @@

use sp_runtime::traits::{Block as BlockT, NumberFor, Saturating, One};
use sp_blockchain::HeaderBackend;
use crate::{TFullBackend, TLightBackend};
use std::sync::Arc;
use sp_runtime::generic::BlockId;

/// An error for if this function is being called on a full node.
pub const CHT_ROOT_ERROR: &str =
"Backend doesn't store CHT roots. Make sure you're calling this on a light client.";

/// Something that might allow access to a `ChtRootStorage`.
pub trait MaybeChtRootStorageProvider<Block> {
/// Potentially get a reference to a `ChtRootStorage`.
fn cht_root_storage(&self) -> Option<&dyn sc_client_api::light::ChtRootStorage<Block>>;
}

impl<Block: BlockT> MaybeChtRootStorageProvider<Block> for TFullBackend<Block> {
fn cht_root_storage(&self) -> Option<&dyn sc_client_api::light::ChtRootStorage<Block>> {
None
}
}

impl<Block: BlockT> MaybeChtRootStorageProvider<Block> for TLightBackend<Block> {
fn cht_root_storage(&self) -> Option<&dyn sc_client_api::light::ChtRootStorage<Block>> {
Some(self.blockchain().storage())
}
}
use sc_client_api::ProvideChtRoots;

/// Build a `LightSyncState` from the CHT roots stored in a backend.
pub fn build_light_sync_state<TBl, TCl, TBackend>(
Expand All @@ -50,9 +28,10 @@ pub fn build_light_sync_state<TBl, TCl, TBackend>(
where
TBl: BlockT,
TCl: HeaderBackend<TBl>,
TBackend: MaybeChtRootStorageProvider<TBl>,
TBackend: sc_client_api::Backend<TBl>,
<TBackend as sc_client_api::Backend<TBl>>::Blockchain: ProvideChtRoots<TBl>,
{
let storage = backend.cht_root_storage().ok_or(CHT_ROOT_ERROR)?;
let cht_root_provider = backend.blockchain();

let finalized_hash = client.info().finalized_hash;
let finalized_number = client.info().finalized_number;
Expand All @@ -67,7 +46,7 @@ pub fn build_light_sync_state<TBl, TCl, TBackend>(
let mut number = NumberFor::<TBl>::one();

while number <= finalized_number.saturating_sub(cht_size_x_2) {
match storage.header_cht_root(cht::size(), number)? {
match cht_root_provider.header_cht_root(cht::size(), number)? {
Some(cht_root) => chts.push(cht_root),
None => log::error!("No CHT found for block {}", number),
}
Expand Down
4 changes: 2 additions & 2 deletions client/service/test/src/client/light.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ use sc_executor::{NativeExecutor, WasmExecutionMethod, RuntimeVersion, NativeVer
use sp_core::{H256, NativeOrEncoded, testing::TaskExecutor};
use sc_client_api::{
blockchain::Info, backend::NewBlockState, Backend as ClientBackend, ProofProvider,
in_mem::{Backend as InMemBackend, Blockchain as InMemoryBlockchain}, ChtRootStorage,
in_mem::{Backend as InMemBackend, Blockchain as InMemoryBlockchain}, ProvideChtRoots,
AuxStore, Storage, CallExecutor, cht, ExecutionStrategy, StorageProof, BlockImportOperation,
RemoteCallRequest, StorageProvider, ChangesProof, RemoteBodyRequest, RemoteReadRequest,
RemoteChangesRequest, FetchChecker, RemoteReadChildRequest, RemoteHeaderRequest, BlockBackend,
Expand Down Expand Up @@ -173,7 +173,7 @@ impl Storage<Block> for DummyStorage {
}
}

impl ChtRootStorage<Block> for DummyStorage {
impl ProvideChtRoots<Block> for DummyStorage {
fn header_cht_root(&self, _cht_size: u64, _block: u64) -> ClientResult<Option<Hash>> {
Err(ClientError::Backend("Test error".into()))
}
Expand Down