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

Limit SYSCALLs in Verification #856

Merged
merged 10 commits into from
Jul 5, 2019
2 changes: 1 addition & 1 deletion neo.UnitTests/TestUtils.cs
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ public static Transaction CreateRandomHashTransaction()
new Witness
{
InvocationScript = new byte[0],
VerificationScript = new byte[0]
VerificationScript = new byte[1]
}
}
};
Expand Down
4 changes: 3 additions & 1 deletion neo/Network/P2P/Payloads/Witness.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
using Neo.IO;
using Neo.IO.Json;
using Neo.SmartContract;
using Neo.VM;
using System;
using System.IO;

namespace Neo.Network.P2P.Payloads
Expand Down Expand Up @@ -30,6 +30,8 @@ void ISerializable.Deserialize(BinaryReader reader)
{
InvocationScript = reader.ReadVarBytes(65536);
VerificationScript = reader.ReadVarBytes(65536);
if (VerificationScript.Length == 0)
throw new FormatException();
}

void ISerializable.Serialize(BinaryWriter writer)
Expand Down
13 changes: 2 additions & 11 deletions neo/SmartContract/Helper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -262,19 +262,10 @@ internal static bool VerifyWitnesses(this IVerifiable verifiable, Snapshot snaps
if (hashes.Length != verifiable.Witnesses.Length) return false;
for (int i = 0; i < hashes.Length; i++)
{
byte[] verification = verifiable.Witnesses[i].VerificationScript;
if (verification.Length == 0)
{
verification = snapshot.Contracts.TryGet(hashes[i])?.Script;
erikzhang marked this conversation as resolved.
Show resolved Hide resolved
if (verification is null) return false;
}
else
{
if (hashes[i] != verifiable.Witnesses[i].ScriptHash) return false;
}
if (hashes[i] != verifiable.Witnesses[i].ScriptHash) return false;
using (ApplicationEngine engine = new ApplicationEngine(TriggerType.Verification, verifiable, snapshot, gas))
{
engine.LoadScript(verification);
engine.LoadScript(verifiable.Witnesses[i].VerificationScript);
engine.LoadScript(verifiable.Witnesses[i].InvocationScript);
if (engine.Execute().HasFlag(VMState.FAULT)) return false;
if (engine.ResultStack.Count != 1 || !engine.ResultStack.Pop().GetBoolean()) return false;
Expand Down
40 changes: 40 additions & 0 deletions neo/SmartContract/InteropDescriptor.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
using Neo.VM;
using System;

namespace Neo.SmartContract
{
internal class InteropDescriptor
{
public string Method { get; }
public uint Hash { get; }
public Func<ApplicationEngine, bool> Handler { get; }
public long Price { get; }
igormcoelho marked this conversation as resolved.
Show resolved Hide resolved
public Func<RandomAccessStack<StackItem>, long> PriceCalculator { get; }
public TriggerType AllowedTriggers { get; }

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

public InteropDescriptor(string method, Func<ApplicationEngine, bool> handler, Func<RandomAccessStack<StackItem>, long> priceCalculator, TriggerType allowedTriggers)
: this(method, handler, allowedTriggers)
{
this.PriceCalculator = priceCalculator;
}

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

public long GetPrice(RandomAccessStack<StackItem> stack)
{
return PriceCalculator is null ? Price : PriceCalculator(stack);
igormcoelho marked this conversation as resolved.
Show resolved Hide resolved
}
}
}
62 changes: 29 additions & 33 deletions neo/SmartContract/InteropService.NEO.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,37 +18,37 @@ namespace Neo.SmartContract
{
static partial class InteropService
{
public static readonly uint Neo_Native_Deploy = Register("Neo.Native.Deploy", Native_Deploy, 0);
public static readonly uint Neo_Crypto_CheckSig = Register("Neo.Crypto.CheckSig", Crypto_CheckSig, 0_01000000);
public static readonly uint Neo_Crypto_CheckMultiSig = Register("Neo.Crypto.CheckMultiSig", Crypto_CheckMultiSig, GetCheckMultiSigPrice);
public static readonly uint Neo_Header_GetVersion = Register("Neo.Header.GetVersion", Header_GetVersion, 0_00000400);
public static readonly uint Neo_Header_GetMerkleRoot = Register("Neo.Header.GetMerkleRoot", Header_GetMerkleRoot, 0_00000400);
public static readonly uint Neo_Header_GetNextConsensus = Register("Neo.Header.GetNextConsensus", Header_GetNextConsensus, 0_00000400);
public static readonly uint Neo_Transaction_GetScript = Register("Neo.Transaction.GetScript", Transaction_GetScript, 0_00000400);
public static readonly uint Neo_Transaction_GetWitnesses = Register("Neo.Transaction.GetWitnesses", Transaction_GetWitnesses, 0_00010000);
public static readonly uint Neo_Witness_GetVerificationScript = Register("Neo.Witness.GetVerificationScript", Witness_GetVerificationScript, 0_00000400);
public static readonly uint Neo_Account_IsStandard = Register("Neo.Account.IsStandard", Account_IsStandard, 0_00030000);
public static readonly uint Neo_Contract_Create = Register("Neo.Contract.Create", Contract_Create, GetDeploymentPrice);
public static readonly uint Neo_Contract_Update = Register("Neo.Contract.Update", Contract_Update, GetDeploymentPrice);
public static readonly uint Neo_Contract_GetScript = Register("Neo.Contract.GetScript", Contract_GetScript, 0_00000400);
public static readonly uint Neo_Contract_IsPayable = Register("Neo.Contract.IsPayable", Contract_IsPayable, 0_00000400);
public static readonly uint Neo_Storage_Find = Register("Neo.Storage.Find", Storage_Find, 0_01000000);
public static readonly uint Neo_Enumerator_Create = Register("Neo.Enumerator.Create", Enumerator_Create, 0_00000400);
public static readonly uint Neo_Enumerator_Next = Register("Neo.Enumerator.Next", Enumerator_Next, 0_01000000);
public static readonly uint Neo_Enumerator_Value = Register("Neo.Enumerator.Value", Enumerator_Value, 0_00000400);
public static readonly uint Neo_Enumerator_Concat = Register("Neo.Enumerator.Concat", Enumerator_Concat, 0_00000400);
public static readonly uint Neo_Iterator_Create = Register("Neo.Iterator.Create", Iterator_Create, 0_00000400);
public static readonly uint Neo_Iterator_Key = Register("Neo.Iterator.Key", Iterator_Key, 0_00000400);
public static readonly uint Neo_Iterator_Keys = Register("Neo.Iterator.Keys", Iterator_Keys, 0_00000400);
public static readonly uint Neo_Iterator_Values = Register("Neo.Iterator.Values", Iterator_Values, 0_00000400);
public static readonly uint Neo_Iterator_Concat = Register("Neo.Iterator.Concat", Iterator_Concat, 0_00000400);
public static readonly uint Neo_Json_Serialize = Register("Neo.Json.Serialize", Json_Serialize, 0_00100000);
public static readonly uint Neo_Json_Deserialize = Register("Neo.Json.Deserialize", Json_Deserialize, 0_00500000);
public static readonly uint Neo_Native_Deploy = Register("Neo.Native.Deploy", Native_Deploy, 0, TriggerType.Application);
public static readonly uint Neo_Crypto_CheckSig = Register("Neo.Crypto.CheckSig", Crypto_CheckSig, 0_01000000, TriggerType.All);
public static readonly uint Neo_Crypto_CheckMultiSig = Register("Neo.Crypto.CheckMultiSig", Crypto_CheckMultiSig, GetCheckMultiSigPrice, TriggerType.All);
public static readonly uint Neo_Header_GetVersion = Register("Neo.Header.GetVersion", Header_GetVersion, 0_00000400, TriggerType.Application);
public static readonly uint Neo_Header_GetMerkleRoot = Register("Neo.Header.GetMerkleRoot", Header_GetMerkleRoot, 0_00000400, TriggerType.Application);
public static readonly uint Neo_Header_GetNextConsensus = Register("Neo.Header.GetNextConsensus", Header_GetNextConsensus, 0_00000400, TriggerType.Application);
public static readonly uint Neo_Transaction_GetScript = Register("Neo.Transaction.GetScript", Transaction_GetScript, 0_00000400, TriggerType.All);
public static readonly uint Neo_Transaction_GetWitnesses = Register("Neo.Transaction.GetWitnesses", Transaction_GetWitnesses, 0_00010000, TriggerType.All);
public static readonly uint Neo_Witness_GetVerificationScript = Register("Neo.Witness.GetVerificationScript", Witness_GetVerificationScript, 0_00000400, TriggerType.All);
public static readonly uint Neo_Account_IsStandard = Register("Neo.Account.IsStandard", Account_IsStandard, 0_00030000, TriggerType.All);
public static readonly uint Neo_Contract_Create = Register("Neo.Contract.Create", Contract_Create, GetDeploymentPrice, TriggerType.Application);
igormcoelho marked this conversation as resolved.
Show resolved Hide resolved
public static readonly uint Neo_Contract_Update = Register("Neo.Contract.Update", Contract_Update, GetDeploymentPrice, TriggerType.Application);
public static readonly uint Neo_Contract_GetScript = Register("Neo.Contract.GetScript", Contract_GetScript, 0_00000400, TriggerType.Application);
public static readonly uint Neo_Contract_IsPayable = Register("Neo.Contract.IsPayable", Contract_IsPayable, 0_00000400, TriggerType.Application);
public static readonly uint Neo_Storage_Find = Register("Neo.Storage.Find", Storage_Find, 0_01000000, TriggerType.Application);
public static readonly uint Neo_Enumerator_Create = Register("Neo.Enumerator.Create", Enumerator_Create, 0_00000400, TriggerType.All);
public static readonly uint Neo_Enumerator_Next = Register("Neo.Enumerator.Next", Enumerator_Next, 0_01000000, TriggerType.All);
public static readonly uint Neo_Enumerator_Value = Register("Neo.Enumerator.Value", Enumerator_Value, 0_00000400, TriggerType.All);
public static readonly uint Neo_Enumerator_Concat = Register("Neo.Enumerator.Concat", Enumerator_Concat, 0_00000400, TriggerType.All);
public static readonly uint Neo_Iterator_Create = Register("Neo.Iterator.Create", Iterator_Create, 0_00000400, TriggerType.All);
public static readonly uint Neo_Iterator_Key = Register("Neo.Iterator.Key", Iterator_Key, 0_00000400, TriggerType.All);
public static readonly uint Neo_Iterator_Keys = Register("Neo.Iterator.Keys", Iterator_Keys, 0_00000400, TriggerType.All);
public static readonly uint Neo_Iterator_Values = Register("Neo.Iterator.Values", Iterator_Values, 0_00000400, TriggerType.All);
public static readonly uint Neo_Iterator_Concat = Register("Neo.Iterator.Concat", Iterator_Concat, 0_00000400, TriggerType.All);
public static readonly uint Neo_Json_Serialize = Register("Neo.Json.Serialize", Json_Serialize, 0_00100000, TriggerType.All);
public static readonly uint Neo_Json_Deserialize = Register("Neo.Json.Deserialize", Json_Deserialize, 0_00500000, TriggerType.All);

static InteropService()
{
foreach (NativeContract contract in NativeContract.Contracts)
Register(contract.ServiceName, contract.Invoke, contract.GetPrice);
Register(contract.ServiceName, contract.Invoke, contract.GetPrice, TriggerType.System | TriggerType.Application);
igormcoelho marked this conversation as resolved.
Show resolved Hide resolved
}

private static long GetCheckMultiSigPrice(RandomAccessStack<StackItem> stack)
Expand All @@ -70,7 +70,6 @@ private static long GetDeploymentPrice(RandomAccessStack<StackItem> stack)

private static bool Native_Deploy(ApplicationEngine engine)
{
if (engine.Trigger != TriggerType.Application) return false;
igormcoelho marked this conversation as resolved.
Show resolved Hide resolved
if (engine.Snapshot.PersistingBlock.Index != 0) return false;
foreach (NativeContract contract in NativeContract.Contracts)
{
Expand Down Expand Up @@ -215,7 +214,7 @@ private static bool Transaction_GetWitnesses(ApplicationEngine engine)
if (tx == null) return false;
if (tx.Witnesses.Length > engine.MaxArraySize)
return false;
engine.CurrentContext.EvaluationStack.Push(WitnessWrapper.Create(tx, engine.Snapshot).Select(p => StackItem.FromInterface(p)).ToArray());
engine.CurrentContext.EvaluationStack.Push(tx.Witnesses.Select(p => StackItem.FromInterface(p)).ToArray());
return true;
}
return false;
Expand All @@ -225,7 +224,7 @@ private static bool Witness_GetVerificationScript(ApplicationEngine engine)
{
if (engine.CurrentContext.EvaluationStack.Pop() is InteropInterface _interface)
{
WitnessWrapper witness = _interface.GetInterface<WitnessWrapper>();
Witness witness = _interface.GetInterface<Witness>();
if (witness == null) return false;
engine.CurrentContext.EvaluationStack.Push(witness.VerificationScript);
return true;
Expand All @@ -244,7 +243,6 @@ private static bool Account_IsStandard(ApplicationEngine engine)

private static bool Contract_Create(ApplicationEngine engine)
{
if (engine.Trigger != TriggerType.Application) return false;
byte[] script = engine.CurrentContext.EvaluationStack.Pop().GetByteArray();
if (script.Length > 1024 * 1024) return false;

Expand All @@ -269,8 +267,6 @@ private static bool Contract_Create(ApplicationEngine engine)

private static bool Contract_Update(ApplicationEngine engine)
{
if (engine.Trigger != TriggerType.Application) return false;

byte[] script = engine.CurrentContext.EvaluationStack.Pop().GetByteArray();
if (script.Length > 1024 * 1024) return false;
var manifest = engine.CurrentContext.EvaluationStack.Pop().GetString();
Expand Down
Loading