Skip to content

Commit

Permalink
Always use wasm executor in container collators (#412)
Browse files Browse the repository at this point in the history
  • Loading branch information
tmpolaczyk authored Feb 16, 2024
1 parent 23f537d commit d28aca5
Show file tree
Hide file tree
Showing 5 changed files with 99 additions and 26 deletions.
46 changes: 37 additions & 9 deletions client/node-common/src/service.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,9 @@ use {
run_manual_seal, ConsensusDataProvider, EngineCommand, ManualSealParams,
},
sc_executor::{
HeapAllocStrategy, NativeElseWasmExecutor, NativeExecutionDispatch, WasmExecutor,
DEFAULT_HEAP_ALLOC_STRATEGY,
sp_wasm_interface::{ExtendedHostFunctions, HostFunctions},
HeapAllocStrategy, NativeElseWasmExecutor, NativeExecutionDispatch, RuntimeVersionOf,
WasmExecutor, DEFAULT_HEAP_ALLOC_STRATEGY,
},
sc_network::{config::FullNetworkConfiguration, NetworkBlock, NetworkService},
sc_network_sync::SyncingService,
Expand All @@ -52,6 +53,7 @@ use {
sp_api::ConstructRuntimeApi,
sp_block_builder::BlockBuilder,
sp_consensus::SelectChain,
sp_core::traits::CodeExecutor,
sp_inherents::CreateInherentDataProviders,
sp_offchain::OffchainWorkerApi,
sp_runtime::Percent,
Expand All @@ -64,7 +66,7 @@ use {
pub trait NodeBuilderConfig {
type Block;
type RuntimeApi;
type ParachainNativeExecutor;
type ParachainExecutor;

/// Create a new `NodeBuilder` using the types of this `Config`, along
/// with the parachain `Configuration` and an optional `HwBench`.
Expand All @@ -75,7 +77,8 @@ pub trait NodeBuilderConfig {
where
Self: Sized,
BlockOf<Self>: cumulus_primitives_core::BlockT,
ParachainNativeExecutorOf<Self>: NativeExecutionDispatch + 'static,
ExecutorOf<Self>:
Clone + CodeExecutor + RuntimeVersionOf + TanssiExecutorExt + Sync + Send + 'static,
RuntimeApiOf<Self>:
ConstructRuntimeApi<BlockOf<Self>, ClientOf<Self>> + Sync + Send + 'static,
ConstructedRuntimeApiOf<Self>:
Expand All @@ -89,8 +92,7 @@ pub type BlockOf<T> = <T as NodeBuilderConfig>::Block;
pub type BlockHashOf<T> = <BlockOf<T> as cumulus_primitives_core::BlockT>::Hash;
pub type BlockHeaderOf<T> = <BlockOf<T> as cumulus_primitives_core::BlockT>::Header;
pub type RuntimeApiOf<T> = <T as NodeBuilderConfig>::RuntimeApi;
pub type ParachainNativeExecutorOf<T> = <T as NodeBuilderConfig>::ParachainNativeExecutor;
pub type ExecutorOf<T> = NativeElseWasmExecutor<ParachainNativeExecutorOf<T>>;
pub type ExecutorOf<T> = <T as NodeBuilderConfig>::ParachainExecutor;
pub type ClientOf<T> = TFullClient<BlockOf<T>, RuntimeApiOf<T>, ExecutorOf<T>>;
pub type BackendOf<T> = TFullBackend<BlockOf<T>>;
pub type ConstructedRuntimeApiOf<T> =
Expand Down Expand Up @@ -130,7 +132,7 @@ pub struct NodeBuilder<
SImportQueueService = (),
> where
BlockOf<T>: cumulus_primitives_core::BlockT,
ParachainNativeExecutorOf<T>: NativeExecutionDispatch + 'static,
ExecutorOf<T>: Clone + CodeExecutor + RuntimeVersionOf + Sync + Send + 'static,
RuntimeApiOf<T>: ConstructRuntimeApi<BlockOf<T>, ClientOf<T>> + Sync + Send + 'static,
ConstructedRuntimeApiOf<T>: TaggedTransactionQueue<BlockOf<T>> + BlockBuilder<BlockOf<T>>,
{
Expand All @@ -157,13 +159,39 @@ pub struct Network<Block: cumulus_primitives_core::BlockT> {
pub sync_service: Arc<SyncingService<Block>>,
}

/// Allows to create a parachain-defined executor from a `WasmExecutor`
pub trait TanssiExecutorExt {
type HostFun: HostFunctions;
fn new_with_wasm_executor(wasm_executor: WasmExecutor<Self::HostFun>) -> Self;
}

impl TanssiExecutorExt for WasmExecutor<sp_io::SubstrateHostFunctions> {
type HostFun = sp_io::SubstrateHostFunctions;

fn new_with_wasm_executor(wasm_executor: WasmExecutor<Self::HostFun>) -> Self {
wasm_executor
}
}

impl<D> TanssiExecutorExt for NativeElseWasmExecutor<D>
where
D: NativeExecutionDispatch,
{
type HostFun = ExtendedHostFunctions<sp_io::SubstrateHostFunctions, D::ExtendHostFunctions>;

fn new_with_wasm_executor(wasm_executor: WasmExecutor<Self::HostFun>) -> Self {
NativeElseWasmExecutor::new_with_wasm_executor(wasm_executor)
}
}

// `new` function doesn't take self, and the Rust compiler cannot infer that
// only one type T implements `TypeIdentity`. With thus need a separate impl
// block with concrete types `()`.
impl<T: NodeBuilderConfig> NodeBuilder<T>
where
BlockOf<T>: cumulus_primitives_core::BlockT,
ParachainNativeExecutorOf<T>: NativeExecutionDispatch + 'static,
ExecutorOf<T>:
Clone + CodeExecutor + RuntimeVersionOf + TanssiExecutorExt + Sync + Send + 'static,
RuntimeApiOf<T>: ConstructRuntimeApi<BlockOf<T>, ClientOf<T>> + Sync + Send + 'static,
ConstructedRuntimeApiOf<T>: TaggedTransactionQueue<BlockOf<T>> + BlockBuilder<BlockOf<T>>,
{
Expand Down Expand Up @@ -255,7 +283,7 @@ impl<T: NodeBuilderConfig, SNetwork, STxHandler, SImportQueueService>
NodeBuilder<T, SNetwork, STxHandler, SImportQueueService>
where
BlockOf<T>: cumulus_primitives_core::BlockT,
ParachainNativeExecutorOf<T>: NativeExecutionDispatch + 'static,
ExecutorOf<T>: Clone + CodeExecutor + RuntimeVersionOf + Sync + Send + 'static,
RuntimeApiOf<T>: ConstructRuntimeApi<BlockOf<T>, ClientOf<T>> + Sync + Send + 'static,
ConstructedRuntimeApiOf<T>: TaggedTransactionQueue<BlockOf<T>>
+ BlockBuilder<BlockOf<T>>
Expand Down
2 changes: 1 addition & 1 deletion container-chains/templates/frontier/node/src/service.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ pub struct NodeConfig;
impl NodeBuilderConfig for NodeConfig {
type Block = Block;
type RuntimeApi = RuntimeApi;
type ParachainNativeExecutor = TemplateRuntimeExecutor;
type ParachainExecutor = ParachainExecutor;
}

pub fn frontier_database_dir(config: &Configuration, path: &str) -> std::path::PathBuf {
Expand Down
2 changes: 1 addition & 1 deletion container-chains/templates/simple/node/src/service.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ pub struct NodeConfig;
impl NodeBuilderConfig for NodeConfig {
type Block = Block;
type RuntimeApi = RuntimeApi;
type ParachainNativeExecutor = ParachainNativeExecutor;
type ParachainExecutor = ParachainExecutor;
}

thread_local!(static TIMESTAMP: std::cell::RefCell<u64> = std::cell::RefCell::new(0));
Expand Down
6 changes: 3 additions & 3 deletions node/src/container_chain_monitor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
use {
crate::{
container_chain_spawner::{CcSpawnMsg, ContainerChainSpawnerState},
service::{ParachainBackend, ParachainClient},
service::{ContainerChainBackend, ContainerChainClient},
},
cumulus_primitives_core::ParaId,
std::{
Expand Down Expand Up @@ -57,9 +57,9 @@ pub struct SpawnedContainer {
/// This won't be precise because it is checked using polling with a high period.
pub stop_refcount_time: Cell<Option<Instant>>,
/// Used to check the reference count, if it's 0 it means the database has been closed
pub backend: std::sync::Weak<ParachainBackend>,
pub backend: std::sync::Weak<ContainerChainBackend>,
/// Used to check the reference count, if it's 0 it means that the client has been closed.
pub client: std::sync::Weak<ParachainClient>,
pub client: std::sync::Weak<ContainerChainClient>,
}

impl SpawnedContainer {
Expand Down
69 changes: 57 additions & 12 deletions node/src/service.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ use {
},
sc_consensus::BlockImport,
sc_consensus::{BasicQueue, ImportQueue},
sc_executor::NativeElseWasmExecutor,
sc_executor::{NativeElseWasmExecutor, WasmExecutor},
sc_network::NetworkBlock,
sc_network_sync::SyncingService,
sc_service::{Configuration, SpawnTaskHandle, TFullBackend, TFullClient, TaskManager},
Expand Down Expand Up @@ -101,19 +101,32 @@ pub struct NodeConfig;
impl NodeBuilderConfig for NodeConfig {
type Block = Block;
type RuntimeApi = RuntimeApi;
type ParachainNativeExecutor = ParachainNativeExecutor;
type ParachainExecutor = ParachainExecutor;
}

type ParachainExecutor = NativeElseWasmExecutor<ParachainNativeExecutor>;
pub struct ContainerChainNodeConfig;
impl NodeBuilderConfig for ContainerChainNodeConfig {
type Block = Block;
// TODO: RuntimeApi here should be the subset of runtime apis available for all containers
// Currently we are using the orchestrator runtime apis
type RuntimeApi = RuntimeApi;
type ParachainExecutor = ContainerChainExecutor;
}

// Orchestrator chain types
type ParachainExecutor = NativeElseWasmExecutor<ParachainNativeExecutor>;
pub type ParachainClient = TFullClient<Block, RuntimeApi, ParachainExecutor>;

pub type ParachainBackend = TFullBackend<Block>;

type DevParachainBlockImport = OrchestratorParachainBlockImport<Arc<ParachainClient>>;

type ParachainBlockImport = TParachainBlockImport<Block, Arc<ParachainClient>, ParachainBackend>;

// Container chains types
type ContainerChainExecutor = WasmExecutor<sp_io::SubstrateHostFunctions>;
pub type ContainerChainClient = TFullClient<Block, RuntimeApi, ContainerChainExecutor>;
pub type ContainerChainBackend = ParachainBackend;
type ContainerChainBlockImport =
TParachainBlockImport<Block, Arc<ContainerChainClient>, ContainerChainBackend>;

thread_local!(static TIMESTAMP: std::cell::RefCell<u64> = std::cell::RefCell::new(0));

/// Provide a mock duration starting at 0 in millisecond for timestamp inherent.
Expand Down Expand Up @@ -242,6 +255,33 @@ pub fn import_queue(
(block_import, import_queue)
}

pub fn container_chain_import_queue(
parachain_config: &Configuration,
node_builder: &NodeBuilder<ContainerChainNodeConfig>,
) -> (ContainerChainBlockImport, BasicQueue<Block>) {
// The nimbus import queue ONLY checks the signature correctness
// Any other checks corresponding to the author-correctness should be done
// in the runtime
let block_import =
ContainerChainBlockImport::new(node_builder.client.clone(), node_builder.backend.clone());

let import_queue = nimbus_consensus::import_queue(
node_builder.client.clone(),
block_import.clone(),
move |_, _| async move {
let time = sp_timestamp::InherentDataProvider::from_system_time();

Ok((time,))
},
&node_builder.task_manager.spawn_essential_handle(),
parachain_config.prometheus_registry(),
false,
)
.expect("function never fails");

(block_import, import_queue)
}

/// Start a node with the given parachain `Configuration` and relay chain `Configuration`.
///
/// This is the actual implementation that is abstract over the executor and the runtime api.
Expand Down Expand Up @@ -469,13 +509,18 @@ pub async fn start_node_impl_container(
para_id: ParaId,
orchestrator_para_id: ParaId,
collator: bool,
) -> sc_service::error::Result<(TaskManager, Arc<ParachainClient>, Arc<ParachainBackend>)> {
) -> sc_service::error::Result<(
TaskManager,
Arc<ContainerChainClient>,
Arc<ParachainBackend>,
)> {
let parachain_config = prepare_node_config(parachain_config);

// Create a `NodeBuilder` which helps setup parachain nodes common systems.
let node_builder = NodeConfig::new_builder(&parachain_config, None)?;
let node_builder = ContainerChainNodeConfig::new_builder(&parachain_config, None)?;

let (block_import, import_queue) = import_queue(&parachain_config, &node_builder);
let (block_import, import_queue) =
container_chain_import_queue(&parachain_config, &node_builder);
let import_queue_service = import_queue.service();

log::info!("are we collators? {:?}", collator);
Expand Down Expand Up @@ -594,15 +639,15 @@ fn build_manual_seal_import_queue(

#[sc_tracing::logging::prefix_logs_with(container_log_str(para_id))]
fn start_consensus_container(
client: Arc<ParachainClient>,
client: Arc<ContainerChainClient>,
orchestrator_client: Arc<ParachainClient>,
block_import: ParachainBlockImport,
block_import: ContainerChainBlockImport,
prometheus_registry: Option<Registry>,
telemetry: Option<TelemetryHandle>,
spawner: SpawnTaskHandle,
relay_chain_interface: Arc<dyn RelayChainInterface>,
orchestrator_chain_interface: Arc<dyn OrchestratorChainInterface>,
transaction_pool: Arc<sc_transaction_pool::FullPool<Block, ParachainClient>>,
transaction_pool: Arc<sc_transaction_pool::FullPool<Block, ContainerChainClient>>,
sync_oracle: Arc<SyncingService<Block>>,
keystore: KeystorePtr,
force_authoring: bool,
Expand Down

0 comments on commit d28aca5

Please sign in to comment.