Skip to content

Commit

Permalink
feat: Add the IConsole to handle admni actions
Browse files Browse the repository at this point in the history
  • Loading branch information
s2quake committed Dec 1, 2024
1 parent 9ab364f commit c0eae1f
Show file tree
Hide file tree
Showing 22 changed files with 103 additions and 36 deletions.
4 changes: 2 additions & 2 deletions src/client/LibplanetConsole.Client/Commands/TxCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
namespace LibplanetConsole.Client.Commands;

[CommandSummary("Sends a transaction using a string")]
internal sealed class TxCommand(IClient client, IBlockChain blockChain) : CommandAsyncBase
internal sealed class TxCommand(IClient client) : CommandAsyncBase
{
[CommandPropertyRequired]
[CommandSummary("Specifies the text to send")]
Expand All @@ -17,7 +17,7 @@ protected override async Task OnExecuteAsync(CancellationToken cancellationToken
{
Value = Text,
};
await blockChain.SendTransactionAsync([action], cancellationToken);
await client.SendTransactionAsync([action], cancellationToken);
await Out.WriteLineAsync($"{client.Address.ToShortString()}: {Text}");
}
}
2 changes: 2 additions & 0 deletions src/client/LibplanetConsole.Client/IClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,4 +23,6 @@ public interface IClient : IVerifier
Task StartAsync(CancellationToken cancellationToken);

Task StopAsync(CancellationToken cancellationToken);

Task<TxId> SendTransactionAsync(IAction[] actions, CancellationToken cancellationToken);
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,11 @@ public InitializeCommand()
[NonNegative]
public int Port { get; set; }

[CommandProperty]
[CommandSummary("Specifies the private key of the genesis")]
[PrivateKey]
public string PrivateKey { get; set; } = string.Empty;

#if DEBUG
[CommandProperty(InitValue = 1)]
#else
Expand Down Expand Up @@ -61,12 +66,6 @@ public InitializeCommand()
[CommandSummary("If set, the command will not output any information")]
public bool Quiet { get; set; }

[CommandProperty]
[CommandSummary("Specifies the private key of the genesis block")]
[PrivateKey]
[Category("Genesis")]
public string GenesisKey { get; set; } = string.Empty;

[CommandProperty("timestamp")]
[CommandSummary("Specifies the timestamp of the genesis block")]
[Category("Genesis")]
Expand Down Expand Up @@ -124,7 +123,7 @@ private async Task<dynamic> ExecuteAsync(CancellationToken cancellationToken)
{
using var progress = new CommandProgress();
var portGenerator = new PortGenerator(Port);
var genesisKey = PrivateKeyUtility.ParseOrRandom(GenesisKey);
var genesisKey = PrivateKeyUtility.ParseOrRandom(PrivateKey);
var ports = portGenerator.Next();
var nodeOptions = GetNodeOptions(portGenerator, ports);
var clientOptions = GetClientOptions(portGenerator);
Expand All @@ -142,6 +141,7 @@ private async Task<dynamic> ExecuteAsync(CancellationToken cancellationToken)
var apvPrivateKey = PrivateKeyUtility.ParseOrRandom(APVPrivateKey);
var repository = new Repository(ports, nodeOptions, clientOptions)
{
PrivateKey = genesisKey,
Port = Port,
Genesis = Repository.CreateGenesis(genesisOptions),
AppProtocolVersion = Repository.CreateAppProtocolVersion(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using System.ComponentModel;
using JSSoft.Commands;
using LibplanetConsole.Common;
using LibplanetConsole.Common.DataAnnotations;
using LibplanetConsole.DataAnnotations;
using Microsoft.AspNetCore.Server.Kestrel.Core;
using Microsoft.Extensions.Options;
Expand All @@ -22,6 +23,11 @@ internal sealed class RunCommand
[NonNegative]
public int Port { get; init; }

[CommandProperty]
[CommandSummary("Specifies the private key for the genesis")]
[PrivateKey]
public string PrivateKey { get; init; } = string.Empty;

#if DEBUG
[CommandProperty(InitValue = 1)]
#else
Expand Down Expand Up @@ -111,11 +117,14 @@ void IConfigureOptions<ApplicationOptions>.Configure(ApplicationOptions options)
var ports = _ports ?? throw new InvalidOperationException("PortGroup is not initialized.");
var nodeOptions = GetNodeOptions(GetNodes(), portGenerator);
var clientOptions = GetClientOptions(GetClients(), portGenerator);
var privateKey = PrivateKeyUtility.ParseOrRandom(PrivateKey);
var repository = new Repository(ports, nodeOptions, clientOptions)
{
PrivateKey = privateKey,
ActionProviderModulePath = ActionProviderModulePath,
ActionProviderType = ActionProviderType,
};
options.PrivateKey = PrivateKeyUtility.ToString(privateKey);
options.LogPath = GetFullPath(LogPath);
options.Nodes = repository.Nodes;
options.Clients = repository.Clients;
Expand All @@ -134,7 +143,7 @@ void IConfigureOptions<ApplicationOptions>.Configure(ApplicationOptions options)
if (options.Genesis == string.Empty && options.GenesisPath == string.Empty)
{
var genesis = repository.CreateGenesis(
genesisKey: new PrivateKey(), DateTimeOffset.UtcNow);
genesisKey: privateKey, DateTimeOffset.UtcNow);
options.Genesis = ByteUtil.Hex(genesis);
}

Expand Down
3 changes: 3 additions & 0 deletions src/console/LibplanetConsole.Console.Executable/Repository.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ public Repository(PortGroup ports, NodeOptions[] nodes, ClientOptions[] clients)
Clients = clients;
}

public required PrivateKey PrivateKey { get; init; }

public int Port { get; set; }

public NodeOptions[] Nodes { get; } = [];
Expand Down Expand Up @@ -187,6 +189,7 @@ public async Task<dynamic> SaveAsync(
var consensusPort = ConsensusPort is not 0 ? ConsensusPort : _ports[5];
var applicationOptions = new ApplicationOptions
{
PrivateKey = PrivateKeyUtility.ToString(PrivateKey),
GenesisPath = PathUtility.GetRelativePath(settingsPath, genesisPath),
AppProtocolVersionPath = PathUtility.GetRelativePath(
settingsPath, appProtocolVersionPath),
Expand Down
11 changes: 11 additions & 0 deletions src/console/LibplanetConsole.Console/ApplicationOptions.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
using System.Text.Json.Serialization;
using Libplanet.Net;
using LibplanetConsole.Common;
using LibplanetConsole.Common.DataAnnotations;
using LibplanetConsole.Options;

namespace LibplanetConsole.Console;
Expand All @@ -11,9 +13,15 @@ public sealed class ApplicationOptions : OptionsBase<ApplicationOptions>, IAppli
public const int SeedBlocksyncPortIncrement = 6;
public const int SeedConsensusPortIncrement = 7;

private PrivateKey? _privateKey;
private Block? _genesisBlock;
private AppProtocolVersion? _appProtocolVersion;

[PrivateKey]
public string PrivateKey { get; set; } = string.Empty;

PrivateKey IApplicationOptions.PrivateKey => ActualPrivateKey;

[JsonIgnore]
public NodeOptions[] Nodes { get; set; } = [];

Expand Down Expand Up @@ -54,6 +62,9 @@ AppProtocolVersion IApplicationOptions.AppProtocolVersion
ProcessOptions? IApplicationOptions.ProcessOptions
=> NoProcess ? null : new ProcessOptions { Detach = Detach, NewWindow = NewWindow, };

private PrivateKey ActualPrivateKey
=> _privateKey ??= PrivateKeyUtility.ParseOrRandom(PrivateKey);

private Block GetGenesisBlock()
{
if (GenesisPath != string.Empty)
Expand Down
31 changes: 24 additions & 7 deletions src/console/LibplanetConsole.Console/BlockChain.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,21 @@

namespace LibplanetConsole.Console;

internal sealed class BlockChain : IBlockChain, IDisposable
internal sealed class BlockChain : IBlockChain, IDisposable, IConsole
{
private readonly INodeCollection _nodes;
private readonly NodeCollection _nodes;
private readonly PrivateKey _privateKey;
private readonly BlockHash _genesisHash;
private readonly ILogger<BlockChain> _logger;
private IBlockChain? _blockChain;
private Node? _node;
private bool _isDisposed;

public BlockChain(NodeCollection nodes, ILogger<BlockChain> logger)
public BlockChain(NodeCollection nodes, IApplicationOptions options, ILogger<BlockChain> logger)
{
_nodes = nodes;
_privateKey = options.PrivateKey;
_genesisHash = options.GenesisBlock.Hash;
_logger = logger;
UpdateCurrent(_nodes.Current);
_nodes.CurrentChanged += Nodes_CurrentChanged;
Expand All @@ -41,15 +46,26 @@ void IDisposable.Dispose()
}
}

Task<TxId> IBlockChain.SendTransactionAsync(
public async Task<TxId> SendTransactionAsync(
IAction[] actions, CancellationToken cancellationToken)
{
if (IsRunning is false || _blockChain is null)
if (IsRunning is false || _blockChain is null || _node is null)
{
throw new InvalidOperationException("BlockChain is not running.");
}

return _blockChain.SendTransactionAsync(actions, cancellationToken);
var privateKey = _privateKey;
var genesisHash = _genesisHash;
var nonce = await _blockChain.GetNextNonceAsync(privateKey.Address, cancellationToken);
var values = actions.Select(item => item.PlainValue).ToArray();
var transaction = Transaction.Create(
nonce: nonce,
privateKey: privateKey,
genesisHash: genesisHash,
actions: new TxActionList(values));

await _node.SendTransactionAsync(transaction, cancellationToken);
return transaction.Id;
}

Task<long> IBlockChain.GetNextNonceAsync(
Expand Down Expand Up @@ -128,7 +144,7 @@ Task<T> IBlockChain.GetActionAsync<T>(
return _blockChain.GetActionAsync<T>(txId, actionIndex, cancellationToken);
}

private void UpdateCurrent(INode? node)
private void UpdateCurrent(Node? node)
{
if (_blockChain is not null)
{
Expand All @@ -144,6 +160,7 @@ private void UpdateCurrent(INode? node)
}
}

_node = node;
_blockChain = node?.GetKeyedService<IBlockChain>(INode.Key);

if (_blockChain is not null)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -122,9 +122,8 @@ public async Task TxAsync(
{
var address = Address;
var client = clients.GetClientOrCurrent(address);
var blockChain = client.GetRequiredService<IBlockChain>();
var action = new StringAction { Value = text };
await blockChain.SendTransactionAsync([action], cancellationToken);
await client.SendTransactionAsync([action], cancellationToken);
await Out.WriteLineAsync($"{client.Address.ToShortString()}: {text}");
}

Expand Down
3 changes: 1 addition & 2 deletions src/console/LibplanetConsole.Console/Commands/NodeCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -116,9 +116,8 @@ public async Task TxAsync(
{
var address = Address;
var node = nodes.GetNodeOrCurrent(address);
var blockChain = node.GetRequiredService<IBlockChain>();
var action = new StringAction { Value = text };
await blockChain.SendTransactionAsync([action], cancellationToken);
await node.SendTransactionAsync([action], cancellationToken);
await Out.WriteLineAsync($"{node.Address.ToShortString()}: {text}");
}

Expand Down
6 changes: 2 additions & 4 deletions src/console/LibplanetConsole.Console/Commands/TxCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,16 +22,14 @@ protected override async Task OnExecuteAsync(CancellationToken cancellationToken
var text = Text;
if (addressable is INode node)
{
var blockChain = node.GetRequiredService<IBlockChain>();
var action = new StringAction { Value = text };
await blockChain.SendTransactionAsync([action], cancellationToken);
await node.SendTransactionAsync([action], cancellationToken);
await Out.WriteLineAsync($"{node.Address.ToShortString()}: {text}");
}
else if (addressable is IClient client)
{
var blockChain = client.GetRequiredService<IBlockChain>();
var action = new StringAction { Value = text };
await blockChain.SendTransactionAsync([action], cancellationToken);
await client.SendTransactionAsync([action], cancellationToken);
await Out.WriteLineAsync($"{client.Address.ToShortString()}: {text}");
}
else
Expand Down
2 changes: 2 additions & 0 deletions src/console/LibplanetConsole.Console/IApplicationOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ namespace LibplanetConsole.Console;

public interface IApplicationOptions
{
PrivateKey PrivateKey { get; }

NodeOptions[] Nodes { get; }

ClientOptions[] Clients { get; }
Expand Down
2 changes: 2 additions & 0 deletions src/console/LibplanetConsole.Console/IClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -42,4 +42,6 @@ public interface IClient : IAddressable, IAsyncDisposable, IKeyedServiceProvider
Task StopAsync(CancellationToken cancellationToken);

string GetCommandLine();

Task<TxId> SendTransactionAsync(IAction[] actions, CancellationToken cancellationToken);
}
9 changes: 9 additions & 0 deletions src/console/LibplanetConsole.Console/IConsole.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
using LibplanetConsole.Common;
using Microsoft.Extensions.DependencyInjection;

namespace LibplanetConsole.Console;

public interface IConsole
{
Task<TxId> SendTransactionAsync(IAction[] actions, CancellationToken cancellationToken);
}
2 changes: 2 additions & 0 deletions src/console/LibplanetConsole.Console/INode.cs
Original file line number Diff line number Diff line change
Expand Up @@ -42,4 +42,6 @@ public interface INode : IAddressable, IAsyncDisposable, IKeyedServiceProvider,
Task StopAsync(CancellationToken cancellationToken);

string GetCommandLine();

Task<TxId> SendTransactionAsync(IAction[] actions, CancellationToken cancellationToken);
}
16 changes: 16 additions & 0 deletions src/console/LibplanetConsole.Console/Node.BlockChain.cs
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,22 @@ public async Task<TxId> SendTransactionAsync(
return ToTxId(response.TxId);
}

public async Task SendTransactionAsync(
Transaction transaction, CancellationToken cancellationToken)
{
if (_blockChainService is null)
{
throw new InvalidOperationException("BlockChainService is not initialized.");
}

var request = new SendTransactionRequest
{
TransactionData = ToGrpc(transaction.Serialize()),
};
var callOptions = new CallOptions(cancellationToken: cancellationToken);
await _blockChainService.SendTransactionAsync(request, callOptions);
}

public async Task<BlockHash> GetTipHashAsync(CancellationToken cancellationToken)
{
if (_blockChainService is null)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,8 @@ public static IServiceCollection AddConsole(
@this.AddSingleton<ClientCollection>()
.AddSingleton<IClientCollection>(s => s.GetRequiredService<ClientCollection>());
@this.AddSingleton<BlockChain>()
.AddSingleton<IBlockChain>(s => s.GetRequiredService<BlockChain>());
.AddSingleton<IBlockChain>(s => s.GetRequiredService<BlockChain>())
.AddSingleton<IConsole>(s => s.GetRequiredService<BlockChain>());
@this.AddSingleton<ApplicationInfoProvider>()
.AddSingleton<IInfoProvider>(s => s.GetRequiredService<ApplicationInfoProvider>());

Expand Down
2 changes: 1 addition & 1 deletion src/node/LibplanetConsole.Node/ActionProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ internal sealed class ActionProvider : IActionProvider

public ImmutableArray<IAction> EndTxActions { get; } = [];

public IAction[] GetGenesisActions(PrivateKey genesisKey, PublicKey[] validatorKeys)
public IAction[] GetGenesisActions(Address genesisAddress, PublicKey[] validatorKeys)
{
var validators = validatorKeys
.Select(item => new Validator(item, BigInteger.One))
Expand Down
3 changes: 2 additions & 1 deletion src/node/LibplanetConsole.Node/BlockUtility.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,13 @@ public static Block CreateGenesisBlock(
GenesisOptions genesisOptions)
{
var genesisKey = genesisOptions.GenesisKey;
var genesisAddress = genesisKey.Address;
var validators = genesisOptions.Validators;
var timestamp = genesisOptions.Timestamp;
var actionLoaderProvider = ModuleLoader.LoadActionLoader(
genesisOptions.ActionProviderModulePath,
genesisOptions.ActionProviderType);
var actions = actionLoaderProvider.GetGenesisActions(genesisKey, validators);
var actions = actionLoaderProvider.GetGenesisActions(genesisAddress, validators);
var genesisBlock = CreateGenesisBlock(genesisKey, timestamp, actions);

return genesisBlock;
Expand Down
4 changes: 2 additions & 2 deletions src/node/LibplanetConsole.Node/Commands/TxCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
namespace LibplanetConsole.Node.Commands;

[CommandSummary("Sends a transaction using a string")]
internal sealed class TxCommand(INode node, IBlockChain blockChain) : CommandAsyncBase
internal sealed class TxCommand(INode node) : CommandAsyncBase
{
[CommandPropertyRequired]
[CommandSummary("Specifies the text to send")]
Expand All @@ -17,7 +17,7 @@ protected override async Task OnExecuteAsync(CancellationToken cancellationToken
{
Value = Text,
};
await blockChain.SendTransactionAsync([action], cancellationToken);
await node.SendTransactionAsync([action], cancellationToken);
await Out.WriteLineAsync($"{node.Address.ToShortString()}: {Text}");
}
}
2 changes: 1 addition & 1 deletion src/node/LibplanetConsole.Node/IActionProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ public interface IActionProvider

ImmutableArray<IAction> EndTxActions { get; }

IAction[] GetGenesisActions(PrivateKey genesisKey, PublicKey[] validatorKeys);
IAction[] GetGenesisActions(Address genesisAddress, PublicKey[] validatorKeys);

IActionLoader GetActionLoader();
}
Loading

0 comments on commit c0eae1f

Please sign in to comment.