Skip to content

Introduce Begin / End block action #3701

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Mar 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 37 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
@@ -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<IAction>`. [[#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
-------------

Expand Down
47 changes: 47 additions & 0 deletions Libplanet.Action.Tests/Common/UpdateValueAction.cs
Original file line number Diff line number Diff line change
@@ -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);
}
}
}
87 changes: 65 additions & 22 deletions Libplanet.Action/ActionEvaluator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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;

/// <summary>
/// Creates a new <see cref="ActionEvaluator"/>.
/// </summary>
/// <param name="policyBlockActionGetter">A delegator to get policy block action to evaluate
/// at the end for each <see cref="IPreEvaluationBlock"/> that gets evaluated.</param>
/// <param name="policyBeginBlockActionsGetter">A delegator to get policy block actions to
/// evaluate at the beginning for each <see cref="IPreEvaluationBlock"/>
/// that gets evaluated.
/// Note the order of the returned list determines the execution order.
/// </param>
/// <param name="policyEndBlockActionsGetter">A delegator to get policy block actions to
/// evaluate at the end for each <see cref="IPreEvaluationBlock"/> that gets evaluated.
/// Note the order of the returned list determines the execution order.
/// </param>
/// <param name="stateStore">The <see cref="IStateStore"/> to use to retrieve
/// the states for a provided <see cref="HashDigest{SHA256}"/>.</param>
/// <param name="actionTypeLoader"> A <see cref="IActionLoader"/> implementation using
/// action type lookup.</param>
public ActionEvaluator(
PolicyBlockActionGetter policyBlockActionGetter,
PolicyBlockActionsGetter policyBeginBlockActionsGetter,
PolicyBlockActionsGetter policyEndBlockActionsGetter,
IStateStore stateStore,
IActionLoader actionTypeLoader)
{
_logger = Log.ForContext<ActionEvaluator>()
.ForContext("Source", nameof(ActionEvaluator));
_policyBlockActionGetter = policyBlockActionGetter;
_policyBeginBlockActionsGetter = policyBeginBlockActionsGetter;
_policyEndBlockActionsGetter = policyEndBlockActionsGetter;
_stateStore = stateStore;
_actionLoader = actionTypeLoader;
}
Expand Down Expand Up @@ -123,16 +133,29 @@ public IReadOnlyList<ICommittedActionEvaluation> Evaluate(
throw new ApplicationException("World cannot be mutated from modern to legacy");
}

ImmutableList<ActionEvaluation> evaluations =
EvaluateBlock(block, previousState).ToImmutableList();
var evaluations = ImmutableList<ActionEvaluation>.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);
Expand Down Expand Up @@ -491,30 +514,50 @@ internal IEnumerable<ActionEvaluation> EvaluateTx(
/// the <see cref="IBlockPolicy.BlockAction"/> held by the instance
/// for the <paramref name="blockHeader"/>.</returns>
[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();
}

/// <summary>
/// Evaluates the <see cref="IBlockPolicy.BlockAction"/> set by the policy when
/// this <see cref="ActionEvaluator"/> was instantiated for a given
/// <see cref="IPreEvaluationBlockHeader"/>.
/// </summary>
/// <param name="blockHeader">The header of the block to evaluate.</param>
/// <param name="previousState">The states immediately before the evaluation of
/// the <see cref="IBlockPolicy.BlockAction"/> held by the instance.</param>
/// <returns>The <see cref="ActionEvaluation"/> of evaluating
/// the <see cref="IBlockPolicy.BlockAction"/> held by the instance
/// for the <paramref name="blockHeader"/>.</returns>
[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<SHA256>? stateRootHash)
Expand Down
6 changes: 0 additions & 6 deletions Libplanet.Action/PolicyBlockActionGetter.cs

This file was deleted.

9 changes: 9 additions & 0 deletions Libplanet.Action/PolicyBlockActionsGetter.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
using System.Collections.Immutable;
using Libplanet.Types.Blocks;

namespace Libplanet.Action
{
public delegate ImmutableArray<IAction> PolicyBlockActionsGetter(
IPreEvaluationBlockHeader blockHeader
);
}
4 changes: 3 additions & 1 deletion Libplanet.Benchmarks/AppendBlock.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
using Libplanet.Types.Blocks;
using Libplanet.Tests;
using Libplanet.Tests.Store;
using System.Collections.Immutable;

namespace Libplanet.Benchmarks
{
Expand All @@ -29,7 +30,8 @@ public AppendBlock()
fx.StateStore,
fx.GenesisBlock,
new ActionEvaluator(
policyBlockActionGetter: _ => null,
policyBeginBlockActionsGetter: _ => ImmutableArray<IAction>.Empty,
policyEndBlockActionsGetter: _ => ImmutableArray<IAction>.Empty,
stateStore: fx.StateStore,
actionTypeLoader: new SingleActionLoader(typeof(DumbAction))));
_privateKey = new PrivateKey();
Expand Down
4 changes: 3 additions & 1 deletion Libplanet.Benchmarks/BlockChain.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using System.Collections.Immutable;
using BenchmarkDotNet.Attributes;
using Libplanet.Action;
using Libplanet.Action.Loader;
Expand Down Expand Up @@ -35,7 +36,8 @@ public void SetupChain()
_fx.StateStore,
_fx.GenesisBlock,
new ActionEvaluator(
policyBlockActionGetter: _ => null,
policyBeginBlockActionsGetter: _ => ImmutableArray<IAction>.Empty,
policyEndBlockActionsGetter: _ => ImmutableArray<IAction>.Empty,
stateStore: _fx.StateStore,
actionTypeLoader: new SingleActionLoader(typeof(DumbAction))));
var key = new PrivateKey();
Expand Down
4 changes: 3 additions & 1 deletion Libplanet.Benchmarks/ProposeBlock.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
using Libplanet.Types.Blocks;
using Libplanet.Tests;
using Libplanet.Tests.Store;
using System.Collections.Immutable;

namespace Libplanet.Benchmarks
{
Expand All @@ -28,7 +29,8 @@ public ProposeBlock()
fx.StateStore,
fx.GenesisBlock,
new ActionEvaluator(
policyBlockActionGetter: _ => null,
policyBeginBlockActionsGetter: _ => ImmutableArray<IAction>.Empty,
policyEndBlockActionsGetter: _ => ImmutableArray<IAction>.Empty,
stateStore: fx.StateStore,
actionTypeLoader: new SingleActionLoader(typeof(DumbAction))));
_privateKey = new PrivateKey();
Expand Down
10 changes: 7 additions & 3 deletions Libplanet.Explorer.Executable/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -341,7 +342,8 @@ private static IStore LoadStore(Options options)
private static BlockPolicy LoadBlockPolicy(Options options)
{
return new BlockPolicy(
blockAction: null,
beginBlockActions: ImmutableArray<IAction>.Empty,
endBlockActions: ImmutableArray<IAction>.Empty,
blockInterval: TimeSpan.FromMilliseconds(options.BlockIntervalMilliseconds),
getMaxTransactionsBytes: i => i > 0
? options.MaxTransactionsBytes
Expand Down Expand Up @@ -384,7 +386,9 @@ public DumbBlockPolicy(BlockPolicy blockPolicy)
_impl = blockPolicy;
}

public IAction BlockAction => _impl.BlockAction;
public ImmutableArray<IAction> BeginBlockActions => _impl.BeginBlockActions;

public ImmutableArray<IAction> EndBlockActions => _impl.EndBlockActions;

public int GetMinTransactionsPerBlock(long index) =>
_impl.GetMinTransactionsPerBlock(index);
Expand Down
3 changes: 2 additions & 1 deletion Libplanet.Explorer.Tests/GeneratedBlockChainFixture.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down
Loading