From 648b18d5b2b9a6a6f20eea0229b51d60e1ec045f Mon Sep 17 00:00:00 2001 From: s2quake Date: Thu, 21 Mar 2024 10:03:42 +0900 Subject: [PATCH 1/3] feat: Add begin/end block actions. --- Libplanet.Action/ActionEvaluator.cs | 87 ++++++++++++++----- Libplanet.Action/PolicyBlockActionGetter.cs | 6 -- Libplanet.Action/PolicyBlockActionsGetter.cs | 9 ++ Libplanet/Blockchain/BlockChain.Evaluate.cs | 3 +- Libplanet/Blockchain/Policies/BlockPolicy.cs | 18 +++- Libplanet/Blockchain/Policies/IBlockPolicy.cs | 12 ++- .../Blockchain/Policies/NullBlockPolicy.cs | 5 +- 7 files changed, 103 insertions(+), 37 deletions(-) delete mode 100644 Libplanet.Action/PolicyBlockActionGetter.cs create mode 100644 Libplanet.Action/PolicyBlockActionsGetter.cs diff --git a/Libplanet.Action/ActionEvaluator.cs b/Libplanet.Action/ActionEvaluator.cs index ec2c03490a6..a628bf49a9f 100644 --- a/Libplanet.Action/ActionEvaluator.cs +++ b/Libplanet.Action/ActionEvaluator.cs @@ -26,27 +26,37 @@ namespace Libplanet.Action public class ActionEvaluator : IActionEvaluator { private readonly ILogger _logger; - private readonly PolicyBlockActionGetter _policyBlockActionGetter; + private readonly PolicyBlockActionsGetter _policyBeginBlockActionsGetter; + private readonly PolicyBlockActionsGetter _policyEndBlockActionsGetter; private readonly IStateStore _stateStore; private readonly IActionLoader _actionLoader; /// /// Creates a new . /// - /// A delegator to get policy block action to evaluate - /// at the end for each that gets evaluated. + /// A delegator to get policy block actions to + /// evaluate at the beginning for each + /// that gets evaluated. + /// Note the order of the returned list determines the execution order. + /// + /// A delegator to get policy block actions to + /// evaluate at the end for each that gets evaluated. + /// Note the order of the returned list determines the execution order. + /// /// The to use to retrieve /// the states for a provided . /// A implementation using /// action type lookup. public ActionEvaluator( - PolicyBlockActionGetter policyBlockActionGetter, + PolicyBlockActionsGetter policyBeginBlockActionsGetter, + PolicyBlockActionsGetter policyEndBlockActionsGetter, IStateStore stateStore, IActionLoader actionTypeLoader) { _logger = Log.ForContext() .ForContext("Source", nameof(ActionEvaluator)); - _policyBlockActionGetter = policyBlockActionGetter; + _policyBeginBlockActionsGetter = policyBeginBlockActionsGetter; + _policyEndBlockActionsGetter = policyEndBlockActionsGetter; _stateStore = stateStore; _actionLoader = actionTypeLoader; } @@ -123,16 +133,29 @@ public IReadOnlyList Evaluate( throw new ApplicationException("World cannot be mutated from modern to legacy"); } - ImmutableList evaluations = - EvaluateBlock(block, previousState).ToImmutableList(); + var evaluations = ImmutableList.Empty; + if (_policyBeginBlockActionsGetter(block) is { } beginBlockActions && + beginBlockActions.Length > 0) + { + evaluations = evaluations.AddRange(EvaluatePolicyBeginBlockActions( + block, previousState + )); + previousState = evaluations.Last().OutputState; + } + + evaluations = evaluations.AddRange( + EvaluateBlock(block, previousState).ToImmutableList() + ); - var policyBlockAction = _policyBlockActionGetter(block); - if (policyBlockAction is { } blockAction) + if (_policyEndBlockActionsGetter(block) is { } endBlockActions && + endBlockActions.Length > 0) { previousState = evaluations.Count > 0 ? evaluations.Last().OutputState : previousState; - evaluations = evaluations.Add(EvaluatePolicyBlockAction(block, previousState)); + evaluations = evaluations.AddRange(EvaluatePolicyEndBlockActions( + block, previousState + )); } var committed = ToCommittedEvaluation(block, evaluations, baseStateRootHash); @@ -491,30 +514,50 @@ internal IEnumerable EvaluateTx( /// the held by the instance /// for the . [Pure] - internal ActionEvaluation EvaluatePolicyBlockAction( + internal ActionEvaluation[] EvaluatePolicyBeginBlockActions( IPreEvaluationBlockHeader blockHeader, IWorld previousState) { - var policyBlockAction = _policyBlockActionGetter(blockHeader); - if (policyBlockAction is null) - { - var message = - "To evaluate policy block action, " + - "policyBlockAction must not be null."; - throw new InvalidOperationException(message); - } + _logger.Information( + $"Evaluating policy begin block actions for block #{blockHeader.Index} " + + $"{ByteUtil.Hex(blockHeader.PreEvaluationHash.ByteArray)}"); + + return EvaluateActions( + blockHeader: blockHeader, + tx: null, + previousState: previousState, + actions: _policyBeginBlockActionsGetter(blockHeader), + stateStore: _stateStore, + logger: _logger).ToArray(); + } + /// + /// Evaluates the set by the policy when + /// this was instantiated for a given + /// . + /// + /// The header of the block to evaluate. + /// The states immediately before the evaluation of + /// the held by the instance. + /// The of evaluating + /// the held by the instance + /// for the . + [Pure] + internal ActionEvaluation[] EvaluatePolicyEndBlockActions( + IPreEvaluationBlockHeader blockHeader, + IWorld previousState) + { _logger.Information( - $"Evaluating policy block action for block #{blockHeader.Index} " + + $"Evaluating policy end block actions for block #{blockHeader.Index} " + $"{ByteUtil.Hex(blockHeader.PreEvaluationHash.ByteArray)}"); return EvaluateActions( blockHeader: blockHeader, tx: null, previousState: previousState, - actions: new[] { policyBlockAction }.ToImmutableList(), + actions: _policyEndBlockActionsGetter(blockHeader), stateStore: _stateStore, - logger: _logger).Single(); + logger: _logger).ToArray(); } internal IWorld PrepareInitialDelta(HashDigest? stateRootHash) diff --git a/Libplanet.Action/PolicyBlockActionGetter.cs b/Libplanet.Action/PolicyBlockActionGetter.cs deleted file mode 100644 index ba57b2d2023..00000000000 --- a/Libplanet.Action/PolicyBlockActionGetter.cs +++ /dev/null @@ -1,6 +0,0 @@ -using Libplanet.Types.Blocks; - -namespace Libplanet.Action -{ - public delegate IAction? PolicyBlockActionGetter(IPreEvaluationBlockHeader blockHeader); -} diff --git a/Libplanet.Action/PolicyBlockActionsGetter.cs b/Libplanet.Action/PolicyBlockActionsGetter.cs new file mode 100644 index 00000000000..41dcfef0ca9 --- /dev/null +++ b/Libplanet.Action/PolicyBlockActionsGetter.cs @@ -0,0 +1,9 @@ +using System.Collections.Immutable; +using Libplanet.Types.Blocks; + +namespace Libplanet.Action +{ + public delegate ImmutableArray PolicyBlockActionsGetter( + IPreEvaluationBlockHeader blockHeader + ); +} diff --git a/Libplanet/Blockchain/BlockChain.Evaluate.cs b/Libplanet/Blockchain/BlockChain.Evaluate.cs index dd5bb5e46be..8715720fb10 100644 --- a/Libplanet/Blockchain/BlockChain.Evaluate.cs +++ b/Libplanet/Blockchain/BlockChain.Evaluate.cs @@ -147,7 +147,8 @@ public IReadOnlyList EvaluateBlock(IPreEvaluationBlo /// /// Evaluates all actions in the and - /// an optional , and returns + /// optional , + /// , and returns /// a instance combined with the /// The returned is signed by the given . /// diff --git a/Libplanet/Blockchain/Policies/BlockPolicy.cs b/Libplanet/Blockchain/Policies/BlockPolicy.cs index e3895050a63..9a316912949 100644 --- a/Libplanet/Blockchain/Policies/BlockPolicy.cs +++ b/Libplanet/Blockchain/Policies/BlockPolicy.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Immutable; using System.Diagnostics.Contracts; using System.Linq; using Libplanet.Action; @@ -34,7 +35,11 @@ public class BlockPolicy : IBlockPolicy /// description for more detail. /// /// - /// A to executed for + /// Array of to executed for + /// every . Set to by default, which results + /// in no additional execution other than those included in s. + /// + /// A to executed for /// every . Set to by default, which results /// in no additional execution other than those included in s. /// @@ -66,7 +71,8 @@ public class BlockPolicy : IBlockPolicy /// Goes to . Set to /// by default. public BlockPolicy( - IAction? blockAction = null, + ImmutableArray? beginBlockActions = null, + ImmutableArray? endBlockActions = null, TimeSpan? blockInterval = null, Func? validateNextBlockTx = null, @@ -77,7 +83,8 @@ public BlockPolicy( Func? getMaxTransactionsPerBlock = null, Func? getMaxTransactionsPerSignerPerBlock = null) { - BlockAction = blockAction; + BeginBlockActions = beginBlockActions ?? ImmutableArray.Empty; + EndBlockActions = endBlockActions ?? ImmutableArray.Empty; BlockInterval = blockInterval ?? DefaultTargetBlockInterval; _getMaxTransactionsBytes = getMaxTransactionsBytes ?? (_ => 100L * 1024L); _getMinTransactionsPerBlock = getMinTransactionsPerBlock ?? (_ => 0); @@ -152,7 +159,10 @@ public BlockPolicy( } /// - public IAction? BlockAction { get; } + public ImmutableArray BeginBlockActions { get; } + + /// + public ImmutableArray EndBlockActions { get; } /// /// Targeted time interval between two consecutive s. diff --git a/Libplanet/Blockchain/Policies/IBlockPolicy.cs b/Libplanet/Blockchain/Policies/IBlockPolicy.cs index d95285985e6..36f95615b97 100644 --- a/Libplanet/Blockchain/Policies/IBlockPolicy.cs +++ b/Libplanet/Blockchain/Policies/IBlockPolicy.cs @@ -1,3 +1,4 @@ +using System.Collections.Immutable; using System.Diagnostics.Contracts; using Libplanet.Action; using Libplanet.Types.Blocks; @@ -21,9 +22,14 @@ namespace Libplanet.Blockchain.Policies public interface IBlockPolicy { /// - /// An to execute and be rendered for every block, if any. - /// - IAction? BlockAction { get; } + /// 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; } /// /// Checks if a can be included in a yet to be mined diff --git a/Libplanet/Blockchain/Policies/NullBlockPolicy.cs b/Libplanet/Blockchain/Policies/NullBlockPolicy.cs index a1145ed46db..d8509509ea2 100644 --- a/Libplanet/Blockchain/Policies/NullBlockPolicy.cs +++ b/Libplanet/Blockchain/Policies/NullBlockPolicy.cs @@ -1,5 +1,6 @@ #nullable disable using System.Collections.Generic; +using System.Collections.Immutable; using Libplanet.Action; using Libplanet.Crypto; using Libplanet.Types.Blocks; @@ -22,7 +23,9 @@ public NullBlockPolicy( public ISet
BlockedMiners { get; } = new HashSet
(); - public IAction BlockAction => null; + public ImmutableArray BeginBlockActions => ImmutableArray.Empty; + + public ImmutableArray EndBlockActions => ImmutableArray.Empty; public int GetMinTransactionsPerBlock(long index) => 0; From 10b7d3842326fc58cef706ac3623ab2ad6db50de Mon Sep 17 00:00:00 2001 From: s2quake Date: Thu, 21 Mar 2024 10:04:57 +0900 Subject: [PATCH 2/3] build: Fix build errors in test projects or etc. --- .../Common/UpdateValueAction.cs | 47 ++++++++ Libplanet.Benchmarks/AppendBlock.cs | 4 +- Libplanet.Benchmarks/BlockChain.cs | 4 +- Libplanet.Benchmarks/ProposeBlock.cs | 4 +- Libplanet.Explorer.Executable/Program.cs | 10 +- .../GeneratedBlockChainFixture.cs | 3 +- .../BlockPolicyParamsTest.cs | 32 +++++- .../BlockPolicyParams.cs | 65 +++++++++-- .../Commands/BlockCommand.cs | 6 +- .../Consensus/ConsensusReactorTest.cs | 8 +- .../Consensus/ContextNonProposerTest.cs | 17 ++- Libplanet.Net.Tests/Consensus/ContextTest.cs | 8 +- .../Consensus/HeightVoteSetTest.cs | 4 +- Libplanet.Net.Tests/SwarmTest.Broadcast.cs | 18 ++- Libplanet.Net.Tests/SwarmTest.Fixtures.cs | 17 ++- Libplanet.Net.Tests/SwarmTest.Preload.cs | 48 ++++++-- Libplanet.Net.Tests/SwarmTest.cs | 18 ++- Libplanet.Net.Tests/TestUtils.cs | 8 +- .../RocksDBStoreBlockChainTest.cs | 9 +- .../RocksDBStoreFixture.cs | 7 +- .../RocksDBStoreTest.cs | 4 +- Libplanet.Tests/Action/ActionEvaluatorTest.cs | 107 +++++++++++++++--- .../Blockchain/BlockChainTest.Append.cs | 16 ++- .../Blockchain/BlockChainTest.ProposeBlock.cs | 24 +++- .../BlockChainTest.ValidateNextBlock.cs | 15 ++- Libplanet.Tests/Blockchain/BlockChainTest.cs | 92 ++++++++++----- .../Blockchain/DefaultStoreBlockChainTest.cs | 9 +- .../Blockchain/Policies/BlockPolicyTest.cs | 13 ++- .../Blockchain/Policies/StagePolicyTest.cs | 3 +- .../Blocks/PreEvaluationBlockTest.cs | 29 +++-- Libplanet.Tests/Fixtures/IntegerSet.cs | 3 +- Libplanet.Tests/Store/DefaultStoreFixture.cs | 9 +- Libplanet.Tests/Store/MemoryStoreFixture.cs | 7 +- Libplanet.Tests/Store/StoreFixture.cs | 9 +- Libplanet.Tests/Store/StoreTest.cs | 3 +- Libplanet.Tests/TestUtils.cs | 3 +- 36 files changed, 541 insertions(+), 142 deletions(-) create mode 100644 Libplanet.Action.Tests/Common/UpdateValueAction.cs diff --git a/Libplanet.Action.Tests/Common/UpdateValueAction.cs b/Libplanet.Action.Tests/Common/UpdateValueAction.cs new file mode 100644 index 00000000000..ffca5b86017 --- /dev/null +++ b/Libplanet.Action.Tests/Common/UpdateValueAction.cs @@ -0,0 +1,47 @@ +using Bencodex.Types; +using Libplanet.Action.State; +using Libplanet.Crypto; + +namespace Libplanet.Action.Tests.Common +{ + public sealed class UpdateValueAction : IAction + { + public static readonly Address ValueAddress = + new Address("0000000000000000000000000000000000000123"); + + public UpdateValueAction() + { + } + + public UpdateValueAction(int increment) + { + Increment = increment; + } + + public int Increment { get; set; } + + public IValue PlainValue => Bencodex.Types.Dictionary.Empty + .Add("value", new Bencodex.Types.Integer(Increment)); + + public void LoadPlainValue(IValue plainValue) + { + Increment = (int)(Bencodex.Types.Integer)((Dictionary)plainValue)["value"]; + } + + public IWorld Execute(IActionContext ctx) + { + IWorld states = ctx.PreviousState; + IAccount account = states.GetAccount(ReservedAddresses.LegacyAccount); + int value = 0; + int increment = Increment; + + if (account.GetState(ValueAddress) is Integer integer) + { + value = (int)integer.Value + increment; + } + + account = account.SetState(ValueAddress, new Integer(value)); + return states.SetAccount(ReservedAddresses.LegacyAccount, account); + } + } +} diff --git a/Libplanet.Benchmarks/AppendBlock.cs b/Libplanet.Benchmarks/AppendBlock.cs index 19c5b107efa..9cec1a71690 100644 --- a/Libplanet.Benchmarks/AppendBlock.cs +++ b/Libplanet.Benchmarks/AppendBlock.cs @@ -8,6 +8,7 @@ using Libplanet.Types.Blocks; using Libplanet.Tests; using Libplanet.Tests.Store; +using System.Collections.Immutable; namespace Libplanet.Benchmarks { @@ -29,7 +30,8 @@ public AppendBlock() fx.StateStore, fx.GenesisBlock, new ActionEvaluator( - policyBlockActionGetter: _ => null, + policyBeginBlockActionsGetter: _ => ImmutableArray.Empty, + policyEndBlockActionsGetter: _ => ImmutableArray.Empty, stateStore: fx.StateStore, actionTypeLoader: new SingleActionLoader(typeof(DumbAction)))); _privateKey = new PrivateKey(); diff --git a/Libplanet.Benchmarks/BlockChain.cs b/Libplanet.Benchmarks/BlockChain.cs index 7f78615a258..c29de36e58a 100644 --- a/Libplanet.Benchmarks/BlockChain.cs +++ b/Libplanet.Benchmarks/BlockChain.cs @@ -1,3 +1,4 @@ +using System.Collections.Immutable; using BenchmarkDotNet.Attributes; using Libplanet.Action; using Libplanet.Action.Loader; @@ -35,7 +36,8 @@ public void SetupChain() _fx.StateStore, _fx.GenesisBlock, new ActionEvaluator( - policyBlockActionGetter: _ => null, + policyBeginBlockActionsGetter: _ => ImmutableArray.Empty, + policyEndBlockActionsGetter: _ => ImmutableArray.Empty, stateStore: _fx.StateStore, actionTypeLoader: new SingleActionLoader(typeof(DumbAction)))); var key = new PrivateKey(); diff --git a/Libplanet.Benchmarks/ProposeBlock.cs b/Libplanet.Benchmarks/ProposeBlock.cs index ce411c0770b..b0e441feada 100644 --- a/Libplanet.Benchmarks/ProposeBlock.cs +++ b/Libplanet.Benchmarks/ProposeBlock.cs @@ -8,6 +8,7 @@ using Libplanet.Types.Blocks; using Libplanet.Tests; using Libplanet.Tests.Store; +using System.Collections.Immutable; namespace Libplanet.Benchmarks { @@ -28,7 +29,8 @@ public ProposeBlock() fx.StateStore, fx.GenesisBlock, new ActionEvaluator( - policyBlockActionGetter: _ => null, + policyBeginBlockActionsGetter: _ => ImmutableArray.Empty, + policyEndBlockActionsGetter: _ => ImmutableArray.Empty, stateStore: fx.StateStore, actionTypeLoader: new SingleActionLoader(typeof(DumbAction)))); _privateKey = new PrivateKey(); diff --git a/Libplanet.Explorer.Executable/Program.cs b/Libplanet.Explorer.Executable/Program.cs index fd3eb5f7084..3c6154c97b0 100644 --- a/Libplanet.Explorer.Executable/Program.cs +++ b/Libplanet.Explorer.Executable/Program.cs @@ -200,7 +200,8 @@ If omitted (default) explorer only the local blockchain store.")] options.GetGenesisBlock(policy), blockChainStates, new ActionEvaluator( - _ => policy.BlockAction, + _ => policy.BeginBlockActions, + _ => policy.EndBlockActions, stateStore, new SingleActionLoader(typeof(NullAction)))); Startup.PreloadedSingleton = false; @@ -341,7 +342,8 @@ private static IStore LoadStore(Options options) private static BlockPolicy LoadBlockPolicy(Options options) { return new BlockPolicy( - blockAction: null, + beginBlockActions: ImmutableArray.Empty, + endBlockActions: ImmutableArray.Empty, blockInterval: TimeSpan.FromMilliseconds(options.BlockIntervalMilliseconds), getMaxTransactionsBytes: i => i > 0 ? options.MaxTransactionsBytes @@ -384,7 +386,9 @@ public DumbBlockPolicy(BlockPolicy blockPolicy) _impl = blockPolicy; } - public IAction BlockAction => _impl.BlockAction; + public ImmutableArray BeginBlockActions => _impl.BeginBlockActions; + + public ImmutableArray EndBlockActions => _impl.EndBlockActions; public int GetMinTransactionsPerBlock(long index) => _impl.GetMinTransactionsPerBlock(index); diff --git a/Libplanet.Explorer.Tests/GeneratedBlockChainFixture.cs b/Libplanet.Explorer.Tests/GeneratedBlockChainFixture.cs index 69c0093aa79..2f2157cac10 100644 --- a/Libplanet.Explorer.Tests/GeneratedBlockChainFixture.cs +++ b/Libplanet.Explorer.Tests/GeneratedBlockChainFixture.cs @@ -71,7 +71,8 @@ public GeneratedBlockChainFixture( getMaxTransactionsPerBlock: _ => int.MaxValue, getMaxTransactionsBytes: _ => long.MaxValue); var actionEvaluator = new ActionEvaluator( - _ => policy.BlockAction, + _ => policy.BeginBlockActions, + _ => policy.EndBlockActions, stateStore, TypedActionLoader.Create(typeof(SimpleAction).Assembly, typeof(SimpleAction))); Block genesisBlock = BlockChain.ProposeGenesisBlock( diff --git a/Libplanet.Extensions.Cocona.Tests/BlockPolicyParamsTest.cs b/Libplanet.Extensions.Cocona.Tests/BlockPolicyParamsTest.cs index 7e6bd2863e1..5ecc1a6900c 100644 --- a/Libplanet.Extensions.Cocona.Tests/BlockPolicyParamsTest.cs +++ b/Libplanet.Extensions.Cocona.Tests/BlockPolicyParamsTest.cs @@ -13,7 +13,8 @@ public void DefaultState() { var blockPolicyParams = new BlockPolicyParams(); Assert.Null(blockPolicyParams.GetBlockPolicy()); - Assert.Null(blockPolicyParams.GetBlockAction()); + Assert.Empty(blockPolicyParams.GetBeginBlockActions()); + Assert.Empty(blockPolicyParams.GetEndBlockActions()); } [Fact] @@ -26,7 +27,10 @@ public void GetBlockPolicy() BlockPolicy blockPolicy = Assert.IsType( blockPolicyParams.GetBlockPolicy(new[] { GetType().Assembly }) ); - Assert.IsType(blockPolicy.BlockAction); + Assert.Single(blockPolicy.BeginBlockActions); + Assert.IsType(blockPolicy.BeginBlockActions[0]); + Assert.Single(blockPolicy.EndBlockActions); + Assert.IsType(blockPolicy.EndBlockActions[0]); } [Fact] @@ -123,18 +127,34 @@ public void GetBlockPolicy_FactoryReturningNull() } [Fact] - public void GetBlockAction() + public void GetBeginBlockActions() { var blockPolicyParams = new BlockPolicyParams { PolicyFactory = $"{GetType().FullName}.{nameof(BlockPolicyFactory)}", }; - var blockAction = blockPolicyParams.GetBlockAction(new[] { GetType().Assembly }); - Assert.IsType(blockAction); + var blockActions = blockPolicyParams.GetBeginBlockActions(new[] { GetType().Assembly }); + Assert.Single(blockActions); + Assert.IsType(blockActions[0]); + } + + [Fact] + public void GetEndBlockActions() + { + var blockPolicyParams = new BlockPolicyParams + { + PolicyFactory = $"{GetType().FullName}.{nameof(BlockPolicyFactory)}", + }; + var blockActions = blockPolicyParams.GetEndBlockActions(new[] { GetType().Assembly }); + Assert.Single(blockActions); + Assert.IsType(blockActions[0]); } internal static BlockPolicy BlockPolicyFactory() => - new BlockPolicy(blockAction: new NullAction()); + new BlockPolicy( + beginBlockActions: new IAction[] { new NullAction() }.ToImmutableArray(), + endBlockActions: new IAction[] { new NullAction() }.ToImmutableArray() + ); internal static BlockPolicy BlockPolicyFactoryWithParams(bool param) => new BlockPolicy(); diff --git a/Libplanet.Extensions.Cocona/BlockPolicyParams.cs b/Libplanet.Extensions.Cocona/BlockPolicyParams.cs index 5a982efe5ef..40ef8e186b6 100644 --- a/Libplanet.Extensions.Cocona/BlockPolicyParams.cs +++ b/Libplanet.Extensions.Cocona/BlockPolicyParams.cs @@ -71,8 +71,11 @@ public Assembly[] LoadAssemblies() public object? GetBlockPolicy() => GetBlockPolicy(LoadAssemblies()); - public IAction? GetBlockAction() => - GetBlockAction(LoadAssemblies()); + public ImmutableArray GetBeginBlockActions() => + GetBeginBlockActions(LoadAssemblies()); + + public ImmutableArray GetEndBlockActions() => + GetEndBlockActions(LoadAssemblies()); [SuppressMessage( "Major Code Smell", @@ -132,17 +135,65 @@ public Assembly[] LoadAssemblies() ); } - internal IAction? GetBlockAction(Assembly[] assemblies) + internal ImmutableArray GetBeginBlockActions(Assembly[] assemblies) { object? policy = GetBlockPolicy(assemblies); if (policy is null) { - return null; + return ImmutableArray.Empty; } - PropertyInfo? prop = policy + PropertyInfo? propertyInfo = policy .GetType() - .GetProperty(nameof(IBlockPolicy.BlockAction)); - return (IAction?)prop!.GetValue(policy); + .GetProperty(nameof(IBlockPolicy.BeginBlockActions)); + if (propertyInfo is null) + { + var message = $"The policy type " + + $"'{policy.GetType().FullName}' does not have a " + + $"'{nameof(IBlockPolicy.BeginBlockActions)}' property."; + throw new InvalidOperationException(message); + } + + var value = propertyInfo.GetValue(policy); + if (value is null) + { + var message = $"The value of property " + + $"'{nameof(IBlockPolicy.BeginBlockActions)}' of type " + + $"'{policy.GetType().FullName}' cannot be null."; + throw new InvalidOperationException(message); + } + + return (ImmutableArray)value; + } + + internal ImmutableArray GetEndBlockActions(Assembly[] assemblies) + { + object? policy = GetBlockPolicy(assemblies); + if (policy is null) + { + return ImmutableArray.Empty; + } + + PropertyInfo? propertyInfo = policy + .GetType() + .GetProperty(nameof(IBlockPolicy.EndBlockActions)); + if (propertyInfo is null) + { + var message = $"The policy type " + + $"'{policy.GetType().FullName}' does not have a " + + $"'{nameof(IBlockPolicy.EndBlockActions)}' property."; + throw new InvalidOperationException(message); + } + + var value = propertyInfo.GetValue(policy); + if (value is null) + { + var message = $"The value of property " + + $"'{nameof(IBlockPolicy.EndBlockActions)}' of type " + + $"'{policy.GetType().FullName}' cannot be null."; + throw new InvalidOperationException(message); + } + + return (ImmutableArray)value; } } diff --git a/Libplanet.Extensions.Cocona/Commands/BlockCommand.cs b/Libplanet.Extensions.Cocona/Commands/BlockCommand.cs index 55f34fdb16b..bd5f57df337 100644 --- a/Libplanet.Extensions.Cocona/Commands/BlockCommand.cs +++ b/Libplanet.Extensions.Cocona/Commands/BlockCommand.cs @@ -156,9 +156,11 @@ public void GenerateGenesis( }.Select(x => x.PlainValue))) .ToImmutableList(); - var blockAction = blockPolicyParams.GetBlockAction(); + var beginBlockActions = blockPolicyParams.GetBeginBlockActions(); + var endBlockActions = blockPolicyParams.GetEndBlockActions(); var actionEvaluator = new ActionEvaluator( - _ => blockAction, + _ => beginBlockActions, + _ => endBlockActions, new TrieStateStore(new DefaultKeyValueStore(null)), new SingleActionLoader(typeof(NullAction))); Block genesis = BlockChain.ProposeGenesisBlock( diff --git a/Libplanet.Net.Tests/Consensus/ConsensusReactorTest.cs b/Libplanet.Net.Tests/Consensus/ConsensusReactorTest.cs index 4b4318f2338..e7d5cd0da82 100644 --- a/Libplanet.Net.Tests/Consensus/ConsensusReactorTest.cs +++ b/Libplanet.Net.Tests/Consensus/ConsensusReactorTest.cs @@ -47,7 +47,10 @@ public async void StartAsync() var consensusReactors = new ConsensusReactor[4]; var stores = new IStore[4]; var blockChains = new BlockChain[4]; - var fx = new MemoryStoreFixture(TestUtils.Policy.BlockAction); + var fx = new MemoryStoreFixture( + TestUtils.Policy.BeginBlockActions, + TestUtils.Policy.EndBlockActions + ); var validatorPeers = new List(); var cancellationTokenSource = new CancellationTokenSource(); @@ -66,7 +69,8 @@ public async void StartAsync() stateStore, fx.GenesisBlock, new ActionEvaluator( - policyBlockActionGetter: _ => TestUtils.Policy.BlockAction, + policyBeginBlockActionsGetter: _ => TestUtils.Policy.BeginBlockActions, + policyEndBlockActionsGetter: _ => TestUtils.Policy.EndBlockActions, stateStore: stateStore, actionTypeLoader: new SingleActionLoader(typeof(DumbAction)))); } diff --git a/Libplanet.Net.Tests/Consensus/ContextNonProposerTest.cs b/Libplanet.Net.Tests/Consensus/ContextNonProposerTest.cs index 73af67e8449..8dcbc7ce6f1 100644 --- a/Libplanet.Net.Tests/Consensus/ContextNonProposerTest.cs +++ b/Libplanet.Net.Tests/Consensus/ContextNonProposerTest.cs @@ -1,9 +1,11 @@ using System; using System.Collections.Generic; +using System.Collections.Immutable; using System.Security.Cryptography; using System.Text.Json; using System.Threading.Tasks; using Bencodex.Types; +using Libplanet.Action; using Libplanet.Action.Loader; using Libplanet.Action.Tests.Common; using Libplanet.Blockchain; @@ -259,7 +261,8 @@ public async Task EnterPreVoteNilOnInvalidBlockContent() var nilPreVoteSent = new AsyncAutoResetEvent(); var invalidKey = new PrivateKey(); var policy = new BlockPolicy( - blockAction: new MinerReward(1), + beginBlockActions: ImmutableArray.Empty, + endBlockActions: ImmutableArray.Create(new MinerReward(1)), getMaxTransactionsBytes: _ => 50 * 1024, validateNextBlockTx: IsSignerValid); @@ -294,7 +297,10 @@ public async Task EnterPreVoteNilOnInvalidBlockContent() } }; - using var fx = new MemoryStoreFixture(policy.BlockAction); + using var fx = new MemoryStoreFixture( + policy.BeginBlockActions, + policy.EndBlockActions + ); var diffPolicyBlockChain = TestUtils.CreateDummyBlockChain( fx, policy, new SingleActionLoader(typeof(DumbAction)), blockChain.Genesis); @@ -332,7 +338,8 @@ public async Task EnterPreVoteNilOnInvalidAction() var nilPreCommitSent = new AsyncAutoResetEvent(); var txSigner = new PrivateKey(); var policy = new BlockPolicy( - blockAction: new MinerReward(1), + beginBlockActions: ImmutableArray.Empty, + endBlockActions: ImmutableArray.Create(new MinerReward(1)), getMaxTransactionsBytes: _ => 50 * 1024); var (blockChain, context) = TestUtils.CreateDummyContext( @@ -363,7 +370,9 @@ message is ConsensusPreCommitMsg commit && } }; - using var fx = new MemoryStoreFixture(policy.BlockAction); + using var fx = new MemoryStoreFixture( + policy.BeginBlockActions, + policy.EndBlockActions); var unsignedInvalidTx = new UnsignedTx( new TxInvoice( diff --git a/Libplanet.Net.Tests/Consensus/ContextTest.cs b/Libplanet.Net.Tests/Consensus/ContextTest.cs index 7a988a3df4b..5c61f4bc776 100644 --- a/Libplanet.Net.Tests/Consensus/ContextTest.cs +++ b/Libplanet.Net.Tests/Consensus/ContextTest.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Immutable; using System.Linq; using System.Text.Json; using System.Threading.Tasks; @@ -291,9 +292,12 @@ public async Task CanPreCommitOnEndCommit() TimeSpan newHeightDelay = TimeSpan.FromSeconds(1); var policy = new BlockPolicy( - blockAction: new MinerReward(1), + beginBlockActions: ImmutableArray.Empty, + endBlockActions: ImmutableArray.Create(new MinerReward(1)), getMaxTransactionsBytes: _ => 50 * 1024); - var fx = new MemoryStoreFixture(policy.BlockAction); + var fx = new MemoryStoreFixture( + policy.BeginBlockActions, + policy.EndBlockActions); var blockChain = Libplanet.Tests.TestUtils.MakeBlockChain( policy, fx.Store, diff --git a/Libplanet.Net.Tests/Consensus/HeightVoteSetTest.cs b/Libplanet.Net.Tests/Consensus/HeightVoteSetTest.cs index 724695159b5..cf200cbb8db 100644 --- a/Libplanet.Net.Tests/Consensus/HeightVoteSetTest.cs +++ b/Libplanet.Net.Tests/Consensus/HeightVoteSetTest.cs @@ -23,7 +23,9 @@ public class HeightVoteSetTest public HeightVoteSetTest() { _blockChain = TestUtils.CreateDummyBlockChain( - new MemoryStoreFixture(TestUtils.Policy.BlockAction)); + new MemoryStoreFixture( + TestUtils.Policy.BeginBlockActions, + TestUtils.Policy.EndBlockActions)); var block = _blockChain.ProposeBlock(TestUtils.PrivateKeys[1]); _lastCommit = TestUtils.CreateBlockCommit(block); _heightVoteSet = new HeightVoteSet(2, TestUtils.ValidatorSet); diff --git a/Libplanet.Net.Tests/SwarmTest.Broadcast.cs b/Libplanet.Net.Tests/SwarmTest.Broadcast.cs index b7ee8e04ef5..98c3db41687 100644 --- a/Libplanet.Net.Tests/SwarmTest.Broadcast.cs +++ b/Libplanet.Net.Tests/SwarmTest.Broadcast.cs @@ -41,7 +41,9 @@ public async Task BroadcastBlock() { const int numBlocks = 5; var policy = new NullBlockPolicy(); - var genesis = new MemoryStoreFixture(policy.BlockAction).GenesisBlock; + var genesis = new MemoryStoreFixture( + policy.BeginBlockActions, + policy.EndBlockActions).GenesisBlock; var swarmA = await CreateSwarm( privateKey: new PrivateKey(), @@ -93,7 +95,9 @@ public async Task BroadcastBlockToReconnectedPeer() { var miner = new PrivateKey(); var policy = new NullBlockPolicy(); - var fx = new MemoryStoreFixture(policy.BlockAction); + var fx = new MemoryStoreFixture( + policy.BeginBlockActions, + policy.EndBlockActions); var minerChain = MakeBlockChain( policy, fx.Store, fx.StateStore, new SingleActionLoader(typeof(DumbAction))); foreach (int i in Enumerable.Range(0, 10)) @@ -466,7 +470,8 @@ public async Task BroadcastTxAsyncMany() fxs[i].StateStore, fxs[i].GenesisBlock, new ActionEvaluator( - policyBlockActionGetter: _ => policy.BlockAction, + policyBeginBlockActionsGetter: _ => policy.BeginBlockActions, + policyEndBlockActionsGetter_ => policy.EndBlockActions, stateStore: fxs[i].StateStore, actionTypeLoader: new SingleActionLoader(typeof(DumbAction)))); swarms[i] = await CreateSwarm(blockChains[i]).ConfigureAwait(false); @@ -700,7 +705,12 @@ public async Task CanBroadcastBlock() [Fact(Timeout = Timeout)] public async Task BroadcastBlockWithSkip() { - var policy = new BlockPolicy(new MinerReward(1)); + var beginActions = ImmutableArray.Create( + ); + var endActions = ImmutableArray.Create( + new MinerReward(1) + ); + var policy = new BlockPolicy(beginActions, endActions); var fx1 = new MemoryStoreFixture(); var blockChain = MakeBlockChain( policy, fx1.Store, fx1.StateStore, new SingleActionLoader(typeof(DumbAction))); diff --git a/Libplanet.Net.Tests/SwarmTest.Fixtures.cs b/Libplanet.Net.Tests/SwarmTest.Fixtures.cs index b44f77fb5a2..69c7db0c418 100644 --- a/Libplanet.Net.Tests/SwarmTest.Fixtures.cs +++ b/Libplanet.Net.Tests/SwarmTest.Fixtures.cs @@ -5,6 +5,7 @@ using System.Linq; using System.Net; using System.Threading.Tasks; +using Libplanet.Action; using Libplanet.Action.Loader; using Libplanet.Action.Tests.Common; using Libplanet.Blockchain; @@ -33,7 +34,12 @@ private static (Address, Block[]) if (blocks is null) { - var policy = new BlockPolicy(new MinerReward(1)); + var beginActions = ImmutableArray.Create( + ); + var endActions = ImmutableArray.Create( + new MinerReward(1) + ); + var policy = new BlockPolicy(beginActions, endActions); using (var storeFx = new MemoryStoreFixture()) { var chain = @@ -116,8 +122,13 @@ private async Task CreateSwarm( Block genesis = null, ConsensusReactorOption? consensusReactorOption = null) { - policy = policy ?? new BlockPolicy(new MinerReward(1)); - var fx = new MemoryStoreFixture(policy.BlockAction); + var beginActions = ImmutableArray.Create( + ); + var endActions = ImmutableArray.Create( + new MinerReward(1) + ); + policy = policy ?? new BlockPolicy(beginActions, endActions); + var fx = new MemoryStoreFixture(policy.BeginBlockActions, policy.EndBlockActions); var blockchain = MakeBlockChain( policy, fx.Store, diff --git a/Libplanet.Net.Tests/SwarmTest.Preload.cs b/Libplanet.Net.Tests/SwarmTest.Preload.cs index b505d60264e..422def21c41 100644 --- a/Libplanet.Net.Tests/SwarmTest.Preload.cs +++ b/Libplanet.Net.Tests/SwarmTest.Preload.cs @@ -269,7 +269,9 @@ public async Task PreloadWithMaliciousPeer() const int honestTipHeight = 7; var policy = new NullBlockPolicy(); var policyB = new NullBlockPolicy(); - var genesis = new MemoryStoreFixture(policy.BlockAction).GenesisBlock; + var genesis = new MemoryStoreFixture( + policy.BeginBlockActions, + policy.EndBlockActions).GenesisBlock; var swarmA = await CreateSwarm( privateKey: new PrivateKey(), @@ -379,7 +381,12 @@ public async Task PreloadWithMaliciousPeer() [RetryFact(Timeout = Timeout)] public async Task NoRenderInPreload() { - var policy = new BlockPolicy(new MinerReward(1)); + var beginActions = ImmutableArray.Create( + ); + var endActions = ImmutableArray.Create( + new MinerReward(1) + ); + var policy = new BlockPolicy(beginActions, endActions); var renderer = new RecordingActionRenderer(); var chain = MakeBlockChain( policy, @@ -502,9 +509,18 @@ public async Task PreloadFromNominer() Swarm minerSwarm = await CreateSwarm(minerKey).ConfigureAwait(false); Swarm receiverSwarm = await CreateSwarm().ConfigureAwait(false); var fxForNominers = new StoreFixture[2]; - var policy = new BlockPolicy(new MinerReward(1)); - fxForNominers[0] = new MemoryStoreFixture(policy.BlockAction); - fxForNominers[1] = new MemoryStoreFixture(policy.BlockAction); + var beginActions = ImmutableArray.Create( + ); + var endActions = ImmutableArray.Create( + new MinerReward(1) + ); + var policy = new BlockPolicy(beginActions, endActions); + fxForNominers[0] = new MemoryStoreFixture( + policy.BeginBlockActions, + policy.EndBlockActions); + fxForNominers[1] = new MemoryStoreFixture( + policy.BeginBlockActions, + policy.EndBlockActions); var blockChainsForNominers = new[] { MakeBlockChain( @@ -1084,9 +1100,14 @@ await receiverSwarm.AddPeersAsync( [Fact(Timeout = Timeout)] public async Task ActionExecutionWithBranchpoint() { - var policy = new BlockPolicy(new MinerReward(1)); - var fx1 = new MemoryStoreFixture(policy.BlockAction); - var fx2 = new MemoryStoreFixture(policy.BlockAction); + var beginActions = ImmutableArray.Create( + ); + var endActions = ImmutableArray.Create( + new MinerReward(1) + ); + var policy = new BlockPolicy(beginActions, endActions); + var fx1 = new MemoryStoreFixture(policy.BeginBlockActions, policy.EndBlockActions); + var fx2 = new MemoryStoreFixture(policy.BeginBlockActions, policy.EndBlockActions); var seedChain = MakeBlockChain( policy, fx1.Store, fx1.StateStore, new SingleActionLoader(typeof(DumbAction))); var receiverChain = MakeBlockChain( @@ -1147,9 +1168,14 @@ public async Task ActionExecutionWithBranchpoint() public async Task UpdateTxExecution() { PrivateKey seedKey = new PrivateKey(); - var policy = new BlockPolicy(new MinerReward(1)); - var fx1 = new MemoryStoreFixture(policy.BlockAction); - var fx2 = new MemoryStoreFixture(policy.BlockAction); + var beginActions = ImmutableArray.Create( + ); + var endActions = ImmutableArray.Create( + new MinerReward(1) + ); + var policy = new BlockPolicy(beginActions, endActions); + var fx1 = new MemoryStoreFixture(policy.BeginBlockActions, policy.EndBlockActions); + var fx2 = new MemoryStoreFixture(policy.BeginBlockActions, policy.EndBlockActions); var seedChain = MakeBlockChain( policy, fx1.Store, fx1.StateStore, new SingleActionLoader(typeof(DumbAction))); var receiverChain = MakeBlockChain( diff --git a/Libplanet.Net.Tests/SwarmTest.cs b/Libplanet.Net.Tests/SwarmTest.cs index 0d5abc645b5..a447ff1e757 100644 --- a/Libplanet.Net.Tests/SwarmTest.cs +++ b/Libplanet.Net.Tests/SwarmTest.cs @@ -398,7 +398,9 @@ public async Task BootstrapContext() new AsyncAutoResetEvent()).ToList(); var roundOneProposed = new AsyncAutoResetEvent(); var policy = new NullBlockPolicy(); - var genesis = new MemoryStoreFixture(policy.BlockAction).GenesisBlock; + var genesis = new MemoryStoreFixture( + policy.BeginBlockActions, + policy.EndBlockActions).GenesisBlock; var consensusPeers = Enumerable.Range(0, 4).Select(i => new BoundPeer( @@ -877,7 +879,12 @@ async Task MineAndBroadcast(CancellationToken cancellationToken) [Fact(Timeout = Timeout)] public async Task RenderInFork() { - var policy = new BlockPolicy(new MinerReward(1)); + var beginActions = ImmutableArray.Create( + ); + var endActions = ImmutableArray.Create( + new MinerReward(1) + ); + var policy = new BlockPolicy(beginActions, endActions); var renderer = new RecordingActionRenderer(); var chain = MakeBlockChain( policy, @@ -946,7 +953,12 @@ public async Task RenderInFork() [Fact(Skip = "This should be fixed to work deterministically.")] public async Task HandleReorgInSynchronizing() { - var policy = new BlockPolicy(new MinerReward(1)); + var beginActions = ImmutableArray.Create( + ); + var endActions = ImmutableArray.Create( + new MinerReward(1) + ); + var policy = new BlockPolicy(beginActions, endActions); async Task MakeSwarm(PrivateKey key = null) => await CreateSwarm( diff --git a/Libplanet.Net.Tests/TestUtils.cs b/Libplanet.Net.Tests/TestUtils.cs index 44524698480..8a49c2f1407 100644 --- a/Libplanet.Net.Tests/TestUtils.cs +++ b/Libplanet.Net.Tests/TestUtils.cs @@ -5,6 +5,7 @@ using System.Net; using System.Threading.Tasks; using Bencodex; +using Libplanet.Action; using Libplanet.Action.Loader; using Libplanet.Action.State; using Libplanet.Action.Tests.Common; @@ -46,7 +47,8 @@ public static class TestUtils public static readonly ValidatorSet ValidatorSet = Libplanet.Tests.TestUtils.ValidatorSet; public static readonly IBlockPolicy Policy = new BlockPolicy( - blockAction: new MinerReward(1), + beginBlockActions: ImmutableArray.Empty, + endBlockActions: ImmutableArray.Create(new MinerReward(1)), getMaxTransactionsBytes: _ => 50 * 1024); public static readonly IActionLoader ActionLoader = new SingleActionLoader( @@ -234,7 +236,9 @@ public static (BlockChain BlockChain, ConsensusContext ConsensusContext) ContextTimeoutOption? contextTimeoutOptions = null) { policy ??= Policy; - var fx = new MemoryStoreFixture(policy.BlockAction); + var fx = new MemoryStoreFixture( + policy.BeginBlockActions, + policy.EndBlockActions); var blockChain = CreateDummyBlockChain(fx, policy, actionLoader); ConsensusContext? consensusContext = null; diff --git a/Libplanet.RocksDBStore.Tests/RocksDBStoreBlockChainTest.cs b/Libplanet.RocksDBStore.Tests/RocksDBStoreBlockChainTest.cs index 6114743caa4..05607aaf9b4 100644 --- a/Libplanet.RocksDBStore.Tests/RocksDBStoreBlockChainTest.cs +++ b/Libplanet.RocksDBStore.Tests/RocksDBStoreBlockChainTest.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Immutable; using Libplanet.Action; using Libplanet.Tests.Blockchain; using Libplanet.Tests.Store; @@ -14,11 +15,15 @@ public RocksDBStoreBlockChainTest(ITestOutputHelper output) { } - protected override StoreFixture GetStoreFixture(IAction blockAction) + protected override StoreFixture GetStoreFixture( + ImmutableArray? beginBlockActions = null, + ImmutableArray? endBlockActions = null) { try { - return new RocksDBStoreFixture(blockAction: blockAction); + return new RocksDBStoreFixture( + beginBlockActions: beginBlockActions, + endBlockActions: endBlockActions); } catch (TypeInitializationException) { diff --git a/Libplanet.RocksDBStore.Tests/RocksDBStoreFixture.cs b/Libplanet.RocksDBStore.Tests/RocksDBStoreFixture.cs index 7441e4a4297..aa6fc80c140 100644 --- a/Libplanet.RocksDBStore.Tests/RocksDBStoreFixture.cs +++ b/Libplanet.RocksDBStore.Tests/RocksDBStoreFixture.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Immutable; using System.IO; using Libplanet.Action; using Libplanet.Store; @@ -9,8 +10,10 @@ namespace Libplanet.RocksDBStore.Tests { public class RocksDBStoreFixture : StoreFixture { - public RocksDBStoreFixture(IAction blockAction = null) - : base(blockAction) + public RocksDBStoreFixture( + ImmutableArray? beginBlockActions = null, + ImmutableArray? endBlockActions = null) + : base(beginBlockActions, endBlockActions) { Path = System.IO.Path.Combine( System.IO.Path.GetTempPath(), diff --git a/Libplanet.RocksDBStore.Tests/RocksDBStoreTest.cs b/Libplanet.RocksDBStore.Tests/RocksDBStoreTest.cs index 85abca8abc7..2927b6d94cd 100644 --- a/Libplanet.RocksDBStore.Tests/RocksDBStoreTest.cs +++ b/Libplanet.RocksDBStore.Tests/RocksDBStoreTest.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Immutable; using System.IO; using System.Linq; using System.Reflection; @@ -86,7 +87,8 @@ public void ReopenStoreAfterDispose() stateStore, Fx.GenesisBlock, new ActionEvaluator( - policyBlockActionGetter: _ => null, + policyBeginBlockActionsGetter: _ => ImmutableArray.Empty, + policyEndBlockActionsGetter: _ => ImmutableArray.Empty, stateStore: stateStore, actionTypeLoader: new SingleActionLoader(typeof(DumbAction)))); store.Dispose(); diff --git a/Libplanet.Tests/Action/ActionEvaluatorTest.cs b/Libplanet.Tests/Action/ActionEvaluatorTest.cs index 0ffad2a6f22..efde4fe5b84 100644 --- a/Libplanet.Tests/Action/ActionEvaluatorTest.cs +++ b/Libplanet.Tests/Action/ActionEvaluatorTest.cs @@ -48,11 +48,18 @@ public ActionEvaluatorTest(ITestOutputHelper output) .CreateLogger() .ForContext(); + var beginBlockActions = new IAction[] { new UpdateValueAction(1) }; + var endBlockActions = new IAction[] { new MinerReward(1) }; + _output = output; _policy = new BlockPolicy( - blockAction: new MinerReward(1), + beginBlockActions: beginBlockActions.ToImmutableArray(), + endBlockActions: endBlockActions.ToImmutableArray(), getMaxTransactionsBytes: _ => 50 * 1024); - _storeFx = new MemoryStoreFixture(_policy.BlockAction); + _storeFx = new MemoryStoreFixture( + _policy.BeginBlockActions, + _policy.EndBlockActions + ); _txFx = new TxFixture(null); } @@ -86,7 +93,8 @@ public void Idempotent() lastCommit: null), transactions: txs).Propose(); var actionEvaluator = new ActionEvaluator( - _ => null, + _ => ImmutableArray.Empty, + _ => ImmutableArray.Empty, stateStore, new SingleActionLoader(typeof(RandomAction))); Block stateRootBlock = noStateRootBlock.Sign( @@ -289,7 +297,8 @@ DumbAction MakeAction(Address address, char identifier, Address? transferTo = nu Block genesis = ProposeGenesisBlock(TestUtils.GenesisProposer); var actionEvaluator = new ActionEvaluator( - policyBlockActionGetter: _ => null, + policyBeginBlockActionsGetter: _ => ImmutableArray.Empty, + policyEndBlockActionsGetter: _ => ImmutableArray.Empty, stateStore: new TrieStateStore(new MemoryKeyValueStore()), actionTypeLoader: new SingleActionLoader(typeof(DumbAction))); @@ -571,7 +580,8 @@ public void EvaluateTx() lastCommit: null), transactions: txs).Propose(); var actionEvaluator = new ActionEvaluator( - policyBlockActionGetter: _ => null, + policyBeginBlockActionsGetter: _ => ImmutableArray.Empty, + policyEndBlockActionsGetter: _ => ImmutableArray.Empty, stateStore: new TrieStateStore(new MemoryKeyValueStore()), actionTypeLoader: new SingleActionLoader(typeof(DumbAction))); @@ -672,7 +682,8 @@ public void EvaluateTxResultThrowingException() var txs = new Transaction[] { tx }; var hash = new BlockHash(GetRandomBytes(BlockHash.Size)); var actionEvaluator = new ActionEvaluator( - policyBlockActionGetter: _ => null, + policyBeginBlockActionsGetter: _ => ImmutableArray.Empty, + policyEndBlockActionsGetter: _ => ImmutableArray.Empty, stateStore: new TrieStateStore(new MemoryKeyValueStore()), actionTypeLoader: new SingleActionLoader(typeof(ThrowException)) ); @@ -820,7 +831,55 @@ public void EvaluateActions() } [Fact] - public void EvaluatePolicyBlockAction() + public void EvaluatePolicyBeginBlockActions() + { + var (chain, actionEvaluator) = MakeBlockChainAndActionEvaluator( + policy: _policy, + store: _storeFx.Store, + stateStore: _storeFx.StateStore, + actionLoader: new SingleActionLoader(typeof(DumbAction)), + genesisBlock: _storeFx.GenesisBlock, + privateKey: ChainPrivateKey); + (_, Transaction[] txs) = MakeFixturesForAppendTests(); + var genesis = chain.Genesis; + var block = chain.ProposeBlock( + GenesisProposer, txs.ToImmutableList(), CreateBlockCommit(chain.Tip)); + + IWorld previousState = actionEvaluator.PrepareInitialDelta(null); + var evaluations = actionEvaluator.EvaluatePolicyBeginBlockActions( + genesis, + previousState); + + Assert.Equal( + chain.Policy.BeginBlockActions, + evaluations.Select(item => item.Action).ToImmutableArray()); + Assert.Single(evaluations); + Assert.Equal( + (Integer)0, + (Integer)evaluations[0].OutputState + .GetAccount(ReservedAddresses.LegacyAccount) + .GetState(UpdateValueAction.ValueAddress)); + Assert.True(evaluations[0].InputContext.BlockAction); + + previousState = evaluations[0].OutputState; + evaluations = actionEvaluator.EvaluatePolicyBeginBlockActions( + block, + previousState); + + Assert.Equal( + chain.Policy.BeginBlockActions, + evaluations.Select(item => item.Action).ToImmutableArray()); + Assert.Single(evaluations); + Assert.Equal( + (Integer)1, + (Integer)evaluations[0].OutputState + .GetAccount(ReservedAddresses.LegacyAccount) + .GetState(UpdateValueAction.ValueAddress)); + Assert.True(evaluations[0].InputContext.BlockAction); + } + + [Fact] + public void EvaluatePolicyEndBlockActions() { var (chain, actionEvaluator) = MakeBlockChainAndActionEvaluator( policy: _policy, @@ -835,24 +894,34 @@ public void EvaluatePolicyBlockAction() GenesisProposer, txs.ToImmutableList(), CreateBlockCommit(chain.Tip)); IWorld previousState = actionEvaluator.PrepareInitialDelta(null); - var evaluation = actionEvaluator.EvaluatePolicyBlockAction(genesis, previousState); + var evaluations = actionEvaluator.EvaluatePolicyEndBlockActions( + genesis, + previousState); - Assert.Equal(chain.Policy.BlockAction, evaluation.Action); + Assert.Equal( + chain.Policy.EndBlockActions, + evaluations.Select(item => item.Action).ToImmutableArray()); + Assert.Single(evaluations); Assert.Equal( (Integer)1, - (Integer)evaluation.OutputState + (Integer)evaluations[0].OutputState .GetAccount(ReservedAddresses.LegacyAccount).GetState(genesis.Miner)); - Assert.True(evaluation.InputContext.BlockAction); + Assert.True(evaluations[0].InputContext.BlockAction); - previousState = evaluation.OutputState; - evaluation = actionEvaluator.EvaluatePolicyBlockAction(block, previousState); + previousState = evaluations[0].OutputState; + evaluations = actionEvaluator.EvaluatePolicyEndBlockActions( + block, + previousState); - Assert.Equal(chain.Policy.BlockAction, evaluation.Action); + Assert.Equal( + chain.Policy.EndBlockActions, + evaluations.Select(item => item.Action).ToImmutableArray()); + Assert.Single(evaluations); Assert.Equal( (Integer)2, - (Integer)evaluation.OutputState + (Integer)evaluations[0].OutputState .GetAccount(ReservedAddresses.LegacyAccount).GetState(block.Miner)); - Assert.True(evaluation.InputContext.BlockAction); + Assert.True(evaluations[0].InputContext.BlockAction); chain.Append(block, CreateBlockCommit(block), render: true); previousState = actionEvaluator.PrepareInitialDelta(genesis.StateRootHash); @@ -860,11 +929,13 @@ public void EvaluatePolicyBlockAction() block, previousState).ToList(); previousState = txEvaluations.Last().OutputState; - evaluation = actionEvaluator.EvaluatePolicyBlockAction(block, previousState); + evaluations = actionEvaluator.EvaluatePolicyEndBlockActions( + block, + previousState); Assert.Equal( (Integer)2, - (Integer)evaluation.OutputState + (Integer)evaluations[0].OutputState .GetAccount(ReservedAddresses.LegacyAccount).GetState(block.Miner)); } diff --git a/Libplanet.Tests/Blockchain/BlockChainTest.Append.cs b/Libplanet.Tests/Blockchain/BlockChainTest.Append.cs index 4513021a4df..87ab3110a9c 100644 --- a/Libplanet.Tests/Blockchain/BlockChainTest.Append.cs +++ b/Libplanet.Tests/Blockchain/BlockChainTest.Append.cs @@ -463,7 +463,8 @@ TxPolicyViolationException IsSignerValid( fx.StateStore, fx.GenesisBlock, new ActionEvaluator( - _ => policy.BlockAction, + _ => policy.BeginBlockActions, + _ => policy.EndBlockActions, stateStore: fx.StateStore, actionTypeLoader: new SingleActionLoader(typeof(DumbAction)))); @@ -593,7 +594,8 @@ public void AppendValidatesBlock() _fx.GenesisBlock, blockChainStates, new ActionEvaluator( - _ => policy.BlockAction, + _ => policy.BeginBlockActions, + _ => policy.EndBlockActions, _fx.StateStore, new SingleActionLoader(typeof(DumbAction)))); Assert.Throws( @@ -759,13 +761,17 @@ public void CannotAppendBlockWithInvalidActions() public void DoesNotMigrateStateWithoutAction() { var policy = new BlockPolicy( - blockAction: null, + beginBlockActions: ImmutableArray.Empty, + endBlockActions: ImmutableArray.Empty, getMaxTransactionsBytes: _ => 50 * 1024); var stagePolicy = new VolatileStagePolicy(); - var fx = GetStoreFixture(policy.BlockAction); + var fx = GetStoreFixture( + policy.BeginBlockActions, + policy.EndBlockActions); var renderer = new ValidatingActionRenderer(); var actionEvaluator = new ActionEvaluator( - _ => policy.BlockAction, + _ => policy.BeginBlockActions, + _ => policy.EndBlockActions, stateStore: fx.StateStore, actionTypeLoader: new SingleActionLoader(typeof(DumbAction))); diff --git a/Libplanet.Tests/Blockchain/BlockChainTest.ProposeBlock.cs b/Libplanet.Tests/Blockchain/BlockChainTest.ProposeBlock.cs index a5970eb3ecb..e70a2da63af 100644 --- a/Libplanet.Tests/Blockchain/BlockChainTest.ProposeBlock.cs +++ b/Libplanet.Tests/Blockchain/BlockChainTest.ProposeBlock.cs @@ -140,7 +140,8 @@ public void CanProposeInvalidGenesisBlock() { var policy = new BlockPolicy(); var actionEvaluator = new ActionEvaluator( - _ => policy.BlockAction, + _ => policy.BeginBlockActions, + _ => policy.EndBlockActions, fx.StateStore, new SingleActionLoader(typeof(DumbAction))); var genesis = BlockChain.ProposeGenesisBlock( @@ -180,7 +181,8 @@ public void CanProposeInvalidBlock() fx.StateStore, fx.GenesisBlock, new ActionEvaluator( - _ => policy.BlockAction, + _ => policy.BeginBlockActions, + _ => policy.EndBlockActions, stateStore: fx.StateStore, actionTypeLoader: new SingleActionLoader(typeof(DumbAction)))); var txs = new[] @@ -404,7 +406,8 @@ TxPolicyViolationException IsSignerValid( fx.StateStore, fx.GenesisBlock, new ActionEvaluator( - _ => policy.BlockAction, + _ => policy.BeginBlockActions, + _ => policy.EndBlockActions, stateStore: fx.StateStore, actionTypeLoader: new SingleActionLoader(typeof(DumbAction)))); @@ -504,8 +507,16 @@ public void ProposeBlockWithBlockAction() var privateKey2 = new PrivateKey(); var address2 = privateKey2.Address; - var blockAction = new DumbAction(address1, "foo"); - var policy = new BlockPolicy(blockAction); + var beginBlockActions = ImmutableArray.Create( + ); + var endBlockActions = ImmutableArray.Create( + new DumbAction(address1, "foo") + ); + + var policy = new BlockPolicy( + beginBlockActions, + endBlockActions + ); var blockChainStates = new BlockChainStates(_fx.Store, _fx.StateStore); var blockChain = new BlockChain( @@ -516,7 +527,8 @@ public void ProposeBlockWithBlockAction() _fx.GenesisBlock, blockChainStates, new ActionEvaluator( - _ => policy.BlockAction, + _ => policy.BeginBlockActions, + _ => policy.EndBlockActions, _fx.StateStore, new SingleActionLoader(typeof(DumbAction)))); diff --git a/Libplanet.Tests/Blockchain/BlockChainTest.ValidateNextBlock.cs b/Libplanet.Tests/Blockchain/BlockChainTest.ValidateNextBlock.cs index ddffc608fae..455d49402f1 100644 --- a/Libplanet.Tests/Blockchain/BlockChainTest.ValidateNextBlock.cs +++ b/Libplanet.Tests/Blockchain/BlockChainTest.ValidateNextBlock.cs @@ -178,7 +178,8 @@ public void ValidateNextBlockInvalidStateRootHash() var stateStore = new TrieStateStore(stateKeyValueStore); IStore store = new MemoryStore(); var actionEvaluator = new ActionEvaluator( - _ => policy.BlockAction, + _ => policy.BeginBlockActions, + _ => policy.EndBlockActions, stateStore, new SingleActionLoader(typeof(DumbAction))); var genesisBlock = TestUtils.ProposeGenesisBlock( @@ -209,8 +210,15 @@ public void ValidateNextBlockInvalidStateRootHash() lastCommit: null)).Propose(), TestUtils.GenesisProposer); + var beginActions = ImmutableArray.Create( + ); + var endActions = ImmutableArray.Create( + new SetStatesAtBlock(default, (Text)"foo", default, 1) + ); + var policyWithBlockAction = new BlockPolicy( - new SetStatesAtBlock(default, (Text)"foo", default, 1), + beginActions, + endActions, policy.BlockInterval ); var blockChainStates = new BlockChainStates(store, stateStore); @@ -222,7 +230,8 @@ public void ValidateNextBlockInvalidStateRootHash() genesisBlock, blockChainStates, new ActionEvaluator( - _ => policyWithBlockAction.BlockAction, + _ => policyWithBlockAction.BeginBlockActions, + _ => policyWithBlockAction.EndBlockActions, stateStore, new SingleActionLoader(typeof(DumbAction)))); Assert.Throws(() => diff --git a/Libplanet.Tests/Blockchain/BlockChainTest.cs b/Libplanet.Tests/Blockchain/BlockChainTest.cs index 8101b0d0c78..020670e9ebb 100644 --- a/Libplanet.Tests/Blockchain/BlockChainTest.cs +++ b/Libplanet.Tests/Blockchain/BlockChainTest.cs @@ -51,10 +51,13 @@ public BlockChainTest(ITestOutputHelper output) .ForContext(); _policy = new BlockPolicy( - blockAction: new MinerReward(1), + beginBlockActions: ImmutableArray.Empty, + endBlockActions: ImmutableArray.Create(new MinerReward(1)), getMaxTransactionsBytes: _ => 50 * 1024); _stagePolicy = new VolatileStagePolicy(); - _fx = GetStoreFixture(_policy.BlockAction); + _fx = GetStoreFixture( + _policy.BeginBlockActions, + _policy.EndBlockActions); _renderer = new ValidatingActionRenderer(); _blockChain = BlockChain.Create( _policy, @@ -63,7 +66,8 @@ public BlockChainTest(ITestOutputHelper output) _fx.StateStore, _fx.GenesisBlock, new ActionEvaluator( - _ => _policy.BlockAction, + _ => _policy.BeginBlockActions, + _ => _policy.EndBlockActions, stateStore: _fx.StateStore, actionTypeLoader: new SingleActionLoader(typeof(DumbAction))), renderers: new[] { new LoggedActionRenderer(_renderer, Log.Logger) } @@ -129,7 +133,16 @@ public void CanonicalId() chain2.Append(block3, CreateBlockCommit(block3)); Assert.Equal(chain1.Id, _fx.Store.GetCanonicalChainId()); - var policy = new BlockPolicy(new MinerReward(1)); + var beginActions = ImmutableArray.Create( + ); + var endActions = ImmutableArray.Create( + new MinerReward(1) + ); + + var policy = new BlockPolicy( + beginActions, + endActions + ); var blockChainStates = new BlockChainStates(_fx.Store, _fx.StateStore); var z = new BlockChain( policy, @@ -139,7 +152,8 @@ public void CanonicalId() _fx.GenesisBlock, blockChainStates, new ActionEvaluator( - _ => policy.BlockAction, + _ => policy.BeginBlockActions, + _ => policy.EndBlockActions, _fx.StateStore, new SingleActionLoader(typeof(DumbAction)))); @@ -185,7 +199,8 @@ public void ProcessActions() var actionLoader = TypedActionLoader.Create( typeof(BaseAction).Assembly, typeof(BaseAction)); var actionEvaluator = new ActionEvaluator( - _ => policy.BlockAction, + _ => policy.BeginBlockActions, + _ => policy.EndBlockActions, stateStore, actionLoader); var nonce = 0; @@ -561,7 +576,9 @@ public void ForkWithBlockNotExistInChain() [SkippableFact] public void ForkChainWithIncompleteBlockStates() { - var fx = new MemoryStoreFixture(_policy.BlockAction); + var fx = new MemoryStoreFixture( + _policy.BeginBlockActions, + _policy.EndBlockActions); (_, _, BlockChain chain) = MakeIncompleteBlockStates(fx.Store, fx.StateStore); BlockChain forked = chain.Fork(chain[5].Hash); @@ -618,7 +635,8 @@ public void ForkShouldSkipExecuteAndRenderGenesis() using (var stateStore = new TrieStateStore(new MemoryKeyValueStore())) { var actionEvaluator = new ActionEvaluator( - _ => _policy.BlockAction, + _ => _policy.BeginBlockActions, + _ => _policy.EndBlockActions, stateStore, new SingleActionLoader(typeof(DumbAction))); var privateKey = new PrivateKey(); @@ -651,7 +669,8 @@ public void ForkShouldSkipExecuteAndRenderGenesis() stateStore, genesis, new ActionEvaluator( - _ => _policy.BlockAction, + _ => _policy.BeginBlockActions, + _ => _policy.EndBlockActions, stateStore: stateStore, actionTypeLoader: new SingleActionLoader(typeof(DumbAction))), renderers: new[] { renderer } @@ -1041,10 +1060,13 @@ public void SwapForSameTip(bool render) [InlineData(false)] public void ReorgIsUnableToHeterogenousChain(bool render) { - using (var fx2 = new MemoryStoreFixture(_policy.BlockAction)) + var beginActions = _policy.BeginBlockActions; + var endActions = _policy.EndBlockActions; + using (var fx2 = new MemoryStoreFixture(beginActions, endActions)) { var actionEvaluator = new ActionEvaluator( - _ => _policy.BlockAction, + _ => _policy.BeginBlockActions, + _ => _policy.EndBlockActions, stateStore: fx2.StateStore, actionTypeLoader: new SingleActionLoader(typeof(DumbAction))); Block genesis2 = ProposeGenesisBlock( @@ -1101,7 +1123,8 @@ public void GetStatesOnCreatingBlockChain() IStore store = new MemoryStore(); var stateStore = new TrieStateStore(new MemoryKeyValueStore()); var actionEvaluator = new ActionEvaluator( - _ => policy.BlockAction, + _ => policy.BeginBlockActions, + _ => policy.EndBlockActions, stateStore, new SingleActionLoader(typeof(DumbAction))); Block genesisWithTx = ProposeGenesisBlock( @@ -1144,7 +1167,8 @@ public void GetStateOnlyDrillsDownUntilRequestedAddressesAreFound() _fx.GenesisBlock, blockChainStates, new ActionEvaluator( - _ => policy.BlockAction, + _ => policy.BeginBlockActions, + _ => policy.EndBlockActions, _fx.StateStore, new SingleActionLoader(typeof(DumbAction)))); @@ -1203,7 +1227,8 @@ public void GetStateReturnsEarlyForNonexistentAccount() _fx.GenesisBlock, blockChainStates, new ActionEvaluator( - _ => policy.BlockAction, + _ => policy.BeginBlockActions, + _ => policy.EndBlockActions, _fx.StateStore, new SingleActionLoader(typeof(DumbAction)))); @@ -1304,7 +1329,8 @@ public void GetStateReturnsLatestStatesWhenMultipleAddresses() _fx.GenesisBlock, blockChainStates, new ActionEvaluator( - _ => policy.BlockAction, + _ => policy.BeginBlockActions, + _ => policy.EndBlockActions, _fx.StateStore, new SingleActionLoader(typeof(DumbAction)))); @@ -1391,9 +1417,11 @@ public void FindBranchPoint() new[] { new BlockHash(TestUtils.GetRandomBytes(BlockHash.Size)) }); var locator = new BlockLocator( new[] { b4.Hash, b3.Hash, b1.Hash, _blockChain.Genesis.Hash }); + var beginActions = _policy.BeginBlockActions; + var endActions = _policy.EndBlockActions; - using (var emptyFx = new MemoryStoreFixture(_policy.BlockAction)) - using (var forkFx = new MemoryStoreFixture(_policy.BlockAction)) + using (var emptyFx = new MemoryStoreFixture(beginActions, endActions)) + using (var forkFx = new MemoryStoreFixture(beginActions, endActions)) { var emptyChain = BlockChain.Create( _blockChain.Policy, @@ -1402,7 +1430,8 @@ public void FindBranchPoint() emptyFx.StateStore, emptyFx.GenesisBlock, new ActionEvaluator( - _ => _blockChain.Policy.BlockAction, + _ => _blockChain.Policy.BeginBlockActions, + _ => _blockChain.Policy.EndBlockActions, stateStore: emptyFx.StateStore, actionTypeLoader: new SingleActionLoader(typeof(DumbAction)))); var fork = BlockChain.Create( @@ -1412,7 +1441,8 @@ public void FindBranchPoint() forkFx.StateStore, forkFx.GenesisBlock, new ActionEvaluator( - _ => _blockChain.Policy.BlockAction, + _ => _blockChain.Policy.BeginBlockActions, + _ => _blockChain.Policy.EndBlockActions, stateStore: forkFx.StateStore, actionTypeLoader: new SingleActionLoader(typeof(DumbAction)))); fork.Append(b1, CreateBlockCommit(b1)); @@ -1768,7 +1798,8 @@ internal static (Address, Address[] Addresses, BlockChain Chain) Guid chainId = Guid.NewGuid(); var chainStates = new BlockChainStates(store, stateStore); var actionEvaluator = new ActionEvaluator( - _ => blockPolicy.BlockAction, + _ => blockPolicy.BeginBlockActions, + _ => blockPolicy.EndBlockActions, stateStore: stateStore, actionTypeLoader: new SingleActionLoader(typeof(DumbAction))); Block genesisBlock = ProposeGenesisBlock( @@ -1863,10 +1894,13 @@ void BuildIndex(Guid id, Block block) /// Configures the store fixture that every test in this class depends on. /// Subclasses should override this. ///
- /// The block action to use. + /// The begin block action to use. + /// The end block action to use. /// The store fixture that every test in this class depends on. - protected virtual StoreFixture GetStoreFixture(IAction blockAction) => - new MemoryStoreFixture(blockAction: blockAction); + protected virtual StoreFixture GetStoreFixture( + ImmutableArray? beginBlockActions = null, + ImmutableArray? endBlockActions = null) + => new MemoryStoreFixture(beginBlockActions, endBlockActions); private (Address[], Transaction[]) MakeFixturesForAppendTests( PrivateKey privateKey = null, @@ -2005,7 +2039,8 @@ private void CreateWithGenesisBlock() var blockChainStates = new BlockChainStates( storeFixture.Store, storeFixture.StateStore); var actionEvaluator = new ActionEvaluator( - _ => policy.BlockAction, + _ => policy.BeginBlockActions, + _ => policy.EndBlockActions, storeFixture.StateStore, new SingleActionLoader(typeof(DumbAction))); BlockChain blockChain = BlockChain.Create( @@ -2052,7 +2087,8 @@ private void ConstructWithUnexpectedGenesisBlock() var stateStore = new TrieStateStore(new MemoryKeyValueStore()); var blockChainStates = new BlockChainStates(store, stateStore); var actionEvaluator = new ActionEvaluator( - _ => policy.BlockAction, + _ => policy.BeginBlockActions, + _ => policy.EndBlockActions, stateStore, new SingleActionLoader(typeof(DumbAction))); var genesisBlockA = BlockChain.ProposeGenesisBlock(actionEvaluator); @@ -2135,7 +2171,8 @@ private void CheckIfTxPolicyExceptionHasInnerException() null, List.Empty); var actionEvaluator = new ActionEvaluator( - _ => policy.BlockAction, + _ => policy.BeginBlockActions, + _ => policy.EndBlockActions, stateStore, new SingleActionLoader(typeof(DumbAction))); var genesisWithTx = ProposeGenesisBlock( @@ -2198,7 +2235,8 @@ private void ValidateNextBlockCommitOnValidatorSetChange() .ToImmutableList(); var actionEvaluator = new ActionEvaluator( - _ => policy.BlockAction, + _ => policy.BeginBlockActions, + _ => policy.EndBlockActions, storeFixture.StateStore, new SingleActionLoader(typeof(SetValidator))); Block genesis = BlockChain.ProposeGenesisBlock( diff --git a/Libplanet.Tests/Blockchain/DefaultStoreBlockChainTest.cs b/Libplanet.Tests/Blockchain/DefaultStoreBlockChainTest.cs index e3e72ced7e8..84e42ae43be 100644 --- a/Libplanet.Tests/Blockchain/DefaultStoreBlockChainTest.cs +++ b/Libplanet.Tests/Blockchain/DefaultStoreBlockChainTest.cs @@ -1,3 +1,4 @@ +using System.Collections.Immutable; using Libplanet.Action; using Libplanet.Tests.Store; using Xunit.Abstractions; @@ -11,7 +12,11 @@ public DefaultStoreBlockChainTest(ITestOutputHelper output) { } - protected override StoreFixture GetStoreFixture(IAction blockAction) => - new DefaultStoreFixture(blockAction: blockAction); + protected override StoreFixture GetStoreFixture( + ImmutableArray? beginBlockActions = null, + ImmutableArray? endBlockActions = null) + => new DefaultStoreFixture( + beginBlockActions: beginBlockActions, + endBlockActions: endBlockActions); } } diff --git a/Libplanet.Tests/Blockchain/Policies/BlockPolicyTest.cs b/Libplanet.Tests/Blockchain/Policies/BlockPolicyTest.cs index 4b498ab2237..1b8f58abd72 100644 --- a/Libplanet.Tests/Blockchain/Policies/BlockPolicyTest.cs +++ b/Libplanet.Tests/Blockchain/Policies/BlockPolicyTest.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Immutable; using System.Linq; using Libplanet.Action; using Libplanet.Action.Loader; @@ -32,7 +33,8 @@ public BlockPolicyTest(ITestOutputHelper output) _fx = new MemoryStoreFixture(); _output = output; _policy = new BlockPolicy( - blockAction: null, + beginBlockActions: ImmutableArray.Empty, + endBlockActions: ImmutableArray.Empty, blockInterval: TimeSpan.FromMilliseconds(3 * 60 * 60 * 1000)); _stagePolicy = new VolatileStagePolicy(); _chain = BlockChain.Create( @@ -42,7 +44,8 @@ public BlockPolicyTest(ITestOutputHelper output) _fx.StateStore, _fx.GenesisBlock, new ActionEvaluator( - _ => _policy.BlockAction, + _ => _policy.BeginBlockActions, + _ => _policy.EndBlockActions, stateStore: _fx.StateStore, actionTypeLoader: new SingleActionLoader(typeof(DumbAction)))); } @@ -57,7 +60,8 @@ public void Constructors() { var tenSec = new TimeSpan(0, 0, 10); var a = new BlockPolicy( - blockAction: null, + beginBlockActions: ImmutableArray.Empty, + endBlockActions: ImmutableArray.Empty, blockInterval: tenSec); Assert.Equal(tenSec, a.BlockInterval); @@ -157,7 +161,8 @@ public void GetMinTransactionsPerBlock() var stateStore = new TrieStateStore(new MemoryKeyValueStore()); var actionLoader = new SingleActionLoader(typeof(DumbAction)); var policy = new BlockPolicy( - blockAction: new MinerReward(1), + beginBlockActions: ImmutableArray.Empty, + endBlockActions: ImmutableArray.Create(new MinerReward(1)), getMinTransactionsPerBlock: index => index == 0 ? 0 : policyLimit); var privateKey = new PrivateKey(); var chain = TestUtils.MakeBlockChain(policy, store, stateStore, actionLoader); diff --git a/Libplanet.Tests/Blockchain/Policies/StagePolicyTest.cs b/Libplanet.Tests/Blockchain/Policies/StagePolicyTest.cs index 421547e65f5..3e114184bce 100644 --- a/Libplanet.Tests/Blockchain/Policies/StagePolicyTest.cs +++ b/Libplanet.Tests/Blockchain/Policies/StagePolicyTest.cs @@ -31,7 +31,8 @@ protected StagePolicyTest() _fx.StateStore, _fx.GenesisBlock, new ActionEvaluator( - _ => _policy.BlockAction, + _ => _policy.BeginBlockActions, + _ => _policy.EndBlockActions, stateStore: _fx.StateStore, actionTypeLoader: new SingleActionLoader(typeof(DumbAction)))); _key = new PrivateKey(); diff --git a/Libplanet.Tests/Blocks/PreEvaluationBlockTest.cs b/Libplanet.Tests/Blocks/PreEvaluationBlockTest.cs index 83d2b6321c3..4fc84113602 100644 --- a/Libplanet.Tests/Blocks/PreEvaluationBlockTest.cs +++ b/Libplanet.Tests/Blocks/PreEvaluationBlockTest.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Immutable; using System.Security.Cryptography; using Libplanet.Action; using Libplanet.Action.Loader; @@ -31,10 +32,15 @@ public PreEvaluationBlockTest(ITestOutputHelper output) public void Evaluate() { Address address = _contents.Block1Tx0.Signer; - var blockAction = new SetStatesAtBlock( - address, (Bencodex.Types.Integer)123, ReservedAddresses.LegacyAccount, 0); + var beginBlockActions = ImmutableArray.Create( + ); + var endBlockActions = ImmutableArray.Create( + new SetStatesAtBlock( + address, (Bencodex.Types.Integer)123, ReservedAddresses.LegacyAccount, 0) + ); var policy = new BlockPolicy( - blockAction: blockAction, + beginBlockActions: beginBlockActions, + endBlockActions: endBlockActions, blockInterval: TimeSpan.FromMilliseconds(3 * 60 * 60 * 1000)); var stagePolicy = new VolatileStagePolicy(); @@ -44,7 +50,8 @@ public void Evaluate() using (var fx = new MemoryStoreFixture()) { var actionEvaluator = new ActionEvaluator( - _ => policy.BlockAction, + _ => policy.BeginBlockActions, + _ => policy.EndBlockActions, fx.StateStore, new SingleActionLoader(typeof(Arithmetic))); Block genesis = preEvalGenesis.Sign( @@ -106,10 +113,15 @@ public void Evaluate() public void DetermineStateRootHash() { Address address = _contents.Block1Tx0.Signer; - var blockAction = new SetStatesAtBlock( - address, (Bencodex.Types.Integer)123, ReservedAddresses.LegacyAccount, 0); + var beginBlockActions = ImmutableArray.Create( + ); + var endBlockActions = ImmutableArray.Create( + new SetStatesAtBlock( + address, (Bencodex.Types.Integer)123, ReservedAddresses.LegacyAccount, 0) + ); var policy = new BlockPolicy( - blockAction: blockAction, + beginBlockActions, + endBlockActions, blockInterval: TimeSpan.FromMilliseconds(3 * 60 * 60 * 1000)); var stagePolicy = new VolatileStagePolicy(); @@ -118,7 +130,8 @@ public void DetermineStateRootHash() using (var fx = new MemoryStoreFixture()) { var actionEvaluator = new ActionEvaluator( - _ => policy.BlockAction, + _ => policy.BeginBlockActions, + _ => policy.EndBlockActions, stateStore: fx.StateStore, actionTypeLoader: new SingleActionLoader(typeof(Arithmetic))); HashDigest genesisStateRootHash = diff --git a/Libplanet.Tests/Fixtures/IntegerSet.cs b/Libplanet.Tests/Fixtures/IntegerSet.cs index 6835fc1335b..9bc57b87d6d 100644 --- a/Libplanet.Tests/Fixtures/IntegerSet.cs +++ b/Libplanet.Tests/Fixtures/IntegerSet.cs @@ -71,7 +71,8 @@ public IntegerSet( KVStore = new MemoryKeyValueStore(); StateStore = new TrieStateStore(KVStore); var actionEvaluator = new ActionEvaluator( - _ => policy.BlockAction, + _ => policy.BeginBlockActions, + _ => policy.EndBlockActions, StateStore, new SingleActionLoader(typeof(Arithmetic))); Genesis = TestUtils.ProposeGenesisBlock( diff --git a/Libplanet.Tests/Store/DefaultStoreFixture.cs b/Libplanet.Tests/Store/DefaultStoreFixture.cs index 592f7a07496..252aed98869 100644 --- a/Libplanet.Tests/Store/DefaultStoreFixture.cs +++ b/Libplanet.Tests/Store/DefaultStoreFixture.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Immutable; using System.IO; using Libplanet.Action; using Libplanet.Store; @@ -8,8 +9,12 @@ namespace Libplanet.Tests.Store { public class DefaultStoreFixture : StoreFixture, IDisposable { - public DefaultStoreFixture(bool memory = true, IAction blockAction = null) - : base(blockAction) + public DefaultStoreFixture( + bool memory = true, + ImmutableArray? beginBlockActions = null, + ImmutableArray? endBlockActions = null + ) + : base(beginBlockActions, endBlockActions) { if (memory) { diff --git a/Libplanet.Tests/Store/MemoryStoreFixture.cs b/Libplanet.Tests/Store/MemoryStoreFixture.cs index 5a4620bb926..914dd4dc9b9 100644 --- a/Libplanet.Tests/Store/MemoryStoreFixture.cs +++ b/Libplanet.Tests/Store/MemoryStoreFixture.cs @@ -1,3 +1,4 @@ +using System.Collections.Immutable; using Libplanet.Action; using Libplanet.Store; using Libplanet.Store.Trie; @@ -6,8 +7,10 @@ namespace Libplanet.Tests.Store { public class MemoryStoreFixture : StoreFixture { - public MemoryStoreFixture(IAction blockAction = null) - : base(blockAction) + public MemoryStoreFixture( + ImmutableArray? beginBlockActions = null, + ImmutableArray? endBlockActions = null) + : base(beginBlockActions, endBlockActions) { Store = new MemoryStore(); StateStore = new TrieStateStore(new MemoryKeyValueStore()); diff --git a/Libplanet.Tests/Store/StoreFixture.cs b/Libplanet.Tests/Store/StoreFixture.cs index 0b06f1936d2..2dec496ce10 100644 --- a/Libplanet.Tests/Store/StoreFixture.cs +++ b/Libplanet.Tests/Store/StoreFixture.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Collections.Immutable; using System.Security.Cryptography; using Libplanet.Action; using Libplanet.Action.Loader; @@ -16,7 +17,10 @@ namespace Libplanet.Tests.Store { public abstract class StoreFixture : IDisposable { - protected StoreFixture(IAction blockAction = null) + protected StoreFixture( + ImmutableArray? beginBlockActions = null, + ImmutableArray? endBlockActions = null + ) { Path = null; @@ -99,7 +103,8 @@ protected StoreFixture(IAction blockAction = null) proposer: Proposer.PublicKey, validatorSet: TestUtils.ValidatorSet); var actionEvaluator = new ActionEvaluator( - _ => blockAction, + _ => beginBlockActions ?? ImmutableArray.Empty, + _ => endBlockActions ?? ImmutableArray.Empty, stateStore, new SingleActionLoader(typeof(DumbAction))); GenesisBlock = preEval.Sign( diff --git a/Libplanet.Tests/Store/StoreTest.cs b/Libplanet.Tests/Store/StoreTest.cs index bf609d9da37..48be9570012 100644 --- a/Libplanet.Tests/Store/StoreTest.cs +++ b/Libplanet.Tests/Store/StoreTest.cs @@ -1007,7 +1007,8 @@ public void Copy() var policy = new NullBlockPolicy(); var preEval = ProposeGenesis(proposer: GenesisProposer.PublicKey); var actionEvaluator = new ActionEvaluator( - _ => policy.BlockAction, + _ => policy.BeginBlockActions, + _ => policy.EndBlockActions, fx.StateStore, new SingleActionLoader(typeof(DumbAction))); var genesis = preEval.Sign( diff --git a/Libplanet.Tests/TestUtils.cs b/Libplanet.Tests/TestUtils.cs index 5455f3cefdd..19531218a72 100644 --- a/Libplanet.Tests/TestUtils.cs +++ b/Libplanet.Tests/TestUtils.cs @@ -611,7 +611,8 @@ public static (BlockChain BlockChain, ActionEvaluator ActionEvaluator) var blockChainStates = new BlockChainStates(store, stateStore); var actionEvaluator = new ActionEvaluator( - _ => policy.BlockAction, + _ => policy.BeginBlockActions, + _ => policy.EndBlockActions, stateStore: stateStore, actionTypeLoader: actionLoader); From 523d937414dec4b296e5ec74d9bd46821151d9be Mon Sep 17 00:00:00 2001 From: s2quake Date: Mon, 25 Mar 2024 18:01:18 +0900 Subject: [PATCH 3/3] Changelog --- CHANGES.md | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/CHANGES.md b/CHANGES.md index fede931bb6a..dd40a6d1737 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,6 +1,43 @@ Libplanet changelog =================== +Version DPoS +------------- + +### Deprecated APIs + +### Backward-incompatible API changes + + - (Libplanet) Removed `IBlockPolicy.BlockAction` property. [[#3701]] + - (Libplanet) Added `IBlockPolicy.BeginBlockActions`. property. [[#3701]] + - (Libplanet) Added `IBlockPolicy.EndBlockActions`. property. [[#3701]] + - (Libplanet) `BlockPolicy` constructor requires `beginBlockActions` and + `endBlockActions` parameters instead of the `blockAction` parameter. + [[#3701]] + - (Libplanet.Action) Renamed `PolicyBlockActionGetter` delegate to + `PolicyBlockActionGetter` and changed return type to + `ImmutableArray`. [[#3701]] + - (Libplanet.Action) `ActionEvaluator` constructor requires + `policyBeginBlockActionGetter` and `policyEndBlockActionGetter` + parameters instead of the `policyBlockActionGetter` parameter. [[#3701]] + +### Backward-incompatible network protocol changes + +### Backward-incompatible storage format changes + +### Added APIs + +### Behavioral changes + +### Bug fixes + +### Dependencies + +### CLI tools + +[#3701]: https://github.com/planetarium/libplanet/pull/3701 + + Version 4.1.0 -------------