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

Neo.VM.3.0.0-CI00201 #1374

Merged
merged 4 commits into from Dec 30, 2019
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
10 changes: 10 additions & 0 deletions src/neo/IO/Helper.cs
Expand Up @@ -88,6 +88,16 @@ public static byte[] DecompressLz4(this byte[] data, int maxOutput)
return result;
}

public static void FillBuffer(this BinaryReader reader, Span<byte> buffer)
{
while (!buffer.IsEmpty)
{
int count = reader.Read(buffer);
if (count == 0) throw new EndOfStreamException();
buffer = buffer[count..];
}
}

public static int GetVarSize(int value)
{
if (value < 0xFD)
Expand Down
92 changes: 73 additions & 19 deletions src/neo/SmartContract/ApplicationEngine.OpCodePrices.cs
Expand Up @@ -78,60 +78,114 @@ partial class ApplicationEngine
[OpCode.REVERSE3] = 60,
[OpCode.REVERSE4] = 60,
[OpCode.REVERSEN] = 400,
[OpCode.TOALTSTACK] = 60,
[OpCode.FROMALTSTACK] = 60,
[OpCode.DUPFROMALTSTACK] = 60,
[OpCode.DUPFROMALTSTACKBOTTOM] = 60,
[OpCode.ISNULL] = 60,
[OpCode.INITSSLOT] = 400,
[OpCode.INITSLOT] = 800,
[OpCode.LDSFLD0] = 60,
[OpCode.LDSFLD1] = 60,
[OpCode.LDSFLD2] = 60,
[OpCode.LDSFLD3] = 60,
[OpCode.LDSFLD4] = 60,
[OpCode.LDSFLD5] = 60,
[OpCode.LDSFLD6] = 60,
[OpCode.LDSFLD] = 60,
[OpCode.STSFLD0] = 60,
[OpCode.STSFLD1] = 60,
[OpCode.STSFLD2] = 60,
[OpCode.STSFLD3] = 60,
[OpCode.STSFLD4] = 60,
[OpCode.STSFLD5] = 60,
[OpCode.STSFLD6] = 60,
[OpCode.STSFLD] = 60,
[OpCode.LDLOC0] = 60,
[OpCode.LDLOC1] = 60,
[OpCode.LDLOC2] = 60,
[OpCode.LDLOC3] = 60,
[OpCode.LDLOC4] = 60,
[OpCode.LDLOC5] = 60,
[OpCode.LDLOC6] = 60,
[OpCode.LDLOC] = 60,
[OpCode.STLOC0] = 60,
[OpCode.STLOC1] = 60,
[OpCode.STLOC2] = 60,
[OpCode.STLOC3] = 60,
[OpCode.STLOC4] = 60,
[OpCode.STLOC5] = 60,
[OpCode.STLOC6] = 60,
[OpCode.STLOC] = 60,
[OpCode.LDARG0] = 60,
[OpCode.LDARG1] = 60,
[OpCode.LDARG2] = 60,
[OpCode.LDARG3] = 60,
[OpCode.LDARG4] = 60,
[OpCode.LDARG5] = 60,
[OpCode.LDARG6] = 60,
[OpCode.LDARG] = 60,
[OpCode.STARG0] = 60,
[OpCode.STARG1] = 60,
[OpCode.STARG2] = 60,
[OpCode.STARG3] = 60,
[OpCode.STARG4] = 60,
[OpCode.STARG5] = 60,
[OpCode.STARG6] = 60,
[OpCode.STARG] = 60,
[OpCode.NEWBUFFER] = 80000,
[OpCode.MEMCPY] = 80000,
[OpCode.CAT] = 80000,
[OpCode.SUBSTR] = 80000,
[OpCode.LEFT] = 80000,
[OpCode.RIGHT] = 80000,
[OpCode.SIZE] = 60,
[OpCode.INVERT] = 100,
[OpCode.AND] = 200,
[OpCode.OR] = 200,
[OpCode.XOR] = 200,
[OpCode.EQUAL] = 200,
[OpCode.INC] = 100,
[OpCode.DEC] = 100,
[OpCode.NOTEQUAL] = 200,
[OpCode.SIGN] = 100,
[OpCode.NEGATE] = 100,
[OpCode.ABS] = 100,
[OpCode.NOT] = 100,
[OpCode.NZ] = 100,
[OpCode.NEGATE] = 100,
[OpCode.INC] = 100,
[OpCode.DEC] = 100,
[OpCode.ADD] = 200,
[OpCode.SUB] = 200,
[OpCode.MUL] = 300,
[OpCode.DIV] = 300,
[OpCode.MOD] = 300,
[OpCode.SHL] = 300,
[OpCode.SHR] = 300,
[OpCode.NOT] = 100,
[OpCode.BOOLAND] = 200,
[OpCode.BOOLOR] = 200,
[OpCode.NZ] = 100,
[OpCode.NUMEQUAL] = 200,
[OpCode.NUMNOTEQUAL] = 200,
[OpCode.LT] = 200,
[OpCode.LE] = 200,
[OpCode.GT] = 200,
[OpCode.LTE] = 200,
[OpCode.GTE] = 200,
[OpCode.GE] = 200,
[OpCode.MIN] = 200,
[OpCode.MAX] = 200,
[OpCode.WITHIN] = 200,
[OpCode.ARRAYSIZE] = 150,
[OpCode.PACK] = 7000,
[OpCode.UNPACK] = 7000,
[OpCode.PICKITEM] = 270000,
[OpCode.SETITEM] = 270000,
[OpCode.NEWARRAY0] = 400,
[OpCode.NEWARRAY] = 15000,
[OpCode.NEWARRAY_T] = 15000,
[OpCode.NEWSTRUCT0] = 400,
[OpCode.NEWSTRUCT] = 15000,
[OpCode.NEWMAP] = 200,
[OpCode.APPEND] = 15000,
[OpCode.REVERSE] = 500,
[OpCode.REMOVE] = 500,
[OpCode.SIZE] = 150,
[OpCode.HASKEY] = 270000,
[OpCode.KEYS] = 500,
[OpCode.VALUES] = 7000,
[OpCode.PICKITEM] = 270000,
[OpCode.APPEND] = 15000,
[OpCode.SETITEM] = 270000,
[OpCode.REVERSEITEMS] = 500,
[OpCode.REMOVE] = 500,
[OpCode.CLEARITEMS] = 400,
[OpCode.ISNULL] = 60,
[OpCode.ISTYPE] = 60,
[OpCode.CONVERT] = 80000,
};
}
}
15 changes: 15 additions & 0 deletions src/neo/SmartContract/ApplicationEngine.cs
Expand Up @@ -5,6 +5,7 @@
using Neo.VM.Types;
using System;
using System.Collections.Generic;
using System.Text;
using Array = System.Array;

namespace Neo.SmartContract
Expand Down Expand Up @@ -140,5 +141,19 @@ internal void SendNotification(UInt160 script_hash, StackItem state)
Notify?.Invoke(this, notification);
notifications.Add(notification);
}

public bool TryPop(out string s)
{
if (TryPop(out ReadOnlySpan<byte> b))
{
s = Encoding.UTF8.GetString(b);
return true;
}
else
{
s = default;
return false;
}
}
}
}
80 changes: 33 additions & 47 deletions src/neo/SmartContract/BinarySerializer.cs
Expand Up @@ -7,31 +7,31 @@
using System.Linq;
using System.Numerics;
using Array = Neo.VM.Types.Array;
using Boolean = Neo.VM.Types.Boolean;
using Buffer = Neo.VM.Types.Buffer;

namespace Neo.SmartContract
{
internal static class BinarySerializer
{
public static StackItem Deserialize(byte[] data, uint maxItemSize, ReferenceCounter referenceCounter = null)
public static StackItem Deserialize(byte[] data, uint maxArraySize, uint maxItemSize, ReferenceCounter referenceCounter = null)
{
using MemoryStream ms = new MemoryStream(data, false);
using BinaryReader reader = new BinaryReader(ms);
return Deserialize(reader, maxItemSize, referenceCounter);
return Deserialize(reader, maxArraySize, maxItemSize, referenceCounter);
}

public static unsafe StackItem Deserialize(ReadOnlySpan<byte> data, uint maxItemSize, ReferenceCounter referenceCounter = null)
public static unsafe StackItem Deserialize(ReadOnlySpan<byte> data, uint maxArraySize, uint maxItemSize, ReferenceCounter referenceCounter = null)
{
if (data.IsEmpty) throw new FormatException();
fixed (byte* pointer = data)
{
using UnmanagedMemoryStream ms = new UnmanagedMemoryStream(pointer, data.Length);
using BinaryReader reader = new BinaryReader(ms);
return Deserialize(reader, maxItemSize, referenceCounter);
return Deserialize(reader, maxArraySize, maxItemSize, referenceCounter);
}
}

private static StackItem Deserialize(BinaryReader reader, uint maxItemSize, ReferenceCounter referenceCounter)
private static StackItem Deserialize(BinaryReader reader, uint maxArraySize, uint maxItemSize, ReferenceCounter referenceCounter)
{
Stack<StackItem> deserialized = new Stack<StackItem>();
int undeserialized = 1;
Expand All @@ -40,41 +40,35 @@ private static StackItem Deserialize(BinaryReader reader, uint maxItemSize, Refe
StackItemType type = (StackItemType)reader.ReadByte();
switch (type)
{
case StackItemType.ByteArray:
deserialized.Push(new ByteArray(reader.ReadVarBytes((int)maxItemSize)));
break;
case StackItemType.Boolean:
deserialized.Push(new Boolean(reader.ReadBoolean()));
case StackItemType.Any:
deserialized.Push(StackItem.Null);
erikzhang marked this conversation as resolved.
Show resolved Hide resolved
break;
case StackItemType.Integer:
deserialized.Push(new Integer(new BigInteger(reader.ReadVarBytes(Integer.MaxSize))));
deserialized.Push(new BigInteger(reader.ReadVarBytes(Integer.MaxSize)));
break;
case StackItemType.ByteArray:
deserialized.Push(reader.ReadVarBytes((int)maxItemSize));
break;
case StackItemType.Buffer:
Buffer buffer = new Buffer((int)reader.ReadVarInt(maxItemSize));
reader.FillBuffer(buffer.InnerBuffer);
deserialized.Push(buffer);
break;
case StackItemType.Array:
case StackItemType.Struct:
{
int count = (int)reader.ReadVarInt(maxItemSize);
deserialized.Push(new ContainerPlaceholder
{
Type = type,
ElementCount = count
});
int count = (int)reader.ReadVarInt(maxArraySize);
deserialized.Push(new ContainerPlaceholder(type, count));
undeserialized += count;
}
break;
case StackItemType.Map:
{
int count = (int)reader.ReadVarInt(maxItemSize);
deserialized.Push(new ContainerPlaceholder
{
Type = type,
ElementCount = count
});
int count = (int)reader.ReadVarInt(maxArraySize);
deserialized.Push(new ContainerPlaceholder(type, count));
undeserialized += count * 2;
}
break;
case StackItemType.Null:
deserialized.Push(StackItem.Null);
break;
default:
throw new FormatException();
}
Expand Down Expand Up @@ -127,36 +121,30 @@ public static byte[] Serialize(StackItem item, uint maxSize)

private static void Serialize(StackItem item, BinaryWriter writer, uint maxSize)
{
List<StackItem> serialized = new List<StackItem>();
List<CompoundType> serialized = new List<CompoundType>();
Stack<StackItem> unserialized = new Stack<StackItem>();
unserialized.Push(item);
while (unserialized.Count > 0)
{
item = unserialized.Pop();
writer.Write((byte)item.Type);
switch (item)
{
case ByteArray bytes:
writer.Write((byte)StackItemType.ByteArray);
writer.WriteVarBytes(bytes.ToByteArray());
break;
case Boolean _:
writer.Write((byte)StackItemType.Boolean);
writer.Write(item.ToBoolean());
case Null _:
break;
case Integer integer:
writer.Write((byte)StackItemType.Integer);
writer.WriteVarBytes(integer.ToByteArray());
writer.WriteVarBytes(integer.Span);
break;
case ByteArray bytes:
writer.WriteVarBytes(bytes.Span);
break;
case Buffer buffer:
writer.WriteVarBytes(buffer.InnerBuffer);
break;
case InteropInterface _:
throw new NotSupportedException();
case Array array:
if (serialized.Any(p => ReferenceEquals(p, array)))
throw new NotSupportedException();
serialized.Add(array);
if (array is Struct)
writer.Write((byte)StackItemType.Struct);
else
writer.Write((byte)StackItemType.Array);
writer.WriteVarInt(array.Count);
for (int i = array.Count - 1; i >= 0; i--)
unserialized.Push(array[i]);
Expand All @@ -165,17 +153,15 @@ private static void Serialize(StackItem item, BinaryWriter writer, uint maxSize)
if (serialized.Any(p => ReferenceEquals(p, map)))
throw new NotSupportedException();
serialized.Add(map);
writer.Write((byte)StackItemType.Map);
writer.WriteVarInt(map.Count);
foreach (var pair in map.Reverse())
{
unserialized.Push(pair.Value);
unserialized.Push(pair.Key);
}
break;
case Null _:
writer.Write((byte)StackItemType.Null);
break;
default:
throw new NotSupportedException();
}
if (writer.BaseStream.Position > maxSize)
throw new InvalidOperationException();
Expand Down
12 changes: 9 additions & 3 deletions src/neo/SmartContract/ContainerPlaceholder.cs
Expand Up @@ -5,10 +5,16 @@ namespace Neo.SmartContract
{
internal class ContainerPlaceholder : StackItem
{
public StackItemType Type;
public int ElementCount;
public override StackItemType Type { get; }
public int ElementCount { get; }

public override bool Equals(StackItem other) => throw new NotSupportedException();
public ContainerPlaceholder(StackItemType type, int count)
{
Type = type;
ElementCount = count;
}

public override bool Equals(object obj) => throw new NotSupportedException();

public override int GetHashCode() => throw new NotSupportedException();

Expand Down
17 changes: 2 additions & 15 deletions src/neo/SmartContract/InteropService.Binary.cs
@@ -1,7 +1,5 @@
using Neo.VM;
using Neo.VM.Types;
using System;
using System.IO;

namespace Neo.SmartContract
{
Expand Down Expand Up @@ -29,19 +27,8 @@ private static bool Binary_Serialize(ApplicationEngine engine)

private static bool Binary_Deserialize(ApplicationEngine engine)
{
StackItem item;
try
{
item = BinarySerializer.Deserialize(engine.CurrentContext.EvaluationStack.Pop().GetSpan(), engine.MaxItemSize, engine.ReferenceCounter);
}
catch (FormatException)
{
return false;
}
catch (IOException)
{
return false;
}
if (!engine.TryPop(out ReadOnlySpan<byte> data)) return false;
StackItem item = BinarySerializer.Deserialize(data, engine.MaxStackSize, engine.MaxItemSize, engine.ReferenceCounter);
engine.CurrentContext.EvaluationStack.Push(item);
return true;
}
Expand Down
2 changes: 1 addition & 1 deletion src/neo/SmartContract/Iterators/ByteArrayWrapper.cs
Expand Up @@ -10,7 +10,7 @@ internal class ByteArrayWrapper : IIterator

public ByteArrayWrapper(PrimitiveType value)
{
this.array = value.ToByteArray().ToArray();
this.array = value.Span.ToArray();
}

public void Dispose() { }
Expand Down