From cc05f779c7f20da1587ce84f3d144a17cf388f5a Mon Sep 17 00:00:00 2001 From: Suho Lee Date: Sat, 17 Aug 2024 19:44:20 +0900 Subject: [PATCH] introduce: IRenderObservables --- .../Services/BlockChainServiceTest.cs | 3 + sdk/node/Libplanet.Node/Libplanet.Node.csproj | 1 + .../Services/BlockChainService.cs | 58 ++++------------ .../Services/IBlockChainService.cs | 2 - .../Services/Renderer/IRenderObservables.cs | 12 ++++ .../Renderer/RenderActionErrorObservable.cs | 65 ++++++++++++++++++ .../Renderer/RenderActionObservable.cs | 64 ++++++++++++++++++ .../Renderer/RenderBlockEndObservable.cs | 65 ++++++++++++++++++ .../Renderer/RenderBlockObservable.cs | 66 +++++++++++++++++++ .../Services/Renderer/RenderObservables.cs | 17 +++++ 10 files changed, 305 insertions(+), 48 deletions(-) create mode 100644 sdk/node/Libplanet.Node/Services/Renderer/IRenderObservables.cs create mode 100644 sdk/node/Libplanet.Node/Services/Renderer/RenderActionErrorObservable.cs create mode 100644 sdk/node/Libplanet.Node/Services/Renderer/RenderActionObservable.cs create mode 100644 sdk/node/Libplanet.Node/Services/Renderer/RenderBlockEndObservable.cs create mode 100644 sdk/node/Libplanet.Node/Services/Renderer/RenderBlockObservable.cs create mode 100644 sdk/node/Libplanet.Node/Services/Renderer/RenderObservables.cs diff --git a/sdk/node/Libplanet.Node.Tests/Services/BlockChainServiceTest.cs b/sdk/node/Libplanet.Node.Tests/Services/BlockChainServiceTest.cs index dd8461585ed..07c3cd22298 100644 --- a/sdk/node/Libplanet.Node.Tests/Services/BlockChainServiceTest.cs +++ b/sdk/node/Libplanet.Node.Tests/Services/BlockChainServiceTest.cs @@ -2,10 +2,12 @@ using Libplanet.Crypto; using Libplanet.Node.Options; using Libplanet.Node.Services; +using Libplanet.Node.Services.Renderer; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging.Abstractions; using Microsoft.Extensions.Options; +using Moq; namespace Libplanet.Node.Tests.Services; @@ -33,6 +35,7 @@ public void Create_Test() storeOptions: storeOptions, policyService: policyService, actionLoaderProviders: [], + rendererService: Mock.Of(), logger: logger); var blockChain = blockChainService.BlockChain; diff --git a/sdk/node/Libplanet.Node/Libplanet.Node.csproj b/sdk/node/Libplanet.Node/Libplanet.Node.csproj index 19bd81fd736..e3f362882de 100644 --- a/sdk/node/Libplanet.Node/Libplanet.Node.csproj +++ b/sdk/node/Libplanet.Node/Libplanet.Node.csproj @@ -9,6 +9,7 @@ + diff --git a/sdk/node/Libplanet.Node/Services/BlockChainService.cs b/sdk/node/Libplanet.Node/Services/BlockChainService.cs index ef2f85c797a..5689268dd01 100644 --- a/sdk/node/Libplanet.Node/Services/BlockChainService.cs +++ b/sdk/node/Libplanet.Node/Services/BlockChainService.cs @@ -1,7 +1,5 @@ -using System.Collections.Concurrent; using System.Collections.Immutable; using System.Numerics; -using System.Security.Cryptography; using Bencodex.Types; using Libplanet.Action; using Libplanet.Action.Loader; @@ -9,13 +7,12 @@ using Libplanet.Blockchain; using Libplanet.Blockchain.Policies; using Libplanet.Blockchain.Renderers; -using Libplanet.Common; using Libplanet.Crypto; using Libplanet.Node.Options; +using Libplanet.Node.Services.Renderer; using Libplanet.RocksDBStore; using Libplanet.Store; using Libplanet.Store.Trie; -using Libplanet.Types.Blocks; using Libplanet.Types.Consensus; using Libplanet.Types.Tx; using Microsoft.Extensions.Logging; @@ -23,28 +20,31 @@ namespace Libplanet.Node.Services; -internal sealed class BlockChainService : IBlockChainService, IActionRenderer +internal sealed class BlockChainService : IBlockChainService { - private readonly SynchronizationContext _synchronizationContext; private readonly ILogger _logger; private readonly BlockChain _blockChain; - private readonly ConcurrentDictionary _eventByTxId = []; - private readonly ConcurrentDictionary _exceptionByAction = []; public BlockChainService( IOptions genesisOptions, IOptions storeOptions, PolicyService policyService, IEnumerable actionLoaderProviders, + IRenderObservables rendererService, ILogger logger) { - _synchronizationContext = SynchronizationContext.Current ?? new(); _logger = logger; _blockChain = CreateBlockChain( genesisOptions: genesisOptions.Value, storeOptions: storeOptions.Value, stagePolicy: policyService.StagePolicy, - renderers: [this], + renderers: + [ + rendererService.RenderActionObservable, + rendererService.RenderActionErrorObservable, + rendererService.RenderBlockObservable, + rendererService.RenderBlockEndObservable, + ], actionLoaders: [.. actionLoaderProviders.Select(item => item.GetActionLoader())]); } @@ -52,40 +52,6 @@ public BlockChainService( public BlockChain BlockChain => _blockChain; - void IRenderer.RenderBlock(Block oldTip, Block newTip) - { - } - - void IActionRenderer.RenderAction( - IValue action, ICommittedActionContext context, HashDigest nextState) - { - } - - void IActionRenderer.RenderActionError( - IValue action, ICommittedActionContext context, Exception exception) - { - _exceptionByAction.AddOrUpdate(action, exception, (_, _) => exception); - } - - void IActionRenderer.RenderBlockEnd(Block oldTip, Block newTip) - { - _synchronizationContext.Post(Action, state: null); - - void Action(object? state) - { - foreach (var transaction in newTip.Transactions) - { - if (_eventByTxId.TryGetValue(transaction.Id, out var manualResetEvent)) - { - manualResetEvent.Set(); - } - } - - _logger.LogInformation("#{Height}: Block appended.", newTip.Index); - BlockAppended?.Invoke(this, new(newTip)); - } - } - private static BlockChain CreateBlockChain( GenesisOptions genesisOptions, StoreOptions storeOptions, @@ -101,8 +67,8 @@ private static BlockChain CreateBlockChain( stateStore, actionLoader); var validators = genesisOptions.Validators.Select(PublicKey.FromHex) - .Select(item => new Validator(item, new BigInteger(1000))) - .ToArray(); + .Select(item => new Validator(item, new BigInteger(1000))) + .ToArray(); var validatorSet = new ValidatorSet(validators: [.. validators]); var nonce = 0L; IAction[] actions = diff --git a/sdk/node/Libplanet.Node/Services/IBlockChainService.cs b/sdk/node/Libplanet.Node/Services/IBlockChainService.cs index 12b543bf49b..bc70ea2954b 100644 --- a/sdk/node/Libplanet.Node/Services/IBlockChainService.cs +++ b/sdk/node/Libplanet.Node/Services/IBlockChainService.cs @@ -4,7 +4,5 @@ namespace Libplanet.Node.Services; public interface IBlockChainService { - event EventHandler? BlockAppended; - BlockChain BlockChain { get; } } diff --git a/sdk/node/Libplanet.Node/Services/Renderer/IRenderObservables.cs b/sdk/node/Libplanet.Node/Services/Renderer/IRenderObservables.cs new file mode 100644 index 00000000000..e78fe79dc63 --- /dev/null +++ b/sdk/node/Libplanet.Node/Services/Renderer/IRenderObservables.cs @@ -0,0 +1,12 @@ +namespace Libplanet.Node.Services.Renderer; + +public interface IRenderObservables +{ + public RenderActionObservable RenderActionObservable { get; } + + public RenderActionErrorObservable RenderActionErrorObservable { get; } + + public RenderBlockObservable RenderBlockObservable { get; } + + public RenderBlockEndObservable RenderBlockEndObservable { get; } +} diff --git a/sdk/node/Libplanet.Node/Services/Renderer/RenderActionErrorObservable.cs b/sdk/node/Libplanet.Node/Services/Renderer/RenderActionErrorObservable.cs new file mode 100644 index 00000000000..80a422972de --- /dev/null +++ b/sdk/node/Libplanet.Node/Services/Renderer/RenderActionErrorObservable.cs @@ -0,0 +1,65 @@ +using System.Security.Cryptography; +using Bencodex.Types; +using Libplanet.Action; +using Libplanet.Blockchain.Renderers; +using Libplanet.Common; +using Libplanet.Types.Blocks; +using R3; +using Output = ( + Bencodex.Types.IValue, + Libplanet.Action.ICommittedActionContext, + System.Exception); + +namespace Libplanet.Node.Services.Renderer; + +public class RenderActionErrorObservable : IObservable, IActionRenderer, IDisposable +{ + private readonly List> _observers = []; + private readonly BooleanDisposable _disposable = new BooleanDisposable(); + + public IDisposable Subscribe(IObserver observer) + { + _observers.Add(observer); + return _disposable; + } + + public void RenderBlock(Block oldTip, Block newTip) + { + } + + public void RenderAction( + IValue action, + ICommittedActionContext context, + HashDigest nextState) + { + } + + public void RenderActionError(IValue action, ICommittedActionContext context, Exception exception) + { + if (_disposable.IsDisposed) + { + return; + } + + foreach (IObserver observer in _observers) + { + observer.OnNext((action, context, exception)); + } + } + + public void RenderBlockEnd(Block oldTip, Block newTip) + { + } + + public void Dispose() + { + _disposable.Dispose(); + + foreach (IObserver observer in _observers) + { + observer.OnCompleted(); + } + + GC.SuppressFinalize(this); + } +} diff --git a/sdk/node/Libplanet.Node/Services/Renderer/RenderActionObservable.cs b/sdk/node/Libplanet.Node/Services/Renderer/RenderActionObservable.cs new file mode 100644 index 00000000000..369a6da98ba --- /dev/null +++ b/sdk/node/Libplanet.Node/Services/Renderer/RenderActionObservable.cs @@ -0,0 +1,64 @@ +using System.Security.Cryptography; +using Bencodex.Types; +using Libplanet.Action; +using Libplanet.Blockchain.Renderers; +using Libplanet.Common; +using Libplanet.Types.Blocks; +using R3; +using Output = ( + Bencodex.Types.IValue, + Libplanet.Action.ICommittedActionContext, + Libplanet.Common.HashDigest); + +namespace Libplanet.Node.Services.Renderer; + +public class RenderActionObservable : IObservable, IActionRenderer, IDisposable +{ + private readonly List> _observers = []; + private readonly BooleanDisposable _disposable = new BooleanDisposable(); + + public IDisposable Subscribe(IObserver observer) + { + _observers.Add(observer); + return _disposable; + } + + public void RenderBlock(Block oldTip, Block newTip) + { + } + + public void RenderAction( + IValue action, + ICommittedActionContext context, + HashDigest nextState) + { + if (_disposable.IsDisposed) + { + return; + } + + foreach (IObserver observer in _observers) + { + observer.OnNext((action, context, nextState)); + } + } + + public void RenderActionError(IValue action, ICommittedActionContext context, Exception exception) + { + } + + public void RenderBlockEnd(Block oldTip, Block newTip) + { + } + + public void Dispose() + { + _disposable.Dispose(); + foreach (IObserver observer in _observers) + { + observer.OnCompleted(); + } + + GC.SuppressFinalize(this); + } +} diff --git a/sdk/node/Libplanet.Node/Services/Renderer/RenderBlockEndObservable.cs b/sdk/node/Libplanet.Node/Services/Renderer/RenderBlockEndObservable.cs new file mode 100644 index 00000000000..2bc371c8c00 --- /dev/null +++ b/sdk/node/Libplanet.Node/Services/Renderer/RenderBlockEndObservable.cs @@ -0,0 +1,65 @@ +using System.Security.Cryptography; +using Bencodex.Types; +using Libplanet.Action; +using Libplanet.Blockchain.Renderers; +using Libplanet.Common; +using Libplanet.Types.Blocks; +using R3; + +namespace Libplanet.Node.Services.Renderer; + +public class RenderBlockEndObservable : IObservable<(Block, Block)>, IActionRenderer, IDisposable +{ + private readonly List> _observers + = new List>(); + + private readonly BooleanDisposable _disposable = new BooleanDisposable(); + + public IDisposable Subscribe(IObserver<(Block, Block)> observer) + { + _observers.Add(observer); + return _disposable; + } + + public void RenderBlock(Block oldTip, Block newTip) + { + } + + public void RenderAction( + IValue action, + ICommittedActionContext context, + HashDigest nextState) + { + } + + public void RenderActionError( + IValue action, + ICommittedActionContext context, + Exception exception) + { + } + + public void RenderBlockEnd(Block oldTip, Block newTip) + { + if (_disposable.IsDisposed) + { + return; + } + + foreach (IObserver<(Block, Block)> observer in _observers) + { + observer.OnNext((oldTip, newTip)); + } + } + + public void Dispose() + { + _disposable.Dispose(); + foreach (IObserver<(Block, Block)> observer in _observers) + { + observer.OnCompleted(); + } + + GC.SuppressFinalize(this); + } +} diff --git a/sdk/node/Libplanet.Node/Services/Renderer/RenderBlockObservable.cs b/sdk/node/Libplanet.Node/Services/Renderer/RenderBlockObservable.cs new file mode 100644 index 00000000000..07d02580f08 --- /dev/null +++ b/sdk/node/Libplanet.Node/Services/Renderer/RenderBlockObservable.cs @@ -0,0 +1,66 @@ +using System.Security.Cryptography; +using Bencodex.Types; +using Libplanet.Action; +using Libplanet.Blockchain.Renderers; +using Libplanet.Common; +using Libplanet.Types.Blocks; +using R3; + +namespace Libplanet.Node.Services.Renderer; + +public class RenderBlockObservable : IObservable<(Block, Block)>, IActionRenderer, IDisposable +{ + private readonly List> _observers + = new List>(); + + private readonly BooleanDisposable _disposable = new BooleanDisposable(); + + public IDisposable Subscribe(IObserver<(Block, Block)> observer) + { + _observers.Add(observer); + return _disposable; + } + + public void RenderBlock(Block oldTip, Block newTip) + { + if (_disposable.IsDisposed) + { + return; + } + + foreach (IObserver<(Block, Block)> observer in _observers) + { + observer.OnNext((oldTip, newTip)); + } + } + + public void RenderAction( + IValue action, + ICommittedActionContext context, + HashDigest nextState) + { + } + + + public void RenderActionError( + IValue action, + ICommittedActionContext context, + Exception exception) + { + } + + public void RenderBlockEnd(Block oldTip, Block newTip) + { + } + + public void Dispose() + { + _disposable.Dispose(); + foreach (IObserver<(Block, Block)> observer in _observers) + { + observer.OnCompleted(); + } + + GC.SuppressFinalize(this); + } +} diff --git a/sdk/node/Libplanet.Node/Services/Renderer/RenderObservables.cs b/sdk/node/Libplanet.Node/Services/Renderer/RenderObservables.cs new file mode 100644 index 00000000000..bee9c5f510f --- /dev/null +++ b/sdk/node/Libplanet.Node/Services/Renderer/RenderObservables.cs @@ -0,0 +1,17 @@ +namespace Libplanet.Node.Services.Renderer; + +public class RenderObservables( + RenderActionObservable renderActionObservable, + RenderActionErrorObservable renderActionErrorObservable, + RenderBlockObservable renderBlockObservable, + RenderBlockEndObservable renderBlockEndObservable) + : IRenderObservables +{ + public RenderActionObservable RenderActionObservable { get; } = renderActionObservable; + + public RenderActionErrorObservable RenderActionErrorObservable { get; } = renderActionErrorObservable; + + public RenderBlockObservable RenderBlockObservable { get; } = renderBlockObservable; + + public RenderBlockEndObservable RenderBlockEndObservable { get; } = renderBlockEndObservable; +}