Skip to content

Commit

Permalink
Add UInt160, UInt256 and ECPoint to SmartContract Framework (#362)
Browse files Browse the repository at this point in the history
  • Loading branch information
devhawk authored Nov 10, 2020
1 parent ff34e42 commit 6051662
Show file tree
Hide file tree
Showing 60 changed files with 459 additions and 152 deletions.
5 changes: 4 additions & 1 deletion src/Neo.Compiler.MSIL/Compiler.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
extern alias scfx;

using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.VisualBasic;
Expand All @@ -7,6 +9,7 @@
using System.Linq;
using System.Xml;
using System.Xml.Linq;
using scfxSmartContract = scfx.Neo.SmartContract.Framework.SmartContract;

namespace Neo.Compiler
{
Expand Down Expand Up @@ -200,7 +203,7 @@ private static MetadataReference[] CreateReferences(params string[] references)
MetadataReference.CreateFromFile(Path.Combine(coreDir, "System.Runtime.Numerics.dll")),
MetadataReference.CreateFromFile(typeof(System.ComponentModel.DisplayNameAttribute).Assembly.Location),
MetadataReference.CreateFromFile(typeof(object).Assembly.Location),
MetadataReference.CreateFromFile(typeof(SmartContract.Framework.SmartContract).Assembly.Location),
MetadataReference.CreateFromFile(typeof(scfxSmartContract).Assembly.Location),
});
refs.AddRange(references.Where(u => u != "Neo.SmartContract.Framework.dll").Select(u => MetadataReference.CreateFromFile(u)));
return refs.ToArray();
Expand Down
8 changes: 7 additions & 1 deletion src/Neo.Compiler.MSIL/FuncExport.cs
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
extern alias scfx;

using Mono.Cecil;
using Neo.IO.Json;
using Neo.SmartContract.Framework;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using IApiInterface = scfx.Neo.SmartContract.Framework.IApiInterface;
using ContractFeatures = scfx.Neo.SmartContract.Framework.ContractFeatures;

namespace Neo.Compiler
{
Expand Down Expand Up @@ -47,6 +50,9 @@ internal static string ConvType(TypeReference t)
case "IInteropInterface": return "InteropInterface";
case "System.Void": return "Void";
case "System.Object": return "Any";
case "Neo.UInt160": return "Hash160";
case "Neo.UInt256": return "Hash256";
case "Neo.Cryptography.ECC.ECPoint": return "PublicKey";
}

if (t.IsArray) return "Array";
Expand Down
55 changes: 29 additions & 26 deletions src/Neo.Compiler.MSIL/MSIL/Conv_Multi.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using Mono.Cecil;
using Neo.IO;
using Neo.SmartContract;
using System;
using System.Collections.Generic;
Expand Down Expand Up @@ -164,7 +165,7 @@ public bool IsSysCall(Mono.Cecil.MethodDefinition defs, out string name)
}
*/

public bool IsContractCall(Mono.Cecil.MethodDefinition defs, out byte[] hash)
public bool IsContractCall(Mono.Cecil.MethodDefinition defs, out UInt160 hash)
{
if (defs == null)
{
Expand All @@ -181,19 +182,12 @@ public bool IsContractCall(Mono.Cecil.MethodDefinition defs, out byte[] hash)
if (a.Type.FullName == "System.String")
{
string hashstr = (string)a.Value;

try
if (UInt160.TryParse(hashstr, out hash))
{
hash = hashstr.HexString2Bytes();
if (hash.Length != 20) throw new Exception("Wrong hash:" + hashstr);

hash = hash.Reverse().ToArray();
return true;
}
catch
{
throw new Exception("hex format error:" + hashstr);
}

throw new Exception("hex format error:" + hashstr);
}
else
{
Expand All @@ -202,12 +196,12 @@ public bool IsContractCall(Mono.Cecil.MethodDefinition defs, out byte[] hash)
{
throw new Exception("hash too short.");
}
hash = new byte[20];
var buffer = new byte[20];
for (var i = 0; i < 20; i++)
{
hash[i] = (byte)list[i].Value;
buffer[i] = (byte)list[i].Value;
}
hash = hash.Reverse().ToArray();
hash = new UInt160(buffer);
return true;
}
}
Expand Down Expand Up @@ -401,7 +395,7 @@ private int ConvertCall(OpCode src, NeoMethod to)
int calltype = 0;
string callname;
int callpcount = 0;
byte[] callhash = null;
UInt160 callhash = null;
VM.OpCode[] callcodes = null;
string[] calldata = null;

Expand Down Expand Up @@ -874,20 +868,28 @@ private int ConvertCall(OpCode src, NeoMethod to)
}
else if (calltype == 4)
{
// Package the arguments into an array.
ConvertPushNumber(pcount, null, to);
Convert1by1(VM.OpCode.PACK, null, to);
if (defs.IsGetter
&& defs.CustomAttributes.Any(a => a.AttributeType.FullName == "Neo.SmartContract.Framework.ContractHashAttribute"))
{
ConvertPushDataArray(callhash.ToArray(), src, to);
}
else
{
// Package the arguments into an array.
ConvertPushNumber(pcount, null, to);
Convert1by1(VM.OpCode.PACK, null, to);

// Push call method name, the first letter should be lowercase.
ConvertPushString(GetMethodName(defs.Body.Method), src, to);
// Push call method name, the first letter should be lowercase.
ConvertPushString(GetMethodName(defs.Body.Method), src, to);

// Push contract hash.
ConvertPushDataArray(callhash, src, to);
Insert1(VM.OpCode.SYSCALL, "", to, BitConverter.GetBytes(ApplicationEngine.System_Contract_Call));
// Push contract hash.
ConvertPushDataArray(callhash.ToArray(), src, to);
Insert1(VM.OpCode.SYSCALL, "", to, BitConverter.GetBytes(ApplicationEngine.System_Contract_Call));

// If the return type is void, insert a DROP.
if (defs.ReturnType.FullName is "System.Void")
Insert1(VM.OpCode.DROP, "", to);
// If the return type is void, insert a DROP.
if (defs.ReturnType.FullName is "System.Void")
Insert1(VM.OpCode.DROP, "", to);
}
}
else if (calltype == 5)
{
Expand Down Expand Up @@ -1451,6 +1453,7 @@ private int ConvertInitObj(OpCode src, NeoMethod to)
private int ConvertNewObj(ILMethod from, OpCode src, NeoMethod to)
{
var _type = (src.tokenUnknown as Mono.Cecil.MethodReference);

if (_type.FullName == "System.Void System.Numerics.BigInteger::.ctor(System.Byte[])")
{
return 0; // donothing;
Expand Down
4 changes: 2 additions & 2 deletions src/Neo.Compiler.MSIL/MSIL/Converter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -109,11 +109,11 @@ public NeoModule Convert(ILModule _in, ConvOption option = null)
nm.paramtypes.Add(new NeoParam(src.name, src.type));
}

if (IsContractCall(m.Value.method, out byte[] outcall))
if (IsContractCall(m.Value.method, out _))
continue;
if (IsNonCall(m.Value.method))
continue;
if (IsMixAttribute(m.Value.method, out VM.OpCode[] opcodes, out string[] opdata))
if (IsMixAttribute(m.Value.method, out _, out _))
continue;

if (m.Key.Contains("::Main("))
Expand Down
10 changes: 9 additions & 1 deletion src/Neo.Compiler.MSIL/Neo.Compiler.MSIL.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,14 @@
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\Neo.SmartContract.Framework\Neo.SmartContract.Framework.csproj" />
<ProjectReference Include="..\Neo.SmartContract.Framework\Neo.SmartContract.Framework.csproj">
<!--
The unified Neo domain model defines types with the same fully namespace qualified name
in different assemblies. Specifying a reference alias allows us to disambiguate types with
colliding names.
Official docs: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/extern-alias
-->
<Aliases>scfx</Aliases>
</ProjectReference>
</ItemGroup>
</Project>
10 changes: 10 additions & 0 deletions src/Neo.SmartContract.Framework/ContractHashAttribute.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
using System;

namespace Neo.SmartContract.Framework
{
[AttributeUsage(AttributeTargets.Method, AllowMultiple = false)]
internal class ContractHashAttribute : Attribute
{

}
}
28 changes: 28 additions & 0 deletions src/Neo.SmartContract.Framework/ECPoint.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
using Neo.SmartContract.Framework;

namespace Neo.Cryptography.ECC
{
public class ECPoint
{
[OpCode(OpCode.CONVERT, StackItemType.ByteString)]
[OpCode(OpCode.DUP)]
[OpCode(OpCode.SIZE)]
[OpCode(OpCode.PUSHINT8, "21")] // 0x21 == 33 bytes expected array size
[OpCode(OpCode.NUMEQUAL)]
[OpCode(OpCode.ASSERT)]
public static extern explicit operator ECPoint(byte[] value);

[OpCode(OpCode.DUP)]
[OpCode(OpCode.SIZE)]
[OpCode(OpCode.PUSHINT8, "21")] // 0x21 == 33 bytes expected array size
[OpCode(OpCode.NUMEQUAL)]
[OpCode(OpCode.ASSERT)]
public static extern explicit operator ECPoint(ByteString value);

[OpCode(OpCode.CONVERT, StackItemType.Buffer)]
public static extern explicit operator byte[](ECPoint value);

[Script]
public static extern implicit operator ByteString(ECPoint value);
}
}
2 changes: 1 addition & 1 deletion src/Neo.SmartContract.Framework/Helper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -193,7 +193,7 @@ public static byte ToByte(this int source)
/// Example: "AFsCjUGzicZmXQtWpwVt6hNeJTBwSipJMS".ToScriptHash() generates 0102030405060708090a0b0c0d0e0faabbccddee
/// </summary>
[NonemitWithConvert(ConvertMethod.ToScriptHash)]
public extern static byte[] ToScriptHash(this string address);
public extern static UInt160 ToScriptHash(this string address);

[NonemitWithConvert(ConvertMethod.ToBigInteger)]
public extern static BigInteger ToBigInteger(this string text);
Expand Down
2 changes: 1 addition & 1 deletion src/Neo.SmartContract.Framework/Services/Neo/Account.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,6 @@ namespace Neo.SmartContract.Framework.Services.Neo
public class Account
{
[Syscall("System.Contract.IsStandard")]
public static extern bool IsStandard(byte[] scripthash);
public static extern bool IsStandard(UInt160 scripthash);
}
}
8 changes: 4 additions & 4 deletions src/Neo.SmartContract.Framework/Services/Neo/Block.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,13 @@ namespace Neo.SmartContract.Framework.Services.Neo
{
public class Block
{
public readonly byte[] Hash;
public readonly UInt256 Hash;
public readonly uint Version;
public readonly byte[] PrevHash;
public readonly byte[] MerkleRoot;
public readonly UInt256 PrevHash;
public readonly UInt256 MerkleRoot;
public readonly ulong Timestamp;
public readonly uint Index;
public readonly byte[] NextConsensus;
public readonly UInt160 NextConsensus;
public readonly int TransactionsCount;
}
}
10 changes: 5 additions & 5 deletions src/Neo.SmartContract.Framework/Services/Neo/Blockchain.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,21 +11,21 @@ public static class Blockchain
public static extern Block GetBlock(uint height);

[Syscall("System.Blockchain.GetBlock")]
public static extern Block GetBlock(byte[] hash);
public static extern Block GetBlock(UInt256 hash);

[Syscall("System.Blockchain.GetTransaction")]
public static extern Transaction GetTransaction(byte[] hash);
public static extern Transaction GetTransaction(UInt256 hash);

[Syscall("System.Blockchain.GetTransactionFromBlock")]
public static extern Transaction GetTransactionFromBlock(byte[] blockHash, int txIndex);
public static extern Transaction GetTransactionFromBlock(UInt256 blockHash, int txIndex);

[Syscall("System.Blockchain.GetTransactionFromBlock")]
public static extern Transaction GetTransactionFromBlock(uint blockIndex, int txIndex);

[Syscall("System.Blockchain.GetTransactionHeight")]
public static extern BigInteger GetTransactionHeight(byte[] hash);
public static extern BigInteger GetTransactionHeight(UInt256 hash);

[Syscall("System.Blockchain.GetContract")]
public static extern Contract GetContract(byte[] script_hash);
public static extern Contract GetContract(UInt160 script_hash);
}
}
6 changes: 3 additions & 3 deletions src/Neo.SmartContract.Framework/Services/Neo/Contract.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,10 @@ public class Contract
public readonly bool IsPayable;

[Syscall("System.Contract.Call")]
public static extern object Call(byte[] scriptHash, string method, object[] arguments);
public static extern object Call(UInt160 scriptHash, string method, object[] arguments);

[Syscall("System.Contract.CallEx")]
public static extern object CallEx(byte[] scriptHash, string method, object[] arguments, CallFlags flag);
public static extern object CallEx(UInt160 scriptHash, string method, object[] arguments, CallFlags flag);

[Syscall("System.Contract.Create")]
public static extern Contract Create(byte[] script, string manifest);
Expand All @@ -41,6 +41,6 @@ public class Contract
public static extern byte GetCallFlags();

[Syscall("System.Contract.CreateStandardAccount")]
public static extern byte[] CreateStandardAccount(byte[] pubKey);
public static extern UInt160 CreateStandardAccount(Cryptography.ECC.ECPoint pubKey);
}
}
8 changes: 4 additions & 4 deletions src/Neo.SmartContract.Framework/Services/Neo/Crypto.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,19 +21,19 @@ public static class ECDsa
public static class Secp256r1
{
[Syscall("Neo.Crypto.VerifyWithECDsaSecp256r1")]
public extern static bool Verify(byte[] message, byte[] pubkey, byte[] signature);
public extern static bool Verify(byte[] message, Cryptography.ECC.ECPoint pubkey, byte[] signature);

[Syscall("Neo.Crypto.CheckMultisigWithECDsaSecp256r1")]
public extern static bool CheckMultiSig(byte[] message, byte[][] pubkey, byte[][] signature);
public extern static bool CheckMultiSig(byte[] message, Cryptography.ECC.ECPoint[] pubkey, byte[][] signature);
}

public static class Secp256k1
{
[Syscall("Neo.Crypto.VerifyWithECDsaSecp256k1")]
public extern static bool Verify(byte[] message, byte[] pubkey, byte[] signature);
public extern static bool Verify(byte[] message, Cryptography.ECC.ECPoint pubkey, byte[] signature);

[Syscall("Neo.Crypto.CheckMultisigWithECDsaSecp256k1")]
public extern static bool CheckMultiSig(byte[] message, byte[][] pubkey, byte[][] signature);
public extern static bool CheckMultiSig(byte[] message, Cryptography.ECC.ECPoint[] pubkey, byte[][] signature);
}
}
}
Expand Down
3 changes: 2 additions & 1 deletion src/Neo.SmartContract.Framework/Services/Neo/Designation.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ namespace Neo.SmartContract.Framework.Services.Neo
[Contract("0x763afecf3ebba0a67568a2c8be06e8f068c62666")]
public class Designation
{
public static extern UInt160 Hash { [ContractHash] get; }
public static extern string Name { get; }
public static extern byte[][] GetDesignatedByRole(DesignationRole role);
public static extern Cryptography.ECC.ECPoint[] GetDesignatedByRole(DesignationRole role);
}
}
5 changes: 3 additions & 2 deletions src/Neo.SmartContract.Framework/Services/Neo/GAS.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,12 @@ namespace Neo.SmartContract.Framework.Services.Neo
[Contract("0x668e0c1f9d7b70a99dd9e06eadd4c784d641afbc")]
public class GAS
{
public static extern UInt160 Hash { [ContractHash] get; }
public static extern string Name { get; }
public static extern string Symbol { get; }
public static extern byte Decimals { get; }
public static extern BigInteger TotalSupply();
public static extern BigInteger BalanceOf(byte[] account);
public static extern bool Transfer(byte[] from, byte[] to, BigInteger amount);
public static extern BigInteger BalanceOf(UInt160 account);
public static extern bool Transfer(UInt160 from, UInt160 to, BigInteger amount);
}
}
Loading

0 comments on commit 6051662

Please sign in to comment.