Skip to content
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

Allow call from native contract #1700

Merged
merged 13 commits into from
Jun 22, 2020
39 changes: 39 additions & 0 deletions src/neo/SmartContract/ApplicationEngine.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,12 @@ namespace Neo.SmartContract
{
public partial class ApplicationEngine : ExecutionEngine
{
private class InvocationState
{
public Type ReturnType;
public Delegate Callback;
}

public static event EventHandler<NotifyEventArgs> Notify;
public static event EventHandler<LogEventArgs> Log;

Expand All @@ -28,6 +34,7 @@ public partial class ApplicationEngine : ExecutionEngine
private readonly List<NotifyEventArgs> notifications = new List<NotifyEventArgs>();
private readonly List<IDisposable> disposables = new List<IDisposable>();
private readonly Dictionary<UInt160, int> invocationCounter = new Dictionary<UInt160, int>();
private readonly Dictionary<ExecutionContext, InvocationState> invocationStates = new Dictionary<ExecutionContext, InvocationState>();

public static IEnumerable<InteropDescriptor> Services => services.Values;
public TriggerType Trigger { get; }
Expand Down Expand Up @@ -55,6 +62,38 @@ internal bool AddGas(long gas)
return testMode || GasConsumed <= gas_amount;
}

internal void CallFromNativeContract(Action onComplete, UInt160 hash, string method, params StackItem[] args)
{
invocationStates.Add(CurrentContext, new InvocationState
{
ReturnType = typeof(void),
Callback = onComplete
});
CallContract(hash, method, new VMArray(args));
}

internal void CallFromNativeContract<T>(Action<T> onComplete, UInt160 hash, string method, params StackItem[] args)
{
invocationStates.Add(CurrentContext, new InvocationState
{
ReturnType = typeof(T),
Callback = onComplete
});
CallContract(hash, method, new VMArray(args));
}

protected override void ContextUnloaded(ExecutionContext context)
{
base.ContextUnloaded(context);
if (!(UncaughtException is null)) return;
if (invocationStates.Count == 0) return;
if (!invocationStates.TryGetValue(CurrentContext, out InvocationState state)) return;
if (state.Callback is Action action)
action();
else
state.Callback.DynamicInvoke(Convert(Pop(), new InteropParameterDescriptor(state.ReturnType)));
}

protected override void LoadContext(ExecutionContext context)
{
// Set default execution context state
Expand Down
15 changes: 10 additions & 5 deletions src/neo/SmartContract/InteropParameterDescriptor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -39,20 +39,25 @@ internal class InteropParameterDescriptor
};

public InteropParameterDescriptor(ParameterInfo parameterInfo)
: this(parameterInfo.ParameterType)
{
Name = parameterInfo.Name;
Type = parameterInfo.ParameterType;
this.Name = parameterInfo.Name;
}

public InteropParameterDescriptor(Type type)
{
this.Type = type;
if (IsEnum)
{
Converter = converters[Type.GetEnumUnderlyingType()];
Converter = converters[type.GetEnumUnderlyingType()];
}
else if (IsArray)
{
Converter = converters[Type.GetElementType()];
Converter = converters[type.GetElementType()];
}
else
{
IsInterface = !converters.TryGetValue(Type, out var converter);
IsInterface = !converters.TryGetValue(type, out var converter);
if (IsInterface)
Converter = converters[typeof(InteropInterface)];
else
Expand Down