Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: ✨ Implement Forest root changes catch up in Blockchain Service #312

Draft
wants to merge 19 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
7e501b6
fix: :rotating_light: Remove error rust analyzer was complaining abou…
ffarall Jan 3, 2025
f5267b5
chore: :see_no_evil: Gitignore cSpell config file
ffarall Jan 6, 2025
af7b41b
feat: :construction: Emit events of mutations applied always
ffarall Jan 6, 2025
02880e6
feat: :construction: Half way implementing apply forest root changes
ffarall Jan 7, 2025
f3644e7
Merge branch 'main' into feat/forest-root-cath-ups-impl
ffarall Jan 9, 2025
67e175b
chore: :see_no_evil: Typo in cSpell gitignore
ffarall Jan 9, 2025
60048fc
fix: :rotating_light: Fix event fields after merge
ffarall Jan 9, 2025
bdedae5
feat: :construction: Implement applying `TrieMutation`s in reverse
ffarall Jan 9, 2025
1190017
feat: :construction: Implement forest root catch ups for BSPs
ffarall Jan 10, 2025
61ab757
chore: :label: Run `pnpm typegen`
ffarall Jan 10, 2025
4e1d9a2
fix: :white_check_mark: Use new `MutationsAppliedForProvider` event i…
ffarall Jan 10, 2025
c2db1de
fix: :bug: Create tree route with old and new best block in regular n…
ffarall Jan 10, 2025
1d038d0
feat: :loud_sound: Improve logs for apply forest root changes
ffarall Jan 10, 2025
3034eab
feat: :fire: Remove now unused code of applying forest root changes i…
ffarall Jan 10, 2025
3b52ab0
feat: :fire: Remove forest root changing from `bsp_charge_fees` and `…
ffarall Jan 10, 2025
c24fa3c
fix: :white_check_mark: Wait for new log from blockchain service to c…
ffarall Jan 10, 2025
891672c
fix: :white_check_mark: Fix race condition in onboarding by using `wa…
ffarall Jan 10, 2025
ab108f0
test: :white_check_mark: Cleanup reorgs test
ffarall Jan 10, 2025
57c1cde
style: :art: Apply cargo format
ffarall Jan 11, 2025
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
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -33,4 +33,4 @@ res/benchmarking
test/dist/*

# Ignore cSpell config files
cSpell.json
cspell.json
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 7 additions & 1 deletion api-augment/dist/interfaces/lookup.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion api-augment/dist/interfaces/lookup.js.map

Large diffs are not rendered by default.

27 changes: 24 additions & 3 deletions api-augment/dist/types/interfaces/augment-api-events.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2071,14 +2071,35 @@ declare module "@polkadot/api-base/types/events" {
}
>;
/**
* A set of mutations has been applied to the Forest.
* A set of mutations has been applied to a given Forest.
* This is the generic version of [`MutationsAppliedForProvider`](Event::MutationsAppliedForProvider)
* when [`generic_apply_delta`](ProofsDealerInterface::generic_apply_delta) is used
* and the root is not necessarily linked to a specific Provider.
**/
MutationsApplied: AugmentedEvent<
ApiType,
[provider: H256, mutations: Vec<ITuple<[H256, ShpTraitsTrieMutation]>>, newRoot: H256],
[mutations: Vec<ITuple<[H256, ShpTraitsTrieMutation]>>, oldRoot: H256, newRoot: H256],
{
provider: H256;
mutations: Vec<ITuple<[H256, ShpTraitsTrieMutation]>>;
oldRoot: H256;
newRoot: H256;
}
>;
/**
* A set of mutations has been applied to the Forest of a given Provider.
**/
MutationsAppliedForProvider: AugmentedEvent<
ApiType,
[
providerId: H256,
mutations: Vec<ITuple<[H256, ShpTraitsTrieMutation]>>,
oldRoot: H256,
newRoot: H256
],
{
providerId: H256;
mutations: Vec<ITuple<[H256, ShpTraitsTrieMutation]>>;
oldRoot: H256;
newRoot: H256;
}
>;
Expand Down
8 changes: 7 additions & 1 deletion api-augment/dist/types/interfaces/lookup.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1650,9 +1650,15 @@ declare const _default: {
provider: string;
maybeProviderAccount: string;
};
MutationsAppliedForProvider: {
providerId: string;
mutations: string;
oldRoot: string;
newRoot: string;
};
MutationsApplied: {
provider: string;
mutations: string;
oldRoot: string;
newRoot: string;
};
ChallengesTickerSet: {
Expand Down
10 changes: 9 additions & 1 deletion api-augment/dist/types/interfaces/types-lookup.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2132,10 +2132,17 @@ declare module "@polkadot/types/lookup" {
readonly provider: H256;
readonly maybeProviderAccount: Option<AccountId32>;
} & Struct;
readonly isMutationsAppliedForProvider: boolean;
readonly asMutationsAppliedForProvider: {
readonly providerId: H256;
readonly mutations: Vec<ITuple<[H256, ShpTraitsTrieMutation]>>;
readonly oldRoot: H256;
readonly newRoot: H256;
} & Struct;
readonly isMutationsApplied: boolean;
readonly asMutationsApplied: {
readonly provider: H256;
readonly mutations: Vec<ITuple<[H256, ShpTraitsTrieMutation]>>;
readonly oldRoot: H256;
readonly newRoot: H256;
} & Struct;
readonly isChallengesTickerSet: boolean;
Expand All @@ -2150,6 +2157,7 @@ declare module "@polkadot/types/lookup" {
| "SlashableProvider"
| "NoRecordOfLastSubmittedProof"
| "NewChallengeCycleInitialised"
| "MutationsAppliedForProvider"
| "MutationsApplied"
| "ChallengesTickerSet";
}
Expand Down
27 changes: 24 additions & 3 deletions api-augment/src/interfaces/augment-api-events.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1601,12 +1601,33 @@ declare module "@polkadot/api-base/types/events" {
**/
ChallengesTickerSet: AugmentedEvent<ApiType, [paused: bool], { paused: bool }>;
/**
* A set of mutations has been applied to the Forest.
* A set of mutations has been applied to a given Forest.
* This is the generic version of [`MutationsAppliedForProvider`](Event::MutationsAppliedForProvider)
* when [`generic_apply_delta`](ProofsDealerInterface::generic_apply_delta) is used
* and the root is not necessarily linked to a specific Provider.
**/
MutationsApplied: AugmentedEvent<
ApiType,
[provider: H256, mutations: Vec<ITuple<[H256, ShpTraitsTrieMutation]>>, newRoot: H256],
{ provider: H256; mutations: Vec<ITuple<[H256, ShpTraitsTrieMutation]>>; newRoot: H256 }
[mutations: Vec<ITuple<[H256, ShpTraitsTrieMutation]>>, oldRoot: H256, newRoot: H256],
{ mutations: Vec<ITuple<[H256, ShpTraitsTrieMutation]>>; oldRoot: H256; newRoot: H256 }
>;
/**
* A set of mutations has been applied to the Forest of a given Provider.
**/
MutationsAppliedForProvider: AugmentedEvent<
ApiType,
[
providerId: H256,
mutations: Vec<ITuple<[H256, ShpTraitsTrieMutation]>>,
oldRoot: H256,
newRoot: H256
],
{
providerId: H256;
mutations: Vec<ITuple<[H256, ShpTraitsTrieMutation]>>;
oldRoot: H256;
newRoot: H256;
}
>;
/**
* A manual challenge was submitted.
Expand Down
8 changes: 7 additions & 1 deletion api-augment/src/interfaces/lookup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1672,9 +1672,15 @@ export default {
provider: "H256",
maybeProviderAccount: "Option<AccountId32>"
},
MutationsAppliedForProvider: {
providerId: "H256",
mutations: "Vec<(H256,ShpTraitsTrieMutation)>",
oldRoot: "H256",
newRoot: "H256"
},
MutationsApplied: {
provider: "H256",
mutations: "Vec<(H256,ShpTraitsTrieMutation)>",
oldRoot: "H256",
newRoot: "H256"
},
ChallengesTickerSet: {
Expand Down
10 changes: 9 additions & 1 deletion api-augment/src/interfaces/types-lookup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2223,10 +2223,17 @@ declare module "@polkadot/types/lookup" {
readonly provider: H256;
readonly maybeProviderAccount: Option<AccountId32>;
} & Struct;
readonly isMutationsAppliedForProvider: boolean;
readonly asMutationsAppliedForProvider: {
readonly providerId: H256;
readonly mutations: Vec<ITuple<[H256, ShpTraitsTrieMutation]>>;
readonly oldRoot: H256;
readonly newRoot: H256;
} & Struct;
readonly isMutationsApplied: boolean;
readonly asMutationsApplied: {
readonly provider: H256;
readonly mutations: Vec<ITuple<[H256, ShpTraitsTrieMutation]>>;
readonly oldRoot: H256;
readonly newRoot: H256;
} & Struct;
readonly isChallengesTickerSet: boolean;
Expand All @@ -2241,6 +2248,7 @@ declare module "@polkadot/types/lookup" {
| "SlashableProvider"
| "NoRecordOfLastSubmittedProof"
| "NewChallengeCycleInitialised"
| "MutationsAppliedForProvider"
| "MutationsApplied"
| "ChallengesTickerSet";
}
Expand Down
2 changes: 1 addition & 1 deletion api-augment/storagehub.json

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions client/blockchain-service/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ sc-network = { workspace = true }
sc-utils = { workspace = true }
sc-tracing = { workspace = true }
sp-api = { workspace = true }
sp-blockchain = { workspace = true }
sp-core = { workspace = true, default-features = true }
sp-keystore = { workspace = true }
sp-runtime = { workspace = true, default-features = true }
Expand Down
4 changes: 2 additions & 2 deletions client/blockchain-service/src/commands.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ use super::{
handler::BlockchainService,
transaction::SubmittedTransaction,
types::{
BestBlockInfo, ConfirmStoringRequest, Extrinsic, ExtrinsicResult, RespondStorageRequest,
ConfirmStoringRequest, Extrinsic, ExtrinsicResult, MinimalBlockInfo, RespondStorageRequest,
RetryStrategy, StopStoringForInsolventUserRequest, SubmitProofRequest, Tip,
},
};
Expand All @@ -55,7 +55,7 @@ pub enum BlockchainServiceCommand {
callback: tokio::sync::oneshot::Sender<Result<()>>,
},
GetBestBlockInfo {
callback: tokio::sync::oneshot::Sender<BestBlockInfo>,
callback: tokio::sync::oneshot::Sender<MinimalBlockInfo>,
},
WaitForBlock {
block_number: BlockNumber,
Expand Down
69 changes: 48 additions & 21 deletions client/blockchain-service/src/handler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ use sc_service::RpcHandlers;
use sc_tracing::tracing::{debug, error, info, trace, warn};
use shc_forest_manager::traits::ForestStorageHandler;
use sp_api::{ApiError, ProvideRuntimeApi};
use sp_blockchain::TreeRoute;
use sp_core::H256;
use sp_keystore::{Keystore, KeystorePtr};
use sp_runtime::{
Expand Down Expand Up @@ -63,7 +64,7 @@ use crate::{
transaction::SubmittedTransaction,
typed_store::{CFDequeAPI, ProvidesTypedDbSingleAccess},
types::{
BestBlockInfo, ForestStorageSnapshotInfo, NewBlockNotificationKind,
ForestStorageSnapshotInfo, MinimalBlockInfo, NewBlockNotificationKind,
StopStoringForInsolventUserRequest, SubmitProofRequest,
},
};
Expand Down Expand Up @@ -103,12 +104,12 @@ where
///
/// This is used to manage Forest Storage instances and update their roots when there are
/// Forest-root-changing events on-chain, for the Storage Provider managed by this service.
pub(crate) _forest_storage_handler: FSH,
pub(crate) forest_storage_handler: FSH,
/// The hash and number of the last best block processed by the BlockchainService.
///
/// This is used to detect when the BlockchainService gets out of syncing mode and should therefore
/// run some initialisation tasks. Also used to detect reorgs.
pub(crate) best_block: BestBlockInfo,
pub(crate) best_block: MinimalBlockInfo,
/// Nonce counter for the extrinsics.
pub(crate) nonce_counter: u32,
/// A registry of waiters for a block number.
Expand Down Expand Up @@ -1022,8 +1023,8 @@ where
client,
keystore,
rpc_handlers,
_forest_storage_handler: forest_storage_handler,
best_block: BestBlockInfo::default(),
forest_storage_handler,
best_block: MinimalBlockInfo::default(),
nonce_counter: 0,
wait_for_block_request_by_number: BTreeMap::new(),
wait_for_tick_request_by_number: BTreeMap::new(),
Expand All @@ -1042,22 +1043,37 @@ where
) where
Block: cumulus_primitives_core::BlockT<Hash = H256>,
{
let last_block_processed = self.best_block.number;
let last_block_processed = self.best_block;

// Check if this new imported block is the new best, and if it causes a reorg.
let new_block_notification_kind = self.register_best_block_and_check_reorg(&notification);
let BestBlockInfo {
number: block_number,
hash: block_hash,
} = match new_block_notification_kind {
NewBlockNotificationKind::NewBestBlock(new_best_block_info) => new_best_block_info,

// Get the new best block info, and the `TreeRoute`, i.e. the blocks from the old best block to the new best block.
// A new non-best block is ignored and not processed.
let (block_info, tree_route) = match new_block_notification_kind {
NewBlockNotificationKind::NewBestBlock(new_best_block_info) => {
// Making up a tree route with the new best block, and the old best block as the pivot.
let tree_route = TreeRoute::new(
vec![
last_block_processed.clone().into(),
new_best_block_info.clone().into(),
],
0,
)
.expect("`TreeRoute` with `pivot` 0 should be valid; qed");
(new_best_block_info, tree_route)
}
NewBlockNotificationKind::NewNonBestBlock(_) => return,
NewBlockNotificationKind::Reorg {
old_best_block: _,
new_best_block,
} => {
// TODO: Handle catch up of reorgs.
new_best_block
}
tree_route,
} => (new_best_block, tree_route),
};
let MinimalBlockInfo {
number: block_number,
hash: block_hash,
} = block_info;

info!(target: LOG_TARGET, "📥 Block import notification (#{}): {}", block_number, block_hash);

Expand All @@ -1068,11 +1084,12 @@ where
// Check if we just came out of syncing mode.
// We use saturating_sub because in a reorg, there is a potential scenario where the last
// block processed is higher than the current block number.
if block_number.saturating_sub(last_block_processed) > SYNC_MODE_MIN_BLOCKS_BEHIND {
if block_number.saturating_sub(last_block_processed.number) > SYNC_MODE_MIN_BLOCKS_BEHIND {
self.handle_initial_sync(notification).await;
}

self.process_block_import(&block_hash, &block_number).await;
self.process_block_import(&block_hash, &block_number, tree_route)
.await;
}

fn pre_block_processing_checks(&mut self, block_hash: &H256) {
Expand Down Expand Up @@ -1166,9 +1183,19 @@ where
}
}

async fn process_block_import(&mut self, block_hash: &H256, block_number: &BlockNumber) {
async fn process_block_import<Block>(
&mut self,
block_hash: &H256,
block_number: &BlockNumber,
tree_route: TreeRoute<Block>,
) where
Block: cumulus_primitives_core::BlockT<Hash = H256>,
{
trace!(target: LOG_TARGET, "📠 Processing block import #{}: {}", block_number, block_hash);

// Before triggering any task, we make sure to be caught up to the Forest roots on-chain.
self.forest_root_changes_catchup(&tree_route).await;

// Trigger catch up of proofs if the block is a multiple of `CHECK_FOR_PENDING_PROOFS_PERIOD`.
// This is only relevant if this node is managing a BSP.
if let Some(StorageProviderId::BackupStorageProvider(bsp_id)) = &self.provider_id {
Expand Down Expand Up @@ -1502,11 +1529,11 @@ where
// Process the events.
for ev in block_events {
match ev.event.clone() {
// New storage request event coming from pallet-file-system.
RuntimeEvent::ProofsDealer(
pallet_proofs_dealer::Event::MutationsApplied {
provider: provider_id,
pallet_proofs_dealer::Event::MutationsAppliedForProvider {
provider_id,
mutations,
old_root: _,
new_root,
},
) => {
Expand Down
Loading
Loading