From e6c885829c09ba99039c87865d0a297dd8657f6e Mon Sep 17 00:00:00 2001
From: smartprogrammer93
Date: Tue, 24 Feb 2026 15:17:14 +0300
Subject: [PATCH 1/4] docs: update plugins page to match current Nethermind API
- Remove IInitializationPlugin and ISynchronizationPlugin (no longer exist)
- Add Enabled property to all plugin examples (now required)
- Remove DisposeAsync and empty method stubs (default implementations exist)
- Add Dependency injection and modules section (Module, IStep, AddStep)
- Update Configuration section with constructor injection pattern
- Add INethermindPlugin interface reference table
- Update log output examples to match current PluginLoader format
- Update JSON-RPC handler sample with same fixes
---
docs/developers/plugins/plugins.md | 198 +++++++++++++-----
.../plugins/samples/json-rpc-handler.md | 6 +-
2 files changed, 151 insertions(+), 53 deletions(-)
diff --git a/docs/developers/plugins/plugins.md b/docs/developers/plugins/plugins.md
index 3538e308ea..b773731d5a 100644
--- a/docs/developers/plugins/plugins.md
+++ b/docs/developers/plugins/plugins.md
@@ -41,7 +41,7 @@ Now, we need to add the NuGet package to get access to the Nethermind API:
dotnet add package Nethermind.ReferenceAssemblies
```
-As the package name implies, it provides [reference assemblies](https://learn.microsoft.com/en-us/dotnet/standard/assembly/reference-assemblies) that are only enough to compile the project. To see the plugin in action, put the library assembly (.dll) in the Nethermind's plugins directory and then run Nethermind. We will get to that soon.
+As the package name implies, it provides [reference assemblies](https://learn.microsoft.com/en-us/dotnet/standard/assembly/reference-assemblies) that are only enough to compile the project. To see the plugin in action, put the library assembly (.dll) in the Nethermind's plugins directory and then run Nethermind. We will get to that soon.
Now, we have everything we need to begin with the actual implementation. For the sake of simplicity, we will create a basic plugin, a classic example, that simply prints the famous "Hello, world!" message.
@@ -58,6 +58,7 @@ public class DemoPlugin : INethermindPlugin
public string Name => "Demo plugin";
public string Description => "A sample plugin for demo";
public string Author => "Anonymous";
+ public bool Enabled => true;
// The entry point of the plugin
public Task Init(INethermindApi nethermindApi)
@@ -67,23 +68,16 @@ public class DemoPlugin : INethermindPlugin
return Task.CompletedTask;
}
-
- // Initializes the network stack
- public Task InitNetworkProtocol() => Task.CompletedTask;
- // Initializes the JSON-RPC stuff
- public Task InitRpcModules() => Task.CompletedTask;
- // Initializes the transaction-related stuff
- public void InitTxTypesAndRlpDecoders(INethermindApi api) { }
- // Cleans up resources
- public ValueTask DisposeAsync() => default;
}
```
-Let's examine the code above. The properties at lines 8-10 are required and self-explanatory. They are displayed on Nethermind startup for each loaded plugin. Next is the `Init()` method at line 13, which is the main entry point of any plugin where initialization begins. Its only argument of type [`INethermindApi`](https://github.com/NethermindEth/nethermind/blob/master/src/Nethermind/Nethermind.Api/INethermindApi.cs) → [`IApiWithNetwork`](https://github.com/NethermindEth/nethermind/blob/master/src/Nethermind/Nethermind.Api/IApiWithNetwork.cs) → [`IApiWithBlockchain`](https://github.com/NethermindEth/nethermind/blob/master/src/Nethermind/Nethermind.Api/IApiWithBlockchain.cs) → [`IApiWithStores`](https://github.com/NethermindEth/nethermind/blob/master/src/Nethermind/Nethermind.Api/IApiWithStores.cs) → [`IBasicApi`](https://github.com/NethermindEth/nethermind/blob/master/src/Nethermind/Nethermind.Api/IBasicApi.cs) is the main gateway to the Nethermind API, as its name implies. The `INethermindApi` interface provides a rich functionality set essential for plugin development and is widely used in the Nethermind codebase.
+Let's examine the code above. The properties at lines 8–11 are required and self-explanatory. The `Name`, `Description`, and `Author` are displayed on Nethermind startup for each loaded plugin. The `Enabled` property at line 11 tells Nethermind whether this plugin should be initialized. Only plugins returning `true` for `Enabled` are activated; the rest are skipped. Next is the `Init()` method at line 14, which is the main entry point of any plugin where initialization begins. Its only argument of type [`INethermindApi`](https://github.com/NethermindEth/nethermind/blob/master/src/Nethermind/Nethermind.Api/INethermindApi.cs) → [`IApiWithNetwork`](https://github.com/NethermindEth/nethermind/blob/master/src/Nethermind/Nethermind.Api/IApiWithNetwork.cs) → [`IApiWithBlockchain`](https://github.com/NethermindEth/nethermind/blob/master/src/Nethermind/Nethermind.Api/IApiWithBlockchain.cs) → [`IApiWithStores`](https://github.com/NethermindEth/nethermind/blob/master/src/Nethermind/Nethermind.Api/IApiWithStores.cs) → [`IBasicApi`](https://github.com/NethermindEth/nethermind/blob/master/src/Nethermind/Nethermind.Api/IBasicApi.cs) is the main gateway to the Nethermind API, as its name implies. The `INethermindApi` interface provides a rich functionality set essential for plugin development and is widely used in the Nethermind codebase.
-In line 15, we get the logger instance we need to print our message. Usually, that instance is stored in a private field to be available to other class members, but in our example, we don't need that. Once we have the instance, we log the message as a warning so you can spot it easily in the logs.
+In line 16, we get the logger instance we need to print our message. Usually, that instance is stored in a private field to be available to other class members, but in our example, we don't need that. Once we have the instance, we log the message as a warning so you can spot it easily in the logs.
-The methods in lines 22-28 are irrelevant for this example, so they are left empty. We will get to them in later examples.
+:::info
+The `INethermindPlugin` interface provides default implementations for the `Init()`, `InitNetworkProtocol()`, `InitRpcModules()`, and `InitTxTypesAndRlpDecoders()` methods. You only need to override the ones your plugin requires. In this basic example, we only override `Init()`.
+:::
To see our plugin in action, let's build it first:
@@ -103,14 +97,12 @@ Once built, we need to copy the `DemoPlugin.dll` to Nethermind's `plugins` direc
# highlight-end
24 Jan 18:01:37 | Loading assembly Nethermind.Api
...
-24 Jan 18:01:39 | Initializing 17 plugins
+24 Jan 18:01:39 | Detected 17 plugins
...
-24 Jan 18:01:39 | EthStats by Nethermind
-24 Jan 18:01:39 | EthStats by Nethermind initialized in 0ms
+24 Jan 18:01:39 | EthStats by Nethermind Enabled
# highlight-start
-24 Jan 18:01:39 | Demo plugin by Anonymous
+24 Jan 18:01:39 | Demo plugin by Anonymous Enabled
24 Jan 18:01:39 | Hello, world!
-24 Jan 18:01:39 | Demo plugin by Anonymous initialized in 0ms
# highlight-end
...
```
@@ -121,7 +113,7 @@ That's it! We created our very first Nethermind plugin.
As Nethermind is highly configurable, so may its plugins. The same flexible configuration features that Nethermind uses internally are also available to its plugins. That means a plugin can be configured with command line options, environment variables, and configuration files by simply implementing a single interface.
-Nethermind loads and runs all the plugins it finds on startup. This behavior may be undesirable for resource-hungry plugins or incompatible with those requiring a specific network (chain) to run on. Thus, a typical scenario for almost any plugin is to be turned on or off by a configuration setting. Let's implement that feature for our Demo plugin.
+Nethermind loads and runs all the plugins it finds on startup, but it only initializes those whose `Enabled` property returns `true`. This behavior is particularly useful for resource-hungry plugins or those requiring a specific network (chain) to run on. Instead of hardcoding the `Enabled` property to `true` as we did above, a typical approach is to base it on a configuration setting. Let's implement that for our Demo plugin.
All Nethermind configurations must implement the [`IConfig`](https://github.com/NethermindEth/nethermind/blob/master/src/Nethermind/Nethermind.Config/IConfig.cs) interface. It's a 2 step process.
@@ -151,24 +143,51 @@ public class DemoConfig : IDemoConfig
}
```
-That's it for the configuration. Now, let's check for the value of `Enabled` in the `Init()` method and only log the message if it's `true`:
+That's it for the configuration. Now, let's update our `DemoPlugin` class to use the configuration. Nethermind uses [Autofac](https://autofac.org/) for dependency injection. This means we can inject our configuration interface directly into the plugin's constructor:
-```csharp
-public Task Init(INethermindApi nethermindApi)
+```csharp title="DemoPlugin.cs" showLineNumbers
+using Nethermind.Api;
+using Nethermind.Api.Extensions;
+
+namespace DemoPlugin;
+
+// highlight-start
+public class DemoPlugin(IDemoConfig demoConfig) : INethermindPlugin
+// highlight-end
{
- var logger = nethermindApi.LogManager.GetClassLogger();
+ public string Name => "Demo plugin";
+ public string Description => "A sample plugin for demo";
+ public string Author => "Anonymous";
+
// highlight-start
- var config = nethermindApi.Config();
+ public bool Enabled => demoConfig.Enabled;
// highlight-end
- if (config.Enabled)
+ public Task Init(INethermindApi nethermindApi)
+ {
+ var logger = nethermindApi.LogManager.GetClassLogger();
logger.Warn("Hello, world!");
- return Task.CompletedTask;
+ return Task.CompletedTask;
+ }
}
```
-The highlighted line shows how to get the configuration instance. Note that we get it by its interface type, not the implementing class. That's an important detail.
+The highlighted lines show the key changes. At line 6, we use a [primary constructor](https://learn.microsoft.com/en-us/dotnet/csharp/whats-new/tutorials/primary-constructors) to accept an `IDemoConfig` instance that Nethermind's dependency injection container resolves automatically. At line 13, `Enabled` delegates to the configuration value, so the plugin is only activated when the user enables it.
+
+:::tip
+You can also retrieve configuration via `INethermindApi.Config()` in the `Init()` method:
+
+```csharp
+public Task Init(INethermindApi nethermindApi)
+{
+ var config = nethermindApi.Config();
+ // ...
+}
+```
+
+However, for controlling the `Enabled` property, constructor injection is preferred since `Enabled` is evaluated before `Init()` is called.
+:::
:::warning Important
The configuration interface name must be in the `I{PluginName}Config` format. In our case, it's `IDemoConfig`.
@@ -180,7 +199,7 @@ The naming convention is crucial for mapping the configuration options. For inst
- `NETHERMIND_DEMOCONFIG_ENABLED` as an environment variable
- `{ "Demo": { "Enabled": true|false } }` as a JSON in a configuration file
-Since now we know what our configuration options are, let's build the project, copy the library to Nethermind's plugins directory, and run Nethermind as we did previously:
+Since now we know what our configuration options are, let's build the project, copy the library to Nethermind's plugins directory, and run Nethermind as we did previously:
```text
24 Jan 18:01:37 | Nethermind is starting up
@@ -192,18 +211,16 @@ Since now we know what our configuration options are, let's build the project, c
# highlight-end
24 Jan 18:01:37 | Loading assembly Nethermind.Api
...
-24 Jan 18:01:39 | Initializing 17 plugins
+24 Jan 18:01:39 | Detected 17 plugins
...
-24 Jan 18:01:39 | EthStats by Nethermind
-24 Jan 18:01:39 | EthStats by Nethermind initialized in 0ms
+24 Jan 18:01:39 | EthStats by Nethermind Enabled
# highlight-start
-24 Jan 18:01:39 | Demo plugin by Anonymous
-24 Jan 18:01:39 | Demo plugin by Anonymous initialized in 0ms
+24 Jan 18:01:39 | Demo plugin by Anonymous Disabled
# highlight-end
...
```
-There's a slight difference compared to the previous run -- the "Hello, world!" message is gone. The reason is that we put it under an `if` condition which has not been entered because of the `IDemoConfig.Enabled` is `false` by default. Let's set it to `true` using the command line option as follows:
+There's a slight difference compared to the previous run -- the "Hello, world!" message is gone and the plugin shows as "Disabled". The reason is that the plugin's `Enabled` property returns `false` because `IDemoConfig.Enabled` defaults to `false`. Let's set it to `true` using the command line option as follows:
```bash
nethermind --demo-enabled
@@ -237,6 +254,82 @@ Options:
...
```
+## Dependency injection and modules
+
+Nethermind uses [Autofac](https://autofac.org/) as its dependency injection (DI) container. Plugins can participate in DI by providing an Autofac `Module` through the `Module` property of `INethermindPlugin`. This is used to register services, override default implementations, and register initialization steps.
+
+Here is an example of a plugin that registers a custom service and an initialization step:
+
+```csharp title="DemoPlugin.cs" showLineNumbers
+using Autofac;
+using Autofac.Core;
+using Nethermind.Api.Extensions;
+using Nethermind.Api.Steps;
+
+namespace DemoPlugin;
+
+public class DemoPlugin(IDemoConfig demoConfig) : INethermindPlugin
+{
+ public string Name => "Demo plugin";
+ public string Description => "A sample plugin for demo";
+ public string Author => "Anonymous";
+ public bool Enabled => demoConfig.Enabled;
+
+ // highlight-start
+ public IModule Module => new DemoModule();
+ // highlight-end
+}
+
+// highlight-start
+public class DemoModule : Module
+{
+ protected override void Load(ContainerBuilder builder)
+ {
+ // Register an initialization step
+ builder.AddStep(typeof(DemoStep));
+ }
+}
+// highlight-end
+```
+
+### Initialization steps (IStep) {#steps}
+
+Initialization steps allow plugins to hook into Nethermind's startup sequence. Each step implements the [`IStep`](https://github.com/NethermindEth/nethermind/blob/master/src/Nethermind/Nethermind.Api/Steps/IEthereumRunnerStep.cs) interface and is resolved through Autofac, so its dependencies are injected automatically via the constructor:
+
+```csharp title="DemoStep.cs" showLineNumbers
+using System.Threading;
+using System.Threading.Tasks;
+using Nethermind.Api.Steps;
+using Nethermind.Logging;
+
+namespace DemoPlugin;
+
+public class DemoStep(ILogManager logManager) : IStep
+{
+ public Task Execute(CancellationToken cancellationToken)
+ {
+ var logger = logManager.GetClassLogger();
+ logger.Warn("Hello from DemoStep!");
+
+ return Task.CompletedTask;
+ }
+}
+```
+
+Steps may declare dependencies on other steps to control the startup order using the `RunnerStepDependencies` attribute:
+
+```csharp
+using Nethermind.Api.Steps;
+using Nethermind.Init.Steps;
+
+// This step runs after InitializeBlockchain
+[RunnerStepDependencies(typeof(InitializeBlockchain))]
+public class DemoStep(ILogManager logManager) : IStep
+{
+ // ...
+}
+```
+
## Debugging
As your code grows more complex and sophisticated, you may want to debug it at some point. These are the two ways to do that:
@@ -244,7 +337,7 @@ As your code grows more complex and sophisticated, you may want to debug it at s
- [Attaching the debugger to the Nethermind process](#debug-attach)
- [Debugging the plugin together with the Nethermind codebase](#debug-codebase)
-### Attaching to process \{#debug-attach\}
+### Attaching to process {#debug-attach}
This approach is preferable if you focus on your plugin only and don't need to debug the Nethermind codebase.
@@ -275,11 +368,11 @@ Either of the above approaches will ensure Nethermind loads our plugin with the
-### Debugging with Nethermind codebase \{#debug-codebase\}
+### Debugging with Nethermind codebase {#debug-codebase}
Another way to debug plugins is to debug them along with the Nethermind codebase. That requires obtaining the Nethermind source code and debugging it with the IDE of your choice. Visual Studio and JetBrains Rider are the most popular choices. Let's try that with our `DemoPlugin` example.
-#### Step 1: Clone the Nethermind repo \{#debug-codebase-step-1\}
+#### Step 1: Clone the Nethermind repo {#debug-codebase-step-1}
We highly recommend cloning a stable version of the codebase to avoid any unwanted behavior on debugging. Usually, it's the [latest](https://github.com/NethermindEth/nethermind/releases/latest) released version of Nethermind. For example, the command below clones Nethermind v1.30.0:
@@ -287,11 +380,11 @@ We highly recommend cloning a stable version of the codebase to avoid any unwant
git clone -b "1.30.0" --depth 1 https://github.com/nethermindeth/nethermind.git
```
-#### Step 2: Configure the startup project \{#debug-codebase-step-2\}
+#### Step 2: Configure the startup project {#debug-codebase-step-2}
In the repo's root directory, open the `src/Nethermind/Nethermind.slnx` and set the `Nethermind.Runner` as a startup project. That is the Nethermind's executable that handles everything, including plugins.
-#### Step 3: Add the plugin project to the solution \{#debug-codebase-step-3\}
+#### Step 3: Add the plugin project to the solution {#debug-codebase-step-3}
Add the `DemoPlugin` project to the solution to have everything in one place. Then, let's set the `DemoPlugin` project output to Nethermind's `plugins` directory so the latest changes are always available for `Nethermind.Runner` to pick up. Add the following to the `DemoPlugin.csproj`:
@@ -302,7 +395,7 @@ Add the `DemoPlugin` project to the solution to have everything in one place. Th
```
-#### Step 4: Configure build dependencies \{#debug-codebase-step-4\}
+#### Step 4: Configure build dependencies {#debug-codebase-step-4}
Last, let's configure build dependencies so that launching `Nethermind.Runner` automatically builds our `DemoPlugin` with its latest changes, so you don't need to build the plugin separately each time before launching the debugger. With this said, we need to make the `Nethermind.Runner` project depend on the `DemoPlugin` project. See how to configure project dependencies below:
@@ -334,7 +427,7 @@ Thus, the `DemoPlugin` won't be included in the output of `Nethermind.Runner`. T
-#### Launching the debugger \{#debug-codebase-launch\}
+#### Launching the debugger {#debug-codebase-launch}
Now, we're ready to launch the debugger and check the Nethermind logs for our plugin. You may notice that the "Hello, world!" message is missing, although Nethermind logs show the plugin is loaded. That's because we made it configurable with the `Demo.Enabled` option, which is `false` by default. Let's set it to `true`.
@@ -382,19 +475,28 @@ Nethermind defines the following plugin types derived from [`INethermindPlugin`]
- #### [`IConsensusPlugin`](https://github.com/NethermindEth/nethermind/blob/master/src/Nethermind/Nethermind.Api/Extensions/IConsensusPlugin.cs)
- Plugins of this type provide support for consensus algorithms. For example, see the [`OptimismPlugin`][optimismplugin] or [`EthashPlugin`](https://github.com/NethermindEth/nethermind/blob/master/src/Nethermind/Nethermind.Consensus.Ethash/EthashPlugin.cs).
+ Plugins of this type provide support for consensus algorithms by implementing the block producer factory interfaces. Only one `IConsensusPlugin` can be active at a time. For example, see the [`OptimismPlugin`][optimismplugin] or [`EthashPlugin`](https://github.com/NethermindEth/nethermind/blob/master/src/Nethermind/Nethermind.Consensus.Ethash/EthashPlugin.cs).
- #### [`IConsensusWrapperPlugin`](https://github.com/NethermindEth/nethermind/blob/master/src/Nethermind/Nethermind.Api/Extensions/IConsensusWrapperPlugin.cs)
- Plugins of this type extend or change the handling of the Ethereum PoS consensus algorithm. For example, see the [`MergePlugin`](https://github.com/NethermindEth/nethermind/blob/master/src/Nethermind/Nethermind.Merge.Plugin/MergePlugin.cs) or [`ShutterPlugin`](https://github.com/NethermindEth/nethermind/blob/master/src/Nethermind/Nethermind.Shutter/ShutterPlugin.cs).
-
-- #### [`IInitializationPlugin`](https://github.com/NethermindEth/nethermind/blob/master/src/Nethermind/Nethermind.Api/Extensions/IInitializationPlugin.cs)
+ Plugins of this type extend or change the handling of the Ethereum PoS consensus algorithm by wrapping the block production pipeline. For example, see the [`MergePlugin`](https://github.com/NethermindEth/nethermind/blob/master/src/Nethermind/Nethermind.Merge.Plugin/MergePlugin.cs) or [`ShutterPlugin`](https://github.com/NethermindEth/nethermind/blob/master/src/Nethermind/Nethermind.Shutter/ShutterPlugin.cs).
- Plugins of this type define _steps_ required to complete during Nethermind initialization. For example, see the [`SnapshotPlugin`](https://github.com/NethermindEth/nethermind/blob/master/src/Nethermind/Nethermind.Init.Snapshot/SnapshotPlugin.cs).
+### INethermindPlugin reference {#plugin-interface}
-- #### [`ISynchronizationPlugin`](https://github.com/NethermindEth/nethermind/blob/master/src/Nethermind/Nethermind.Api/Extensions/ISynchronizationPlugin.cs)
+The [`INethermindPlugin`][inethermindplugin] interface has the following members. Properties `Name`, `Description`, `Author`, and `Enabled` are required. All methods have default (empty) implementations.
- Plugins of this type implement a custom sync logic. For example, see the [`OptimismPlugin`][optimismplugin] or [`TaikoPlugin`][taikoplugin].
+| Member | Description |
+|---|---|
+| `Name` | The display name of the plugin. |
+| `Description` | A brief description of the plugin. |
+| `Author` | The author of the plugin. |
+| `Enabled` | Whether the plugin is enabled. Only enabled plugins are initialized. |
+| `MustInitialize` | If `true`, Nethermind will not start if this plugin's initialization fails. Defaults to `false`. |
+| `Module` | An optional Autofac [`IModule`](https://autofac.readthedocs.io/en/latest/configuration/modules.html) for registering services and [initialization steps](#steps) with the DI container. Defaults to `null`. |
+| `Init(INethermindApi)` | The main initialization entry point. Called after the DI container is built. |
+| `InitNetworkProtocol()` | Initializes the network stack. |
+| `InitRpcModules()` | Initializes the JSON-RPC modules. |
+| `InitTxTypesAndRlpDecoders(INethermindApi)` | Registers custom transaction types and RLP decoders. |
## Samples
diff --git a/docs/developers/plugins/samples/json-rpc-handler.md b/docs/developers/plugins/samples/json-rpc-handler.md
index b6b47164c7..3f06de2bd3 100644
--- a/docs/developers/plugins/samples/json-rpc-handler.md
+++ b/docs/developers/plugins/samples/json-rpc-handler.md
@@ -73,6 +73,7 @@ public class DemoRpcPlugin : INethermindPlugin
public string Name => "Demo JSON-RPC plugin";
public string Description => "A sample plugin for demo";
public string Author => "Anonymous";
+ public bool Enabled => true;
public Task Init(INethermindApi nethermindApi)
{
@@ -81,8 +82,6 @@ public class DemoRpcPlugin : INethermindPlugin
return Task.CompletedTask;
}
- public Task InitNetworkProtocol() => Task.CompletedTask;
-
// highlight-start
public Task InitRpcModules()
{
@@ -91,9 +90,6 @@ public class DemoRpcPlugin : INethermindPlugin
return Task.CompletedTask;
}
// highlight-end
-
- public void InitTxTypesAndRlpDecoders(INethermindApi api) { }
- public ValueTask DisposeAsync() => default;
}
```
From 2689ee929b410a53dccc66adcbcfdacafe374dfc Mon Sep 17 00:00:00 2001
From: smartprogrammer93
Date: Tue, 24 Feb 2026 15:56:22 +0300
Subject: [PATCH 2/4] fixes
---
docs/developers/plugins/plugins.md | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/docs/developers/plugins/plugins.md b/docs/developers/plugins/plugins.md
index b773731d5a..fc028fa7dd 100644
--- a/docs/developers/plugins/plugins.md
+++ b/docs/developers/plugins/plugins.md
@@ -258,7 +258,7 @@ Options:
Nethermind uses [Autofac](https://autofac.org/) as its dependency injection (DI) container. Plugins can participate in DI by providing an Autofac `Module` through the `Module` property of `INethermindPlugin`. This is used to register services, override default implementations, and register initialization steps.
-Here is an example of a plugin that registers a custom service and an initialization step:
+Here is an example of a plugin that registers an initialization step:
```csharp title="DemoPlugin.cs" showLineNumbers
using Autofac;
@@ -294,7 +294,7 @@ public class DemoModule : Module
### Initialization steps (IStep) {#steps}
-Initialization steps allow plugins to hook into Nethermind's startup sequence. Each step implements the [`IStep`](https://github.com/NethermindEth/nethermind/blob/master/src/Nethermind/Nethermind.Api/Steps/IEthereumRunnerStep.cs) interface and is resolved through Autofac, so its dependencies are injected automatically via the constructor:
+Initialization steps allow plugins to hook into Nethermind's startup sequence. Each step implements the `IStep` interface (defined in [`IEthereumRunnerStep.cs`](https://github.com/NethermindEth/nethermind/blob/master/src/Nethermind/Nethermind.Api/Steps/IEthereumRunnerStep.cs)) and is resolved through Autofac, so its dependencies are injected automatically via the constructor:
```csharp title="DemoStep.cs" showLineNumbers
using System.Threading;
From b03f050b1c075264fca07ec85492e4bf3f344d80 Mon Sep 17 00:00:00 2001
From: Ruben Buniatyan
Date: Wed, 25 Feb 2026 15:46:33 +0100
Subject: [PATCH 3/4] Revise
---
docs/developers/plugins/plugins.md | 30 +++++++++++++++---------------
1 file changed, 15 insertions(+), 15 deletions(-)
diff --git a/docs/developers/plugins/plugins.md b/docs/developers/plugins/plugins.md
index fc028fa7dd..3cdc0a14b7 100644
--- a/docs/developers/plugins/plugins.md
+++ b/docs/developers/plugins/plugins.md
@@ -143,7 +143,7 @@ public class DemoConfig : IDemoConfig
}
```
-That's it for the configuration. Now, let's update our `DemoPlugin` class to use the configuration. Nethermind uses [Autofac](https://autofac.org/) for dependency injection. This means we can inject our configuration interface directly into the plugin's constructor:
+That's it for the configuration. Now, let's update our `DemoPlugin` class to use the configuration. Nethermind uses Autofac for [dependency injection](#dependency-injection-and-modules). This means we can inject our configuration interface directly into the plugin's constructor:
```csharp title="DemoPlugin.cs" showLineNumbers
using Nethermind.Api;
@@ -292,9 +292,9 @@ public class DemoModule : Module
// highlight-end
```
-### Initialization steps (IStep) {#steps}
+### Initialization steps {#steps}
-Initialization steps allow plugins to hook into Nethermind's startup sequence. Each step implements the `IStep` interface (defined in [`IEthereumRunnerStep.cs`](https://github.com/NethermindEth/nethermind/blob/master/src/Nethermind/Nethermind.Api/Steps/IEthereumRunnerStep.cs)) and is resolved through Autofac, so its dependencies are injected automatically via the constructor:
+Initialization steps allow plugins to hook into Nethermind's startup sequence. Each step implements the [`IStep`](https://github.com/NethermindEth/nethermind/blob/master/src/Nethermind/Nethermind.Api/Steps/IEthereumRunnerStep.cs) interface and is resolved through Autofac, so its dependencies are injected automatically via the constructor:
```csharp title="DemoStep.cs" showLineNumbers
using System.Threading;
@@ -485,18 +485,18 @@ Nethermind defines the following plugin types derived from [`INethermindPlugin`]
The [`INethermindPlugin`][inethermindplugin] interface has the following members. Properties `Name`, `Description`, `Author`, and `Enabled` are required. All methods have default (empty) implementations.
-| Member | Description |
-|---|---|
-| `Name` | The display name of the plugin. |
-| `Description` | A brief description of the plugin. |
-| `Author` | The author of the plugin. |
-| `Enabled` | Whether the plugin is enabled. Only enabled plugins are initialized. |
-| `MustInitialize` | If `true`, Nethermind will not start if this plugin's initialization fails. Defaults to `false`. |
-| `Module` | An optional Autofac [`IModule`](https://autofac.readthedocs.io/en/latest/configuration/modules.html) for registering services and [initialization steps](#steps) with the DI container. Defaults to `null`. |
-| `Init(INethermindApi)` | The main initialization entry point. Called after the DI container is built. |
-| `InitNetworkProtocol()` | Initializes the network stack. |
-| `InitRpcModules()` | Initializes the JSON-RPC modules. |
-| `InitTxTypesAndRlpDecoders(INethermindApi)` | Registers custom transaction types and RLP decoders. |
+| Member | Description |
+| ------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
+| `Name` | The display name of the plugin. |
+| `Description` | A brief description of the plugin. |
+| `Author` | The author of the plugin. |
+| `Enabled` | Whether the plugin is enabled. Only enabled plugins are initialized. |
+| `MustInitialize` | If `true`, Nethermind will not start if this plugin's initialization fails. Defaults to `false`. |
+| `Module` | An optional Autofac [`IModule`](https://autofac.readthedocs.io/en/latest/configuration/modules.html) for registering services and [initialization steps](#steps) with the DI container. Defaults to `null`. |
+| `Init(INethermindApi)` | The main initialization entry point. Called after the DI container is built. |
+| `InitNetworkProtocol()` | Initializes the network stack. |
+| `InitRpcModules()` | Initializes the JSON-RPC modules. |
+| `InitTxTypesAndRlpDecoders(INethermindApi)` | Registers custom transaction types and RLP decoders. |
## Samples
From 6c40860c809f61a3321fd1ebac2263f9a597e390 Mon Sep 17 00:00:00 2001
From: Ruben Buniatyan
Date: Wed, 25 Feb 2026 15:58:46 +0100
Subject: [PATCH 4/4] Update source link
---
docs/developers/plugins/plugins.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/docs/developers/plugins/plugins.md b/docs/developers/plugins/plugins.md
index 3cdc0a14b7..39aae35f66 100644
--- a/docs/developers/plugins/plugins.md
+++ b/docs/developers/plugins/plugins.md
@@ -294,7 +294,7 @@ public class DemoModule : Module
### Initialization steps {#steps}
-Initialization steps allow plugins to hook into Nethermind's startup sequence. Each step implements the [`IStep`](https://github.com/NethermindEth/nethermind/blob/master/src/Nethermind/Nethermind.Api/Steps/IEthereumRunnerStep.cs) interface and is resolved through Autofac, so its dependencies are injected automatically via the constructor:
+Initialization steps allow plugins to hook into Nethermind's startup sequence. Each step implements the [`IStep`](https://github.com/NethermindEth/nethermind/blob/master/src/Nethermind/Nethermind.Api/Steps/IStep.cs) interface and is resolved through Autofac, so its dependencies are injected automatically via the constructor:
```csharp title="DemoStep.cs" showLineNumbers
using System.Threading;