diff --git a/sdk/node/Libplanet.Node.Executable/Libplanet.Node.Executable.csproj b/sdk/node/Libplanet.Node.Executable/Libplanet.Node.Executable.csproj
index d43112eaed4..620462b7549 100644
--- a/sdk/node/Libplanet.Node.Executable/Libplanet.Node.Executable.csproj
+++ b/sdk/node/Libplanet.Node.Executable/Libplanet.Node.Executable.csproj
@@ -12,6 +12,7 @@
+
@@ -21,6 +22,7 @@
+
diff --git a/sdk/node/Libplanet.Node.Executable/PluginLoader.cs b/sdk/node/Libplanet.Node.Executable/PluginLoader.cs
new file mode 100644
index 00000000000..edecb11b409
--- /dev/null
+++ b/sdk/node/Libplanet.Node.Executable/PluginLoader.cs
@@ -0,0 +1,90 @@
+using System.Reflection;
+using Libplanet.Action;
+using Libplanet.Action.Loader;
+using Libplanet.Blockchain.Policies;
+
+namespace Libplanet.Node.API;
+
+public static class PluginLoader
+{
+ public static IActionLoader LoadActionLoader(string relativePath, string typeName)
+ {
+ Assembly assembly = LoadPlugin(relativePath);
+ IEnumerable loaders = Create(assembly);
+ foreach (IActionLoader loader in loaders)
+ {
+ if (loader.GetType().FullName == typeName)
+ {
+ return loader;
+ }
+ }
+
+ throw new ApplicationException(
+ $"Can't find {typeName} in {assembly} from {assembly.Location}. " +
+ $"Available types: {string
+ .Join(",", loaders.Select(x => x.GetType().FullName))}");
+ }
+
+ public static IPolicyActionsRegistry LoadPolicyActionRegistry(
+ string relativePath,
+ string typeName)
+ {
+ Assembly assembly = LoadPlugin(relativePath);
+ IEnumerable policies = Create(assembly);
+ foreach (IPolicyActionsRegistry policy in policies)
+ {
+ if (policy.GetType().FullName == typeName)
+ {
+ return policy;
+ }
+ }
+
+ throw new ApplicationException(
+ $"Can't find {typeName} in {assembly} from {assembly.Location}. " +
+ $"Available types: {string
+ .Join(",", policies.Select(x => x.GetType().FullName))}");
+ }
+
+ private static IEnumerable Create(Assembly assembly)
+ where T : class
+ {
+ int count = 0;
+
+ foreach (Type type in assembly.GetTypes())
+ {
+ if (typeof(T).IsAssignableFrom(type))
+ {
+ T result = Activator.CreateInstance(type) as T;
+ if (result != null)
+ {
+ count++;
+ yield return result;
+ }
+ }
+ }
+
+ if (count == 0)
+ {
+ string availableTypes = string.Join(",", assembly.GetTypes().Select(t => t.FullName));
+ throw new ApplicationException(
+ $"Can't find any type which implements ICommand in {assembly} from {assembly.Location}.\n" +
+ $"Available types: {availableTypes}");
+ }
+ }
+
+ private static Assembly LoadPlugin(string relativePath)
+ {
+ // Navigate up to the solution root
+ string root = Path.GetFullPath(Path.Combine(
+ Path.GetDirectoryName(
+ Path.GetDirectoryName(
+ Path.GetDirectoryName(
+ Path.GetDirectoryName(
+ Path.GetDirectoryName(typeof(Program).Assembly.Location)))))));
+
+ string pluginLocation = Path.GetFullPath(Path.Combine(root, relativePath.Replace('\\', Path.DirectorySeparatorChar)));
+ Console.WriteLine($"Loading commands from: {pluginLocation}");
+ PluginLoadContext loadContext = new PluginLoadContext(pluginLocation);
+ return loadContext.LoadFromAssemblyName(new AssemblyName(Path.GetFileNameWithoutExtension(pluginLocation)));
+ }
+}
diff --git a/sdk/node/Libplanet.Node.Executable/Program.cs b/sdk/node/Libplanet.Node.Executable/Program.cs
index 53ccd302d64..616209efe80 100644
--- a/sdk/node/Libplanet.Node.Executable/Program.cs
+++ b/sdk/node/Libplanet.Node.Executable/Program.cs
@@ -3,6 +3,8 @@
using Libplanet.Node.Options.Schema;
using Microsoft.AspNetCore;
using Microsoft.AspNetCore.Server.Kestrel.Core;
+using Serilog;
+using Serilog.Events;
var builder = WebHost.CreateDefaultBuilder(args);
var assemblies = new string[]
@@ -14,6 +16,16 @@
builder.ConfigureLogging(logging =>
{
logging.AddConsole();
+
+ // Logging setting
+ var loggerConfig = new LoggerConfiguration();
+ loggerConfig = loggerConfig.MinimumLevel.Information();
+ loggerConfig = loggerConfig
+ .MinimumLevel.Override("Microsoft", LogEventLevel.Information)
+ .Enrich.FromLogContext()
+ .WriteTo.Console();
+
+ Log.Logger = loggerConfig.CreateLogger();
});
builder.ConfigureKestrel((context, options) =>
{
@@ -26,6 +38,19 @@
});
builder.ConfigureServices((context, services) =>
{
+// string pluginPath = "/Users/bin_bash_shell/Workspaces/planetarium/NineChronicles/" +
+// "lib9c/Lib9c.NCActionLoader/bin/Debug/net6.0/Lib9c.NCActionLoader.dll";
+// string actionLoaderType = "Lib9c.NCActionLoader.NineChroniclesActionLoader";
+// string blockPolicyType = "Lib9c.NCActionLoader.NineChroniclesPolicyActionRegistry";
+// IActionLoader actionLoader = PluginLoader.LoadActionLoader(pluginPath, actionLoaderType);
+// IPolicyActionsRegistry policyActionRegistry =
+// PluginLoader.LoadPolicyActionRegistry(pluginPath, blockPolicyType);
+
+// Libplanet.Crypto.CryptoConfig.CryptoBackend = new Secp256k1CryptoBackend();
+
+// builder.Services.AddSingleton(actionLoader);
+// builder.Services.AddSingleton(policyActionRegistry);
+
services.AddGrpc();
services.AddGrpcReflection();
services.AddLibplanetNode(context.Configuration);
diff --git a/sdk/node/Libplanet.Node.Executable/appsettings.Development.json b/sdk/node/Libplanet.Node.Executable/appsettings.Development.json
index 734f125c83e..eb63d43e77b 100644
--- a/sdk/node/Libplanet.Node.Executable/appsettings.Development.json
+++ b/sdk/node/Libplanet.Node.Executable/appsettings.Development.json
@@ -16,9 +16,16 @@
},
"Swarm": {
"IsEnabled": true,
- "AppProtocolVersion": "200210/AB2da648b9154F2cCcAFBD85e0Bc3d51f97330Fc/MEUCIQCBr..8VdITFe9nMTobl4akFid.s8G2zy2pBidAyRXSeAIgER77qX+eywjgyth6QYi7rQw5nK3KXO6cQ6ngUh.CyfU=/ZHU5OnRpbWVzdGFtcHUxMDoyMDI0LTA3LTMwZQ=="
+ "AppProtocolVersion": "200210/AB2da648b9154F2cCcAFBD85e0Bc3d51f97330Fc/MEUCIQCBr..8VdITFe9nMTobl4akFid.s8G2zy2pBidAyRXSeAIgER77qX+eywjgyth6QYi7rQw5nK3KXO6cQ6ngUh.CyfU=/ZHU5OnRpbWVzdGFtcHUxMDoyMDI0LTA3LTMwZQ==",
+ "BlocksyncSeedPeer": "027bd36895d68681290e570692ad3736750ceaab37be402442ffb203967f98f7b6,9c-main-tcp-seed-1.planetarium.dev:31234"
},
"Validator": {
"IsEnabled": true
+ },
+ "Store": {
+ "Type": 0,
+ "RootPath": "/Users/jeesu/Projects/Storage/Chain",
+ "StoreName": "9c-main-snapshot-slim",
+ "StateStoreName": "9c-main-snapshot-slim/states"
}
}
diff --git a/sdk/node/Libplanet.Node.Tests/Services/BlockChainServiceTest.cs b/sdk/node/Libplanet.Node.Tests/Services/BlockChainServiceTest.cs
index dd8461585ed..da8fc1d9c7a 100644
--- a/sdk/node/Libplanet.Node.Tests/Services/BlockChainServiceTest.cs
+++ b/sdk/node/Libplanet.Node.Tests/Services/BlockChainServiceTest.cs
@@ -1,3 +1,4 @@
+using Libplanet.Action.Loader;
using Libplanet.Blockchain;
using Libplanet.Crypto;
using Libplanet.Node.Options;
@@ -32,7 +33,7 @@ public void Create_Test()
genesisOptions: genesisOptions,
storeOptions: storeOptions,
policyService: policyService,
- actionLoaderProviders: [],
+ actionLoader: TypedActionLoader.Create(),
logger: logger);
var blockChain = blockChainService.BlockChain;
diff --git a/sdk/node/Libplanet.Node/PluginLoadContext.cs b/sdk/node/Libplanet.Node/PluginLoadContext.cs
new file mode 100644
index 00000000000..387ce52f09a
--- /dev/null
+++ b/sdk/node/Libplanet.Node/PluginLoadContext.cs
@@ -0,0 +1,36 @@
+using System.Reflection;
+using System.Runtime.Loader;
+
+namespace Libplanet.Node;
+
+public class PluginLoadContext : AssemblyLoadContext
+{
+ private AssemblyDependencyResolver _resolver;
+
+ public PluginLoadContext(string pluginPath)
+ {
+ _resolver = new AssemblyDependencyResolver(pluginPath);
+ }
+
+ protected override Assembly Load(AssemblyName assemblyName)
+ {
+ string assemblyPath = _resolver.ResolveAssemblyToPath(assemblyName);
+ if (assemblyPath != null)
+ {
+ return LoadFromAssemblyPath(assemblyPath);
+ }
+
+ return null;
+ }
+
+ protected override IntPtr LoadUnmanagedDll(string unmanagedDllName)
+ {
+ string libraryPath = _resolver.ResolveUnmanagedDllToPath(unmanagedDllName);
+ if (libraryPath != null)
+ {
+ return LoadUnmanagedDllFromPath(libraryPath);
+ }
+
+ return IntPtr.Zero;
+ }
+}
diff --git a/sdk/node/Libplanet.Node/Services/BlockChainService.cs b/sdk/node/Libplanet.Node/Services/BlockChainService.cs
index 2f528bce875..56842bf6c14 100644
--- a/sdk/node/Libplanet.Node/Services/BlockChainService.cs
+++ b/sdk/node/Libplanet.Node/Services/BlockChainService.cs
@@ -38,7 +38,8 @@ public BlockChainService(
IOptions genesisOptions,
IOptions storeOptions,
PolicyService policyService,
- IEnumerable actionLoaderProviders,
+ IActionLoader actionLoader,
+ IPolicyActionsRegistry policyActions,
ILogger logger)
{
_synchronizationContext = SynchronizationContext.Current ?? new();
@@ -48,7 +49,8 @@ public BlockChainService(
storeOptions: storeOptions.Value,
stagePolicy: policyService.StagePolicy,
renderers: [this],
- actionLoaders: [.. actionLoaderProviders.Select(item => item.GetActionLoader())]);
+ actionLoader: actionLoader,
+ policyActions: policyActions);
}
public event EventHandler? BlockAppended;
@@ -84,7 +86,7 @@ void Action(object? state)
}
}
- _logger.LogInformation("#{Height}: Block appended.", newTip.Index);
+ _logger.LogInformation("#{Height}: Block appended", newTip.Index);
BlockAppended?.Invoke(this, new(newTip));
}
}
@@ -94,20 +96,27 @@ private static BlockChain CreateBlockChain(
StoreOptions storeOptions,
IStagePolicy stagePolicy,
IRenderer[] renderers,
- IActionLoader[] actionLoaders)
+ IActionLoader actionLoader,
+ IPolicyActionsRegistry policyActions)
{
var (store, stateStore) = CreateStore(storeOptions);
- var actionLoader = new AggregateTypedActionLoader(actionLoaders);
var actionEvaluator = new ActionEvaluator(
- policyActionsRegistry: new(),
+ policyActionsRegistry: policyActions,
stateStore,
actionLoader);
var genesisBlock = CreateGenesisBlock(genesisOptions);
var policy = new BlockPolicy(
- blockInterval: TimeSpan.FromSeconds(10),
- getMaxTransactionsPerBlock: _ => int.MaxValue,
- getMaxTransactionsBytes: _ => long.MaxValue);
+ policyActionsRegistry: policyActions,
+ blockInterval: TimeSpan.FromSeconds(8),
+ validateNextBlockTx: (chain, transaction) => null,
+ validateNextBlock: (chain, block) => null,
+ getMaxTransactionsBytes: l => long.MaxValue,
+ getMinTransactionsPerBlock: l => 0,
+ getMaxTransactionsPerBlock: l => int.MaxValue,
+ getMaxTransactionsPerSignerPerBlock: l => int.MaxValue
+ );
+
var blockChainStates = new BlockChainStates(store, stateStore);
if (store.GetCanonicalChainId() is null)
{
diff --git a/sdk/node/Libplanet.Node/Services/SwarmService.cs b/sdk/node/Libplanet.Node/Services/SwarmService.cs
index 1c9f99c4937..7835d3017c8 100644
--- a/sdk/node/Libplanet.Node/Services/SwarmService.cs
+++ b/sdk/node/Libplanet.Node/Services/SwarmService.cs
@@ -1,3 +1,4 @@
+using System.Collections.Immutable;
using System.Net;
using Libplanet.Common;
using Libplanet.Crypto;
@@ -184,9 +185,17 @@ private static async Task CreateTransport(
var appProtocolVersionOptions = new Net.Options.AppProtocolVersionOptions
{
AppProtocolVersion = appProtocolVersion,
+ TrustedAppProtocolVersionSigners = new HashSet()
+ {
+ PublicKey.FromHex("030ffa9bd579ee1503ce008394f687c182279da913bfaec12baca34e79698a7cd1"),
+ }.ToImmutableHashSet(),
};
var hostOptions = new Net.Options.HostOptions(endPoint.Host, [], endPoint.Port);
- return await NetMQTransport.Create(privateKey, appProtocolVersionOptions, hostOptions);
+ return await NetMQTransport.Create(
+ privateKey,
+ appProtocolVersionOptions,
+ hostOptions,
+ TimeSpan.FromSeconds(60));
}
private static ConsensusReactorOption CreateConsensusReactorOption(
diff --git a/src/Libplanet.Action/ActionEvaluator.cs b/src/Libplanet.Action/ActionEvaluator.cs
index 8d6eda0bbb7..a27967b4ac4 100644
--- a/src/Libplanet.Action/ActionEvaluator.cs
+++ b/src/Libplanet.Action/ActionEvaluator.cs
@@ -24,7 +24,7 @@ namespace Libplanet.Action
public class ActionEvaluator : IActionEvaluator
{
private readonly ILogger _logger;
- private readonly PolicyActionsRegistry _policyActionsRegistry;
+ private readonly IPolicyActionsRegistry _policyActionsRegistry;
private readonly IStateStore _stateStore;
private readonly IActionLoader _actionLoader;
@@ -40,7 +40,7 @@ public class ActionEvaluator : IActionEvaluator
/// A implementation using
/// action type lookup.
public ActionEvaluator(
- PolicyActionsRegistry policyActionsRegistry,
+ IPolicyActionsRegistry policyActionsRegistry,
IStateStore stateStore,
IActionLoader actionTypeLoader)
{
diff --git a/src/Libplanet.Action/IPolicyActionsRegistry.cs b/src/Libplanet.Action/IPolicyActionsRegistry.cs
new file mode 100644
index 00000000000..545340d41d0
--- /dev/null
+++ b/src/Libplanet.Action/IPolicyActionsRegistry.cs
@@ -0,0 +1,36 @@
+using System.Collections.Immutable;
+
+namespace Libplanet.Action
+{
+ public interface IPolicyActionsRegistry
+ {
+ ///
+ /// An array of to execute and be rendered at the beginning
+ /// for every block, if any.
+ ImmutableArray BeginBlockActions
+ {
+ get;
+ }
+ ///
+ /// An array of to execute and be rendered at the end
+ /// for every block, if any.
+ ImmutableArray EndBlockActions
+ {
+ get;
+ }
+ ///
+ /// An array of to execute and be rendered at the beginning
+ /// for every transaction, if any.
+ ImmutableArray BeginTxActions
+ {
+ get;
+ }
+ ///
+ /// An array of to execute and be rendered at the end
+ /// for every transaction, if any.
+ ImmutableArray EndTxActions
+ {
+ get;
+ }
+ }
+}
diff --git a/src/Libplanet.Action/PolicyActionsRegistry.cs b/src/Libplanet.Action/PolicyActionsRegistry.cs
index e9793899bd6..fb25d957127 100644
--- a/src/Libplanet.Action/PolicyActionsRegistry.cs
+++ b/src/Libplanet.Action/PolicyActionsRegistry.cs
@@ -4,7 +4,7 @@
namespace Libplanet.Action
{
- public class PolicyActionsRegistry
+ public class PolicyActionsRegistry : IPolicyActionsRegistry
{
///
/// A class containing policy actions to evaluate at each situation.
diff --git a/src/Libplanet.Net/Transports/NetMQTransport.cs b/src/Libplanet.Net/Transports/NetMQTransport.cs
index cb70133db43..7b97ba83f8d 100644
--- a/src/Libplanet.Net/Transports/NetMQTransport.cs
+++ b/src/Libplanet.Net/Transports/NetMQTransport.cs
@@ -454,8 +454,7 @@ await _requests.Writer.WriteAsync(
oce
),
peer,
- content,
- reqId
+ content
);
}
catch (OperationCanceledException oce2)
@@ -476,7 +475,7 @@ await _requests.Writer.WriteAsync(
{
a?.SetStatus(ActivityStatusCode.Error);
a?.AddTag("Exception", nameof(ChannelClosedException));
- throw WrapCommunicationFailException(ce.InnerException ?? ce, peer, content, reqId);
+ throw WrapCommunicationFailException(ce.InnerException ?? ce, peer, content);
}
catch (Exception e)
{
@@ -964,14 +963,9 @@ await Task.Factory.StartNew(
private CommunicationFailException WrapCommunicationFailException(
Exception innerException,
BoundPeer peer,
- MessageContent message,
- Guid reqId
+ MessageContent message
)
{
- const string errMsg =
- "Failed to send and receive replies from {Peer} for request " +
- "{Message} {RequestId}.";
- _logger.Error(innerException, errMsg, peer, message, reqId);
return new CommunicationFailException(
$"Failed to send and receive replies from {peer} for request {message}.",
message.Type,
diff --git a/src/Libplanet.RocksDBStore/RocksDBKeyValueStore.cs b/src/Libplanet.RocksDBStore/RocksDBKeyValueStore.cs
index 029cb17a156..0c9cb0be6c3 100644
--- a/src/Libplanet.RocksDBStore/RocksDBKeyValueStore.cs
+++ b/src/Libplanet.RocksDBStore/RocksDBKeyValueStore.cs
@@ -69,6 +69,7 @@ namespace Libplanet.RocksDBStore
public class RocksDBKeyValueStore : IKeyValueStore
{
private readonly RocksDb _keyValueDb;
+ private WriteBatch _writeBatch;
private bool _disposed = false;
///
@@ -89,6 +90,7 @@ public RocksDBKeyValueStore(
.SetHardPendingCompactionBytesLimit(1038176821042);
_keyValueDb = RocksDBUtils.OpenRocksDb(options, path, type: type);
+ _writeBatch = new WriteBatch();
Type = type;
}
@@ -101,26 +103,22 @@ public byte[] Get(in KeyBytes key) => _keyValueDb.Get(key.ToByteArray())
///
public void Set(in KeyBytes key, byte[] value)
{
- _keyValueDb.Put(key.ToByteArray(), value);
+ _writeBatch.Put(key.ToByteArray(), value);
}
///
public void Set(IDictionary values)
{
- using var writeBatch = new WriteBatch();
-
foreach (KeyValuePair kv in values)
{
- writeBatch.Put(kv.Key.ToByteArray(), kv.Value);
+ _writeBatch.Put(kv.Key.ToByteArray(), kv.Value);
}
-
- _keyValueDb.Write(writeBatch);
}
///
public void Delete(in KeyBytes key)
{
- _keyValueDb.Remove(key.ToByteArray());
+ _writeBatch.Delete(key.ToByteArray());
}
///
@@ -128,7 +126,7 @@ public void Delete(IEnumerable keys)
{
foreach (KeyBytes key in keys)
{
- _keyValueDb.Remove(key.ToByteArray());
+ _writeBatch.Delete(key.ToByteArray());
}
}
@@ -156,6 +154,12 @@ public IEnumerable ListKeys()
}
}
+ public void Commit()
+ {
+ _keyValueDb.Write(_writeBatch);
+ _writeBatch = new WriteBatch();
+ }
+
public void TryCatchUpWithPrimary()
{
_keyValueDb.TryCatchUpWithPrimary();
diff --git a/src/Libplanet.Store/BlockSet.cs b/src/Libplanet.Store/BlockSet.cs
index 61ff0736e96..f57cf001896 100644
--- a/src/Libplanet.Store/BlockSet.cs
+++ b/src/Libplanet.Store/BlockSet.cs
@@ -3,6 +3,7 @@
using System.Collections.Generic;
using System.Linq;
using Caching;
+using Jitbit.Utils;
using Libplanet.Types.Blocks;
namespace Libplanet.Store
@@ -10,12 +11,12 @@ namespace Libplanet.Store
public class BlockSet : IReadOnlyDictionary
{
private readonly IStore _store;
- private readonly LRUCache _cache;
+ private readonly FastCache _fastCache;
public BlockSet(IStore store, int cacheSize = 4096)
{
_store = store;
- _cache = new LRUCache(cacheSize, Math.Max(cacheSize / 64, 8));
+ _fastCache = new FastCache();
}
public IEnumerable Keys =>
@@ -68,7 +69,7 @@ public Block this[BlockHash key]
value.ValidateTimestamp();
_store.PutBlock(value);
- _cache.AddReplace(value.Hash, value);
+ _fastCache.AddOrUpdate(value.Hash, value, TimeSpan.FromMinutes(1));
}
}
@@ -82,7 +83,7 @@ public bool Remove(BlockHash key)
{
bool deleted = _store.DeleteBlock(key);
- _cache.Remove(key);
+ _fastCache.Remove(key);
return deleted;
}
@@ -153,23 +154,15 @@ public IEnumerator> GetEnumerator()
private Block? GetBlock(BlockHash key)
{
- if (_cache.TryGet(key, out Block cached))
+ if (_fastCache.TryGet(key, out Block cached))
{
- if (_store.ContainsBlock(key))
- {
- return cached;
- }
- else
- {
- // The cached block had been deleted on _store...
- _cache.Remove(key);
- }
+ return cached;
}
Block? fetched = _store.GetBlock(key);
if (fetched is { })
{
- _cache.AddReplace(key, fetched);
+ _fastCache.AddOrUpdate(key, fetched, TimeSpan.FromMinutes(1));
}
return fetched;
diff --git a/src/Libplanet.Store/HashNodeCache.cs b/src/Libplanet.Store/HashNodeCache.cs
index 37145e1ca25..47d783234ac 100644
--- a/src/Libplanet.Store/HashNodeCache.cs
+++ b/src/Libplanet.Store/HashNodeCache.cs
@@ -1,11 +1,9 @@
-using System.Diagnostics;
+using System;
using System.Security.Cryptography;
-using System.Threading;
using Bencodex.Types;
+using Jitbit.Utils;
using Libplanet.Common;
using Libplanet.Store.Trie;
-using LruCacheNet;
-using Serilog;
namespace Libplanet.Store
{
@@ -14,37 +12,17 @@ namespace Libplanet.Store
///
public class HashNodeCache
{
- // FIXME: Tuned to 9c mainnet. Should be refactored to accept cache size as an argument.
- private const int _cacheSize = 524_288;
- private const int _reportPeriod = 60_000;
-
- private LruCache, IValue> _cache;
- private Stopwatch _stopwatch;
- private int _attempts;
- private int _hits;
- private object _reportLock;
+ private FastCache, IValue> _fastCache;
internal HashNodeCache()
{
- _cache = new LruCache, IValue>(_cacheSize);
- _stopwatch = new Stopwatch();
- _attempts = 0;
- _hits = 0;
- _reportLock = new object();
- _stopwatch.Start();
+ _fastCache = new FastCache, IValue>();
}
public bool TryGetValue(HashDigest hash, out IValue? value)
{
- lock (_reportLock)
+ if (_fastCache.TryGet(hash, out value))
{
- Report();
- }
-
- Interlocked.Increment(ref _attempts);
- if (_cache.TryGetValue(hash, out value))
- {
- Interlocked.Increment(ref _hits);
return true;
}
else
@@ -56,33 +34,7 @@ public bool TryGetValue(HashDigest hash, out IValue? value)
public void AddOrUpdate(HashDigest hash, IValue value)
{
- _cache.AddOrUpdate(hash, value);
- }
-
- private void Report()
- {
- long period = _stopwatch.ElapsedMilliseconds;
- if (period > _reportPeriod)
- {
- Log
- .ForContext("Source", nameof(HashNodeCache))
- .ForContext("Tag", "Metric")
- .ForContext("Subtag", "HashNodeCacheReport")
- .Debug(
- "Successfully fetched {HitCount} cached values out of last " +
- "{AttemptCount} attempts with hitrate of {HitRate} and " +
- "{CacheUsed}/{CacheSize} cache in use during last {PeriodMs} ms",
- _hits,
- _attempts,
- (double)_hits / _attempts,
- _cache.Count,
- _cache.Capacity,
- period);
-
- _stopwatch.Restart();
- Interlocked.Exchange(ref _attempts, 0);
- Interlocked.Exchange(ref _hits, 0);
- }
+ _fastCache.AddOrUpdate(hash, value, TimeSpan.FromMinutes(1));
}
}
}
diff --git a/src/Libplanet.Store/Libplanet.Store.csproj b/src/Libplanet.Store/Libplanet.Store.csproj
index 6d61716151c..c17b8a6256b 100644
--- a/src/Libplanet.Store/Libplanet.Store.csproj
+++ b/src/Libplanet.Store/Libplanet.Store.csproj
@@ -5,6 +5,7 @@
+
diff --git a/src/Libplanet.Store/Trie/CacheableKeyValueStore.cs b/src/Libplanet.Store/Trie/CacheableKeyValueStore.cs
index 43d9e8f59cd..4c75235a000 100644
--- a/src/Libplanet.Store/Trie/CacheableKeyValueStore.cs
+++ b/src/Libplanet.Store/Trie/CacheableKeyValueStore.cs
@@ -79,6 +79,11 @@ public bool Exists(in KeyBytes key)
///
public IEnumerable ListKeys() => _keyValueStore.ListKeys();
+ public void Commit()
+ {
+ throw new NotSupportedException();
+ }
+
///
public void Dispose()
{
diff --git a/src/Libplanet.Store/Trie/DefaultKeyValueStore.cs b/src/Libplanet.Store/Trie/DefaultKeyValueStore.cs
index a864ec0f15a..241482b54d4 100644
--- a/src/Libplanet.Store/Trie/DefaultKeyValueStore.cs
+++ b/src/Libplanet.Store/Trie/DefaultKeyValueStore.cs
@@ -152,6 +152,11 @@ public IEnumerable ListKeys() =>
_root.EnumerateFiles(UPath.Root)
.Select(path => KeyBytes.FromHex(path.GetName()));
+ public void Commit()
+ {
+ throw new NotSupportedException();
+ }
+
private UPath DataPath(in KeyBytes key) =>
UPath.Root / key.Hex;
}
diff --git a/src/Libplanet.Store/Trie/IKeyValueStore.cs b/src/Libplanet.Store/Trie/IKeyValueStore.cs
index 216b61dacb5..298fa833659 100644
--- a/src/Libplanet.Store/Trie/IKeyValueStore.cs
+++ b/src/Libplanet.Store/Trie/IKeyValueStore.cs
@@ -56,5 +56,10 @@ public interface IKeyValueStore : IDisposable
/// All keys in an arbitrary order. The order might be vary for each call.
///
public IEnumerable ListKeys();
+
+ ///
+ /// Commits the changes to the store.
+ ///
+ public void Commit();
}
}
diff --git a/src/Libplanet.Store/Trie/MemoryKeyValueStore.cs b/src/Libplanet.Store/Trie/MemoryKeyValueStore.cs
index 1ab2acff69f..7b7b0a37c7c 100644
--- a/src/Libplanet.Store/Trie/MemoryKeyValueStore.cs
+++ b/src/Libplanet.Store/Trie/MemoryKeyValueStore.cs
@@ -62,5 +62,10 @@ void IDisposable.Dispose()
IEnumerable IKeyValueStore.ListKeys() =>
_dictionary.Keys;
+
+ public void Commit()
+ {
+ throw new NotSupportedException();
+ }
}
}
diff --git a/src/Libplanet.Store/TrieStateStore.Commit.cs b/src/Libplanet.Store/TrieStateStore.Commit.cs
index 259f467d7be..d585922b494 100644
--- a/src/Libplanet.Store/TrieStateStore.Commit.cs
+++ b/src/Libplanet.Store/TrieStateStore.Commit.cs
@@ -1,4 +1,5 @@
using System;
+using System.Buffers;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
@@ -28,7 +29,7 @@ public ITrie Commit(ITrie trie)
}
else
{
- var writeBatch = new WriteBatch(StateKeyValueStore, 4096);
+ var writeBatch = new WriteBatch(StateKeyValueStore);
INode newRoot = Commit(root, writeBatch, _cache);
// It assumes embedded node if it's not HashNode.
@@ -138,32 +139,20 @@ private static HashNode Write(
private class WriteBatch
{
private readonly IKeyValueStore _store;
- private readonly int _batchSize;
- private readonly Dictionary _batch;
- public WriteBatch(IKeyValueStore store, int batchSize)
+ public WriteBatch(IKeyValueStore store)
{
_store = store;
- _batchSize = batchSize;
- _batch = new Dictionary(_batchSize);
}
- public bool ContainsKey(KeyBytes key) => _batch.ContainsKey(key);
-
public void Add(KeyBytes key, byte[] value)
{
- _batch[key] = value;
-
- if (_batch.Count == _batchSize)
- {
- Flush();
- }
+ _store.Set(key, value);
}
public void Flush()
{
- _store.Set(_batch);
- _batch.Clear();
+ _store.Commit();
}
}
}
diff --git a/src/Libplanet/Blockchain/Policies/BlockPolicy.cs b/src/Libplanet/Blockchain/Policies/BlockPolicy.cs
index 63366847532..63b1f24196a 100644
--- a/src/Libplanet/Blockchain/Policies/BlockPolicy.cs
+++ b/src/Libplanet/Blockchain/Policies/BlockPolicy.cs
@@ -22,7 +22,7 @@ public class BlockPolicy : IBlockPolicy
private readonly Func
_validateNextBlock;
- private readonly PolicyActionsRegistry _policyActionsRegistry;
+ private readonly IPolicyActionsRegistry _policyActionsRegistry;
private readonly Func _getMaxTransactionsBytes;
private readonly Func _getMinTransactionsPerBlock;
private readonly Func _getMaxTransactionsPerBlock;
@@ -73,7 +73,7 @@ public class BlockPolicy : IBlockPolicy
/// Goes to . Set to a constant function
/// of 10 by default.
public BlockPolicy(
- PolicyActionsRegistry? policyActionsRegistry = null,
+ IPolicyActionsRegistry? policyActionsRegistry = null,
TimeSpan? blockInterval = null,
Func?
validateNextBlockTx = null,
@@ -169,7 +169,7 @@ public BlockPolicy(
}
}
- public PolicyActionsRegistry PolicyActionsRegistry => _policyActionsRegistry;
+ public IPolicyActionsRegistry PolicyActionsRegistry => _policyActionsRegistry;
///
/// Targeted time interval between two consecutive s.
diff --git a/src/Libplanet/Blockchain/Policies/IBlockPolicy.cs b/src/Libplanet/Blockchain/Policies/IBlockPolicy.cs
index 7de700e2680..ba97914b349 100644
--- a/src/Libplanet/Blockchain/Policies/IBlockPolicy.cs
+++ b/src/Libplanet/Blockchain/Policies/IBlockPolicy.cs
@@ -24,7 +24,7 @@ public interface IBlockPolicy
///
/// A set of policy s to evaluate at each situation.
///
- PolicyActionsRegistry PolicyActionsRegistry { get; }
+ IPolicyActionsRegistry PolicyActionsRegistry { get; }
///
/// Checks if a can be included in a yet to be mined
diff --git a/src/Libplanet/Blockchain/Policies/NullBlockPolicy.cs b/src/Libplanet/Blockchain/Policies/NullBlockPolicy.cs
index 8e679648b36..19a28fea5d4 100644
--- a/src/Libplanet/Blockchain/Policies/NullBlockPolicy.cs
+++ b/src/Libplanet/Blockchain/Policies/NullBlockPolicy.cs
@@ -21,7 +21,7 @@ public NullBlockPolicy(
public ISet BlockedMiners { get; } = new HashSet();
- public PolicyActionsRegistry PolicyActionsRegistry => new PolicyActionsRegistry();
+ public IPolicyActionsRegistry PolicyActionsRegistry => new PolicyActionsRegistry();
public ImmutableArray BeginBlockActions => ImmutableArray.Empty;
diff --git a/tools/Libplanet.Explorer.Executable/Program.cs b/tools/Libplanet.Explorer.Executable/Program.cs
index 2c852312405..d3c2126f30a 100644
--- a/tools/Libplanet.Explorer.Executable/Program.cs
+++ b/tools/Libplanet.Explorer.Executable/Program.cs
@@ -378,7 +378,7 @@ public DumbBlockPolicy(BlockPolicy blockPolicy)
_impl = blockPolicy;
}
- public PolicyActionsRegistry PolicyActionsRegistry => _impl.PolicyActionsRegistry;
+ public IPolicyActionsRegistry PolicyActionsRegistry => _impl.PolicyActionsRegistry;
public int GetMinTransactionsPerBlock(long index) =>
_impl.GetMinTransactionsPerBlock(index);