Skip to main content

Nethereum.DevChain

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

Nethereum.DevChain

Development blockchain with full EVM execution up to the Prague hardfork, automatic mining, SQLite storage, and extended RPC support. A local Ethereum-compatible chain for testing and development.

Overview

Nethereum.DevChain provides a complete local blockchain environment:

  • Instant Mining - Transactions mined immediately or on a configurable interval
  • Full EVM Execution - EVM opcode support up to Prague via Nethereum.EVM
  • SQLite Storage - Default lightweight storage with auto-cleanup (no native dependencies)
  • State Management - Patricia trie-based state with snapshot/revert
  • Extended RPC - Development, debug, and Anvil-compatible APIs
  • Transaction Tracing - Geth-compatible debug_traceTransaction and debug_traceCall
  • Forking - Fork from live Ethereum networks

Installation

dotnet add package Nethereum.DevChain

Dependencies

  • Nethereum.CoreChain - Core blockchain infrastructure
  • Nethereum.RPC.Extensions - Extended RPC utilities
  • Nethereum.JsonRpc.RpcClient - JSON-RPC client
  • Nethereum.RPC - Standard debug tracing DTOs
  • Microsoft.Data.Sqlite - SQLite storage provider

Quick Start

Default (SQLite with auto-cleanup)

using Nethereum.DevChain;

var node = new DevChainNode();
await node.StartAsync(new[] { "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266" });

// Use the node...

node.Dispose(); // SQLite DB deleted automatically

With Custom Config

var config = new DevChainConfig
{
ChainId = 1337,
BlockGasLimit = 30_000_000,
AutoMine = true,
InitialBalance = BigInteger.Parse("10000000000000000000000") // 10000 ETH
};

var node = new DevChainNode(config);
await node.StartAsync(fundedAddresses);

Fully In-Memory

var node = DevChainNode.CreateInMemory();
await node.StartAsync(fundedAddresses);

Persistent SQLite

var node = new DevChainNode("./mychain/chain.db", persistDb: true);
await node.StartAsync(fundedAddresses);
// DB survives restart

Convenience Factory

var node = await DevChainNode.CreateAndStartAsync(
fundedAddresses,
new DevChainConfig { ChainId = 31337 }
);

Storage Architecture

DevChain uses a hybrid storage strategy by default:

DataStoreReason
BlocksSQLiteHistorical, grows unbounded
TransactionsSQLiteHistorical, grows unbounded
ReceiptsSQLiteHistorical, grows unbounded
LogsSQLiteHistorical, grows unbounded
StateIn-MemoryNeeds fast snapshot/revert
FiltersIn-MemoryTransient, bounded
Trie NodesIn-MemoryNeeds fast access

SQLite uses WAL journal mode for concurrent reads during block production. The database is auto-deleted on dispose unless persistence is enabled.

Configuration

public class DevChainConfig
{
public int ChainId { get; set; } = 1337;
public long BlockGasLimit { get; set; } = 30_000_000;
public bool AutoMine { get; set; } = true;
public long BlockTime { get; set; } = 0; // 0 = instant
public int MaxTransactionsPerBlock { get; set; } = 100;
public BigInteger BaseFee { get; set; } = 1_000_000_000; // 1 gwei
public BigInteger InitialBalance { get; set; };

// Forking
public string ForkUrl { get; set; }
public long? ForkBlockNumber { get; set; }

// Auto-mine batching
public int AutoMineBatchSize { get; set; } = 1;
public int AutoMineBatchTimeoutMs { get; set; } = 100;
}

// Built-in presets
var config = DevChainConfig.Default; // ChainId 1337
var config = DevChainConfig.Hardhat; // ChainId 31337
var config = DevChainConfig.Anvil; // ChainId 31337

Core Features

Transaction Processing

// Send raw transaction
var txHash = await node.SendRawTransactionAsync(signedTxBytes);

// Get receipt
var receipt = await node.GetTransactionReceiptAsync(txHash);

Contract Execution

using Nethereum.RPC.Eth.DTOs;

var callInput = new CallInput
{
From = "0x1234...",
To = contractAddress,
Data = "0x..."
};

// Execute without state change
var result = await node.CallAsync(callInput);

// Estimate gas
var gasEstimate = await node.EstimateGasAsync(callInput);

State Access

var balance = await node.GetBalanceAsync(address);
var code = await node.GetCodeAsync(contractAddress);
var storage = await node.GetStorageAtAsync(contractAddress, slot);
var nonce = await node.GetTransactionCountAsync(address);

Account Management

Modify account state for testing:

await node.SetBalanceAsync(address, newBalance);
await node.SetCodeAsync(address, bytecode);
await node.SetStorageAtAsync(address, slot, value);
await node.SetNonceAsync(address, nonce);

Snapshots

// Take snapshot
var snapshotId = await node.SnapshotAsync();

// Execute transactions...

// Revert all changes
await node.RevertToSnapshotAsync(snapshotId);

Block Mining

// Manual mining
await node.MineBlockAsync();

// Time manipulation
node.Config.NextBlockTimestamp = DateTimeOffset.UtcNow.AddDays(1).ToUnixTimeSeconds();
await node.MineBlockAsync();

Debug/Trace APIs

debug_traceTransaction

Trace a mined transaction step-by-step:

using Nethereum.RPC.DebugNode.Tracers;

var config = new OpcodeTracerConfigDto
{
EnableMemory = true,
DisableStack = false,
DisableStorage = false,
EnableReturnData = true,
Limit = 1000
};

var trace = await node.TraceTransactionAsync(txHash, config);

foreach (var log in trace.StructLogs)
{
Console.WriteLine($"PC: {log.Pc}, Op: {log.Op}, Gas: {log.Gas}");
}

debug_traceCall

Trace a call without mining, with optional state overrides:

var stateOverrides = new Dictionary<string, StateOverrideDto>
{
[address] = new StateOverrideDto
{
Balance = "0x1000000000000000000",
Code = "0x...",
State = new Dictionary<string, string>
{
["0x0"] = "0x..."
}
}
};

var trace = await node.TraceCallAsync(callInput, config, stateOverrides);

RPC Handler Extensions

Register DevChain-specific RPC handlers:

using Nethereum.DevChain.Rpc;
using Nethereum.CoreChain.Rpc;

var registry = new RpcHandlerRegistry();
registry.AddStandardHandlers(); // Core Ethereum methods
registry.AddDevHandlers(); // Dev/debug methods
registry.AddAnvilAliases(); // Anvil compatibility

Development Methods

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

Account Management Methods

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

Debug Methods

MethodDescription
debug_traceTransactionTrace mined transaction
debug_traceCallTrace call without mining

Anvil Aliases

All hardhat_* methods are also available as anvil_* for compatibility:

Anvil MethodMaps To
anvil_setBalancehardhat_setBalance
anvil_setCodehardhat_setCode
anvil_setNoncehardhat_setNonce
anvil_setStorageAthardhat_setStorageAt
anvil_impersonateAccounthardhat_impersonateAccount
anvil_stopImpersonatingAccounthardhat_stopImpersonatingAccount
anvil_mineevm_mine
anvil_snapshotevm_snapshot
anvil_revertevm_revert

Usage with RPC Server

DevChain is typically used with Nethereum.DevChain.Server:

using Nethereum.DevChain;
using Nethereum.DevChain.Rpc;
using Nethereum.CoreChain.Rpc;

var node = new DevChainNode(config);
await node.StartAsync(fundedAddresses);

var registry = new RpcHandlerRegistry();
registry.AddStandardHandlers();
registry.AddDevHandlers();
registry.AddAnvilAliases();

var context = new RpcContext(node, chainId, services);
var dispatcher = new RpcDispatcher(registry, context);

var response = await dispatcher.DispatchAsync(request);

Forking

Fork from live Ethereum networks to test against real state:

var config = new DevChainConfig
{
ForkUrl = "https://eth.llamarpc.com",
ForkBlockNumber = 19000000
};

var node = await DevChainNode.CreateAndStartAsync(fundedAddresses, config);

// Reads hit fork source on cache miss, writes are local only
var balance = await node.GetBalanceAsync("0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045");

Historical State

DevChain supports querying state at any past block when using HistoricalStateStore:

// State diffs are automatically recorded per block
// Query balance at a specific block
var pastBalance = await node.GetBalanceAsync(address, blockNumber: 5);
  • Nethereum.CoreChain - Core blockchain infrastructure and storage interfaces
  • Nethereum.DevChain.Server - HTTP JSON-RPC server (dotnet tool)
  • Nethereum.Aspire.DevChain - Aspire-orchestrated variant for distributed dev environments
  • Nethereum.EVM - EVM simulator
  • Nethereum.RPC - Standard debug tracing DTOs

Additional Resources