![]() |
VOOZH | about |
dotnet add package Nethereum.DevChain --version 6.1.0
NuGet\Install-Package Nethereum.DevChain -Version 6.1.0
<PackageReference Include="Nethereum.DevChain" Version="6.1.0" />
<PackageVersion Include="Nethereum.DevChain" Version="6.1.0" />Directory.Packages.props
<PackageReference Include="Nethereum.DevChain" />Project file
paket add Nethereum.DevChain --version 6.1.0
#r "nuget: Nethereum.DevChain, 6.1.0"
#:package Nethereum.DevChain@6.1.0
#addin nuget:?package=Nethereum.DevChain&version=6.1.0Install as a Cake Addin
#tool nuget:?package=Nethereum.DevChain&version=6.1.0Install as a Cake Tool
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.
Nethereum.DevChain provides a complete local blockchain environment:
dotnet add package Nethereum.DevChain
using Nethereum.DevChain;
var node = new DevChainNode();
await node.StartAsync(new[] { "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266" });
// Use the node...
node.Dispose(); // SQLite DB deleted automatically
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);
var node = DevChainNode.CreateInMemory();
await node.StartAsync(fundedAddresses);
var node = new DevChainNode(DevChainConfig.Default, "./mychain/chain.db", persistDb: true);
await node.StartAsync(fundedAddresses);
// DB survives restart
var node = new DevChainNode(new DevChainConfig { ChainId = 31337 });
await node.StartAsync(new[] { "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266" });
DevChain uses a hybrid storage strategy by default:
| Data | Store | Reason |
|---|---|---|
| Blocks | SQLite | Historical, grows unbounded |
| Transactions | SQLite | Historical, grows unbounded |
| Receipts | SQLite | Historical, grows unbounded |
| Logs | SQLite | Historical, grows unbounded |
| State | In-Memory | Needs fast snapshot/revert |
| Filters | In-Memory | Transient, bounded |
| Trie Nodes | In-Memory | Needs fast access |
SQLite uses WAL journal mode for concurrent reads during block production. The database is auto-deleted on dispose unless persistence is enabled.
DevChainConfig inherits from ChainConfig. Properties like ChainId, BlockGasLimit, BaseFee, and InitialBalance come from the base class.
public class DevChainConfig : ChainConfig
{
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; }; // Default: 10000 ETH (BigInteger.Parse("10000000000000000000000"))
// 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; } = 10;
}
// Built-in presets
var config = DevChainConfig.Default; // ChainId 1337
var config = DevChainConfig.Hardhat; // ChainId 31337
var config = DevChainConfig.Anvil; // ChainId 31337
// Send a signed transaction
var txHash = await node.SendTransactionAsync(signedTransaction);
// Get receipt
var receipt = await node.GetTransactionReceiptAsync(txHash);
// Raw byte sending (eth_sendRawTransaction) is available via the RPC layer
// Execute without state change (individual parameters)
var result = await node.CallAsync(
to: contractAddress,
data: dataBytes,
from: senderAddress,
value: null,
gasLimit: null
);
// eth_call and eth_estimateGas are also available via the RPC layer with CallInput objects
var balance = await node.GetBalanceAsync(address);
var code = await node.GetCodeAsync(contractAddress);
var storage = await node.GetStorageAtAsync(contractAddress, slot);
var nonce = await node.GetNonceAsync(address);
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);
// Take snapshot (returns IStateSnapshot)
var snapshot = await node.TakeSnapshotAsync();
// Execute transactions...
// Revert all changes (takes the snapshot object)
await node.RevertToSnapshotAsync(snapshot);
// Manual mining
await node.MineBlockAsync();
// Time manipulation
node.DevConfig.NextBlockTimestamp = DateTimeOffset.UtcNow.AddDays(1).ToUnixTimeSeconds();
await node.MineBlockAsync();
Trace a mined transaction step-by-step:
using Nethereum.CoreChain.Tracing;
var config = new OpcodeTraceConfig
{
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}");
}
Trace a call without mining, with optional state overrides:
using Nethereum.CoreChain.Tracing;
var stateOverrides = new Dictionary<string, StateOverride>
{
[address] = new StateOverride
{
Balance = "0x1000000000000000000",
Code = "0x...",
State = new Dictionary<string, string>
{
["0x0"] = "0x..."
}
}
};
var trace = await node.TraceCallAsync(callInput, config, stateOverrides);
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
| Method | Description |
|---|---|
evm_mine |
Mine a block |
evm_snapshot |
Create state snapshot |
evm_revert |
Revert to snapshot |
evm_increaseTime |
Increase block timestamp |
evm_setNextBlockTimestamp |
Set next block timestamp |
| Method | Description |
|---|---|
hardhat_setBalance |
Set account balance |
hardhat_setCode |
Set contract code |
hardhat_setNonce |
Set account nonce |
hardhat_setStorageAt |
Set storage slot |
hardhat_impersonateAccount |
Impersonate account |
hardhat_stopImpersonatingAccount |
Stop impersonating |
| Method | Description |
|---|---|
debug_traceTransaction |
Trace mined transaction |
debug_traceCall |
Trace call without mining |
All hardhat_* methods are also available as anvil_* for compatibility:
| Anvil Method | Maps To |
|---|---|
anvil_setBalance |
hardhat_setBalance |
anvil_setCode |
hardhat_setCode |
anvil_setNonce |
hardhat_setNonce |
anvil_setStorageAt |
hardhat_setStorageAt |
anvil_mine |
evm_mine |
anvil_snapshot |
evm_snapshot |
anvil_revert |
evm_revert |
anvil_impersonateAccount |
hardhat_impersonateAccount |
anvil_stopImpersonatingAccount |
hardhat_stopImpersonatingAccount |
DevChain includes reusable extensions for hosting in any ASP.NET Core application:
using Nethereum.DevChain.Configuration;
using Nethereum.DevChain.Hosting;
var builder = WebApplication.CreateBuilder(args);
var config = new DevChainServerConfig { ChainId = 31337, Storage = "sqlite" };
builder.AddDevChainServer(config); // Registers DI services, CORS, and hosted service
var app = builder.Build();
app.MapDevChainEndpoints(); // Maps JSON-RPC POST /, health GET /, and CORS middleware
app.Run();
AddDevChainServer registers DevChainNode, RpcDispatcher, DevAccountManager, storage providers, CORS, and DevChainHostedService as singletons.
For non-web scenarios, use the lower-level DI extension on IServiceCollection:
using Nethereum.DevChain.Hosting;
services.AddDevChainServer(config); // IServiceCollection extension
Fork from live Ethereum networks to test against real state:
var config = new DevChainConfig
{
ForkUrl = "https://eth.llamarpc.com",
ForkBlockNumber = 19000000
};
var node = new DevChainNode(config);
await node.StartAsync(fundedAddresses);
// Reads hit fork source on cache miss, writes are local only
var balance = await node.GetBalanceAsync("0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045");
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);
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net8.0 net8.0 is compatible. net8.0-android net8.0-android was computed. net8.0-browser net8.0-browser was computed. net8.0-ios net8.0-ios was computed. net8.0-maccatalyst net8.0-maccatalyst was computed. net8.0-macos net8.0-macos was computed. net8.0-tvos net8.0-tvos was computed. net8.0-windows net8.0-windows was computed. net9.0 net9.0 is compatible. net9.0-android net9.0-android was computed. net9.0-browser net9.0-browser was computed. net9.0-ios net9.0-ios was computed. net9.0-maccatalyst net9.0-maccatalyst was computed. net9.0-macos net9.0-macos was computed. net9.0-tvos net9.0-tvos was computed. net9.0-windows net9.0-windows was computed. net10.0 net10.0 is compatible. net10.0-android net10.0-android was computed. net10.0-browser net10.0-browser was computed. net10.0-ios net10.0-ios was computed. net10.0-maccatalyst net10.0-maccatalyst was computed. net10.0-macos net10.0-macos was computed. net10.0-tvos net10.0-tvos was computed. net10.0-windows net10.0-windows was computed. |
This package is not used by any NuGet packages.
This package is not used by any popular GitHub repositories.