Skip to content

Commit

Permalink
Notification limits (#1100)
Browse files Browse the repository at this point in the history
  • Loading branch information
erikzhang authored Oct 18, 2019
1 parent df48b5d commit 4112df2
Showing 1 changed file with 59 additions and 4 deletions.
63 changes: 59 additions & 4 deletions neo/SmartContract/InteropService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@
using System.Linq;
using System.Numerics;
using System.Text;
using Array = Neo.VM.Types.Array;
using Boolean = Neo.VM.Types.Boolean;

namespace Neo.SmartContract
{
Expand All @@ -22,6 +24,7 @@ public static partial class InteropService
public const long GasPerByte = 100000;
public const int MaxStorageKeySize = 64;
public const int MaxStorageValueSize = ushort.MaxValue;
public const int MaxNotificationSize = 1024;

private static readonly Dictionary<uint, InteropDescriptor> methods = new Dictionary<uint, InteropDescriptor>();

Expand All @@ -32,8 +35,8 @@ public static partial class InteropService
public static readonly uint System_Runtime_Platform = Register("System.Runtime.Platform", Runtime_Platform, 0_00000250, TriggerType.All);
public static readonly uint System_Runtime_GetTrigger = Register("System.Runtime.GetTrigger", Runtime_GetTrigger, 0_00000250, TriggerType.All);
public static readonly uint System_Runtime_CheckWitness = Register("System.Runtime.CheckWitness", Runtime_CheckWitness, 0_00030000, TriggerType.All);
public static readonly uint System_Runtime_Notify = Register("System.Runtime.Notify", Runtime_Notify, 0_00000250, TriggerType.All);
public static readonly uint System_Runtime_Log = Register("System.Runtime.Log", Runtime_Log, 0_00300000, TriggerType.All);
public static readonly uint System_Runtime_Notify = Register("System.Runtime.Notify", Runtime_Notify, 0_01000000, TriggerType.All);
public static readonly uint System_Runtime_Log = Register("System.Runtime.Log", Runtime_Log, 0_01000000, TriggerType.All);
public static readonly uint System_Runtime_GetTime = Register("System.Runtime.GetTime", Runtime_GetTime, 0_00000250, TriggerType.Application);
public static readonly uint System_Runtime_Serialize = Register("System.Runtime.Serialize", Runtime_Serialize, 0_00100000, TriggerType.All);
public static readonly uint System_Runtime_Deserialize = Register("System.Runtime.Deserialize", Runtime_Deserialize, 0_00500000, TriggerType.All);
Expand All @@ -56,6 +59,54 @@ public static partial class InteropService
public static readonly uint System_Storage_Delete = Register("System.Storage.Delete", Storage_Delete, 0_01000000, TriggerType.Application);
public static readonly uint System_StorageContext_AsReadOnly = Register("System.StorageContext.AsReadOnly", StorageContext_AsReadOnly, 0_00000400, TriggerType.Application);

private static bool CheckItemForNotification(StackItem state)
{
int size = 0;
List<StackItem> items_checked = new List<StackItem>();
Queue<StackItem> items_unchecked = new Queue<StackItem>();
while (true)
{
switch (state)
{
case Struct array:
foreach (StackItem item in array)
items_unchecked.Enqueue(item);
break;
case Array array:
if (items_checked.All(p => !ReferenceEquals(p, array)))
{
items_checked.Add(array);
foreach (StackItem item in array)
items_unchecked.Enqueue(item);
}
break;
case Boolean _:
case ByteArray _:
case Integer _:
size += state.GetByteLength();
break;
case Null _:
break;
case InteropInterface _:
return false;
case Map map:
if (items_checked.All(p => !ReferenceEquals(p, map)))
{
items_checked.Add(map);
foreach (var pair in map)
{
size += pair.Key.GetByteLength();
items_unchecked.Enqueue(pair.Value);
}
}
break;
}
if (size > MaxNotificationSize) return false;
if (items_unchecked.Count == 0) return true;
state = items_unchecked.Dequeue();
}
}

private static bool CheckStorageContext(ApplicationEngine engine, StorageContext context)
{
ContractState contract = engine.Snapshot.Contracts.TryGet(context.ScriptHash);
Expand Down Expand Up @@ -194,13 +245,17 @@ private static bool Runtime_CheckWitness(ApplicationEngine engine)

private static bool Runtime_Notify(ApplicationEngine engine)
{
engine.SendNotification(engine.CurrentScriptHash, engine.CurrentContext.EvaluationStack.Pop());
StackItem state = engine.CurrentContext.EvaluationStack.Pop();
if (!CheckItemForNotification(state)) return false;
engine.SendNotification(engine.CurrentScriptHash, state);
return true;
}

private static bool Runtime_Log(ApplicationEngine engine)
{
string message = Encoding.UTF8.GetString(engine.CurrentContext.EvaluationStack.Pop().GetByteArray());
byte[] state = engine.CurrentContext.EvaluationStack.Pop().GetByteArray();
if (state.Length > MaxNotificationSize) return false;
string message = Encoding.UTF8.GetString(state);
engine.SendLog(engine.CurrentScriptHash, message);
return true;
}
Expand Down

0 comments on commit 4112df2

Please sign in to comment.