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

CallEx implementation #1364

Merged
merged 8 commits into from
Dec 19, 2019
Merged
Show file tree
Hide file tree
Changes from 3 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
16 changes: 16 additions & 0 deletions src/neo/SmartContract/CallFlags.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
using System;

namespace Neo.SmartContract
{
[Flags]
public enum CallFlags : byte
{
None = 0,

AllowModifyStates = 0b00000001,
AllowCall = 0b00000010,
AllowNotify = 0b00000100,

All = AllowModifyStates | AllowCall | AllowNotify
}
}
5 changes: 5 additions & 0 deletions src/neo/SmartContract/ExecutionContextState.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,10 @@ internal class ExecutionContextState
/// Calling script hash
/// </summary>
public UInt160 CallingScriptHash { get; set; }

/// <summary>
/// Execution context rights
/// </summary>
public CallFlags CallFlags { get; set; }
}
}
12 changes: 7 additions & 5 deletions src/neo/SmartContract/InteropDescriptor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,25 +11,27 @@ public class InteropDescriptor
public long Price { get; }
public Func<EvaluationStack, long> PriceCalculator { get; }
public TriggerType AllowedTriggers { get; }
public CallFlags RequiredCallFlags { get; }

internal InteropDescriptor(string method, Func<ApplicationEngine, bool> handler, long price, TriggerType allowedTriggers)
: this(method, handler, allowedTriggers)
internal InteropDescriptor(string method, Func<ApplicationEngine, bool> handler, long price, TriggerType allowedTriggers, CallFlags requiredCallFlags)
: this(method, handler, allowedTriggers, requiredCallFlags)
{
this.Price = price;
}

internal InteropDescriptor(string method, Func<ApplicationEngine, bool> handler, Func<EvaluationStack, long> priceCalculator, TriggerType allowedTriggers)
: this(method, handler, allowedTriggers)
internal InteropDescriptor(string method, Func<ApplicationEngine, bool> handler, Func<EvaluationStack, long> priceCalculator, TriggerType allowedTriggers, CallFlags requiredCallFlags)
: this(method, handler, allowedTriggers, requiredCallFlags)
{
this.PriceCalculator = priceCalculator;
}

private InteropDescriptor(string method, Func<ApplicationEngine, bool> handler, TriggerType allowedTriggers)
private InteropDescriptor(string method, Func<ApplicationEngine, bool> handler, TriggerType allowedTriggers, CallFlags requiredCallFlags)
{
this.Method = method;
this.Hash = method.ToInteropMethodHash();
this.Handler = handler;
this.AllowedTriggers = allowedTriggers;
this.RequiredCallFlags = requiredCallFlags;
}

public long GetPrice(EvaluationStack stack)
Expand Down
4 changes: 2 additions & 2 deletions src/neo/SmartContract/InteropService.Binary.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ partial class InteropService
{
public static class Binary
{
public static readonly InteropDescriptor Serialize = Register("System.Binary.Serialize", Binary_Serialize, 0_00100000, TriggerType.All);
public static readonly InteropDescriptor Deserialize = Register("System.Binary.Deserialize", Binary_Deserialize, 0_00500000, TriggerType.All);
public static readonly InteropDescriptor Serialize = Register("System.Binary.Serialize", Binary_Serialize, 0_00100000, TriggerType.All, CallFlags.None);
public static readonly InteropDescriptor Deserialize = Register("System.Binary.Deserialize", Binary_Deserialize, 0_00500000, TriggerType.All, CallFlags.None);

private static bool Binary_Serialize(ApplicationEngine engine)
{
Expand Down
12 changes: 6 additions & 6 deletions src/neo/SmartContract/InteropService.Blockchain.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,12 @@ partial class InteropService
{
public static class Blockchain
{
public static readonly InteropDescriptor GetHeight = Register("System.Blockchain.GetHeight", Blockchain_GetHeight, 0_00000400, TriggerType.Application);
public static readonly InteropDescriptor GetBlock = Register("System.Blockchain.GetBlock", Blockchain_GetBlock, 0_02500000, TriggerType.Application);
public static readonly InteropDescriptor GetTransaction = Register("System.Blockchain.GetTransaction", Blockchain_GetTransaction, 0_01000000, TriggerType.Application);
public static readonly InteropDescriptor GetTransactionHeight = Register("System.Blockchain.GetTransactionHeight", Blockchain_GetTransactionHeight, 0_01000000, TriggerType.Application);
public static readonly InteropDescriptor GetTransactionFromBlock = Register("System.Blockchain.GetTransactionFromBlock", Blockchain_GetTransactionFromBlock, 0_01000000, TriggerType.Application);
public static readonly InteropDescriptor GetContract = Register("System.Blockchain.GetContract", Blockchain_GetContract, 0_01000000, TriggerType.Application);
public static readonly InteropDescriptor GetHeight = Register("System.Blockchain.GetHeight", Blockchain_GetHeight, 0_00000400, TriggerType.Application, CallFlags.None);
public static readonly InteropDescriptor GetBlock = Register("System.Blockchain.GetBlock", Blockchain_GetBlock, 0_02500000, TriggerType.Application, CallFlags.None);
public static readonly InteropDescriptor GetTransaction = Register("System.Blockchain.GetTransaction", Blockchain_GetTransaction, 0_01000000, TriggerType.Application, CallFlags.None);
public static readonly InteropDescriptor GetTransactionHeight = Register("System.Blockchain.GetTransactionHeight", Blockchain_GetTransactionHeight, 0_01000000, TriggerType.Application, CallFlags.None);
public static readonly InteropDescriptor GetTransactionFromBlock = Register("System.Blockchain.GetTransactionFromBlock", Blockchain_GetTransactionFromBlock, 0_01000000, TriggerType.Application, CallFlags.None);
public static readonly InteropDescriptor GetContract = Register("System.Blockchain.GetContract", Blockchain_GetContract, 0_01000000, TriggerType.Application, CallFlags.None);

private static bool Blockchain_GetHeight(ApplicationEngine engine)
{
Expand Down
44 changes: 36 additions & 8 deletions src/neo/SmartContract/InteropService.Contract.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using Neo.SmartContract.Manifest;
using Neo.VM;
using Neo.VM.Types;
using System;
using System.Linq;

namespace Neo.SmartContract
Expand All @@ -11,11 +12,12 @@ partial class InteropService
{
public static class Contract
{
public static readonly InteropDescriptor Create = Register("System.Contract.Create", Contract_Create, GetDeploymentPrice, TriggerType.Application);
public static readonly InteropDescriptor Update = Register("System.Contract.Update", Contract_Update, GetDeploymentPrice, TriggerType.Application);
public static readonly InteropDescriptor Destroy = Register("System.Contract.Destroy", Contract_Destroy, 0_01000000, TriggerType.Application);
public static readonly InteropDescriptor Call = Register("System.Contract.Call", Contract_Call, 0_01000000, TriggerType.System | TriggerType.Application);
public static readonly InteropDescriptor IsStandard = Register("System.Contract.IsStandard", Contract_IsStandard, 0_00030000, TriggerType.All);
public static readonly InteropDescriptor Create = Register("System.Contract.Create", Contract_Create, GetDeploymentPrice, TriggerType.Application, CallFlags.AllowModifyStates);
public static readonly InteropDescriptor Update = Register("System.Contract.Update", Contract_Update, GetDeploymentPrice, TriggerType.Application, CallFlags.AllowModifyStates);
public static readonly InteropDescriptor Destroy = Register("System.Contract.Destroy", Contract_Destroy, 0_01000000, TriggerType.Application, CallFlags.AllowModifyStates);
public static readonly InteropDescriptor Call = Register("System.Contract.Call", Contract_Call, 0_01000000, TriggerType.System | TriggerType.Application, CallFlags.AllowCall);
public static readonly InteropDescriptor CallEx = Register("System.Contract.CallEx", Contract_CallEx, 0_01000000, TriggerType.System | TriggerType.Application, CallFlags.AllowCall);
public static readonly InteropDescriptor IsStandard = Register("System.Contract.IsStandard", Contract_IsStandard, 0_00030000, TriggerType.All, CallFlags.None);

private static long GetDeploymentPrice(EvaluationStack stack)
{
Expand Down Expand Up @@ -112,12 +114,34 @@ private static bool Contract_Destroy(ApplicationEngine engine)
private static bool Contract_Call(ApplicationEngine engine)
{
StackItem contractHash = engine.CurrentContext.EvaluationStack.Pop();
StackItem method = engine.CurrentContext.EvaluationStack.Pop();
StackItem args = engine.CurrentContext.EvaluationStack.Pop();

ContractState contract = engine.Snapshot.Contracts.TryGet(new UInt160(contractHash.GetSpan()));
if (contract is null) return false;
return Contract_CallEx(engine, new UInt160(contractHash.GetSpan()), method, args, CallFlags.All);
}

private static bool Contract_CallEx(ApplicationEngine engine)
{
StackItem contractHash = engine.CurrentContext.EvaluationStack.Pop();
StackItem method = engine.CurrentContext.EvaluationStack.Pop();
StackItem args = engine.CurrentContext.EvaluationStack.Pop();

if (!engine.CurrentContext.EvaluationStack.TryPop<PrimitiveType>(out var flagItem))
{
return false;
}

CallFlags flags = (CallFlags)(int)flagItem.ToBigInteger();
if (!Enum.IsDefined(typeof(CallFlags), flags)) return false;

return Contract_CallEx(engine, new UInt160(contractHash.GetSpan()), method, args, flags);
}

private static bool Contract_CallEx(ApplicationEngine engine, UInt160 contractHash, StackItem method, StackItem args, CallFlags flags)
{
ContractState contract = engine.Snapshot.Contracts.TryGet(contractHash);
if (contract is null) return false;

ContractManifest currentManifest = engine.Snapshot.Contracts.TryGet(engine.CurrentScriptHash)?.Manifest;

if (currentManifest != null && !currentManifest.CanCall(contract.Manifest, method.GetString()))
Expand All @@ -134,7 +158,11 @@ private static bool Contract_Call(ApplicationEngine engine)

UInt160 callingScriptHash = engine.CurrentScriptHash;
ExecutionContext context_new = engine.LoadScript(contract.Script, 1);
context_new.GetState<ExecutionContextState>().CallingScriptHash = callingScriptHash;

ExecutionContextState state = context_new.GetState<ExecutionContextState>();
state.CallingScriptHash = callingScriptHash;
state.CallFlags = flags;

context_new.EvaluationStack.Push(args);
context_new.EvaluationStack.Push(method);
return true;
Expand Down
4 changes: 2 additions & 2 deletions src/neo/SmartContract/InteropService.Crypto.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ partial class InteropService
{
public static class Crypto
{
public static readonly InteropDescriptor ECDsaVerify = Register("Neo.Crypto.ECDsaVerify", Crypto_ECDsaVerify, 0_01000000, TriggerType.All);
public static readonly InteropDescriptor ECDsaCheckMultiSig = Register("Neo.Crypto.ECDsaCheckMultiSig", Crypto_ECDsaCheckMultiSig, GetECDsaCheckMultiSigPrice, TriggerType.All);
public static readonly InteropDescriptor ECDsaVerify = Register("Neo.Crypto.ECDsaVerify", Crypto_ECDsaVerify, 0_01000000, TriggerType.All, CallFlags.None);
public static readonly InteropDescriptor ECDsaCheckMultiSig = Register("Neo.Crypto.ECDsaCheckMultiSig", Crypto_ECDsaCheckMultiSig, GetECDsaCheckMultiSigPrice, TriggerType.All, CallFlags.None);

private static long GetECDsaCheckMultiSigPrice(EvaluationStack stack)
{
Expand Down
8 changes: 4 additions & 4 deletions src/neo/SmartContract/InteropService.Enumerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,10 @@ partial class InteropService
{
public static class Enumerator
{
public static readonly InteropDescriptor Create = Register("System.Enumerator.Create", Enumerator_Create, 0_00000400, TriggerType.All);
public static readonly InteropDescriptor Next = Register("System.Enumerator.Next", Enumerator_Next, 0_01000000, TriggerType.All);
public static readonly InteropDescriptor Value = Register("System.Enumerator.Value", Enumerator_Value, 0_00000400, TriggerType.All);
public static readonly InteropDescriptor Concat = Register("System.Enumerator.Concat", Enumerator_Concat, 0_00000400, TriggerType.All);
public static readonly InteropDescriptor Create = Register("System.Enumerator.Create", Enumerator_Create, 0_00000400, TriggerType.All, CallFlags.None);
public static readonly InteropDescriptor Next = Register("System.Enumerator.Next", Enumerator_Next, 0_01000000, TriggerType.All, CallFlags.None);
public static readonly InteropDescriptor Value = Register("System.Enumerator.Value", Enumerator_Value, 0_00000400, TriggerType.All, CallFlags.None);
public static readonly InteropDescriptor Concat = Register("System.Enumerator.Concat", Enumerator_Concat, 0_00000400, TriggerType.All, CallFlags.None);

private static bool Enumerator_Create(ApplicationEngine engine)
{
Expand Down
10 changes: 5 additions & 5 deletions src/neo/SmartContract/InteropService.Iterator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,11 @@ partial class InteropService
{
public static class Iterator
{
public static readonly InteropDescriptor Create = Register("System.Iterator.Create", Iterator_Create, 0_00000400, TriggerType.All);
public static readonly InteropDescriptor Key = Register("System.Iterator.Key", Iterator_Key, 0_00000400, TriggerType.All);
public static readonly InteropDescriptor Keys = Register("System.Iterator.Keys", Iterator_Keys, 0_00000400, TriggerType.All);
public static readonly InteropDescriptor Values = Register("System.Iterator.Values", Iterator_Values, 0_00000400, TriggerType.All);
public static readonly InteropDescriptor Concat = Register("System.Iterator.Concat", Iterator_Concat, 0_00000400, TriggerType.All);
public static readonly InteropDescriptor Create = Register("System.Iterator.Create", Iterator_Create, 0_00000400, TriggerType.All, CallFlags.None);
public static readonly InteropDescriptor Key = Register("System.Iterator.Key", Iterator_Key, 0_00000400, TriggerType.All, CallFlags.None);
public static readonly InteropDescriptor Keys = Register("System.Iterator.Keys", Iterator_Keys, 0_00000400, TriggerType.All, CallFlags.None);
public static readonly InteropDescriptor Values = Register("System.Iterator.Values", Iterator_Values, 0_00000400, TriggerType.All, CallFlags.None);
public static readonly InteropDescriptor Concat = Register("System.Iterator.Concat", Iterator_Concat, 0_00000400, TriggerType.All, CallFlags.None);

private static bool Iterator_Create(ApplicationEngine engine)
{
Expand Down
4 changes: 2 additions & 2 deletions src/neo/SmartContract/InteropService.Json.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ partial class InteropService
{
public static class Json
{
public static readonly InteropDescriptor Serialize = Register("System.Json.Serialize", Json_Serialize, 0_00100000, TriggerType.All);
public static readonly InteropDescriptor Deserialize = Register("System.Json.Deserialize", Json_Deserialize, 0_00500000, TriggerType.All);
public static readonly InteropDescriptor Serialize = Register("System.Json.Serialize", Json_Serialize, 0_00100000, TriggerType.All, CallFlags.None);
public static readonly InteropDescriptor Deserialize = Register("System.Json.Deserialize", Json_Deserialize, 0_00500000, TriggerType.All, CallFlags.None);

private static bool Json_Serialize(ApplicationEngine engine)
{
Expand Down
4 changes: 2 additions & 2 deletions src/neo/SmartContract/InteropService.Native.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,12 @@ partial class InteropService
{
internal static class Native
{
public static readonly InteropDescriptor Deploy = Register("Neo.Native.Deploy", Native_Deploy, 0, TriggerType.Application);
public static readonly InteropDescriptor Deploy = Register("Neo.Native.Deploy", Native_Deploy, 0, TriggerType.Application, CallFlags.AllowModifyStates);

static Native()
{
foreach (NativeContract contract in NativeContract.Contracts)
Register(contract.ServiceName, contract.Invoke, contract.GetPrice, TriggerType.System | TriggerType.Application);
Register(contract.ServiceName, contract.Invoke, contract.GetPrice, TriggerType.System | TriggerType.Application, CallFlags.AllowCall);
}

private static bool Native_Deploy(ApplicationEngine engine)
Expand Down
Loading