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

Add MethodToken #2185

Merged
merged 3 commits into from
Dec 28, 2020
Merged
Show file tree
Hide file tree
Changes from all 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
42 changes: 42 additions & 0 deletions src/neo/SmartContract/MethodToken.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
using Neo.IO;
using System;
using System.IO;

namespace Neo.SmartContract
{
public class MethodToken : ISerializable
{
public UInt160 Hash;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this hash of some other contracts?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes.

public string Method;
public ushort ParametersCount;
public ushort RVCount;
public CallFlags CallFlags;

public int Size =>
UInt160.Length + // Hash
Method.GetVarSize() + // Method
sizeof(ushort) + // ParametersCount
sizeof(ushort) + // RVCount
sizeof(CallFlags); // CallFlags

void ISerializable.Deserialize(BinaryReader reader)
{
Hash = reader.ReadSerializable<UInt160>();
Method = reader.ReadVarString(32);
ParametersCount = reader.ReadUInt16();
RVCount = reader.ReadUInt16();
CallFlags = (CallFlags)reader.ReadByte();
if ((CallFlags & ~CallFlags.All) != 0)
throw new FormatException();
}

void ISerializable.Serialize(BinaryWriter writer)
{
writer.Write(Hash);
writer.WriteVarString(Method);
writer.Write(ParametersCount);
writer.Write(RVCount);
writer.Write((byte)CallFlags);
}
}
}
45 changes: 34 additions & 11 deletions src/neo/SmartContract/NefFile.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,22 @@
namespace Neo.SmartContract
{
/// <summary>
/// +------------+-----------+------------------------------------------------------------+
/// | Field | Length | Comment |
/// +------------+-----------+------------------------------------------------------------+
/// | Magic | 4 bytes | Magic header |
/// | Compiler | 32 bytes | Compiler used |
/// | Version | 32 bytes | Compiler version |
/// +------------+-----------+------------------------------------------------------------+
/// | Script | Var bytes | Var bytes for the payload |
/// +------------+-----------+------------------------------------------------------------+
/// | Checksum | 4 bytes | First four bytes of double SHA256 hash |
/// +------------+-----------+------------------------------------------------------------+
/// ┌───────────────────────────────────────────────────────────────────────┐
/// │ NEO Executable Format 3 (NEF3) │
/// ├──────────┬───────────────┬────────────────────────────────────────────┤
/// │ Field │ Type │ Comment │
/// ├──────────┼───────────────┼────────────────────────────────────────────┤
/// │ Magic │ uint32 │ Magic header │
/// │ Compiler │ byte[32] │ Compiler used │
/// │ Version │ byte[32] │ Compiler version │
/// ├──────────┼───────────────┼────────────────────────────────────────────┤
/// │ Reserve │ byte[2] │ Reserved for future extensions. Must be 0. │
/// │ Tokens │ MethodToken[] │ Method tokens. │
/// │ Reserve │ byte[2] │ Reserved for future extensions. Must be 0. │
/// │ Script │ byte[] │ Var bytes for the payload │
/// ├──────────┼───────────────┼────────────────────────────────────────────┤
/// │ Checksum │ uint32 │ First four bytes of double SHA256 hash │
/// └──────────┴───────────────┴────────────────────────────────────────────┘
/// </summary>
public class NefFile : ISerializable
{
Expand All @@ -35,6 +40,11 @@ public class NefFile : ISerializable
/// </summary>
public string Version { get; set; }

/// <summary>
/// Method tokens
/// </summary>
public MethodToken[] Tokens { get; set; }

/// <summary>
/// Script
/// </summary>
Expand All @@ -53,12 +63,18 @@ public class NefFile : ISerializable

public int Size =>
HeaderSize + // Header
2 + // Reserve
Tokens.GetVarSize() + // Tokens
2 + // Reserve
Script.GetVarSize() + // Script
sizeof(uint); // Checksum

public void Serialize(BinaryWriter writer)
{
SerializeHeader(writer);
writer.Write((short)0);
writer.Write(Tokens);
writer.Write((short)0);
writer.WriteVarBytes(Script ?? Array.Empty<byte>());
writer.Write(CheckSum);
}
Expand All @@ -78,6 +94,13 @@ public void Deserialize(BinaryReader reader)

Compiler = reader.ReadFixedString(32);
Version = reader.ReadFixedString(32);

if (reader.ReadUInt16() != 0) throw new FormatException("Reserved bytes must be 0");

Tokens = reader.ReadSerializableArray<MethodToken>(128);

if (reader.ReadUInt16() != 0) throw new FormatException("Reserved bytes must be 0");

Script = reader.ReadVarBytes(MaxScriptLength);
if (Script.Length == 0) throw new ArgumentException($"Script can't be empty");

Expand Down
2 changes: 2 additions & 0 deletions tests/neo.UnitTests/SmartContract/UT_Helper.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Neo.SmartContract;
using System;

namespace Neo.UnitTests.SmartContract
{
Expand All @@ -13,6 +14,7 @@ public void TestGetContractHash()
{
Compiler = "test",
Version = new System.Version().ToString(),
Tokens = Array.Empty<MethodToken>(),
Script = new byte[] { 1, 2, 3 }
};
nef.CheckSum = NefFile.ComputeChecksum(nef);
Expand Down
15 changes: 10 additions & 5 deletions tests/neo.UnitTests/SmartContract/UT_InteropService.NEO.cs
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,8 @@ public void TestContract_Create()
{
Script = new byte[byte.MaxValue],
Compiler = "",
Version = new Version(1, 2, 3, 4).ToString()
Version = new Version(1, 2, 3, 4).ToString(),
Tokens = System.Array.Empty<MethodToken>()
};
nef.CheckSum = NefFile.ComputeChecksum(nef);
var nefFile = nef.ToArray();
Expand All @@ -149,7 +150,8 @@ public void TestContract_Create()
{
Script = new byte[NefFile.MaxScriptLength - 1],
Compiler = "",
Version = new Version(1, 2, 3, 4).ToString()
Version = new Version(1, 2, 3, 4).ToString(),
Tokens = System.Array.Empty<MethodToken>()
};
script_exceedMaxLength.CheckSum = NefFile.ComputeChecksum(nef);
Assert.ThrowsException<InvalidOperationException>(() => snapshot.DeployContract(UInt160.Zero, script_exceedMaxLength.ToArray(), manifest.ToJson().ToByteArray(true)));
Expand Down Expand Up @@ -181,7 +183,8 @@ public void TestContract_Update()
{
Script = new byte[] { 0x01 },
Compiler = "",
Version = new Version(1, 2, 3, 4).ToString()
Version = new Version(1, 2, 3, 4).ToString(),
Tokens = System.Array.Empty<MethodToken>()
};
nef.CheckSum = NefFile.ComputeChecksum(nef);
Assert.ThrowsException<InvalidOperationException>(() => snapshot.UpdateContract(null, nef.ToArray(), new byte[0]));
Expand Down Expand Up @@ -232,7 +235,8 @@ public void TestContract_Update_Invalid()
{
Script = new byte[] { 0x01 },
Version = new Version(1, 2, 3, 4).ToString(),
Compiler = ""
Compiler = "",
Tokens = System.Array.Empty<MethodToken>()
};
nefFile.CheckSum = NefFile.ComputeChecksum(nefFile);

Expand All @@ -247,7 +251,8 @@ public void TestContract_Update_Invalid()
{
Script = new byte[0],
Version = new Version(1, 2, 3, 4).ToString(),
Compiler = ""
Compiler = "",
Tokens = System.Array.Empty<MethodToken>()
};
nefFile.CheckSum = NefFile.ComputeChecksum(nefFile);

Expand Down
51 changes: 51 additions & 0 deletions tests/neo.UnitTests/SmartContract/UT_MethodToken.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Neo.IO;
using Neo.SmartContract;
using System;

namespace Neo.UnitTests.SmartContract
{
[TestClass]
public class UT_MethodToken
{
[TestMethod]
public void TestSerialize()
{
var result = new MethodToken()
{
CallFlags = CallFlags.AllowCall,
Hash = UInt160.Parse("0xa400ff00ff00ff00ff00ff00ff00ff00ff00ff01"),
Method = "myMethod",
ParametersCount = 123,
RVCount = 456
};

var copy = result.ToArray().AsSerializable<MethodToken>();

Assert.AreEqual(CallFlags.AllowCall, copy.CallFlags);
Assert.AreEqual("0xa400ff00ff00ff00ff00ff00ff00ff00ff00ff01", copy.Hash.ToString());
Assert.AreEqual("myMethod", copy.Method);
Assert.AreEqual(123, copy.ParametersCount);
Assert.AreEqual(456, copy.RVCount);
}

[TestMethod]
public void TestSerializeErrors()
{
var result = new MethodToken()
{
CallFlags = (CallFlags)byte.MaxValue,
Hash = UInt160.Parse("0xa400ff00ff00ff00ff00ff00ff00ff00ff00ff01"),
Method = "myLongMethod",
ParametersCount = 123,
RVCount = 456
};

Assert.ThrowsException<FormatException>(() => result.ToArray().AsSerializable<MethodToken>());

result.CallFlags = CallFlags.All;
result.Method += "-123123123123123123123123";
Assert.ThrowsException<FormatException>(() => result.ToArray().AsSerializable<MethodToken>());
}
}
}
5 changes: 4 additions & 1 deletion tests/neo.UnitTests/SmartContract/UT_NefFile.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ public class UT_NefFile
{
Compiler = "".PadLeft(32, ' '),
Version = new Version(1, 2, 3, 4).ToString(),
Tokens = Array.Empty<MethodToken>(),
Script = new byte[] { 0x01, 0x02, 0x03 }
};

Expand Down Expand Up @@ -78,7 +79,7 @@ public void TestDeserialize()
[TestMethod]
public void TestGetSize()
{
file.Size.Should().Be(4 + 32 + 32 + 4 + 4);
file.Size.Should().Be(4 + 32 + 32 + 2 + 1 + 2 + 4 + 4);
}

[TestMethod]
Expand All @@ -88,6 +89,7 @@ public void ParseTest()
{
Compiler = "".PadLeft(32, ' '),
Version = new Version(1, 2, 3, 4).ToString(),
Tokens = Array.Empty<MethodToken>(),
Script = new byte[] { 0x01, 0x02, 0x03 }
};

Expand All @@ -108,6 +110,7 @@ public void LimitTest()
{
Compiler = "".PadLeft(byte.MaxValue, ' '),
Version = new Version(1, 2, 3, 4).ToString(),
Tokens = Array.Empty<MethodToken>(),
Script = new byte[1024 * 1024],
CheckSum = 0
};
Expand Down