-
Notifications
You must be signed in to change notification settings - Fork 149
Commit
- Loading branch information
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,79 @@ | ||
using System.Security.Cryptography; | ||
using Bencodex; | ||
using Bencodex.Types; | ||
using Libplanet.Action; | ||
using Libplanet.Common; | ||
using Libplanet.Crypto; | ||
using Libplanet.Types.Tx; | ||
using Boolean = Bencodex.Types.Boolean; | ||
|
||
namespace Libplanet.Node.Actions; | ||
|
||
public static class ActionContextMarshaller | ||
{ | ||
private static readonly Codec Codec = new Codec(); | ||
|
||
public static byte[] Serialize(this ICommittedActionContext actionContext) | ||
{ | ||
return Codec.Encode(Marshal(actionContext)); | ||
} | ||
|
||
public static Dictionary Marshal(this ICommittedActionContext actionContext) | ||
{ | ||
var dictionary = Bencodex.Types.Dictionary.Empty | ||
.Add("signer", actionContext.Signer.ToHex()) | ||
.Add("miner", actionContext.Miner.ToHex()) | ||
.Add("block_index", actionContext.BlockIndex) | ||
.Add("block_protocol_version", actionContext.BlockProtocolVersion) | ||
.Add("previous_states", actionContext.PreviousState.ByteArray) | ||
.Add("random_seed", actionContext.RandomSeed) | ||
.Add("block_action", actionContext.IsPolicyAction); | ||
|
||
if (actionContext.TxId is { } txId) | ||
{ | ||
dictionary = dictionary.Add("tx_id", txId.ByteArray); | ||
} | ||
|
||
return dictionary; | ||
} | ||
|
||
public static ICommittedActionContext Unmarshal(Dictionary dictionary) | ||
{ | ||
return new CommittedActionContext( | ||
signer: new Address(((Text)dictionary["signer"]).Value), | ||
txId: GetTxId(dictionary, "tx_id"), | ||
miner: new Address(((Text)dictionary["miner"]).Value), | ||
blockIndex: (Integer)dictionary["block_index"], | ||
blockProtocolVersion: (Integer)dictionary["block_protocol_version"], | ||
previousState: new HashDigest<SHA256>(dictionary["previous_states"]), | ||
randomSeed: (Integer)dictionary["random_seed"], | ||
isPolicyAction: (Boolean)dictionary["block_action"] | ||
); | ||
|
||
static TxId? GetTxId(Dictionary dictionary, string key) | ||
{ | ||
if (dictionary.TryGetValue((Text)key, out IValue txIdValue) | ||
&& txIdValue is Binary txIdBinaryValue) | ||
{ | ||
return new TxId(txIdBinaryValue.ByteArray); | ||
} | ||
else | ||
{ | ||
return null; | ||
} | ||
} | ||
} | ||
|
||
public static ICommittedActionContext Deserialize(byte[] serialized) | ||
{ | ||
var decoded = Codec.Decode(serialized); | ||
if (decoded is not Dictionary dictionary) | ||
{ | ||
throw new ArgumentException( | ||
message: $"Expected 'Dictionary' but {decoded.GetType().Name}", | ||
paramName: nameof(serialized)); | ||
} | ||
|
||
return Unmarshal(dictionary); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
using System.Security.Cryptography; | ||
using Bencodex; | ||
using Bencodex.Types; | ||
using Libplanet.Action; | ||
using Libplanet.Common; | ||
|
||
namespace Libplanet.Node.Actions; | ||
|
||
public static class ActionEvaluationMarshaller | ||
{ | ||
private static readonly Codec Codec = new(); | ||
|
||
public static byte[] Serialize(this ICommittedActionEvaluation actionEvaluation) | ||
{ | ||
return Codec.Encode(Marshal(actionEvaluation)); | ||
} | ||
|
||
public static Dictionary Marshal(this ICommittedActionEvaluation actionEvaluation) => | ||
Dictionary.Empty | ||
.Add("action", actionEvaluation.Action) | ||
.Add("output_states", actionEvaluation.OutputState.ByteArray) | ||
.Add("input_context", actionEvaluation.InputContext.Marshal()) | ||
.Add("exception", GetException(actionEvaluation.Exception)); | ||
|
||
public static ICommittedActionEvaluation Unmarshal(IValue value) | ||
{ | ||
if (value is not Dictionary dictionary) | ||
{ | ||
throw new ArgumentException("The value must be a dictionary.", nameof(value)); | ||
} | ||
|
||
return new CommittedActionEvaluation( | ||
dictionary["action"], | ||
ActionContextMarshaller.Unmarshal((Dictionary)dictionary["input_context"]), | ||
new HashDigest<SHA256>(dictionary["output_states"]), | ||
dictionary["exception"] is Text typeName ? new Exception(typeName) : null | ||
); | ||
} | ||
|
||
public static ICommittedActionEvaluation Deserialize(byte[] serialized) | ||
{ | ||
var decoded = Codec.Decode(serialized); | ||
return Unmarshal(decoded); | ||
} | ||
|
||
private static IValue GetException(Exception? exception) | ||
=> exception?.GetType().FullName is { } typeName ? (Text)typeName : Null.Value; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
using System.Diagnostics; | ||
using System.Reflection; | ||
using System.Security.Cryptography; | ||
using Lib9c.Plugin.Shared; | ||
Check failure on line 4 in sdk/node/Libplanet.Node/Actions/PluggedActionEvaluator.cs GitHub Actions / docs
Check failure on line 4 in sdk/node/Libplanet.Node/Actions/PluggedActionEvaluator.cs GitHub Actions / docs
|
||
using Libplanet.Action; | ||
using Libplanet.Action.Loader; | ||
using Libplanet.Common; | ||
using Libplanet.Node.Actions; | ||
using Libplanet.Store.Trie; | ||
using Libplanet.Types.Blocks; | ||
|
||
namespace Libplanet.Node.Actions; | ||
|
||
public class PluggedActionEvaluator : IActionEvaluator | ||
{ | ||
private readonly IPluginActionEvaluator _pluginActionEvaluator; | ||
Check failure on line 16 in sdk/node/Libplanet.Node/Actions/PluggedActionEvaluator.cs GitHub Actions / docs
|
||
|
||
public PluggedActionEvaluator( | ||
string pluginPath, | ||
string typeName, | ||
IKeyValueStore keyValueStore, | ||
IActionLoader actionLoader) | ||
{ | ||
_pluginActionEvaluator = CreateActionEvaluator(pluginPath, typeName, keyValueStore); | ||
ActionLoader = actionLoader; | ||
} | ||
|
||
public IActionLoader ActionLoader { get; } | ||
|
||
public static Assembly LoadPlugin(string absolutePath) | ||
{ | ||
var loadContext = new PluginLoadContext(absolutePath); | ||
var pluginBaseName = Path.GetFileNameWithoutExtension(absolutePath) | ||
?? throw new UnreachableException("Path.GetFileNameWithoutExtension returned null"); | ||
var pluginAssemblyName = new AssemblyName(pluginBaseName); | ||
return loadContext.LoadFromAssemblyName(pluginAssemblyName); | ||
} | ||
|
||
public static IPluginActionEvaluator CreateActionEvaluator( | ||
Check failure on line 39 in sdk/node/Libplanet.Node/Actions/PluggedActionEvaluator.cs GitHub Actions / docs
|
||
Assembly assembly, string typeName, IPluginKeyValueStore keyValueStore) | ||
Check failure on line 40 in sdk/node/Libplanet.Node/Actions/PluggedActionEvaluator.cs GitHub Actions / docs
Check failure on line 40 in sdk/node/Libplanet.Node/Actions/PluggedActionEvaluator.cs GitHub Actions / docs
|
||
{ | ||
if (assembly.GetType(typeName) is Type type && | ||
Activator.CreateInstance(type, args: keyValueStore) as IPluginActionEvaluator | ||
is IPluginActionEvaluator pluginActionEvaluator) | ||
{ | ||
return pluginActionEvaluator; | ||
} | ||
|
||
throw new NullReferenceException("PluginActionEvaluator not found with given parameters"); | ||
} | ||
|
||
public static IPluginActionEvaluator CreateActionEvaluator( | ||
Check failure on line 52 in sdk/node/Libplanet.Node/Actions/PluggedActionEvaluator.cs GitHub Actions / docs
|
||
string pluginPath, string typeName, IKeyValueStore keyValueStore) | ||
{ | ||
var assembly = LoadPlugin(pluginPath); | ||
var pluginKeyValueStore = new PluginKeyValueStore(keyValueStore); | ||
return CreateActionEvaluator(assembly, typeName, pluginKeyValueStore); | ||
} | ||
|
||
public IReadOnlyList<ICommittedActionEvaluation> Evaluate( | ||
IPreEvaluationBlock block, | ||
HashDigest<SHA256>? baseStateRootHash) | ||
{ | ||
var evaluations = _pluginActionEvaluator.Evaluate( | ||
PreEvaluationBlockMarshaller.Serialize(block), | ||
baseStateRootHash is { } srh ? srh.ToByteArray() : null) | ||
.Select(ActionEvaluationMarshaller.Deserialize).ToList().AsReadOnly(); | ||
return evaluations; | ||
} | ||
} |