-
Notifications
You must be signed in to change notification settings - Fork 22
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #491 from Atralupus/feat/initializer
Introduce Initializer
- Loading branch information
Showing
11 changed files
with
354 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
using Libplanet.Crypto; | ||
using Mimir.Worker.Constants; | ||
|
||
namespace Mimir.Initializer; | ||
|
||
public class Configuration | ||
{ | ||
public string MongoDbConnectionString { get; init; } | ||
public PlanetType PlanetType { get; init; } | ||
public string? MongoDbCAFile { get; init; } | ||
public string ChainStorePath { get; init; } | ||
public string[] TargetAccounts { get; init; } | ||
|
||
public Address[] GetTargetAddresses() => | ||
TargetAccounts.Select(adr => new Address(adr)).ToArray(); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
using Libplanet.Crypto; | ||
using Mimir.Worker.StateDocumentConverter; | ||
using Nekoyume; | ||
|
||
namespace Mimir.Initializer.Initializer; | ||
|
||
public static class ConverterMappings | ||
{ | ||
private static Dictionary<Address, IStateDocumentConverter> pairs = new(); | ||
|
||
static ConverterMappings() | ||
{ | ||
pairs.Add(Addresses.Agent, new AgentStateDocumentConverter()); | ||
pairs.Add(Addresses.Avatar, new AvatarStateDocumentConverter()); | ||
} | ||
|
||
public static IStateDocumentConverter GetConverter(Address accountAddress) | ||
{ | ||
return pairs[accountAddress]; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,145 @@ | ||
using Bencodex.Types; | ||
using Libplanet.Action.State; | ||
using Libplanet.Blockchain; | ||
using Libplanet.Common; | ||
using Libplanet.Crypto; | ||
using Libplanet.Store; | ||
using Libplanet.Store.Trie; | ||
using Mimir.Initializer.Util; | ||
using Mimir.MongoDB; | ||
using Mimir.MongoDB.Bson; | ||
using Mimir.Worker.Services; | ||
using Mimir.Worker.StateDocumentConverter; | ||
using Serilog; | ||
using ILogger = Serilog.ILogger; | ||
|
||
namespace Mimir.Initializer.Initializer; | ||
|
||
public class SnapshotInitializer | ||
{ | ||
private readonly MongoDbService _dbService; | ||
private readonly ILogger _logger; | ||
private readonly string _chainStorePath; | ||
private Address[] _targetAccounts; | ||
|
||
public SnapshotInitializer( | ||
MongoDbService dbService, | ||
string chainStorePath, | ||
Address[] targetAccounts | ||
) | ||
{ | ||
_dbService = dbService; | ||
_chainStorePath = chainStorePath; | ||
_targetAccounts = targetAccounts; | ||
_logger = Log.ForContext<SnapshotInitializer>(); | ||
} | ||
|
||
public async Task RunAsync(CancellationToken stoppingToken) | ||
{ | ||
var started = DateTime.UtcNow; | ||
|
||
(BlockChain blockChain, IStore store, IStateStore stateStore) = ChainUtil.LoadBlockChain( | ||
_chainStorePath | ||
); | ||
|
||
foreach (var address in _targetAccounts) | ||
{ | ||
await ProcessByAccountAddress(blockChain, stateStore, address, stoppingToken); | ||
|
||
if (stoppingToken.IsCancellationRequested) | ||
{ | ||
break; | ||
} | ||
} | ||
|
||
store.Dispose(); | ||
stateStore.Dispose(); | ||
|
||
_logger.Information( | ||
"Finished SnapshotInitializer. Elapsed {TotalElapsedMinutes} minutes", | ||
DateTime.UtcNow.Subtract(started).Minutes | ||
); | ||
} | ||
|
||
private async Task ProcessByAccountAddress( | ||
BlockChain blockChain, | ||
IStateStore stateStore, | ||
Address accountAddress, | ||
CancellationToken stoppingToken | ||
) | ||
{ | ||
int predicateLength = Address.Size * 2; | ||
|
||
ITrie worldTrie = ChainUtil.GetWorldTrie(blockChain); | ||
IWorldState world = new WorldBaseState(worldTrie, stateStore); | ||
IAccountState account = world.GetAccountState(accountAddress); | ||
ITrie accountTrie = account.Trie; | ||
_logger.Information( | ||
"Iterating over trie with state root hash {StateRootHash}", | ||
accountTrie.Hash | ||
); | ||
|
||
long addressCount = 0; | ||
string? currentAddress = null; | ||
|
||
foreach ((KeyBytes keyBytes, IValue value) in accountTrie.IterateValues()) | ||
{ | ||
if (keyBytes.Length == predicateLength) | ||
{ | ||
addressCount++; | ||
Address address = ChainUtil.ToAddress(keyBytes); | ||
currentAddress = ByteUtil.Hex(address.ByteArray); | ||
} | ||
|
||
if (currentAddress is string hex) | ||
{ | ||
await HandleByAccount( | ||
accountAddress, | ||
new Address(currentAddress), | ||
value, | ||
blockChain.Tip.Index | ||
); | ||
} | ||
|
||
if (stoppingToken.IsCancellationRequested) | ||
{ | ||
break; | ||
} | ||
} | ||
|
||
_logger.Information("Total address count: {AddressCount}", addressCount); | ||
} | ||
|
||
private async Task HandleByAccount( | ||
Address accountAddress, | ||
Address address, | ||
IValue state, | ||
long blockIndex | ||
) | ||
{ | ||
var collectionName = CollectionNames.GetCollectionName(accountAddress); | ||
var documents = new List<MimirBsonDocument>(); | ||
var document = ConverterMappings | ||
.GetConverter(accountAddress) | ||
.ConvertToDocument( | ||
new AddressStatePair | ||
{ | ||
BlockIndex = blockIndex, | ||
Address = address, | ||
RawState = state | ||
} | ||
); | ||
|
||
documents.Add(document); | ||
|
||
if (documents.Count > 0) | ||
await _dbService.UpsertStateDataManyAsync(collectionName, documents, null, default); | ||
|
||
_logger.Information( | ||
"{DocumentCount} Handled, {CollectionName} - {Address}", | ||
documents.Count, | ||
collectionName, | ||
address | ||
); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
<Project Sdk="Microsoft.NET.Sdk"> | ||
|
||
<PropertyGroup> | ||
<OutputType>Exe</OutputType> | ||
<TargetFramework>net8.0</TargetFramework> | ||
<ImplicitUsings>enable</ImplicitUsings> | ||
<Nullable>enable</Nullable> | ||
</PropertyGroup> | ||
|
||
<ItemGroup> | ||
<ProjectReference Include="..\Mimir.Worker\Mimir.Worker.csproj" /> | ||
</ItemGroup> | ||
|
||
</Project> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
using Microsoft.Extensions.Configuration; | ||
using Microsoft.Extensions.DependencyInjection; | ||
using Microsoft.Extensions.Hosting; | ||
using Microsoft.Extensions.Options; | ||
using Mimir.Initializer; | ||
using Mimir.Initializer.Initializer; | ||
using Mimir.Worker.Services; | ||
using Serilog; | ||
|
||
var builder = Host.CreateDefaultBuilder(args) | ||
.ConfigureAppConfiguration( | ||
(hostingContext, config) => | ||
{ | ||
string configPath = | ||
Environment.GetEnvironmentVariable("INITIALIZER_CONFIG_FILE") ?? "appsettings.json"; | ||
config | ||
.AddJsonFile(configPath, optional: true, reloadOnChange: true) | ||
.AddEnvironmentVariables("INITIALIZER_"); | ||
} | ||
) | ||
.ConfigureServices( | ||
(hostContext, services) => | ||
{ | ||
services.Configure<Configuration>( | ||
hostContext.Configuration.GetSection("Configuration") | ||
); | ||
services.AddSingleton<MongoDbService>(); | ||
services.AddSingleton(serviceProvider => | ||
{ | ||
var config = serviceProvider.GetRequiredService<IOptions<Configuration>>().Value; | ||
return new MongoDbService( | ||
config.MongoDbConnectionString, | ||
config.PlanetType, | ||
config.MongoDbCAFile | ||
); | ||
}); | ||
services.AddTransient<SnapshotInitializer>(serviceProvider => | ||
{ | ||
var config = serviceProvider.GetRequiredService<IOptions<Configuration>>().Value; | ||
var dbService = serviceProvider.GetRequiredService<MongoDbService>(); | ||
var targetAccounts = config.GetTargetAddresses(); | ||
return new SnapshotInitializer(dbService, config.ChainStorePath, targetAccounts); | ||
}); | ||
} | ||
) | ||
.UseSerilog( | ||
(context, configuration) => | ||
{ | ||
configuration.ReadFrom.Configuration(context.Configuration); | ||
} | ||
) | ||
.Build(); | ||
|
||
using var scope = builder.Services.CreateScope(); | ||
var initializer = scope.ServiceProvider.GetRequiredService<SnapshotInitializer>(); | ||
|
||
var stoppingToken = new CancellationTokenSource().Token; | ||
|
||
await initializer.RunAsync(stoppingToken); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
{ | ||
"Serilog": { | ||
"Using": [], | ||
"MinimumLevel": { | ||
"Default": "Information", | ||
"Override": { | ||
"Microsoft": "Warning", | ||
"System": "Warning" | ||
} | ||
}, | ||
"WriteTo": [ | ||
{ | ||
"Name": "Console", | ||
"Args": { | ||
"formatter": "Serilog.Formatting.Compact.CompactJsonFormatter, Serilog.Formatting.Compact", | ||
"outputTemplate": "[{Timestamp:HH:mm:ss} {Level:u3}] [{SourceContext}] [{AccountAddress}] {Message:lj}{NewLine}{Exception}" | ||
} | ||
} | ||
], | ||
"Enrich": [ | ||
"FromLogContext", | ||
"WithMachineName", | ||
"WithThreadId" | ||
], | ||
"Properties": { | ||
"Application": "Mimir.Initializer" | ||
} | ||
}, | ||
"Configuration": { | ||
"MongoDbConnectionString": "mongodb://rootuser:rootpass@localhost:27017", | ||
"PlanetType": "heimdall", | ||
"ChainStorePath": "your path", | ||
"TargetAccounts": [ | ||
"000000000000000000000000000000000000001a", | ||
"000000000000000000000000000000000000001b" | ||
], | ||
"EnableInitializing": true | ||
} | ||
} |
Oops, something went wrong.