Skip to content

Commit 3bc0939

Browse files
Nethereum DevChain updates using the core chain base node
1 parent 8d43b6b commit 3bc0939

11 files changed

Lines changed: 702 additions & 981 deletions

File tree

src/Nethereum.DevChain.Server/Accounts/DevAccountManager.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
using System.Numerics;
2-
using Nethereum.HdWallet;
2+
using Nethereum.Wallet.Bip32;
33
using Nethereum.DevChain.Server.Configuration;
44

55
namespace Nethereum.DevChain.Server.Accounts
@@ -8,15 +8,15 @@ public class DevAccountManager
88
{
99
private readonly List<DevAccount> _accounts = new();
1010
private readonly HashSet<string> _impersonatedAccounts = new(StringComparer.OrdinalIgnoreCase);
11-
private readonly Wallet _wallet;
11+
private readonly MinimalHDWallet _wallet;
1212
private readonly BigInteger _chainId;
1313

1414
public IReadOnlyList<DevAccount> Accounts => _accounts;
1515
public IReadOnlySet<string> ImpersonatedAccounts => _impersonatedAccounts;
1616

1717
public DevAccountManager(DevChainServerConfig config)
1818
{
19-
_wallet = new Wallet(config.Mnemonic, null);
19+
_wallet = new MinimalHDWallet(config.Mnemonic);
2020
_chainId = config.ChainId;
2121

2222
var initialBalance = config.GetAccountBalance();

src/Nethereum.DevChain.Server/Configuration/DevChainServerConfig.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,10 @@ public class DevChainServerConfig
1717
public string AccountBalance { get; set; } = "10000000000000000000000";
1818
public ForkConfig? Fork { get; set; }
1919
public bool Verbose { get; set; } = false;
20+
public int AutoMineBatchSize { get; set; } = 1;
21+
public int AutoMineBatchTimeoutMs { get; set; } = 10;
22+
public string Storage { get; set; } = "memory";
23+
public string DataDir { get; set; } = "./chaindata";
2024

2125
public BigInteger GetAccountBalance()
2226
{
@@ -30,6 +34,8 @@ public DevChainConfig ToDevChainConfig()
3034
ChainId = ChainId,
3135
BlockGasLimit = BlockGasLimit,
3236
AutoMine = AutoMine,
37+
AutoMineBatchSize = AutoMineBatchSize,
38+
AutoMineBatchTimeoutMs = AutoMineBatchTimeoutMs,
3339
InitialBalance = GetAccountBalance(),
3440
ForkUrl = Fork?.Url,
3541
ForkBlockNumber = Fork?.BlockNumber

src/Nethereum.DevChain.Server/Nethereum.DevChain.Server.csproj

Lines changed: 26 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,18 @@
33

44
<PropertyGroup>
55
<OutputType>Exe</OutputType>
6-
<TargetFramework>net8.0</TargetFramework>
6+
<TargetFramework>net9.0</TargetFramework>
77
<ImplicitUsings>enable</ImplicitUsings>
88
<Nullable>enable</Nullable>
99
<RootNamespace>Nethereum.DevChain.Server</RootNamespace>
1010

11+
<!-- AOT Configuration (disabled for RocksDB compatibility)
12+
<PublishAot>true</PublishAot>
13+
<IsAotCompatible>true</IsAotCompatible>
14+
-->
15+
<InvariantGlobalization>true</InvariantGlobalization>
16+
<EnableRequestDelegateGenerator>false</EnableRequestDelegateGenerator>
17+
1118
<!-- Tool Configuration -->
1219
<PackAsTool>true</PackAsTool>
1320
<ToolCommandName>nethereum-devchain</ToolCommandName>
@@ -26,21 +33,34 @@
2633
<None Include="README.md" Pack="true" PackagePath="" />
2734
</ItemGroup>
2835

36+
<!-- Link Bip32 files from Nethereum.Wallet (no NBitcoin dependency) -->
37+
<ItemGroup>
38+
<Compile Include="..\Nethereum.Wallet\Bip32\MinimalHDWallet.cs" Link="Bip32\MinimalHDWallet.cs" />
39+
<Compile Include="..\Nethereum.Wallet\Bip32\Bip39.cs" Link="Bip32\Bip39.cs" />
40+
</ItemGroup>
41+
2942
<ItemGroup>
3043
<ProjectReference Include="..\Nethereum.DevChain\Nethereum.DevChain.csproj" />
3144
<ProjectReference Include="..\Nethereum.CoreChain\Nethereum.CoreChain.csproj" />
45+
<ProjectReference Include="..\Nethereum.CoreChain.RocksDB\Nethereum.CoreChain.RocksDB.csproj" />
3246
<ProjectReference Include="..\Nethereum.Web3\Nethereum.Web3.csproj" />
33-
<ProjectReference Include="..\Nethereum.HdWallet\Nethereum.HdWallet.csproj" />
3447
<ProjectReference Include="..\Nethereum.JsonRpc.Client\Nethereum.JsonRpc.Client.csproj" />
3548
<ProjectReference Include="..\Nethereum.JsonRpc.RpcClient\Nethereum.JsonRpc.RpcClient.csproj" />
3649
<ProjectReference Include="..\Nethereum.Signer\Nethereum.Signer.csproj" />
3750
</ItemGroup>
3851

3952
<ItemGroup>
40-
<PackageReference Include="Microsoft.Extensions.Hosting" Version="8.0.0" />
41-
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="8.0.0" />
42-
<PackageReference Include="Microsoft.Extensions.Configuration.CommandLine" Version="8.0.0" />
43-
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="8.0.0" />
53+
<PackageReference Include="Microsoft.Extensions.Hosting" Version="9.0.0" />
54+
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="9.0.0" />
55+
<PackageReference Include="Microsoft.Extensions.Configuration.CommandLine" Version="9.0.0" />
56+
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="9.0.0" />
57+
</ItemGroup>
58+
59+
<ItemGroup>
60+
<TrimmerRootAssembly Include="Nethereum.Contracts" />
61+
<TrimmerRootAssembly Include="Nethereum.ABI" />
62+
<TrimmerRootAssembly Include="Nethereum.Hex" />
63+
<TrimmerRootAssembly Include="Nethereum.DevChain.Server" />
4464
</ItemGroup>
4565

4666
</Project>

src/Nethereum.DevChain.Server/Program.cs

Lines changed: 90 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -56,54 +56,57 @@
5656
return;
5757
}
5858

59-
var jsonOptions = new JsonSerializerOptions
60-
{
61-
PropertyNameCaseInsensitive = true
62-
};
59+
httpContext.Response.ContentType = "application/json";
6360

6461
if (json.TrimStart().StartsWith('['))
6562
{
66-
var requests = JsonSerializer.Deserialize<RpcRequestMessage[]>(json, jsonOptions);
63+
var requests = JsonSerializer.Deserialize(json, CoreChainJsonContext.Default.JsonRpcRequestArray);
6764
if (requests != null)
6865
{
69-
var responses = await dispatcher.DispatchBatchAsync(requests);
70-
httpContext.Response.ContentType = "application/json";
71-
await httpContext.Response.WriteAsync(JsonSerializer.Serialize(responses));
66+
var rpcRequests = requests.Select(ToRpcRequestMessage).ToArray();
67+
var responses = await dispatcher.DispatchBatchAsync(rpcRequests);
68+
var jsonResponses = responses.Select(ToJsonRpcResponse).ToArray();
69+
await httpContext.Response.WriteAsync(JsonSerializer.Serialize(jsonResponses, CoreChainJsonContext.Default.JsonRpcResponseArray));
7270
return;
7371
}
7472
}
7573

76-
var request = JsonSerializer.Deserialize<RpcRequestMessage>(json, jsonOptions);
74+
var request = JsonSerializer.Deserialize(json, CoreChainJsonContext.Default.JsonRpcRequest);
7775
if (request == null)
7876
{
7977
httpContext.Response.StatusCode = 400;
80-
await httpContext.Response.WriteAsJsonAsync(new { error = "Invalid JSON-RPC request" });
78+
await httpContext.Response.WriteAsync("{\"error\":\"Invalid JSON-RPC request\"}");
8179
return;
8280
}
8381

84-
var response = await dispatcher.DispatchAsync(request);
85-
httpContext.Response.ContentType = "application/json";
86-
await httpContext.Response.WriteAsync(JsonSerializer.Serialize(response));
82+
var rpcRequest = ToRpcRequestMessage(request);
83+
var response = await dispatcher.DispatchAsync(rpcRequest);
84+
var jsonResponse = ToJsonRpcResponse(response);
85+
await httpContext.Response.WriteAsync(JsonSerializer.Serialize(jsonResponse, CoreChainJsonContext.Default.JsonRpcResponse));
8786
}
8887
catch (JsonException ex)
8988
{
9089
logger.LogError(ex, "JSON parsing error");
9190
httpContext.Response.StatusCode = 400;
92-
await httpContext.Response.WriteAsJsonAsync(new RpcResponseMessage(null, new RpcError
91+
httpContext.Response.ContentType = "application/json";
92+
var errorResponse = new JsonRpcResponse
9393
{
94-
Code = -32700,
95-
Message = "Parse error: " + ex.Message
96-
}));
94+
Id = null,
95+
Error = new JsonRpcError { Code = -32700, Message = "Parse error: " + ex.Message }
96+
};
97+
await httpContext.Response.WriteAsync(JsonSerializer.Serialize(errorResponse, CoreChainJsonContext.Default.JsonRpcResponse));
9798
}
9899
catch (Exception ex)
99100
{
100101
logger.LogError(ex, "Unexpected error");
101102
httpContext.Response.StatusCode = 500;
102-
await httpContext.Response.WriteAsJsonAsync(new RpcResponseMessage(null, new RpcError
103+
httpContext.Response.ContentType = "application/json";
104+
var errorResponse = new JsonRpcResponse
103105
{
104-
Code = -32603,
105-
Message = "Internal error: " + ex.Message
106-
}));
106+
Id = null,
107+
Error = new JsonRpcError { Code = -32603, Message = "Internal error: " + ex.Message }
108+
};
109+
await httpContext.Response.WriteAsync(JsonSerializer.Serialize(errorResponse, CoreChainJsonContext.Default.JsonRpcResponse));
107110
}
108111
});
109112

@@ -133,6 +136,20 @@ void PrintBanner(DevChainServerConfig config, DevAccountManager accounts)
133136
Console.ResetColor();
134137
Console.WriteLine($"Chain ID: {config.ChainId}");
135138

139+
if (config.Storage?.ToLowerInvariant() == "rocksdb")
140+
{
141+
Console.ForegroundColor = ConsoleColor.Blue;
142+
Console.WriteLine($"Storage: RocksDB ({config.DataDir})");
143+
Console.ResetColor();
144+
}
145+
146+
if (config.AutoMineBatchSize > 1)
147+
{
148+
Console.ForegroundColor = ConsoleColor.Magenta;
149+
Console.WriteLine($"Batch Mining: {config.AutoMineBatchSize} txs / {config.AutoMineBatchTimeoutMs}ms timeout");
150+
Console.ResetColor();
151+
}
152+
136153
if (config.Fork?.Url != null)
137154
{
138155
Console.WriteLine($"Forking from: {config.Fork.Url}");
@@ -213,5 +230,57 @@ void ApplyCommandLineOverrides(DevChainServerConfig config, string[] args)
213230
{
214231
config.Verbose = true;
215232
}
233+
else if (arg == "--batch-size" && i + 1 < args.Length)
234+
{
235+
if (int.TryParse(args[++i], out var batchSize))
236+
config.AutoMineBatchSize = batchSize;
237+
}
238+
else if (arg == "--batch-timeout" && i + 1 < args.Length)
239+
{
240+
if (int.TryParse(args[++i], out var timeoutMs))
241+
config.AutoMineBatchTimeoutMs = timeoutMs;
242+
}
243+
else if (arg == "--storage" && i + 1 < args.Length)
244+
{
245+
config.Storage = args[++i];
246+
}
247+
else if (arg == "--data-dir" && i + 1 < args.Length)
248+
{
249+
config.DataDir = args[++i];
250+
}
251+
}
252+
}
253+
254+
RpcRequestMessage ToRpcRequestMessage(JsonRpcRequest request)
255+
{
256+
return new RpcRequestMessage
257+
{
258+
Id = request.Id,
259+
Method = request.Method,
260+
JsonRpcVersion = request.Jsonrpc,
261+
RawParameters = request.Params.HasValue ? request.Params.Value : null
262+
};
263+
}
264+
265+
JsonRpcResponse ToJsonRpcResponse(RpcResponseMessage response)
266+
{
267+
if (response.HasError)
268+
{
269+
return new JsonRpcResponse
270+
{
271+
Id = response.Id,
272+
Error = new JsonRpcError
273+
{
274+
Code = response.Error.Code,
275+
Message = response.Error.Message,
276+
Data = response.Error.Data
277+
}
278+
};
216279
}
280+
281+
return new JsonRpcResponse
282+
{
283+
Id = response.Id,
284+
Result = response.Result
285+
};
217286
}

src/Nethereum.DevChain.Server/Server/ServiceCollectionExtensions.cs

Lines changed: 42 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
using Microsoft.Extensions.DependencyInjection;
22
using Microsoft.Extensions.Logging;
33
using Nethereum.CoreChain.Rpc;
4+
using Nethereum.CoreChain.RocksDB;
5+
using Nethereum.CoreChain.RocksDB.Stores;
6+
using Nethereum.CoreChain.Storage;
7+
using Nethereum.CoreChain.Storage.InMemory;
48
using Nethereum.DevChain;
59
using Nethereum.DevChain.Rpc;
610
using Nethereum.DevChain.Server.Accounts;
@@ -15,11 +19,43 @@ public static IServiceCollection AddDevChainServer(this IServiceCollection servi
1519
{
1620
services.AddSingleton(config);
1721

18-
services.AddSingleton(provider =>
22+
if (config.Storage?.ToLowerInvariant() == "rocksdb")
1923
{
20-
var devChainConfig = config.ToDevChainConfig();
21-
return new DevChainNode(devChainConfig);
22-
});
24+
services.AddRocksDbStorage(new RocksDbStorageOptions
25+
{
26+
DatabasePath = config.DataDir
27+
});
28+
29+
services.AddSingleton(provider =>
30+
{
31+
var devChainConfig = config.ToDevChainConfig();
32+
var blockStore = provider.GetRequiredService<IBlockStore>();
33+
var transactionStore = provider.GetRequiredService<ITransactionStore>();
34+
var receiptStore = provider.GetRequiredService<IReceiptStore>();
35+
var logStore = provider.GetRequiredService<ILogStore>();
36+
var stateStore = provider.GetRequiredService<IStateStore>();
37+
var filterStore = provider.GetRequiredService<IFilterStore>();
38+
var trieNodeStore = provider.GetRequiredService<ITrieNodeStore>();
39+
40+
return new DevChainNode(
41+
devChainConfig,
42+
blockStore,
43+
transactionStore,
44+
receiptStore,
45+
logStore,
46+
stateStore,
47+
filterStore,
48+
trieNodeStore);
49+
});
50+
}
51+
else
52+
{
53+
services.AddSingleton(provider =>
54+
{
55+
var devChainConfig = config.ToDevChainConfig();
56+
return new DevChainNode(devChainConfig);
57+
});
58+
}
2359

2460
services.AddSingleton<DevAccountManager>();
2561

@@ -47,12 +83,9 @@ public static IServiceCollection AddDevChainServer(this IServiceCollection servi
4783
{
4884
var registry = provider.GetRequiredService<RpcHandlerRegistry>();
4985
var context = provider.GetRequiredService<RpcContext>();
50-
var logger = provider.GetRequiredService<ILogger<RpcDispatcher>>();
51-
52-
Action<string>? logInfo = config.Verbose ? msg => logger.LogInformation("{Message}", msg) : null;
53-
Action<string, Exception>? logError = (msg, ex) => logger.LogError(ex, "{Message}", msg);
86+
var logger = config.Verbose ? provider.GetRequiredService<ILogger<RpcDispatcher>>() : null;
5487

55-
return new RpcDispatcher(registry, context, logInfo, logError);
88+
return new RpcDispatcher(registry, context, logger);
5689
});
5790

5891
return services;

src/Nethereum.DevChain/BlockContext.cs

Lines changed: 0 additions & 31 deletions
This file was deleted.

0 commit comments

Comments
 (0)