From 34f2a45e073052519697f41f264d05fa187ea678 Mon Sep 17 00:00:00 2001 From: Igor Aleksanov Date: Mon, 1 Jul 2024 19:18:09 +0400 Subject: [PATCH] feat(node_framework): Implement FromContext and IntoContext derive macro (#2330) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## What ❔ - Improves context interfaces: removes unneded `async` when fetching resources, and made `add_task` accept `T` instead of `Box`. - Adds previously proposed `FromContext` and `IntoContext` macro that will allow to redefine the wiring layer interface so that it doesn't have direct access to the context. ⚠️ I didn't port the whole framework to using macros, since there may be changes in the macro itself during this review. Once we merge this, I will simultaneously rework the `WiringLayer` interface and will port layers. For now, I've used new macros in the `BatchStatusUpdater` layer to see how it works. Seems that it works fine 😅 ## Why ❔ Ergonomics. ## Checklist - [ ] PR title corresponds to the body of PR (we generate changelog entries from PRs). - [ ] Tests for the changes have been added / updated. - [ ] Documentation comments have been added / updated. - [ ] Code has been formatted via `zk fmt` and `zk lint`. --- Cargo.lock | 44 ++++ Cargo.toml | 8 + core/lib/node_framework_derive/Cargo.toml | 18 ++ core/lib/node_framework_derive/src/helpers.rs | 44 ++++ core/lib/node_framework_derive/src/labels.rs | 98 +++++++++ core/lib/node_framework_derive/src/lib.rs | 39 ++++ .../node_framework_derive/src/macro_impl.rs | 190 ++++++++++++++++++ core/node/node_framework/Cargo.toml | 3 + core/node/node_framework/examples/showcase.rs | 6 +- .../layers/batch_status_updater.rs | 31 ++- .../layers/circuit_breaker_checker.rs | 6 +- .../layers/commitment_generator.rs | 8 +- .../src/implementations/layers/consensus.rs | 14 +- .../layers/consistency_checker.rs | 8 +- .../layers/contract_verification_api.rs | 10 +- .../src/implementations/layers/eth_sender.rs | 34 ++-- .../src/implementations/layers/eth_watch.rs | 8 +- .../layers/healtcheck_server.rs | 4 +- .../implementations/layers/house_keeper.rs | 44 ++-- .../l1_batch_commitment_mode_validation.rs | 4 +- .../src/implementations/layers/l1_gas.rs | 4 +- .../layers/main_node_client.rs | 2 +- .../layers/main_node_fee_params_fetcher.rs | 4 +- .../layers/metadata_calculator.rs | 17 +- .../layers/pk_signing_eth_client.rs | 2 +- .../src/implementations/layers/pools_layer.rs | 8 +- .../layers/postgres_metrics.rs | 4 +- .../layers/prometheus_exporter.rs | 6 +- .../layers/proof_data_handler.rs | 8 +- .../src/implementations/layers/pruning.rs | 6 +- .../layers/reorg_detector_checker.rs | 8 +- .../layers/reorg_detector_runner.rs | 10 +- .../src/implementations/layers/sigint.rs | 2 +- .../layers/state_keeper/external_io.rs | 4 +- .../layers/state_keeper/mempool_io.rs | 9 +- .../layers/state_keeper/mod.rs | 19 +- .../layers/state_keeper/output_handler.rs | 6 +- .../layers/sync_state_updater.rs | 10 +- .../layers/tee_verifier_input_producer.rs | 7 +- .../layers/tree_data_fetcher.rs | 10 +- .../layers/validate_chain_ids.rs | 6 +- .../layers/vm_runner/protective_reads.rs | 10 +- .../implementations/layers/web3_api/caches.rs | 4 +- .../implementations/layers/web3_api/server.rs | 20 +- .../layers/web3_api/tree_api_client.rs | 2 +- .../layers/web3_api/tx_sender.rs | 22 +- .../layers/web3_api/tx_sink.rs | 10 +- core/node/node_framework/src/lib.rs | 12 ++ core/node/node_framework/src/resource/mod.rs | 12 +- .../node_framework/src/service/context.rs | 16 +- .../src/service/context_traits.rs | 133 ++++++++++++ core/node/node_framework/src/service/mod.rs | 8 +- core/node/node_framework/src/service/tests.rs | 10 +- core/node/node_framework/src/task/types.rs | 1 + core/node/node_framework/tests/ui.rs | 11 + .../tests/ui/correct/01_from_context.rs | 41 ++++ .../tests/ui/correct/02_into_context.rs | 41 ++++ .../ui/incorrect/01_from_context_task.rs | 34 ++++ .../ui/incorrect/01_from_context_task.stderr | 5 + .../incorrect/02_into_context_default_task.rs | 35 ++++ .../02_into_context_default_task.stderr | 5 + .../03_into_context_default_resource.rs | 35 ++++ .../03_into_context_default_resource.stderr | 5 + .../tests/ui/incorrect/04_field_crate_attr.rs | 48 +++++ .../ui/incorrect/04_field_crate_attr.stderr | 17 ++ 65 files changed, 1089 insertions(+), 221 deletions(-) create mode 100644 core/lib/node_framework_derive/Cargo.toml create mode 100644 core/lib/node_framework_derive/src/helpers.rs create mode 100644 core/lib/node_framework_derive/src/labels.rs create mode 100644 core/lib/node_framework_derive/src/lib.rs create mode 100644 core/lib/node_framework_derive/src/macro_impl.rs create mode 100644 core/node/node_framework/src/service/context_traits.rs create mode 100644 core/node/node_framework/tests/ui.rs create mode 100644 core/node/node_framework/tests/ui/correct/01_from_context.rs create mode 100644 core/node/node_framework/tests/ui/correct/02_into_context.rs create mode 100644 core/node/node_framework/tests/ui/incorrect/01_from_context_task.rs create mode 100644 core/node/node_framework/tests/ui/incorrect/01_from_context_task.stderr create mode 100644 core/node/node_framework/tests/ui/incorrect/02_into_context_default_task.rs create mode 100644 core/node/node_framework/tests/ui/incorrect/02_into_context_default_task.stderr create mode 100644 core/node/node_framework/tests/ui/incorrect/03_into_context_default_resource.rs create mode 100644 core/node/node_framework/tests/ui/incorrect/03_into_context_default_resource.stderr create mode 100644 core/node/node_framework/tests/ui/incorrect/04_field_crate_attr.rs create mode 100644 core/node/node_framework/tests/ui/incorrect/04_field_crate_attr.stderr diff --git a/Cargo.lock b/Cargo.lock index 09f87489a121..30f80564eaa6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -478,6 +478,15 @@ version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" +[[package]] +name = "basic-toml" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7bfc506e7a2370ec239e1d072507b2a80c833083699d3c6fa176fbb4de8448c6" +dependencies = [ + "serde", +] + [[package]] name = "beef" version = "0.5.2" @@ -6496,6 +6505,15 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "termcolor" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755" +dependencies = [ + "winapi-util", +] + [[package]] name = "test-casing" version = "0.1.2" @@ -7015,6 +7033,21 @@ version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3528ecfd12c466c6f163363caf2d02a71161dd5e1cc6ae7b34207ea2d42d81ed" +[[package]] +name = "trybuild" +version = "1.0.86" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8419ecd263363827c5730386f418715766f584e2f874d32c23c5b00bd9727e7e" +dependencies = [ + "basic-toml", + "glob", + "once_cell", + "serde", + "serde_derive", + "serde_json", + "termcolor", +] + [[package]] name = "typenum" version = "1.17.0" @@ -8857,6 +8890,7 @@ dependencies = [ "thiserror", "tokio", "tracing", + "trybuild", "zksync_block_reverter", "zksync_circuit_breaker", "zksync_commitment_generator", @@ -8878,6 +8912,7 @@ dependencies = [ "zksync_node_consensus", "zksync_node_db_pruner", "zksync_node_fee_model", + "zksync_node_framework_derive", "zksync_node_sync", "zksync_object_store", "zksync_proof_data_handler", @@ -8896,6 +8931,15 @@ dependencies = [ "zksync_web3_decl", ] +[[package]] +name = "zksync_node_framework_derive" +version = "0.1.0" +dependencies = [ + "proc-macro2 1.0.69", + "quote 1.0.33", + "syn 2.0.38", +] + [[package]] name = "zksync_node_genesis" version = "0.1.0" diff --git a/Cargo.toml b/Cargo.toml index b927aec79252..665f7ff06564 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -50,6 +50,7 @@ members = [ "core/lib/mempool", "core/lib/merkle_tree", "core/lib/mini_merkle_tree", + "core/lib/node_framework_derive", "core/lib/object_store", "core/lib/prover_interface", "core/lib/queued_job_processor", @@ -172,6 +173,12 @@ tracing-opentelemetry = "0.21.0" url = "2" web3 = "0.19.0" +# Proc-macro +syn = "2.0" +quote = "1.0" +proc-macro2 = "1.0" +trybuild = "1.0" + # "Internal" dependencies circuit_sequencer_api_1_3_3 = { package = "circuit_sequencer_api", git = "https://github.com/matter-labs/era-zkevm_test_harness.git", branch = "v1.3.3" } circuit_sequencer_api_1_4_0 = { package = "circuit_sequencer_api", git = "https://github.com/matter-labs/era-zkevm_test_harness.git", branch = "v1.4.0" } @@ -239,6 +246,7 @@ zksync_crypto_primitives = { path = "core/lib/crypto_primitives" } # Framework and components zksync_node_framework = { path = "core/node/node_framework" } +zksync_node_framework_derive = { path = "core/lib/node_framework_derive" } zksync_eth_watch = { path = "core/node/eth_watch" } zksync_shared_metrics = { path = "core/node/shared_metrics" } zksync_proof_data_handler = { path = "core/node/proof_data_handler" } diff --git a/core/lib/node_framework_derive/Cargo.toml b/core/lib/node_framework_derive/Cargo.toml new file mode 100644 index 000000000000..3b3198545298 --- /dev/null +++ b/core/lib/node_framework_derive/Cargo.toml @@ -0,0 +1,18 @@ +[package] +name = "zksync_node_framework_derive" +version.workspace = true +edition.workspace = true +authors.workspace = true +homepage.workspace = true +repository.workspace = true +license.workspace = true +keywords.workspace = true +categories.workspace = true + +[lib] +proc-macro = true + +[dependencies] +syn = { workspace = true, features = ["full"] } +quote.workspace = true +proc-macro2.workspace = true diff --git a/core/lib/node_framework_derive/src/helpers.rs b/core/lib/node_framework_derive/src/helpers.rs new file mode 100644 index 000000000000..005e959b2bee --- /dev/null +++ b/core/lib/node_framework_derive/src/helpers.rs @@ -0,0 +1,44 @@ +use std::fmt; + +use syn::{GenericArgument, PathArguments, Type}; + +use crate::labels::CtxLabel; + +/// Representation of a single structure field. +pub(crate) struct Field { + /// Name of the field. + pub(crate) ident: syn::Ident, + /// Type of the field. + pub(crate) ty: syn::Type, + /// Parsed label. + pub(crate) label: CtxLabel, +} + +impl fmt::Debug for Field { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("Field") + .field("ident", &self.ident) + .field("label", &self.label) + .finish() + } +} + +// Helper function to check if a field is of type Option and extract T +pub(crate) fn extract_option_inner_type(ty: &Type) -> Option<&Type> { + if let Type::Path(type_path) = ty { + // Check if the path is `Option` + if type_path.path.segments.len() == 1 { + let segment = &type_path.path.segments[0]; + if segment.ident == "Option" { + if let PathArguments::AngleBracketed(angle_bracketed_args) = &segment.arguments { + if angle_bracketed_args.args.len() == 1 { + if let GenericArgument::Type(inner_type) = &angle_bracketed_args.args[0] { + return Some(inner_type); + } + } + } + } + } + } + None +} diff --git a/core/lib/node_framework_derive/src/labels.rs b/core/lib/node_framework_derive/src/labels.rs new file mode 100644 index 000000000000..2bac5a7f7552 --- /dev/null +++ b/core/lib/node_framework_derive/src/labels.rs @@ -0,0 +1,98 @@ +use std::fmt; + +use syn::{spanned::Spanned as _, Attribute, Result}; + +/// Context label, e.g. `ctx(crate = "crate")`. +#[derive(Default)] +pub(crate) struct CtxLabel { + /// Special attribute that marks the derive as internal. + /// Alters the path to the trait to be implemented. + pub(crate) krate: Option, // `crate` is a reserved keyword and cannot be a raw identifier. + pub(crate) span: Option, + pub(crate) task: bool, + pub(crate) default: bool, +} + +impl fmt::Debug for CtxLabel { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + // For some weird reason, doc tests fail with the derived impl, stating that + // `syn::Path` does not implement `Debug`. + f.debug_struct("CtxLabel") + .field("krate", &self.krate.as_ref().and_then(|p| p.get_ident())) + .field("span", &self.span) + .field("task", &self.task) + .field("default", &self.default) + .finish() + } +} + +impl CtxLabel { + const ATTR_NAME: &'static str = "context"; + const CRATE_LABEL: &'static str = "crate"; + const TASK_LABEL: &'static str = "task"; + const DEFAULT_LABEL: &'static str = "default"; + const LABELS: &'static [&'static str] = + &[Self::CRATE_LABEL, Self::TASK_LABEL, Self::DEFAULT_LABEL]; + + pub(crate) fn parse(attrs: &[Attribute]) -> Result> { + let mut self_ = Self::default(); + + let mut found = false; + for attr in attrs { + if attr.path().is_ident(Self::ATTR_NAME) { + found = true; + self_.span = Some(attr.span()); + match attr.meta { + syn::Meta::Path(_) => { + // No values to parse. + break; + } + syn::Meta::NameValue(_) => { + return Err(syn::Error::new_spanned( + attr, + "Unexpected value, expected a list of labels", + )); + } + syn::Meta::List(_) => { + // Do nothing, parsing happens below. + } + } + attr.parse_nested_meta(|meta| { + let mut added = false; + for &label in Self::LABELS { + if meta.path.is_ident(label) { + match label { + Self::CRATE_LABEL => { + let value = meta.value()?; + let path: syn::Path = value.parse()?; + self_.krate = Some(path); + } + Self::TASK_LABEL => { + self_.task = true; + } + Self::DEFAULT_LABEL => { + self_.default = true; + } + _ => unreachable!(), + } + added = true; + break; + } + } + + if !added { + let err_msg = + format!("Unexpected token, supported labels: `{:?}`", Self::LABELS); + let err = syn::Error::new_spanned(attr, err_msg); + return Err(err); + } + Ok(()) + })?; + } + } + if !found { + return Ok(None); + } + Ok(Some(self_)) + } +} diff --git a/core/lib/node_framework_derive/src/lib.rs b/core/lib/node_framework_derive/src/lib.rs new file mode 100644 index 000000000000..867e0c75fa54 --- /dev/null +++ b/core/lib/node_framework_derive/src/lib.rs @@ -0,0 +1,39 @@ +extern crate proc_macro; + +use proc_macro::TokenStream; +use syn::{parse_macro_input, DeriveInput}; + +use crate::macro_impl::{MacroImpl, MacroKind}; + +pub(crate) mod helpers; +mod labels; +mod macro_impl; + +/// Derive macro for the `FromContext` trait. +/// Allows to automatically fetch all the resources and tasks from the context. +/// +/// See the trait documentation for more details. +#[proc_macro_derive(FromContext, attributes(context))] +pub fn from_context_derive(input: TokenStream) -> TokenStream { + // Parse the input tokens into a syntax tree + let input = parse_macro_input!(input as DeriveInput); + MacroImpl::parse(MacroKind::FromContext, input) + .and_then(|from_context| from_context.render()) + .unwrap_or_else(syn::Error::into_compile_error) + .into() +} + +/// Derive macro for the `IntoContext` trait. +/// Allows to automatically insert all the resources in tasks created by the wiring layer +/// into the context. +/// +/// See the trait documentation for more details. +#[proc_macro_derive(IntoContext, attributes(context))] +pub fn into_context_derive(input: TokenStream) -> TokenStream { + // Parse the input tokens into a syntax tree + let input = parse_macro_input!(input as DeriveInput); + MacroImpl::parse(MacroKind::IntoContext, input) + .and_then(|from_context| from_context.render()) + .unwrap_or_else(syn::Error::into_compile_error) + .into() +} diff --git a/core/lib/node_framework_derive/src/macro_impl.rs b/core/lib/node_framework_derive/src/macro_impl.rs new file mode 100644 index 000000000000..30532184fd2c --- /dev/null +++ b/core/lib/node_framework_derive/src/macro_impl.rs @@ -0,0 +1,190 @@ +use std::fmt; + +use quote::quote; +use syn::{DeriveInput, Result}; + +use crate::{helpers::Field, labels::CtxLabel}; + +#[derive(Debug)] +pub enum MacroKind { + FromContext, + IntoContext, +} + +impl fmt::Display for MacroKind { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Self::FromContext => write!(f, "FromContext"), + Self::IntoContext => write!(f, "IntoContext"), + } + } +} + +/// Parser and renderer for `FromContext` derive macro. +#[derive(Debug)] +pub struct MacroImpl { + macro_kind: MacroKind, + ctx: CtxLabel, + ident: syn::Ident, + fields: Vec, +} + +impl MacroImpl { + pub(crate) fn parse(macro_kind: MacroKind, input: DeriveInput) -> Result { + let ctx = CtxLabel::parse(&input.attrs)?.unwrap_or_default(); + let ident = input.ident; + if !input.generics.params.is_empty() { + return Err(syn::Error::new( + ident.span(), + format!("Generics are not supported for `{macro_kind}`"), + )); + } + let fields = match input.data { + syn::Data::Struct(data) => match data.fields { + syn::Fields::Named(fields) => fields + .named + .into_iter() + .map(|field| { + let ident = field.ident.unwrap(); + let ty = field.ty; + let label = CtxLabel::parse(&field.attrs)?.unwrap_or_default(); + Ok(Field { ident, ty, label }) + }) + .collect::>>()?, + _ => { + return Err(syn::Error::new( + ident.span(), + format!("Only named fields are supported for `{macro_kind}`"), + )) + } + }, + _ => { + return Err(syn::Error::new( + ident.span(), + format!("Only structures are supported for `{macro_kind}`"), + )) + } + }; + + Ok(Self { + macro_kind, + ctx, + ident, + fields, + }) + } + + pub fn render(self) -> Result { + match self.macro_kind { + MacroKind::FromContext => self.render_from_context(), + MacroKind::IntoContext => self.render_into_context(), + } + } + + fn crate_path(&self) -> proc_macro2::TokenStream { + if let Some(krate) = &self.ctx.krate { + quote! { #krate } + } else { + quote! { zksync_node_framework } + } + } + + fn render_from_context(self) -> Result { + let crate_path = self.crate_path(); + let ident = self.ident; + let mut fields = Vec::new(); + for field in self.fields { + let ty = field.ty; + let ident = field.ident; + let default = field.label.default; + + if field.label.krate.is_some() { + return Err(syn::Error::new_spanned( + ident, + "`crate` attribute is not allowed for fields", + )); + } + + if field.label.task { + return Err(syn::Error::new_spanned( + ident, + "`task` attribute is not allowed in `FromContext` macro", + )); + } + + let field = if default { + quote! { + #ident: ctx.get_resource_or_default::<#ty>() + } + } else { + quote! { + #ident: <#ty as #crate_path::service::FromContext>::from_context(ctx)? + } + }; + + fields.push(field) + } + + Ok(quote! { + impl #crate_path::FromContext for #ident { + fn from_context(ctx: &mut #crate_path::service::ServiceContext<'_>) -> std::result::Result { + Ok(Self { + #(#fields),* + }) + } + } + }) + } + + fn render_into_context(self) -> Result { + let crate_path = self.crate_path(); + let ident = self.ident; + let mut actions = Vec::new(); + for field in self.fields { + let ty = field.ty; + let ident = field.ident; + if field.label.default { + return Err(syn::Error::new_spanned( + ident, + "`default` attribute is not allowed in `IntoContext` macro", + )); + } + + if field.label.krate.is_some() { + return Err(syn::Error::new_spanned( + ident, + "`crate` attribute is not allowed for fields", + )); + } + + let action = if field.label.task { + // Check whether the task is an `Option`. + if let Some(_inner_ty) = crate::helpers::extract_option_inner_type(&ty) { + quote! { + if let Some(task) = self.#ident { + ctx.add_task(task); + } + } + } else { + quote! { + ctx.add_task(self.#ident); + } + } + } else { + quote! { + <#ty as #crate_path::service::IntoContext>::into_context(self.#ident, ctx)?; + } + }; + actions.push(action); + } + + Ok(quote! { + impl #crate_path::IntoContext for #ident { + fn into_context(self, ctx: &mut #crate_path::service::ServiceContext<'_>) -> std::result::Result<(), #crate_path::WiringError> { + #(#actions)* + Ok(()) + } + } + }) + } +} diff --git a/core/node/node_framework/Cargo.toml b/core/node/node_framework/Cargo.toml index 45e18fba3996..f6ce714178f8 100644 --- a/core/node/node_framework/Cargo.toml +++ b/core/node/node_framework/Cargo.toml @@ -10,6 +10,7 @@ keywords.workspace = true categories.workspace = true [dependencies] +zksync_node_framework_derive.workspace = true zksync_vlog.workspace = true zksync_types.workspace = true zksync_health_check.workspace = true @@ -59,3 +60,5 @@ ctrlc.workspace = true [dev-dependencies] zksync_env_config.workspace = true assert_matches.workspace = true +# For running UI tests for proc macro +trybuild.workspace = true diff --git a/core/node/node_framework/examples/showcase.rs b/core/node/node_framework/examples/showcase.rs index 67fa819880bc..24e3c04a1759 100644 --- a/core/node/node_framework/examples/showcase.rs +++ b/core/node/node_framework/examples/showcase.rs @@ -192,12 +192,12 @@ impl WiringLayer for TasksLayer { // We fetch the database resource from the context. // Note that we don't really care where it comes from or what's the actual implementation is. // We only care whether it's available and bail out if not. - let db = context.get_resource::().await?.0; + let db = context.get_resource::()?.0; let put_task = PutTask { db: db.clone() }; let check_task = CheckTask { db }; // These tasks will be launched by the service once the wiring process is complete. - context.add_task(Box::new(put_task)); - context.add_task(Box::new(check_task)); + context.add_task(put_task); + context.add_task(check_task); Ok(()) } } diff --git a/core/node/node_framework/src/implementations/layers/batch_status_updater.rs b/core/node/node_framework/src/implementations/layers/batch_status_updater.rs index a54950b1f95d..d2b522ad026c 100644 --- a/core/node/node_framework/src/implementations/layers/batch_status_updater.rs +++ b/core/node/node_framework/src/implementations/layers/batch_status_updater.rs @@ -9,8 +9,25 @@ use crate::{ service::{ServiceContext, StopReceiver}, task::{Task, TaskId}, wiring_layer::{WiringError, WiringLayer}, + FromContext, IntoContext, }; +#[derive(Debug, FromContext)] +#[context(crate = crate)] +struct LayerInput { + pool: PoolResource, + client: MainNodeClientResource, + #[context(default)] + app_health: AppHealthCheckResource, +} + +#[derive(Debug, IntoContext)] +#[context(crate = crate)] +struct LayerOutput { + #[context(task)] + updater: BatchStatusUpdater, +} + /// Wiring layer for `BatchStatusUpdater`, part of the external node. /// /// ## Requests resources @@ -32,19 +49,23 @@ impl WiringLayer for BatchStatusUpdaterLayer { } async fn wire(self: Box, mut context: ServiceContext<'_>) -> Result<(), WiringError> { - let pool = context.get_resource::>().await?; - let MainNodeClientResource(client) = context.get_resource().await?; + let LayerInput { + pool, + client, + app_health, + } = LayerInput::from_context(&mut context)?; - let updater = BatchStatusUpdater::new(client, pool.get().await?); + let updater = BatchStatusUpdater::new(client.0, pool.get().await?); // Insert healthcheck - let AppHealthCheckResource(app_health) = context.get_resource_or_default().await; app_health + .0 .insert_component(updater.health_check()) .map_err(WiringError::internal)?; // Insert task - context.add_task(Box::new(updater)); + let layer_output = LayerOutput { updater }; + layer_output.into_context(&mut context)?; Ok(()) } diff --git a/core/node/node_framework/src/implementations/layers/circuit_breaker_checker.rs b/core/node/node_framework/src/implementations/layers/circuit_breaker_checker.rs index d7334147bdc2..14ac5591840c 100644 --- a/core/node/node_framework/src/implementations/layers/circuit_breaker_checker.rs +++ b/core/node/node_framework/src/implementations/layers/circuit_breaker_checker.rs @@ -32,9 +32,7 @@ impl WiringLayer for CircuitBreakerCheckerLayer { async fn wire(self: Box, mut node: ServiceContext<'_>) -> Result<(), WiringError> { // Get resources. - let circuit_breaker_resource = node - .get_resource_or_default::() - .await; + let circuit_breaker_resource = node.get_resource_or_default::(); let circuit_breaker_checker = CircuitBreakerChecker::new(circuit_breaker_resource.breakers, self.0.sync_interval()); @@ -44,7 +42,7 @@ impl WiringLayer for CircuitBreakerCheckerLayer { circuit_breaker_checker, }; - node.add_task(Box::new(task)); + node.add_task(task); Ok(()) } } diff --git a/core/node/node_framework/src/implementations/layers/commitment_generator.rs b/core/node/node_framework/src/implementations/layers/commitment_generator.rs index 19b74a3676cc..b2f8cd2d30c2 100644 --- a/core/node/node_framework/src/implementations/layers/commitment_generator.rs +++ b/core/node/node_framework/src/implementations/layers/commitment_generator.rs @@ -52,7 +52,7 @@ impl WiringLayer for CommitmentGeneratorLayer { } async fn wire(self: Box, mut context: ServiceContext<'_>) -> Result<(), WiringError> { - let pool_resource = context.get_resource::>().await?; + let pool_resource = context.get_resource::>()?; let pool_size = self .max_parallelism @@ -65,14 +65,14 @@ impl WiringLayer for CommitmentGeneratorLayer { commitment_generator.set_max_parallelism(max_parallelism); } - let AppHealthCheckResource(app_health) = context.get_resource_or_default().await; + let AppHealthCheckResource(app_health) = context.get_resource_or_default(); app_health .insert_component(commitment_generator.health_check()) .map_err(WiringError::internal)?; - context.add_task(Box::new(CommitmentGeneratorTask { + context.add_task(CommitmentGeneratorTask { commitment_generator, - })); + }); Ok(()) } diff --git a/core/node/node_framework/src/implementations/layers/consensus.rs b/core/node/node_framework/src/implementations/layers/consensus.rs index 421e13115ef2..14b20aaa3c38 100644 --- a/core/node/node_framework/src/implementations/layers/consensus.rs +++ b/core/node/node_framework/src/implementations/layers/consensus.rs @@ -53,8 +53,7 @@ impl WiringLayer for ConsensusLayer { async fn wire(self: Box, mut context: ServiceContext<'_>) -> Result<(), WiringError> { let pool = context - .get_resource::>() - .await? + .get_resource::>()? .get() .await?; @@ -71,14 +70,13 @@ impl WiringLayer for ConsensusLayer { secrets, pool, }; - context.add_task(Box::new(task)); + context.add_task(task); } Mode::External => { - let main_node_client = context.get_resource::().await?.0; - let sync_state = context.get_resource::().await?.0; + let main_node_client = context.get_resource::()?.0; + let sync_state = context.get_resource::()?.0; let action_queue_sender = context - .get_resource::() - .await? + .get_resource::()? .0 .take() .ok_or_else(|| { @@ -108,7 +106,7 @@ impl WiringLayer for ConsensusLayer { sync_state, action_queue_sender, }; - context.add_task(Box::new(task)); + context.add_task(task); } } Ok(()) diff --git a/core/node/node_framework/src/implementations/layers/consistency_checker.rs b/core/node/node_framework/src/implementations/layers/consistency_checker.rs index 165bcf690b00..d9b5582f76b7 100644 --- a/core/node/node_framework/src/implementations/layers/consistency_checker.rs +++ b/core/node/node_framework/src/implementations/layers/consistency_checker.rs @@ -52,9 +52,9 @@ impl WiringLayer for ConsistencyCheckerLayer { async fn wire(self: Box, mut context: ServiceContext<'_>) -> Result<(), WiringError> { // Get resources. - let l1_client = context.get_resource::().await?.0; + let l1_client = context.get_resource::()?.0; - let pool_resource = context.get_resource::>().await?; + let pool_resource = context.get_resource::>()?; let singleton_pool = pool_resource.get_singleton().await?; let consistency_checker = ConsistencyChecker::new( @@ -66,13 +66,13 @@ impl WiringLayer for ConsistencyCheckerLayer { .map_err(WiringError::Internal)? .with_diamond_proxy_addr(self.diamond_proxy_addr); - let AppHealthCheckResource(app_health) = context.get_resource_or_default().await; + let AppHealthCheckResource(app_health) = context.get_resource_or_default(); app_health .insert_component(consistency_checker.health_check().clone()) .map_err(WiringError::internal)?; // Create and add tasks. - context.add_task(Box::new(consistency_checker)); + context.add_task(consistency_checker); Ok(()) } diff --git a/core/node/node_framework/src/implementations/layers/contract_verification_api.rs b/core/node/node_framework/src/implementations/layers/contract_verification_api.rs index 519df8e76268..94264fc27411 100644 --- a/core/node/node_framework/src/implementations/layers/contract_verification_api.rs +++ b/core/node/node_framework/src/implementations/layers/contract_verification_api.rs @@ -31,20 +31,18 @@ impl WiringLayer for ContractVerificationApiLayer { async fn wire(self: Box, mut context: ServiceContext<'_>) -> Result<(), WiringError> { let master_pool = context - .get_resource::>() - .await? + .get_resource::>()? .get() .await?; let replica_pool = context - .get_resource::>() - .await? + .get_resource::>()? .get() .await?; - context.add_task(Box::new(ContractVerificationApiTask { + context.add_task(ContractVerificationApiTask { master_pool, replica_pool, config: self.0, - })); + }); Ok(()) } } diff --git a/core/node/node_framework/src/implementations/layers/eth_sender.rs b/core/node/node_framework/src/implementations/layers/eth_sender.rs index 16ab8b8135e3..6a9c0894b432 100644 --- a/core/node/node_framework/src/implementations/layers/eth_sender.rs +++ b/core/node/node_framework/src/implementations/layers/eth_sender.rs @@ -54,16 +54,13 @@ impl WiringLayer for EthTxManagerLayer { async fn wire(self: Box, mut context: ServiceContext<'_>) -> Result<(), WiringError> { // Get resources. - let master_pool_resource = context.get_resource::>().await?; + let master_pool_resource = context.get_resource::>()?; let master_pool = master_pool_resource.get().await.unwrap(); - let replica_pool_resource = context.get_resource::>().await?; + let replica_pool_resource = context.get_resource::>()?; let replica_pool = replica_pool_resource.get().await.unwrap(); - let eth_client = context.get_resource::().await?.0; - let eth_client_blobs = match context - .get_resource::() - .await - { + let eth_client = context.get_resource::()?.0; + let eth_client_blobs = match context.get_resource::() { Ok(BoundEthInterfaceForBlobsResource(client)) => Some(client), Err(WiringError::ResourceLacking { .. }) => None, Err(err) => return Err(err), @@ -71,7 +68,7 @@ impl WiringLayer for EthTxManagerLayer { let config = self.eth_sender_config.sender.context("sender")?; - let gas_adjuster = context.get_resource::().await?.0; + let gas_adjuster = context.get_resource::()?.0; let eth_tx_manager_actor = EthTxManager::new( master_pool, @@ -81,10 +78,10 @@ impl WiringLayer for EthTxManagerLayer { eth_client_blobs, ); - context.add_task(Box::new(eth_tx_manager_actor)); + context.add_task(eth_tx_manager_actor); // Insert circuit breaker. - let CircuitBreakersResource { breakers } = context.get_resource_or_default().await; + let CircuitBreakersResource { breakers } = context.get_resource_or_default(); breakers .insert(Box::new(FailedL1TransactionChecker { pool: replica_pool })) .await; @@ -143,21 +140,18 @@ impl WiringLayer for EthTxAggregatorLayer { async fn wire(self: Box, mut context: ServiceContext<'_>) -> Result<(), WiringError> { // Get resources. - let master_pool_resource = context.get_resource::>().await?; + let master_pool_resource = context.get_resource::>()?; let master_pool = master_pool_resource.get().await.unwrap(); - let replica_pool_resource = context.get_resource::>().await?; + let replica_pool_resource = context.get_resource::>()?; let replica_pool = replica_pool_resource.get().await.unwrap(); - let eth_client = context.get_resource::().await?.0; - let eth_client_blobs = match context - .get_resource::() - .await - { + let eth_client = context.get_resource::()?.0; + let eth_client_blobs = match context.get_resource::() { Ok(BoundEthInterfaceForBlobsResource(client)) => Some(client), Err(WiringError::ResourceLacking { .. }) => None, Err(err) => return Err(err), }; - let object_store = context.get_resource::().await?.0; + let object_store = context.get_resource::()?.0; // Create and add tasks. let eth_client_blobs_addr = eth_client_blobs @@ -185,10 +179,10 @@ impl WiringLayer for EthTxAggregatorLayer { ) .await; - context.add_task(Box::new(eth_tx_aggregator_actor)); + context.add_task(eth_tx_aggregator_actor); // Insert circuit breaker. - let CircuitBreakersResource { breakers } = context.get_resource_or_default().await; + let CircuitBreakersResource { breakers } = context.get_resource_or_default(); breakers .insert(Box::new(FailedL1TransactionChecker { pool: replica_pool })) .await; diff --git a/core/node/node_framework/src/implementations/layers/eth_watch.rs b/core/node/node_framework/src/implementations/layers/eth_watch.rs index d498064a4358..8c7fe4269586 100644 --- a/core/node/node_framework/src/implementations/layers/eth_watch.rs +++ b/core/node/node_framework/src/implementations/layers/eth_watch.rs @@ -51,10 +51,10 @@ impl WiringLayer for EthWatchLayer { } async fn wire(self: Box, mut context: ServiceContext<'_>) -> Result<(), WiringError> { - let pool_resource = context.get_resource::>().await?; + let pool_resource = context.get_resource::>()?; let main_pool = pool_resource.get().await.unwrap(); - let client = context.get_resource::().await?.0; + let client = context.get_resource::()?.0; let eth_client = EthHttpQueryClient::new( client, @@ -65,13 +65,13 @@ impl WiringLayer for EthWatchLayer { self.contracts_config.governance_addr, self.eth_watch_config.confirmations_for_eth_event, ); - context.add_task(Box::new(EthWatchTask { + context.add_task(EthWatchTask { main_pool, client: eth_client, governance_contract: governance_contract(), diamond_proxy_address: self.contracts_config.diamond_proxy_addr, poll_interval: self.eth_watch_config.poll_interval(), - })); + }); Ok(()) } diff --git a/core/node/node_framework/src/implementations/layers/healtcheck_server.rs b/core/node/node_framework/src/implementations/layers/healtcheck_server.rs index 3982044c3f96..126b7c0a2d4d 100644 --- a/core/node/node_framework/src/implementations/layers/healtcheck_server.rs +++ b/core/node/node_framework/src/implementations/layers/healtcheck_server.rs @@ -34,14 +34,14 @@ impl WiringLayer for HealthCheckLayer { } async fn wire(self: Box, mut node: ServiceContext<'_>) -> Result<(), WiringError> { - let AppHealthCheckResource(app_health_check) = node.get_resource_or_default().await; + let AppHealthCheckResource(app_health_check) = node.get_resource_or_default(); let task = HealthCheckTask { config: self.0, app_health_check, }; - node.add_task(Box::new(task)); + node.add_task(task); Ok(()) } } diff --git a/core/node/node_framework/src/implementations/layers/house_keeper.rs b/core/node/node_framework/src/implementations/layers/house_keeper.rs index feaee5ed2e3b..f14a01587f71 100644 --- a/core/node/node_framework/src/implementations/layers/house_keeper.rs +++ b/core/node/node_framework/src/implementations/layers/house_keeper.rs @@ -75,10 +75,10 @@ impl WiringLayer for HouseKeeperLayer { async fn wire(self: Box, mut context: ServiceContext<'_>) -> Result<(), WiringError> { // Initialize resources - let replica_pool_resource = context.get_resource::>().await?; + let replica_pool_resource = context.get_resource::>()?; let replica_pool = replica_pool_resource.get().await?; - let prover_pool_resource = context.get_resource::>().await?; + let prover_pool_resource = context.get_resource::>()?; let prover_pool = prover_pool_resource.get().await?; // Initialize and add tasks @@ -87,9 +87,9 @@ impl WiringLayer for HouseKeeperLayer { .l1_batch_metrics_reporting_interval_ms, replica_pool.clone(), ); - context.add_task(Box::new(L1BatchMetricsReporterTask { + context.add_task(L1BatchMetricsReporterTask { l1_batch_metrics_reporter, - })); + }); let fri_prover_job_retry_manager = FriProverJobRetryManager::new( self.fri_prover_config.max_attempts, @@ -97,9 +97,9 @@ impl WiringLayer for HouseKeeperLayer { self.house_keeper_config.prover_job_retrying_interval_ms, prover_pool.clone(), ); - context.add_task(Box::new(FriProverJobRetryManagerTask { + context.add_task(FriProverJobRetryManagerTask { fri_prover_job_retry_manager, - })); + }); let fri_witness_gen_job_retry_manager = FriWitnessGeneratorJobRetryManager::new( self.fri_witness_generator_config.max_attempts, @@ -109,26 +109,26 @@ impl WiringLayer for HouseKeeperLayer { .witness_generator_job_retrying_interval_ms, prover_pool.clone(), ); - context.add_task(Box::new(FriWitnessGeneratorJobRetryManagerTask { + context.add_task(FriWitnessGeneratorJobRetryManagerTask { fri_witness_gen_job_retry_manager, - })); + }); let waiting_to_queued_fri_witness_job_mover = WaitingToQueuedFriWitnessJobMover::new( self.house_keeper_config.witness_job_moving_interval_ms, prover_pool.clone(), ); - context.add_task(Box::new(WaitingToQueuedFriWitnessJobMoverTask { + context.add_task(WaitingToQueuedFriWitnessJobMoverTask { waiting_to_queued_fri_witness_job_mover, - })); + }); if let Some((archiving_interval, archive_after)) = self.house_keeper_config.prover_job_archiver_params() { let fri_prover_job_archiver = FriProverJobsArchiver::new(prover_pool.clone(), archiving_interval, archive_after); - context.add_task(Box::new(FriProverJobArchiverTask { + context.add_task(FriProverJobArchiverTask { fri_prover_job_archiver, - })); + }); } if let Some((archiving_interval, archive_after)) = @@ -136,9 +136,9 @@ impl WiringLayer for HouseKeeperLayer { { let fri_prover_gpu_archiver = FriGpuProverArchiver::new(prover_pool.clone(), archiving_interval, archive_after); - context.add_task(Box::new(FriProverGpuArchiverTask { + context.add_task(FriProverGpuArchiverTask { fri_prover_gpu_archiver, - })); + }); } let fri_witness_generator_stats_reporter = FriWitnessGeneratorQueueReporter::new( @@ -146,9 +146,9 @@ impl WiringLayer for HouseKeeperLayer { self.house_keeper_config .witness_generator_stats_reporting_interval_ms, ); - context.add_task(Box::new(FriWitnessGeneratorStatsReporterTask { + context.add_task(FriWitnessGeneratorStatsReporterTask { fri_witness_generator_stats_reporter, - })); + }); let fri_prover_stats_reporter = FriProverQueueReporter::new( self.house_keeper_config.prover_stats_reporting_interval_ms, @@ -156,18 +156,18 @@ impl WiringLayer for HouseKeeperLayer { replica_pool.clone(), self.fri_prover_group_config, ); - context.add_task(Box::new(FriProverStatsReporterTask { + context.add_task(FriProverStatsReporterTask { fri_prover_stats_reporter, - })); + }); let fri_proof_compressor_stats_reporter = FriProofCompressorQueueReporter::new( self.house_keeper_config .proof_compressor_stats_reporting_interval_ms, prover_pool.clone(), ); - context.add_task(Box::new(FriProofCompressorStatsReporterTask { + context.add_task(FriProofCompressorStatsReporterTask { fri_proof_compressor_stats_reporter, - })); + }); let fri_proof_compressor_retry_manager = FriProofCompressorJobRetryManager::new( self.fri_proof_compressor_config.max_attempts, @@ -176,9 +176,9 @@ impl WiringLayer for HouseKeeperLayer { .proof_compressor_job_retrying_interval_ms, prover_pool.clone(), ); - context.add_task(Box::new(FriProofCompressorJobRetryManagerTask { + context.add_task(FriProofCompressorJobRetryManagerTask { fri_proof_compressor_retry_manager, - })); + }); Ok(()) } diff --git a/core/node/node_framework/src/implementations/layers/l1_batch_commitment_mode_validation.rs b/core/node/node_framework/src/implementations/layers/l1_batch_commitment_mode_validation.rs index 3bb82dde98b6..893c8d361164 100644 --- a/core/node/node_framework/src/implementations/layers/l1_batch_commitment_mode_validation.rs +++ b/core/node/node_framework/src/implementations/layers/l1_batch_commitment_mode_validation.rs @@ -43,14 +43,14 @@ impl WiringLayer for L1BatchCommitmentModeValidationLayer { } async fn wire(self: Box, mut context: ServiceContext<'_>) -> Result<(), WiringError> { - let EthInterfaceResource(query_client) = context.get_resource().await?; + let EthInterfaceResource(query_client) = context.get_resource()?; let task = L1BatchCommitmentModeValidationTask::new( self.diamond_proxy_addr, self.l1_batch_commit_data_generator_mode, query_client, ); - context.add_task(Box::new(task)); + context.add_task(task); Ok(()) } diff --git a/core/node/node_framework/src/implementations/layers/l1_gas.rs b/core/node/node_framework/src/implementations/layers/l1_gas.rs index c8b51d62c34e..d7ece6331882 100644 --- a/core/node/node_framework/src/implementations/layers/l1_gas.rs +++ b/core/node/node_framework/src/implementations/layers/l1_gas.rs @@ -64,7 +64,7 @@ impl WiringLayer for SequencerL1GasLayer { } async fn wire(self: Box, mut context: ServiceContext<'_>) -> Result<(), WiringError> { - let client = context.get_resource::().await?.0; + let client = context.get_resource::()?.0; let adjuster = GasAdjuster::new( client, self.gas_adjuster_config, @@ -83,7 +83,7 @@ impl WiringLayer for SequencerL1GasLayer { context.insert_resource(L1TxParamsResource(gas_adjuster.clone()))?; - context.add_task(Box::new(GasAdjusterTask { gas_adjuster })); + context.add_task(GasAdjusterTask { gas_adjuster }); Ok(()) } } diff --git a/core/node/node_framework/src/implementations/layers/main_node_client.rs b/core/node/node_framework/src/implementations/layers/main_node_client.rs index a07b0eaaec7b..d875a2bc07f8 100644 --- a/core/node/node_framework/src/implementations/layers/main_node_client.rs +++ b/core/node/node_framework/src/implementations/layers/main_node_client.rs @@ -56,7 +56,7 @@ impl WiringLayer for MainNodeClientLayer { context.insert_resource(MainNodeClientResource(client.clone()))?; // Insert healthcheck - let AppHealthCheckResource(app_health) = context.get_resource_or_default().await; + let AppHealthCheckResource(app_health) = context.get_resource_or_default(); app_health .insert_custom_component(Arc::new(MainNodeHealthCheck::from(client))) .map_err(WiringError::internal)?; diff --git a/core/node/node_framework/src/implementations/layers/main_node_fee_params_fetcher.rs b/core/node/node_framework/src/implementations/layers/main_node_fee_params_fetcher.rs index 79596c0f8cf7..06db8e69f194 100644 --- a/core/node/node_framework/src/implementations/layers/main_node_fee_params_fetcher.rs +++ b/core/node/node_framework/src/implementations/layers/main_node_fee_params_fetcher.rs @@ -35,10 +35,10 @@ impl WiringLayer for MainNodeFeeParamsFetcherLayer { } async fn wire(self: Box, mut context: ServiceContext<'_>) -> Result<(), WiringError> { - let MainNodeClientResource(main_node_client) = context.get_resource().await?; + let MainNodeClientResource(main_node_client) = context.get_resource()?; let fetcher = Arc::new(MainNodeFeeParamsFetcher::new(main_node_client)); context.insert_resource(FeeInputResource(fetcher.clone()))?; - context.add_task(Box::new(MainNodeFeeParamsFetcherTask { fetcher })); + context.add_task(MainNodeFeeParamsFetcherTask { fetcher }); Ok(()) } } diff --git a/core/node/node_framework/src/implementations/layers/metadata_calculator.rs b/core/node/node_framework/src/implementations/layers/metadata_calculator.rs index 9185aeea553c..41e7561b70f3 100644 --- a/core/node/node_framework/src/implementations/layers/metadata_calculator.rs +++ b/core/node/node_framework/src/implementations/layers/metadata_calculator.rs @@ -74,20 +74,19 @@ impl WiringLayer for MetadataCalculatorLayer { } async fn wire(self: Box, mut context: ServiceContext<'_>) -> Result<(), WiringError> { - let pool = context.get_resource::>().await?; + let pool = context.get_resource::>()?; let main_pool = pool.get().await?; // The number of connections in a recovery pool is based on the mainnet recovery runs. It doesn't need // to be particularly accurate at this point, since the main node isn't expected to recover from a snapshot. let recovery_pool = context - .get_resource::>() - .await? + .get_resource::>()? .get_custom(10) .await?; let object_store = match self.config.mode { MerkleTreeMode::Lightweight => None, MerkleTreeMode::Full => { - let store = context.get_resource::().await?; + let store = context.get_resource::()?; Some(store) } }; @@ -100,7 +99,7 @@ impl WiringLayer for MetadataCalculatorLayer { .await? .with_recovery_pool(recovery_pool); - let AppHealthCheckResource(app_health) = context.get_resource_or_default().await; + let AppHealthCheckResource(app_health) = context.get_resource_or_default(); app_health .insert_custom_component(Arc::new(metadata_calculator.tree_health_check())) .map_err(WiringError::internal)?; @@ -108,14 +107,14 @@ impl WiringLayer for MetadataCalculatorLayer { if let Some(tree_api_config) = self.tree_api_config { let bind_addr = (Ipv4Addr::UNSPECIFIED, tree_api_config.port).into(); let tree_reader = metadata_calculator.tree_reader(); - context.add_task(Box::new(TreeApiTask { + context.add_task(TreeApiTask { bind_addr, tree_reader, - })); + }); } if let Some(pruning_removal_delay) = self.pruning_config { - let pruning_task = Box::new(metadata_calculator.pruning_task(pruning_removal_delay)); + let pruning_task = metadata_calculator.pruning_task(pruning_removal_delay); app_health .insert_component(pruning_task.health_check()) .map_err(|err| WiringError::Internal(err.into()))?; @@ -126,7 +125,7 @@ impl WiringLayer for MetadataCalculatorLayer { metadata_calculator.tree_reader(), )))?; - context.add_task(Box::new(metadata_calculator)); + context.add_task(metadata_calculator); context.add_shutdown_hook("rocksdb_terminaton", async { // Wait for all the instances of RocksDB to be destroyed. diff --git a/core/node/node_framework/src/implementations/layers/pk_signing_eth_client.rs b/core/node/node_framework/src/implementations/layers/pk_signing_eth_client.rs index c923780e9098..74eb5e3bae35 100644 --- a/core/node/node_framework/src/implementations/layers/pk_signing_eth_client.rs +++ b/core/node/node_framework/src/implementations/layers/pk_signing_eth_client.rs @@ -61,7 +61,7 @@ impl WiringLayer for PKSigningEthClientLayer { .gas_adjuster .as_ref() .context("gas_adjuster config is missing")?; - let EthInterfaceResource(query_client) = context.get_resource().await?; + let EthInterfaceResource(query_client) = context.get_resource()?; let signing_client = PKSigningClient::new_raw( private_key.clone(), diff --git a/core/node/node_framework/src/implementations/layers/pools_layer.rs b/core/node/node_framework/src/implementations/layers/pools_layer.rs index b4cde04c6192..880b793115b7 100644 --- a/core/node/node_framework/src/implementations/layers/pools_layer.rs +++ b/core/node/node_framework/src/implementations/layers/pools_layer.rs @@ -144,19 +144,17 @@ impl WiringLayer for PoolsLayer { // Insert health checks for the core pool. let connection_pool = if self.with_replica { context - .get_resource::>() - .await? + .get_resource::>()? .get() .await? } else { context - .get_resource::>() - .await? + .get_resource::>()? .get() .await? }; let db_health_check = ConnectionPoolHealthCheck::new(connection_pool); - let AppHealthCheckResource(app_health) = context.get_resource_or_default().await; + let AppHealthCheckResource(app_health) = context.get_resource_or_default(); app_health .insert_custom_component(Arc::new(db_health_check)) .map_err(WiringError::internal)?; diff --git a/core/node/node_framework/src/implementations/layers/postgres_metrics.rs b/core/node/node_framework/src/implementations/layers/postgres_metrics.rs index b0690880a4c1..9b290b76cad0 100644 --- a/core/node/node_framework/src/implementations/layers/postgres_metrics.rs +++ b/core/node/node_framework/src/implementations/layers/postgres_metrics.rs @@ -30,9 +30,9 @@ impl WiringLayer for PostgresMetricsLayer { } async fn wire(self: Box, mut context: ServiceContext<'_>) -> Result<(), WiringError> { - let replica_pool_resource = context.get_resource::>().await?; + let replica_pool_resource = context.get_resource::>()?; let pool_for_metrics = replica_pool_resource.get_singleton().await?; - context.add_task(Box::new(PostgresMetricsScrapingTask { pool_for_metrics })); + context.add_task(PostgresMetricsScrapingTask { pool_for_metrics }); Ok(()) } diff --git a/core/node/node_framework/src/implementations/layers/prometheus_exporter.rs b/core/node/node_framework/src/implementations/layers/prometheus_exporter.rs index 91b205f38cd8..3a5b0f2dd93b 100644 --- a/core/node/node_framework/src/implementations/layers/prometheus_exporter.rs +++ b/core/node/node_framework/src/implementations/layers/prometheus_exporter.rs @@ -36,15 +36,15 @@ impl WiringLayer for PrometheusExporterLayer { let (prometheus_health_check, prometheus_health_updater) = ReactiveHealthCheck::new("prometheus_exporter"); - let AppHealthCheckResource(app_health) = node.get_resource_or_default().await; + let AppHealthCheckResource(app_health) = node.get_resource_or_default(); app_health .insert_component(prometheus_health_check) .map_err(WiringError::internal)?; - let task = Box::new(PrometheusExporterTask { + let task = PrometheusExporterTask { config: self.0, prometheus_health_updater, - }); + }; node.add_task(task); Ok(()) diff --git a/core/node/node_framework/src/implementations/layers/proof_data_handler.rs b/core/node/node_framework/src/implementations/layers/proof_data_handler.rs index 07213edb18cf..b7c543f3d4ab 100644 --- a/core/node/node_framework/src/implementations/layers/proof_data_handler.rs +++ b/core/node/node_framework/src/implementations/layers/proof_data_handler.rs @@ -50,17 +50,17 @@ impl WiringLayer for ProofDataHandlerLayer { } async fn wire(self: Box, mut context: ServiceContext<'_>) -> Result<(), WiringError> { - let pool_resource = context.get_resource::>().await?; + let pool_resource = context.get_resource::>()?; let main_pool = pool_resource.get().await.unwrap(); - let object_store = context.get_resource::().await?; + let object_store = context.get_resource::()?; - context.add_task(Box::new(ProofDataHandlerTask { + context.add_task(ProofDataHandlerTask { proof_data_handler_config: self.proof_data_handler_config, blob_store: object_store.0, main_pool, commitment_mode: self.commitment_mode, - })); + }); Ok(()) } diff --git a/core/node/node_framework/src/implementations/layers/pruning.rs b/core/node/node_framework/src/implementations/layers/pruning.rs index 8747901dc9d8..c5acefcbebdd 100644 --- a/core/node/node_framework/src/implementations/layers/pruning.rs +++ b/core/node/node_framework/src/implementations/layers/pruning.rs @@ -50,7 +50,7 @@ impl WiringLayer for PruningLayer { } async fn wire(self: Box, mut context: ServiceContext<'_>) -> Result<(), WiringError> { - let pool_resource = context.get_resource::>().await?; + let pool_resource = context.get_resource::>()?; let main_pool = pool_resource.get().await?; let db_pruner = DbPruner::new( @@ -62,12 +62,12 @@ impl WiringLayer for PruningLayer { main_pool, ); - let AppHealthCheckResource(app_health) = context.get_resource_or_default().await; + let AppHealthCheckResource(app_health) = context.get_resource_or_default(); app_health .insert_component(db_pruner.health_check()) .map_err(WiringError::internal)?; - context.add_task(Box::new(db_pruner)); + context.add_task(db_pruner); Ok(()) } diff --git a/core/node/node_framework/src/implementations/layers/reorg_detector_checker.rs b/core/node/node_framework/src/implementations/layers/reorg_detector_checker.rs index a55c8a5e74ab..0d846501a568 100644 --- a/core/node/node_framework/src/implementations/layers/reorg_detector_checker.rs +++ b/core/node/node_framework/src/implementations/layers/reorg_detector_checker.rs @@ -38,16 +38,16 @@ impl WiringLayer for ReorgDetectorCheckerLayer { async fn wire(self: Box, mut context: ServiceContext<'_>) -> Result<(), WiringError> { // Get resources. - let main_node_client = context.get_resource::().await?.0; + let main_node_client = context.get_resource::()?.0; - let pool_resource = context.get_resource::>().await?; + let pool_resource = context.get_resource::>()?; let pool = pool_resource.get().await?; // Create and insert precondition. - context.add_task(Box::new(CheckerPrecondition { + context.add_task(CheckerPrecondition { pool: pool.clone(), reorg_detector: ReorgDetector::new(main_node_client, pool), - })); + }); Ok(()) } diff --git a/core/node/node_framework/src/implementations/layers/reorg_detector_runner.rs b/core/node/node_framework/src/implementations/layers/reorg_detector_runner.rs index ab0995f10211..04ebb9ec3c14 100644 --- a/core/node/node_framework/src/implementations/layers/reorg_detector_runner.rs +++ b/core/node/node_framework/src/implementations/layers/reorg_detector_runner.rs @@ -38,18 +38,18 @@ impl WiringLayer for ReorgDetectorRunnerLayer { async fn wire(self: Box, mut context: ServiceContext<'_>) -> Result<(), WiringError> { // Get resources. - let main_node_client = context.get_resource::().await?.0; + let main_node_client = context.get_resource::()?.0; - let pool_resource = context.get_resource::>().await?; + let pool_resource = context.get_resource::>()?; let pool = pool_resource.get().await?; - let reverter = context.get_resource::().await?.0; + let reverter = context.get_resource::()?.0; // Create and insert task. - context.add_task(Box::new(RunnerUnconstrainedOneshotTask { + context.add_task(RunnerUnconstrainedOneshotTask { reorg_detector: ReorgDetector::new(main_node_client, pool), reverter, - })); + }); Ok(()) } diff --git a/core/node/node_framework/src/implementations/layers/sigint.rs b/core/node/node_framework/src/implementations/layers/sigint.rs index 5c1fab73fa16..9df13285b3a1 100644 --- a/core/node/node_framework/src/implementations/layers/sigint.rs +++ b/core/node/node_framework/src/implementations/layers/sigint.rs @@ -23,7 +23,7 @@ impl WiringLayer for SigintHandlerLayer { async fn wire(self: Box, mut node: ServiceContext<'_>) -> Result<(), WiringError> { // SIGINT may happen at any time, so we must handle it as soon as it happens. - node.add_task(Box::new(SigintHandlerTask)); + node.add_task(SigintHandlerTask); Ok(()) } } diff --git a/core/node/node_framework/src/implementations/layers/state_keeper/external_io.rs b/core/node/node_framework/src/implementations/layers/state_keeper/external_io.rs index c875ff10b0ea..e923bc9f567a 100644 --- a/core/node/node_framework/src/implementations/layers/state_keeper/external_io.rs +++ b/core/node/node_framework/src/implementations/layers/state_keeper/external_io.rs @@ -50,8 +50,8 @@ impl WiringLayer for ExternalIOLayer { async fn wire(self: Box, mut context: ServiceContext<'_>) -> Result<(), WiringError> { // Fetch required resources. - let master_pool = context.get_resource::>().await?; - let MainNodeClientResource(main_node_client) = context.get_resource().await?; + let master_pool = context.get_resource::>()?; + let MainNodeClientResource(main_node_client) = context.get_resource()?; // Create `SyncState` resource. let sync_state = SyncState::default(); diff --git a/core/node/node_framework/src/implementations/layers/state_keeper/mempool_io.rs b/core/node/node_framework/src/implementations/layers/state_keeper/mempool_io.rs index 2951d5edc9e9..05eff33303a5 100644 --- a/core/node/node_framework/src/implementations/layers/state_keeper/mempool_io.rs +++ b/core/node/node_framework/src/implementations/layers/state_keeper/mempool_io.rs @@ -27,8 +27,6 @@ use crate::{ /// - `FeeInputResource` /// - `PoolResource` /// -/// - `AppHealthCheckResource` (adds a health check) -/// /// ## Adds resources /// /// - `StateKeeperIOResource` @@ -37,7 +35,6 @@ use crate::{ /// ## Adds tasks /// /// - `MempoolFetcherTask` -/// - `TaskTypeName2` #[derive(Debug)] pub struct MempoolIOLayer { zksync_network_id: L2ChainId, @@ -87,8 +84,8 @@ impl WiringLayer for MempoolIOLayer { async fn wire(self: Box, mut context: ServiceContext<'_>) -> Result<(), WiringError> { // Fetch required resources. - let batch_fee_input_provider = context.get_resource::().await?.0; - let master_pool = context.get_resource::>().await?; + let batch_fee_input_provider = context.get_resource::()?.0; + let master_pool = context.get_resource::>()?; // Create mempool fetcher task. let mempool_guard = self.build_mempool_guard(&master_pool).await?; @@ -102,7 +99,7 @@ impl WiringLayer for MempoolIOLayer { &self.mempool_config, mempool_fetcher_pool, ); - context.add_task(Box::new(MempoolFetcherTask(mempool_fetcher))); + context.add_task(MempoolFetcherTask(mempool_fetcher)); // Create mempool IO resource. let mempool_db_pool = master_pool diff --git a/core/node/node_framework/src/implementations/layers/state_keeper/mod.rs b/core/node/node_framework/src/implementations/layers/state_keeper/mod.rs index 3627779c8695..15237a5b3bd5 100644 --- a/core/node/node_framework/src/implementations/layers/state_keeper/mod.rs +++ b/core/node/node_framework/src/implementations/layers/state_keeper/mod.rs @@ -66,40 +66,37 @@ impl WiringLayer for StateKeeperLayer { async fn wire(self: Box, mut context: ServiceContext<'_>) -> Result<(), WiringError> { let io = context - .get_resource::() - .await? + .get_resource::()? .0 .take() .context("StateKeeperIO was provided but taken by some other task")?; let batch_executor_base = context - .get_resource::() - .await? + .get_resource::()? .0 .take() .context("L1BatchExecutorBuilder was provided but taken by some other task")?; let output_handler = context - .get_resource::() - .await? + .get_resource::()? .0 .take() .context("HandleStateKeeperOutput was provided but taken by another task")?; - let sealer = context.get_resource::().await?.0; - let master_pool = context.get_resource::>().await?; + let sealer = context.get_resource::()?.0; + let master_pool = context.get_resource::>()?; let (storage_factory, task) = AsyncRocksdbCache::new( master_pool.get_custom(2).await?, self.state_keeper_db_path, self.rocksdb_options, ); - context.add_task(Box::new(RocksdbCatchupTask(task))); + context.add_task(RocksdbCatchupTask(task)); - context.add_task(Box::new(StateKeeperTask { + context.add_task(StateKeeperTask { io, batch_executor_base, output_handler, sealer, storage_factory: Arc::new(storage_factory), - })); + }); context.add_shutdown_hook("rocksdb_terminaton", async { // Wait for all the instances of RocksDB to be destroyed. diff --git a/core/node/node_framework/src/implementations/layers/state_keeper/output_handler.rs b/core/node/node_framework/src/implementations/layers/state_keeper/output_handler.rs index 3d27dfdcd608..d79ce9a5846f 100644 --- a/core/node/node_framework/src/implementations/layers/state_keeper/output_handler.rs +++ b/core/node/node_framework/src/implementations/layers/state_keeper/output_handler.rs @@ -78,9 +78,9 @@ impl WiringLayer for OutputHandlerLayer { async fn wire(self: Box, mut context: ServiceContext<'_>) -> Result<(), WiringError> { // Fetch required resources. - let master_pool = context.get_resource::>().await?; + let master_pool = context.get_resource::>()?; // Use `SyncState` if provided. - let sync_state = match context.get_resource::().await { + let sync_state = match context.get_resource::() { Ok(sync_state) => Some(sync_state.0), Err(WiringError::ResourceLacking { .. }) => None, Err(err) => return Err(err), @@ -114,7 +114,7 @@ impl WiringLayer for OutputHandlerLayer { output_handler = output_handler.with_handler(Box::new(sync_state)); } context.insert_resource(OutputHandlerResource(Unique::new(output_handler)))?; - context.add_task(Box::new(L2BlockSealerTask(l2_block_sealer))); + context.add_task(L2BlockSealerTask(l2_block_sealer)); Ok(()) } diff --git a/core/node/node_framework/src/implementations/layers/sync_state_updater.rs b/core/node/node_framework/src/implementations/layers/sync_state_updater.rs index 0c7c04e45d2e..cca96f9ee079 100644 --- a/core/node/node_framework/src/implementations/layers/sync_state_updater.rs +++ b/core/node/node_framework/src/implementations/layers/sync_state_updater.rs @@ -38,7 +38,7 @@ impl WiringLayer for SyncStateUpdaterLayer { } async fn wire(self: Box, mut context: ServiceContext<'_>) -> Result<(), WiringError> { - if context.get_resource::().await.is_ok() { + if context.get_resource::().is_ok() { // `SyncState` was provided by some other layer -- we assume that the layer that added this resource // will be responsible for its maintenance. tracing::info!( @@ -47,8 +47,8 @@ impl WiringLayer for SyncStateUpdaterLayer { return Ok(()); } - let pool = context.get_resource::>().await?; - let MainNodeClientResource(main_node_client) = context.get_resource().await?; + let pool = context.get_resource::>()?; + let MainNodeClientResource(main_node_client) = context.get_resource()?; let sync_state = SyncState::default(); @@ -56,11 +56,11 @@ impl WiringLayer for SyncStateUpdaterLayer { context.insert_resource(SyncStateResource(sync_state.clone()))?; // Insert task - context.add_task(Box::new(SyncStateUpdater { + context.add_task(SyncStateUpdater { sync_state, connection_pool: pool.get().await?, main_node_client, - })); + }); Ok(()) } diff --git a/core/node/node_framework/src/implementations/layers/tee_verifier_input_producer.rs b/core/node/node_framework/src/implementations/layers/tee_verifier_input_producer.rs index 00b5ab4d9795..dc03a0563709 100644 --- a/core/node/node_framework/src/implementations/layers/tee_verifier_input_producer.rs +++ b/core/node/node_framework/src/implementations/layers/tee_verifier_input_producer.rs @@ -41,15 +41,14 @@ impl WiringLayer for TeeVerifierInputProducerLayer { async fn wire(self: Box, mut context: ServiceContext<'_>) -> Result<(), WiringError> { // Get resources. let pool_resource = context - .get_resource::>() - .await? + .get_resource::>()? .get() .await?; - let object_store = context.get_resource::().await?; + let object_store = context.get_resource::()?; let tee = TeeVerifierInputProducer::new(pool_resource, object_store.0, self.l2_chain_id).await?; - context.add_task(Box::new(tee)); + context.add_task(tee); Ok(()) } diff --git a/core/node/node_framework/src/implementations/layers/tree_data_fetcher.rs b/core/node/node_framework/src/implementations/layers/tree_data_fetcher.rs index 7a54b1332037..76db94f1ac20 100644 --- a/core/node/node_framework/src/implementations/layers/tree_data_fetcher.rs +++ b/core/node/node_framework/src/implementations/layers/tree_data_fetcher.rs @@ -43,9 +43,9 @@ impl WiringLayer for TreeDataFetcherLayer { } async fn wire(self: Box, mut context: ServiceContext<'_>) -> Result<(), WiringError> { - let pool = context.get_resource::>().await?; - let MainNodeClientResource(client) = context.get_resource().await?; - let EthInterfaceResource(eth_client) = context.get_resource().await?; + let pool = context.get_resource::>()?; + let MainNodeClientResource(client) = context.get_resource()?; + let EthInterfaceResource(eth_client) = context.get_resource()?; tracing::warn!( "Running tree data fetcher (allows a node to operate w/o a Merkle tree or w/o waiting the tree to catch up). \ @@ -55,13 +55,13 @@ impl WiringLayer for TreeDataFetcherLayer { .with_l1_data(eth_client, self.diamond_proxy_addr)?; // Insert healthcheck - let AppHealthCheckResource(app_health) = context.get_resource_or_default().await; + let AppHealthCheckResource(app_health) = context.get_resource_or_default(); app_health .insert_component(fetcher.health_check()) .map_err(WiringError::internal)?; // Insert task - context.add_task(Box::new(fetcher)); + context.add_task(fetcher); Ok(()) } diff --git a/core/node/node_framework/src/implementations/layers/validate_chain_ids.rs b/core/node/node_framework/src/implementations/layers/validate_chain_ids.rs index 5d3a9b9e82f5..e3323a01b778 100644 --- a/core/node/node_framework/src/implementations/layers/validate_chain_ids.rs +++ b/core/node/node_framework/src/implementations/layers/validate_chain_ids.rs @@ -43,8 +43,8 @@ impl WiringLayer for ValidateChainIdsLayer { } async fn wire(self: Box, mut context: ServiceContext<'_>) -> Result<(), WiringError> { - let EthInterfaceResource(query_client) = context.get_resource().await?; - let MainNodeClientResource(main_node_client) = context.get_resource().await?; + let EthInterfaceResource(query_client) = context.get_resource()?; + let MainNodeClientResource(main_node_client) = context.get_resource()?; let task = ValidateChainIdsTask::new( self.l1_chain_id, @@ -53,7 +53,7 @@ impl WiringLayer for ValidateChainIdsLayer { main_node_client, ); - context.add_task(Box::new(task)); + context.add_task(task); Ok(()) } diff --git a/core/node/node_framework/src/implementations/layers/vm_runner/protective_reads.rs b/core/node/node_framework/src/implementations/layers/vm_runner/protective_reads.rs index dfc17a342af9..6e33cca538fd 100644 --- a/core/node/node_framework/src/implementations/layers/vm_runner/protective_reads.rs +++ b/core/node/node_framework/src/implementations/layers/vm_runner/protective_reads.rs @@ -45,7 +45,7 @@ impl WiringLayer for ProtectiveReadsWriterLayer { } async fn wire(self: Box, mut context: ServiceContext<'_>) -> Result<(), WiringError> { - let master_pool = context.get_resource::>().await?; + let master_pool = context.get_resource::>()?; let (protective_reads_writer, tasks) = ProtectiveReadsWriter::new( // One for `StorageSyncTask` which can hold a long-term connection in case it needs to @@ -67,11 +67,11 @@ impl WiringLayer for ProtectiveReadsWriterLayer { ) .await?; - context.add_task(Box::new(tasks.loader_task)); - context.add_task(Box::new(tasks.output_handler_factory_task)); - context.add_task(Box::new(ProtectiveReadsWriterTask { + context.add_task(tasks.loader_task); + context.add_task(tasks.output_handler_factory_task); + context.add_task(ProtectiveReadsWriterTask { protective_reads_writer, - })); + }); Ok(()) } } diff --git a/core/node/node_framework/src/implementations/layers/web3_api/caches.rs b/core/node/node_framework/src/implementations/layers/web3_api/caches.rs index cc62d2ebd4c5..805e7c91eaeb 100644 --- a/core/node/node_framework/src/implementations/layers/web3_api/caches.rs +++ b/core/node/node_framework/src/implementations/layers/web3_api/caches.rs @@ -47,11 +47,11 @@ impl WiringLayer for MempoolCacheLayer { } async fn wire(self: Box, mut context: ServiceContext<'_>) -> Result<(), WiringError> { - let pool_resource = context.get_resource::>().await?; + let pool_resource = context.get_resource::>()?; let replica_pool = pool_resource.get().await?; let mempool_cache = MempoolCache::new(self.capacity); let update_task = mempool_cache.update_task(replica_pool, self.update_interval); - context.add_task(Box::new(MempoolCacheUpdateTask(update_task))); + context.add_task(MempoolCacheUpdateTask(update_task)); context.insert_resource(MempoolCacheResource(mempool_cache))?; Ok(()) } diff --git a/core/node/node_framework/src/implementations/layers/web3_api/server.rs b/core/node/node_framework/src/implementations/layers/web3_api/server.rs index e45583e2cfc6..365f49c1122c 100644 --- a/core/node/node_framework/src/implementations/layers/web3_api/server.rs +++ b/core/node/node_framework/src/implementations/layers/web3_api/server.rs @@ -131,21 +131,21 @@ impl WiringLayer for Web3ServerLayer { async fn wire(self: Box, mut context: ServiceContext<'_>) -> Result<(), WiringError> { // Get required resources. - let replica_resource_pool = context.get_resource::>().await?; + let replica_resource_pool = context.get_resource::>()?; let updaters_pool = replica_resource_pool.get_custom(2).await?; let replica_pool = replica_resource_pool.get().await?; - let tx_sender = context.get_resource::().await?.0; - let sync_state = match context.get_resource::().await { + let tx_sender = context.get_resource::()?.0; + let sync_state = match context.get_resource::() { Ok(sync_state) => Some(sync_state.0), Err(WiringError::ResourceLacking { .. }) => None, Err(err) => return Err(err), }; - let tree_api_client = match context.get_resource::().await { + let tree_api_client = match context.get_resource::() { Ok(client) => Some(client.0), Err(WiringError::ResourceLacking { .. }) => None, Err(err) => return Err(err), }; - let MempoolCacheResource(mempool_cache) = context.get_resource().await?; + let MempoolCacheResource(mempool_cache) = context.get_resource()?; // Build server. let mut api_builder = @@ -180,15 +180,13 @@ impl WiringLayer for Web3ServerLayer { // Insert healthcheck. let api_health_check = server.health_check(); - let AppHealthCheckResource(app_health) = context.get_resource_or_default().await; + let AppHealthCheckResource(app_health) = context.get_resource_or_default(); app_health .insert_component(api_health_check) .map_err(WiringError::internal)?; // Insert circuit breaker. - let circuit_breaker_resource = context - .get_resource_or_default::() - .await; + let circuit_breaker_resource = context.get_resource_or_default::(); circuit_breaker_resource .breakers .insert(Box::new(ReplicationLagChecker { @@ -205,8 +203,8 @@ impl WiringLayer for Web3ServerLayer { task_sender, }; let garbage_collector_task = ApiTaskGarbageCollector { task_receiver }; - context.add_task(Box::new(web3_api_task)); - context.add_task(Box::new(garbage_collector_task)); + context.add_task(web3_api_task); + context.add_task(garbage_collector_task); Ok(()) } diff --git a/core/node/node_framework/src/implementations/layers/web3_api/tree_api_client.rs b/core/node/node_framework/src/implementations/layers/web3_api/tree_api_client.rs index 492893a3b7f2..b481e1ea25d7 100644 --- a/core/node/node_framework/src/implementations/layers/web3_api/tree_api_client.rs +++ b/core/node/node_framework/src/implementations/layers/web3_api/tree_api_client.rs @@ -57,7 +57,7 @@ impl WiringLayer for TreeApiClientLayer { } // Only provide the health check if necessary. - let AppHealthCheckResource(app_health) = context.get_resource_or_default().await; + let AppHealthCheckResource(app_health) = context.get_resource_or_default(); app_health .insert_custom_component(client) .map_err(WiringError::internal)?; diff --git a/core/node/node_framework/src/implementations/layers/web3_api/tx_sender.rs b/core/node/node_framework/src/implementations/layers/web3_api/tx_sender.rs index 209d6d995bb1..0b45b3279680 100644 --- a/core/node/node_framework/src/implementations/layers/web3_api/tx_sender.rs +++ b/core/node/node_framework/src/implementations/layers/web3_api/tx_sender.rs @@ -95,15 +95,15 @@ impl WiringLayer for TxSenderLayer { async fn wire(self: Box, mut context: ServiceContext<'_>) -> Result<(), WiringError> { // Get required resources. - let tx_sink = context.get_resource::().await?.0; - let pool_resource = context.get_resource::>().await?; + let tx_sink = context.get_resource::()?.0; + let pool_resource = context.get_resource::>()?; let replica_pool = pool_resource.get().await?; - let sealer = match context.get_resource::().await { + let sealer = match context.get_resource::() { Ok(sealer) => Some(sealer.0), Err(WiringError::ResourceLacking { .. }) => None, Err(other) => return Err(other), }; - let fee_input = context.get_resource::().await?.0; + let fee_input = context.get_resource::()?.0; // Initialize Postgres caches. let factory_deps_capacity = self.postgres_storage_caches_config.factory_deps_cache_size; @@ -117,17 +117,17 @@ impl WiringLayer for TxSenderLayer { if values_capacity > 0 { let values_cache_task = storage_caches .configure_storage_values_cache(values_capacity, replica_pool.clone()); - context.add_task(Box::new(PostgresStorageCachesTask { + context.add_task(PostgresStorageCachesTask { task: values_cache_task, - })); + }); } // Initialize `VmConcurrencyLimiter`. let (vm_concurrency_limiter, vm_concurrency_barrier) = VmConcurrencyLimiter::new(self.max_vm_concurrency); - context.add_task(Box::new(VmConcurrencyBarrierTask { + context.add_task(VmConcurrencyBarrierTask { barrier: vm_concurrency_barrier, - })); + }); // Build `TxSender`. let mut tx_sender = TxSenderBuilder::new(self.tx_sender_config, replica_pool, tx_sink); @@ -137,12 +137,12 @@ impl WiringLayer for TxSenderLayer { // Add the task for updating the whitelisted tokens for the AA cache. if self.whitelisted_tokens_for_aa_cache { - let MainNodeClientResource(main_node_client) = context.get_resource().await?; + let MainNodeClientResource(main_node_client) = context.get_resource()?; let whitelisted_tokens = Arc::new(RwLock::new(Default::default())); - context.add_task(Box::new(WhitelistedTokensForAaUpdateTask { + context.add_task(WhitelistedTokensForAaUpdateTask { whitelisted_tokens: whitelisted_tokens.clone(), main_node_client, - })); + }); tx_sender = tx_sender.with_whitelisted_tokens_for_aa(whitelisted_tokens); } diff --git a/core/node/node_framework/src/implementations/layers/web3_api/tx_sink.rs b/core/node/node_framework/src/implementations/layers/web3_api/tx_sink.rs index 6ce5b47513f7..f7530f835765 100644 --- a/core/node/node_framework/src/implementations/layers/web3_api/tx_sink.rs +++ b/core/node/node_framework/src/implementations/layers/web3_api/tx_sink.rs @@ -46,23 +46,21 @@ impl WiringLayer for TxSinkLayer { let tx_sink = match self.as_ref() { TxSinkLayer::MasterPoolSink => { let pool = context - .get_resource::>() - .await? + .get_resource::>()? .get() .await?; TxSinkResource(Arc::new(MasterPoolSink::new(pool))) } TxSinkLayer::ProxySink => { - let MainNodeClientResource(client) = context.get_resource().await?; + let MainNodeClientResource(client) = context.get_resource()?; let proxy = TxProxy::new(client); let pool = context - .get_resource::>() - .await? + .get_resource::>()? .get_singleton() .await?; let task = proxy.account_nonce_sweeper_task(pool); - context.add_task(Box::new(task)); + context.add_task(task); TxSinkResource(Arc::new(proxy)) } diff --git a/core/node/node_framework/src/lib.rs b/core/node/node_framework/src/lib.rs index da788609b57c..633086103fb4 100644 --- a/core/node/node_framework/src/lib.rs +++ b/core/node/node_framework/src/lib.rs @@ -15,3 +15,15 @@ pub mod resource; pub mod service; pub mod task; pub mod wiring_layer; + +/// Derive macro for the `FromContext` trait. +pub use zksync_node_framework_derive::FromContext; +/// Derive macro for the `IntoContext` trait. +pub use zksync_node_framework_derive::IntoContext; + +pub use self::{ + resource::Resource, + service::{FromContext, IntoContext, StopReceiver}, + task::{Task, TaskId}, + wiring_layer::{WiringError, WiringLayer}, +}; diff --git a/core/node/node_framework/src/resource/mod.rs b/core/node/node_framework/src/resource/mod.rs index 2e62d8421f89..5ddc7ba2e45e 100644 --- a/core/node/node_framework/src/resource/mod.rs +++ b/core/node/node_framework/src/resource/mod.rs @@ -19,7 +19,7 @@ mod unique; /// /// An abstract interface you want to share. /// /// Normally you want the interface to be thread-safe. /// trait MyInterface: 'static + Send + Sync { -/// fn do_something(&self); +/// fn do_something(&self); /// } /// /// /// Resource wrapper. @@ -27,11 +27,11 @@ mod unique; /// struct MyResource(Arc); /// /// impl Resource for MyResource { -/// fn name() -> String { -/// // It is a helpful practice to follow a structured naming pattern for resource names. -/// // For example, you can use a certain prefix for all resources related to a some component, e.g. `api`. -/// "common/my_resource".to_string() -/// } +/// fn name() -> String { +/// // It is a helpful practice to follow a structured naming pattern for resource names. +/// // For example, you can use a certain prefix for all resources related to a some component, e.g. `api`. +/// "common/my_resource".to_string() +/// } /// } /// ``` pub trait Resource: 'static + Send + Sync + std::any::Any { diff --git a/core/node/node_framework/src/service/context.rs b/core/node/node_framework/src/service/context.rs index d4bb4db95464..0280bb1c8927 100644 --- a/core/node/node_framework/src/service/context.rs +++ b/core/node/node_framework/src/service/context.rs @@ -29,7 +29,7 @@ impl<'a> ServiceContext<'a> { /// Provides access to the runtime used by the service. /// /// Can be used to spawn additional tasks within the same runtime. - /// If some tasks stores the handle to spawn additional tasks, it is expected to do all the required + /// If some task stores the handle to spawn additional tasks, it is expected to do all the required /// cleanup. /// /// In most cases, however, it is recommended to use [`add_task`](ServiceContext::add_task) or its alternative @@ -52,9 +52,9 @@ impl<'a> ServiceContext<'a> { /// /// Added tasks will be launched after the wiring process will be finished and all the preconditions /// are met. - pub fn add_task(&mut self, task: Box) -> &mut Self { + pub fn add_task(&mut self, task: T) -> &mut Self { tracing::info!("Layer {} has added a new task: {}", self.layer, task.id()); - self.service.runnables.tasks.push(task); + self.service.runnables.tasks.push(Box::new(task)); self } @@ -85,7 +85,7 @@ impl<'a> ServiceContext<'a> { /// ## Panics /// /// Panics if the resource with the specified [`ResourceId`] exists, but is not of the requested type. - pub async fn get_resource(&mut self) -> Result { + pub fn get_resource(&mut self) -> Result { // Implementation details: // Internally the resources are stored as [`std::any::Any`], and this method does the downcasting // on behalf of the caller. @@ -131,11 +131,11 @@ impl<'a> ServiceContext<'a> { /// Attempts to retrieve the resource of the specified type. /// If the resource is not available, it is created using the provided closure. - pub async fn get_resource_or_insert_with T>( + pub fn get_resource_or_insert_with T>( &mut self, f: F, ) -> T { - if let Ok(resource) = self.get_resource::().await { + if let Ok(resource) = self.get_resource::() { return resource; } @@ -154,8 +154,8 @@ impl<'a> ServiceContext<'a> { /// Attempts to retrieve the resource of the specified type. /// If the resource is not available, it is created using `T::default()`. - pub async fn get_resource_or_default(&mut self) -> T { - self.get_resource_or_insert_with(T::default).await + pub fn get_resource_or_default(&mut self) -> T { + self.get_resource_or_insert_with(T::default) } /// Adds a resource to the service. diff --git a/core/node/node_framework/src/service/context_traits.rs b/core/node/node_framework/src/service/context_traits.rs new file mode 100644 index 000000000000..129bbb1a00f0 --- /dev/null +++ b/core/node/node_framework/src/service/context_traits.rs @@ -0,0 +1,133 @@ +use crate::{resource::Resource, service::context::ServiceContext, wiring_layer::WiringError}; + +/// Trait used as input for wiring layers, aiming to provide all the resources the layer needs for wiring. +/// +/// For most cases, the most conevenient way to implement this trait is to use the `#[derive(FromContext)]`. +/// Otherwise, the trait has several blanket implementations (including the implementation for `()` and `Option`). +/// +/// # Example +/// +/// ``` +/// use zksync_node_framework::FromContext; +/// # #[derive(Clone)] +/// # struct MandatoryResource; +/// # impl zksync_node_framework::resource::Resource for MandatoryResource { fn name() -> String { "a".into() } } +/// # #[derive(Clone)] +/// # struct OptionalResource; +/// # impl zksync_node_framework::resource::Resource for OptionalResource { fn name() -> String { "b".into() } } +/// # #[derive(Default, Clone)] +/// # struct ResourceWithDefault; +/// # impl zksync_node_framework::resource::Resource for ResourceWithDefault { fn name() -> String { "c".into() } } +/// #[derive(FromContext)] +/// struct MyWiringLayerInput { +/// // The following field _must_ be present in the context. +/// mandatory_resource: MandatoryResource, +/// // The following field is optional. +/// // If will be `None` if there is no such resource in the context. +/// optional_resource: Option, +/// // The following field is guaranteed to fetch the value from the context. +/// // In case the value is missing, a default value will be added to the context. +/// #[context(default)] +/// resource_with_default: ResourceWithDefault, +/// } +/// ``` +pub trait FromContext: Sized { + fn from_context(context: &mut ServiceContext<'_>) -> Result; +} + +impl FromContext for T { + fn from_context(context: &mut ServiceContext<'_>) -> Result { + context.get_resource::() + } +} + +impl FromContext for () { + fn from_context(_context: &mut ServiceContext<'_>) -> Result { + Ok(()) + } +} + +impl FromContext for Option { + fn from_context(context: &mut ServiceContext<'_>) -> Result { + match T::from_context(context) { + Ok(inner) => Ok(Some(inner)), + Err(WiringError::ResourceLacking { .. }) => Ok(None), + Err(err) => Err(err), + } + } +} + +/// Trait used as output for wiring layers, aiming to provide all the resources and tasks the layer creates. +/// +/// For most cases, the most conevenient way to implement this trait is to use the `#[derive(IntoContext)]`. +/// Otherwise, the trait has several blanket implementations (including the implementation for `()` and `Option`). +/// Note, however, that due to the lack of specialization, the blanket implementation for `Option` is not +/// provided. When used in the macro, tasks must be annotated with the `#[context(task)]` attribute. +/// +/// Note: returning a resource that already exists in the context will result in a wiring error. If you need to provide +/// a "substitute" resource, request `Option` of it in the `FromContext` implementation to check whether it's already +/// provided. +/// +/// +/// # Example +/// +/// ``` +/// use zksync_node_framework::IntoContext; +/// # struct MyTask; +/// # #[async_trait::async_trait] +/// # impl zksync_node_framework::task::Task for MyTask { +/// # fn id(&self) -> zksync_node_framework::TaskId { "a".into() } +/// # async fn run(self: Box, _: zksync_node_framework::StopReceiver) -> anyhow::Result<()> { Ok(()) } +/// # } +/// # struct MaybeTask; +/// # #[async_trait::async_trait] +/// # impl zksync_node_framework::task::Task for MaybeTask { +/// # fn id(&self) -> zksync_node_framework::TaskId { "b".into() } +/// # async fn run(self: Box, _: zksync_node_framework::StopReceiver) -> anyhow::Result<()> { Ok(()) } +/// # } +/// # struct MyResource; +/// # impl zksync_node_framework::resource::Resource for MyResource { fn name() -> String { "a".into() } } +/// # struct MaybeResource; +/// # impl zksync_node_framework::resource::Resource for MaybeResource { fn name() -> String { "b".into() } } +/// #[derive(IntoContext)] +/// struct MyWiringLayerOutput { +/// // This resource will be inserted unconditionally. +/// // Will err if such resource is already present in the context. +/// recource: MyResource, +/// // Will only provide the resource if it's `Some`. +/// maybe_resource: Option, +/// // Will provide task unconditionally. +/// #[context(task)] +/// task: MyTask, +/// // Will provide task only if it's `Some`. +/// #[context(task)] +/// maybe_task: Option, +/// } +/// ``` +pub trait IntoContext { + fn into_context(self, context: &mut ServiceContext<'_>) -> Result<(), WiringError>; +} + +// Unfortunately, without specialization we cannot provide a blanket implementation for `T: Task` +// as well. `Resource` is chosen because it also has a blanket implementation of `FromContext`. +impl IntoContext for T { + fn into_context(self, context: &mut ServiceContext<'_>) -> Result<(), WiringError> { + context.insert_resource(self) + } +} + +impl IntoContext for () { + fn into_context(self, _context: &mut ServiceContext<'_>) -> Result<(), WiringError> { + Ok(()) + } +} + +impl IntoContext for Option { + fn into_context(self, context: &mut ServiceContext<'_>) -> Result<(), WiringError> { + if let Some(inner) = self { + inner.into_context(context) + } else { + Ok(()) + } + } +} diff --git a/core/node/node_framework/src/service/mod.rs b/core/node/node_framework/src/service/mod.rs index e727a536e9c4..2744c08ceba6 100644 --- a/core/node/node_framework/src/service/mod.rs +++ b/core/node/node_framework/src/service/mod.rs @@ -5,7 +5,12 @@ use futures::future::Fuse; use tokio::{runtime::Runtime, sync::watch, task::JoinHandle}; use zksync_utils::panic_extractor::try_extract_panic_message; -pub use self::{context::ServiceContext, error::ZkStackServiceError, stop_receiver::StopReceiver}; +pub use self::{ + context::ServiceContext, + context_traits::{FromContext, IntoContext}, + error::ZkStackServiceError, + stop_receiver::StopReceiver, +}; use crate::{ resource::{ResourceId, StoredResource}, service::{ @@ -17,6 +22,7 @@ use crate::{ }; mod context; +mod context_traits; mod error; mod named_future; mod runnables; diff --git a/core/node/node_framework/src/service/tests.rs b/core/node/node_framework/src/service/tests.rs index b5bcc3aaa255..994e41ef21cc 100644 --- a/core/node/node_framework/src/service/tests.rs +++ b/core/node/node_framework/src/service/tests.rs @@ -117,7 +117,7 @@ impl WiringLayer for TaskErrorLayer { } async fn wire(self: Box, mut node: ServiceContext<'_>) -> Result<(), WiringError> { - node.add_task(Box::new(ErrorTask)); + node.add_task(ErrorTask); Ok(()) } } @@ -160,14 +160,14 @@ impl WiringLayer for TasksLayer { // Barrier is needed to make sure that both tasks have started, otherwise the second task // may exit even before it starts. let barrier = Arc::new(Barrier::new(2)); - node.add_task(Box::new(SuccessfulTask( + node.add_task(SuccessfulTask( barrier.clone(), self.successful_task_was_run.clone(), - ))) - .add_task(Box::new(RemainingTask( + )) + .add_task(RemainingTask( barrier.clone(), self.remaining_task_was_run.clone(), - ))); + )); Ok(()) } } diff --git a/core/node/node_framework/src/task/types.rs b/core/node/node_framework/src/task/types.rs index 70df61e56989..e9b8b6e37f26 100644 --- a/core/node/node_framework/src/task/types.rs +++ b/core/node/node_framework/src/task/types.rs @@ -6,6 +6,7 @@ use std::{ /// Task kind. /// See [`Task`](super::Task) documentation for more details. #[derive(Debug, Clone, Copy)] +#[non_exhaustive] pub enum TaskKind { Task, OneshotTask, diff --git a/core/node/node_framework/tests/ui.rs b/core/node/node_framework/tests/ui.rs new file mode 100644 index 000000000000..f2f9697b2c13 --- /dev/null +++ b/core/node/node_framework/tests/ui.rs @@ -0,0 +1,11 @@ +#[test] +fn ui_pass() { + let t = trybuild::TestCases::new(); + t.pass("tests/ui/correct/*.rs"); +} + +#[test] +fn ui_fail() { + let t = trybuild::TestCases::new(); + t.compile_fail("tests/ui/incorrect/*.rs"); +} diff --git a/core/node/node_framework/tests/ui/correct/01_from_context.rs b/core/node/node_framework/tests/ui/correct/01_from_context.rs new file mode 100644 index 000000000000..165c53fd0886 --- /dev/null +++ b/core/node/node_framework/tests/ui/correct/01_from_context.rs @@ -0,0 +1,41 @@ +#![allow(dead_code)] + +use zksync_node_framework::{FromContext, Resource}; + +#[derive(Clone)] +struct ResourceA; + +impl Resource for ResourceA { + fn name() -> String { + "a".to_string() + } +} + +#[derive(Clone, Default)] +struct ResourceB; + +impl Resource for ResourceB { + fn name() -> String { + "b".to_string() + } +} + +#[derive(FromContext)] +struct SimpleStruct { + _field: ResourceA, + _field_2: ResourceB, +} + +#[derive(FromContext)] +struct StructWithDefault { + _field: ResourceA, + #[context(default)] + _field_default: ResourceB, +} + +#[derive(FromContext)] +struct StructWithOption { + _field: Option, +} + +fn main() {} diff --git a/core/node/node_framework/tests/ui/correct/02_into_context.rs b/core/node/node_framework/tests/ui/correct/02_into_context.rs new file mode 100644 index 000000000000..33104aeea2be --- /dev/null +++ b/core/node/node_framework/tests/ui/correct/02_into_context.rs @@ -0,0 +1,41 @@ +#![allow(dead_code)] + +use zksync_node_framework::{IntoContext, Resource, StopReceiver, Task, TaskId}; + +#[derive(Clone)] +struct ResourceA; + +impl Resource for ResourceA { + fn name() -> String { + "a".to_string() + } +} + +struct TaskA; + +#[async_trait::async_trait] +impl Task for TaskA { + fn id(&self) -> TaskId { + "batch_status_updater".into() + } + + async fn run(self: Box, _stop_receiver: StopReceiver) -> anyhow::Result<()> { + Ok(()) + } +} + +#[derive(IntoContext)] +struct SimpleStruct { + _field: ResourceA, + #[context(task)] + _field_2: TaskA, +} + +#[derive(IntoContext)] +struct Options { + _field: Option, + #[context(task)] + _field_2: Option, +} + +fn main() {} diff --git a/core/node/node_framework/tests/ui/incorrect/01_from_context_task.rs b/core/node/node_framework/tests/ui/incorrect/01_from_context_task.rs new file mode 100644 index 000000000000..b49347eef00b --- /dev/null +++ b/core/node/node_framework/tests/ui/incorrect/01_from_context_task.rs @@ -0,0 +1,34 @@ +#![allow(dead_code)] + +use zksync_node_framework::{FromContext, Resource, StopReceiver, Task, TaskId}; + +#[derive(Clone)] +struct ResourceA; + +impl Resource for ResourceA { + fn name() -> String { + "a".to_string() + } +} + +struct TaskA; + +#[async_trait::async_trait] +impl Task for TaskA { + fn id(&self) -> TaskId { + "batch_status_updater".into() + } + + async fn run(self: Box, _stop_receiver: StopReceiver) -> anyhow::Result<()> { + Ok(()) + } +} + +#[derive(FromContext)] +struct SimpleStruct { + _field: ResourceA, + #[context(task)] + _field_2: TaskA, +} + +fn main() {} diff --git a/core/node/node_framework/tests/ui/incorrect/01_from_context_task.stderr b/core/node/node_framework/tests/ui/incorrect/01_from_context_task.stderr new file mode 100644 index 000000000000..52acbc48be19 --- /dev/null +++ b/core/node/node_framework/tests/ui/incorrect/01_from_context_task.stderr @@ -0,0 +1,5 @@ +error: `task` attribute is not allowed in `FromContext` macro + --> tests/ui/incorrect/01_from_context_task.rs:31:5 + | +31 | _field_2: TaskA, + | ^^^^^^^^ diff --git a/core/node/node_framework/tests/ui/incorrect/02_into_context_default_task.rs b/core/node/node_framework/tests/ui/incorrect/02_into_context_default_task.rs new file mode 100644 index 000000000000..755605b8151d --- /dev/null +++ b/core/node/node_framework/tests/ui/incorrect/02_into_context_default_task.rs @@ -0,0 +1,35 @@ +#![allow(dead_code)] + +use zksync_node_framework::{IntoContext, Resource, StopReceiver, Task, TaskId}; + +#[derive(Clone)] +struct ResourceA; + +impl Resource for ResourceA { + fn name() -> String { + "a".to_string() + } +} + +#[derive(Default)] +struct TaskA; + +#[async_trait::async_trait] +impl Task for TaskA { + fn id(&self) -> TaskId { + "batch_status_updater".into() + } + + async fn run(self: Box, _stop_receiver: StopReceiver) -> anyhow::Result<()> { + Ok(()) + } +} + +#[derive(IntoContext)] +struct SimpleStruct { + _field: ResourceA, + #[context(task, default)] + _field_2: TaskA, +} + +fn main() {} diff --git a/core/node/node_framework/tests/ui/incorrect/02_into_context_default_task.stderr b/core/node/node_framework/tests/ui/incorrect/02_into_context_default_task.stderr new file mode 100644 index 000000000000..b1a751f45dbb --- /dev/null +++ b/core/node/node_framework/tests/ui/incorrect/02_into_context_default_task.stderr @@ -0,0 +1,5 @@ +error: `default` attribute is not allowed in `IntoContext` macro + --> tests/ui/incorrect/02_into_context_default_task.rs:32:5 + | +32 | _field_2: TaskA, + | ^^^^^^^^ diff --git a/core/node/node_framework/tests/ui/incorrect/03_into_context_default_resource.rs b/core/node/node_framework/tests/ui/incorrect/03_into_context_default_resource.rs new file mode 100644 index 000000000000..3f815b830eb5 --- /dev/null +++ b/core/node/node_framework/tests/ui/incorrect/03_into_context_default_resource.rs @@ -0,0 +1,35 @@ +#![allow(dead_code)] + +use zksync_node_framework::{IntoContext, Resource, StopReceiver, Task, TaskId}; + +#[derive(Clone)] +struct ResourceA; + +impl Resource for ResourceA { + fn name() -> String { + "a".to_string() + } +} + +struct TaskA; + +#[async_trait::async_trait] +impl Task for TaskA { + fn id(&self) -> TaskId { + "batch_status_updater".into() + } + + async fn run(self: Box, _stop_receiver: StopReceiver) -> anyhow::Result<()> { + Ok(()) + } +} + +#[derive(IntoContext)] +struct SimpleStruct { + #[context(default)] + _field: ResourceA, + #[context(task)] + _field_2: TaskA, +} + +fn main() {} diff --git a/core/node/node_framework/tests/ui/incorrect/03_into_context_default_resource.stderr b/core/node/node_framework/tests/ui/incorrect/03_into_context_default_resource.stderr new file mode 100644 index 000000000000..e69da3ad9bba --- /dev/null +++ b/core/node/node_framework/tests/ui/incorrect/03_into_context_default_resource.stderr @@ -0,0 +1,5 @@ +error: `default` attribute is not allowed in `IntoContext` macro + --> tests/ui/incorrect/03_into_context_default_resource.rs:30:5 + | +30 | _field: ResourceA, + | ^^^^^^ diff --git a/core/node/node_framework/tests/ui/incorrect/04_field_crate_attr.rs b/core/node/node_framework/tests/ui/incorrect/04_field_crate_attr.rs new file mode 100644 index 000000000000..48c17222333f --- /dev/null +++ b/core/node/node_framework/tests/ui/incorrect/04_field_crate_attr.rs @@ -0,0 +1,48 @@ +#![allow(dead_code)] + +use zksync_node_framework::{IntoContext, Resource, StopReceiver, Task, TaskId}; + +#[derive(Clone)] +struct ResourceA; + +impl Resource for ResourceA { + fn name() -> String { + "a".to_string() + } +} + +struct TaskA; + +#[async_trait::async_trait] +impl Task for TaskA { + fn id(&self) -> TaskId { + "batch_status_updater".into() + } + + async fn run(self: Box, _stop_receiver: StopReceiver) -> anyhow::Result<()> { + Ok(()) + } +} + +#[derive(IntoContext)] +struct SimpleStruct { + #[context(crate = a)] + _field: ResourceA, +} + +#[derive(IntoContext)] +struct SimpleStruct2 { + #[context(crate = b)] + _field: ResourceA, + #[context(task)] + _field_2: TaskA, +} + +#[derive(IntoContext)] +struct SimpleStruct3 { + _field: ResourceA, + #[context(task, crate = c)] + _field_2: TaskA, +} + +fn main() {} diff --git a/core/node/node_framework/tests/ui/incorrect/04_field_crate_attr.stderr b/core/node/node_framework/tests/ui/incorrect/04_field_crate_attr.stderr new file mode 100644 index 000000000000..6346c4cb7e9e --- /dev/null +++ b/core/node/node_framework/tests/ui/incorrect/04_field_crate_attr.stderr @@ -0,0 +1,17 @@ +error: `crate` attribute is not allowed for fields + --> tests/ui/incorrect/04_field_crate_attr.rs:30:5 + | +30 | _field: ResourceA, + | ^^^^^^ + +error: `crate` attribute is not allowed for fields + --> tests/ui/incorrect/04_field_crate_attr.rs:36:5 + | +36 | _field: ResourceA, + | ^^^^^^ + +error: `crate` attribute is not allowed for fields + --> tests/ui/incorrect/04_field_crate_attr.rs:45:5 + | +45 | _field_2: TaskA, + | ^^^^^^^^