Skip to main content

Nethereum.DevChain.Server

NuGet: Nethereum.DevChain.Server | Source: src/Nethereum.DevChain.Server/

Nethereum.DevChain.Server

A local Ethereum development node with JSON-RPC server. Similar to Hardhat Network or Anvil but built entirely in .NET. Supports EVM opcodes up to the Prague hardfork.

Overview

  • HTTP JSON-RPC server on configurable port
  • Pre-funded accounts from HD wallet (default mnemonic compatible with Hardhat/Anvil)
  • Instant transaction mining (auto-mine) or configurable block intervals
  • Full EVM execution up to Prague hardfork with Geth-compatible tracing
  • SQLite storage by default with auto-cleanup on exit
  • State forking from live networks
  • Hardhat and Anvil-compatible RPC methods
  • Account impersonation for testing

Installation

As a .NET Global Tool

dotnet tool install -g Nethereum.DevChain.Server

Then run:

nethereum-devchain

From Source

dotnet run --project src/Nethereum.DevChain.Server

Quick Start

# Start with defaults (port 8545, 10 accounts, SQLite, auto-mine)
nethereum-devchain

# Custom port and more accounts
nethereum-devchain -p 8546 -a 20

# Set account balance to 100 ETH
nethereum-devchain -e 100

# Interval mining (1 block per second)
nethereum-devchain -b 1000

# Fork mainnet
nethereum-devchain -f https://eth.llamarpc.com --fork-block 19000000

# Persist chain data between restarts
nethereum-devchain --persist ./mychain

# Use in-memory storage (no SQLite)
nethereum-devchain --in-memory

Command-Line Options

USAGE: nethereum-devchain [OPTIONS]

SERVER:
-p, --port <PORT> Port to listen on (default: 8545)
--host <HOST> Host to bind to (default: 127.0.0.1)
-v, --verbose Enable verbose RPC logging

ACCOUNTS:
-a, --accounts <NUM> Number of accounts to generate (default: 10)
-m, --mnemonic <MNEMONIC> HD wallet mnemonic phrase
-e, --balance <ETH> Account balance in ETH (default: 10000)

CHAIN:
-c, --chain-id <ID> Chain ID (default: 31337)
-b, --block-time <MS> Block time in ms, 0 = auto-mine (default: 0)
--gas-limit <GAS> Block gas limit (default: 30000000)

FORK:
-f, --fork <URL> Fork from a remote RPC endpoint
--fork-block <NUMBER> Fork at a specific block number

STORAGE:
--persist [DIR] Persist chain data to disk (default: ./chaindata)
--in-memory Use in-memory storage instead of SQLite

Default storage is SQLite with auto-cleanup on exit. Use --persist to keep data between restarts.

Storage Modes

ModeFlagBlocks/TX/Receipts/LogsState/Filters/TrieCleanup
SQLite (default)(none)SQLite (temp file)In-MemoryAuto-delete on exit
SQLite persistent--persistSQLite (./chaindata)In-MemoryKept between restarts
In-memory--in-memoryIn-MemoryIn-MemoryLost on exit

SQLite uses WAL journal mode for good read/write concurrency. State, filters, and trie nodes remain in-memory for fast snapshot/revert operations.

Startup Banner

 _   _      _   _
| \ | | ___| |_| |__ ___ _ __ ___ _ _ _ __ ___
| \| |/ _ \ __| '_ \ / _ \ '__/ _ \ | | | '_ ` _ \
| |\ | __/ |_| | | | __/ | | __/ |_| | | | | | |
|_| \_|\___|\__|_| |_|\___|_| \___|\__,_|_| |_| |_|

DevChain Server v5.8.0

RPC: http://127.0.0.1:8545
Chain ID: 31337
Gas Limit: 30,000,000
Mining: auto-mine (instant)
Storage: SQLite (auto-cleanup on exit)

Available Accounts
==================
(0) 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266 (10000 ETH)
(1) 0x70997970C51812dc3A010C7d01b50e0d17dc79C8 (10000 ETH)
...

Private Keys
============
(0) 0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80
(1) 0x59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d
...

HD Wallet
=========
Mnemonic: test test test test test test test test test test test junk
Derivation Path: m/44'/60'/0'/0/x

Configuration File

Create appsettings.json in the working directory:

{
"DevChain": {
"Port": 8545,
"Host": "127.0.0.1",
"ChainId": 31337,
"BlockGasLimit": 30000000,
"AutoMine": true,
"BlockTime": 0,
"AccountCount": 10,
"Mnemonic": "test test test test test test test test test test test junk",
"Verbose": false,
"Storage": "sqlite",
"Persist": false,
"DataDir": "./chaindata",
"Fork": {
"Url": null,
"BlockNumber": null
}
}
}

Supported RPC Methods

Standard Ethereum

MethodDescription
web3_clientVersionClient version
web3_sha3Keccak-256 hash
net_versionNetwork ID
net_listeningListening status
net_peerCountPeer count
eth_chainIdChain ID
eth_blockNumberCurrent block number
eth_gasPriceGas price
eth_maxPriorityFeePerGasPriority fee
eth_feeHistoryFee history
eth_getBalanceAccount balance
eth_getCodeContract code
eth_getStorageAtStorage value
eth_getTransactionCountAccount nonce
eth_getBlockByNumberBlock by number
eth_getBlockByHashBlock by hash
eth_getBlockReceiptsAll receipts in block
eth_getTransactionByHashTransaction by hash
eth_getTransactionReceiptTransaction receipt
eth_sendRawTransactionSubmit transaction
eth_callExecute call
eth_estimateGasEstimate gas
eth_createAccessListGenerate access list
eth_getLogsQuery logs
eth_getProofMerkle proof
eth_accountsList funded accounts
eth_syncingSync status
eth_miningMining status

Development

MethodDescription
evm_mineMine a block
evm_snapshotCreate state snapshot
evm_revertRevert to snapshot
evm_increaseTimeAdvance block time
evm_setNextBlockTimestampSet next block timestamp

Account Management

MethodDescription
hardhat_setBalanceSet account balance
hardhat_setCodeSet contract code
hardhat_setNonceSet account nonce
hardhat_setStorageAtSet storage slot
hardhat_impersonateAccountImpersonate account
hardhat_stopImpersonatingAccountStop impersonating

Debug

MethodDescription
debug_traceTransactionTrace mined transaction
debug_traceCallTrace call without mining

Anvil Aliases

All hardhat_* and evm_* methods are also available with anvil_* prefix for Foundry/Anvil compatibility.

Usage Examples

Connect with Nethereum (C#)

using Nethereum.Web3;
using Nethereum.Web3.Accounts;

var account = new Account(
"0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80",
31337);
var web3 = new Web3(account, "http://127.0.0.1:8545");

var balance = await web3.Eth.GetBalance.SendRequestAsync(account.Address);
Console.WriteLine($"Balance: {Web3.Convert.FromWei(balance.Value)} ETH");

Connect with ethers.js

const { ethers } = require("ethers");

const provider = new ethers.JsonRpcProvider("http://127.0.0.1:8545");
const wallet = new ethers.Wallet(
"0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80",
provider);

const balance = await provider.getBalance(wallet.address);
console.log(`Balance: ${ethers.formatEther(balance)} ETH`);

Deploy Contract

var receipt = await web3.Eth.DeployContract.SendRequestAndWaitForReceiptAsync(
abi, bytecode, account.Address, new HexBigInteger(3000000));

Console.WriteLine($"Deployed at: {receipt.ContractAddress}");

Fork Mainnet

nethereum-devchain -f https://eth.llamarpc.com --fork-block 19000000

When forking:

  • State is fetched on-demand from the fork source
  • Local transactions modify local state only
  • Original fork state remains accessible

Time Manipulation

// Advance 1 day
await provider.send("evm_increaseTime", [86400]);
await provider.send("evm_mine", []);

// Set specific timestamp
await provider.send("evm_setNextBlockTimestamp", [1700000000]);
await provider.send("evm_mine", []);

Snapshots

const snapshotId = await provider.send("evm_snapshot", []);
// ... make changes ...
await provider.send("evm_revert", [snapshotId]);

Account Impersonation

await provider.send("hardhat_impersonateAccount", ["0xWhaleAddress"]);
// Send transactions as the impersonated account
await provider.send("hardhat_stopImpersonatingAccount", ["0xWhaleAddress"]);

Trace Transaction

const trace = await provider.send("debug_traceTransaction", [
txHash,
{ enableMemory: true, disableStack: false }
]);

console.log(`Gas: ${trace.gas}, Steps: ${trace.structLogs.length}`);

HTTP Endpoints

MethodPathDescription
POST/JSON-RPC endpoint (single or batch requests)
GET/Health check: {"status":"ok","version":"..."}

Max request body: 10MB. CORS enabled (any origin).

Default Accounts

Using the default mnemonic test test test test test test test test test test test junk:

IndexAddressPrivate Key
00xf39Fd6e51aad88F6F4ce6aB8827279cffFb922660xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80
10x70997970C51812dc3A010C7d01b50e0d17dc79C80x59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d
20x3C44CdDdB6a900fa2b585dd299e03d12FA4293BC0x5de4111afa1a4b94908f83103eb1f1706367c2e68ca870fc3fb9a804cdab365a
30x90F79bf6EB2c4f870365E785982E1f101E93b9060x7c852118294e51e653712a81e05800f419141751be58f605c371e15141b007a6
40x15d34AAf54267DB7D7c367839AAf71A00a2C6A650x47e179ec197488593b187f80a00eb0da91f1b9d0b13f8733639f19c30a34926a

Each account is funded with 10,000 ETH by default. The mnemonic and derivation path (m/44'/60'/0'/0/x) are the same as Hardhat and Anvil.

Architecture

┌─────────────────────────────────────────────────────────┐
│ HTTP Server (ASP.NET Minimal) │
├─────────────────────────────────────────────────────────┤
│ RpcDispatcher │
├──────────┬──────────┬──────────┬──────────┬─────────────┤
│ Standard │ Dev │ Debug │ Hardhat │ Anvil │
│ Handlers │ Handlers │ Handlers │ Handlers │ Aliases │
├─────────────────────────────────────────────────────────┤
│ DevChainNode │
├──────────┬──────────────────────┬───────────────────────┤
│ Block │ Transaction │ State │
│ Producer │ Processor │ Store │
├──────────┴──────────────────────┴───────────────────────┤
│ EVMSimulator (Nethereum.EVM) │
├─────────────────────────────────────────────────────────┤
│ SQLite (blocks/tx/receipts/logs) │ InMemory (state) │
└─────────────────────────────────────────────────────────┘

Standard Dev Chain Features

Nethereum DevChain implements the standard feature set expected from Ethereum development nodes (Hardhat Network, Anvil, etc.):

  • Fork support from live networks
  • Transaction tracing (Geth-compatible debug APIs)
  • Account impersonation
  • State snapshots and revert
  • evm_* and hardhat_* RPC methods
  • Same default mnemonic and derivation path as Hardhat/Anvil
  • Pre-funded accounts with configurable balances

Additionally, Nethereum DevChain provides:

  • Native .NET integration - embed directly in .NET applications and tests
  • SQLite default storage - bounded memory usage for long-running sessions
  • Persistent storage - keep chain state between restarts with --persist
  • Prague hardfork support - latest EVM opcode support

Aspire Integration

DevChain.Server integrates with .NET Aspire for orchestrated development environments. The Nethereum.Aspire.DevChain project wraps the server with Aspire service defaults:

// AppHost/Program.cs
var devchain = builder.AddProject<Projects.Nethereum_Aspire_DevChain>("devchain");

var indexer = builder.AddProject<Projects.Nethereum_Aspire_Indexer>("indexer")
.WithReference(devchain)
.WaitFor(devchain);

The Aspire wrapper uses the same AddDevChainServer(config) DI extension and DevChainHostedService. Configuration via appsettings.json or environment variables works identically. The Aspire variant defaults to in-memory storage since lifecycle is managed by the orchestrator.

Embedding in .NET Applications

Use AddDevChainServer directly in any ASP.NET application:

var config = new DevChainServerConfig { ChainId = 31337, Storage = "memory" };
builder.Services.AddDevChainServer(config);
builder.Services.AddHostedService<DevChainHostedService>();

This registers DevChainNode, RpcDispatcher, DevAccountManager, and all storage providers as singletons. The DevChainHostedService handles startup and graceful shutdown.

  • Nethereum.DevChain - Core development chain library
  • Nethereum.CoreChain - Blockchain infrastructure and storage interfaces
  • Nethereum.EVM - EVM simulator
  • Nethereum.Geth - Geth-compatible APIs

Additional Resources