From c6ff7b8980ca63ece8290866a873439e6f8e9720 Mon Sep 17 00:00:00 2001 From: lights Date: Tue, 21 Jan 2020 19:32:09 +0800 Subject: [PATCH 01/19] parseTryCatch --- src/Neo.Compiler.MSIL/MSIL/Converter.cs | 85 +++++++-- src/Neo.Compiler.MSIL/MSIL/ILModule.cs | 169 +++++++++++++++++- .../TestClasses/Contract_TryCatch.cs | 24 +++ .../UnitTest_TryCatch.cs | 28 +++ 4 files changed, 295 insertions(+), 11 deletions(-) create mode 100644 tests/Neo.Compiler.MSIL.UnitTests/TestClasses/Contract_TryCatch.cs create mode 100644 tests/Neo.Compiler.MSIL.UnitTests/UnitTest_TryCatch.cs diff --git a/src/Neo.Compiler.MSIL/MSIL/Converter.cs b/src/Neo.Compiler.MSIL/MSIL/Converter.cs index 2d869eee2..41fc14e1e 100644 --- a/src/Neo.Compiler.MSIL/MSIL/Converter.cs +++ b/src/Neo.Compiler.MSIL/MSIL/Converter.cs @@ -520,17 +520,32 @@ private void ConvertAddrInMethod(NeoMethod to) { if (c.needfix) { - - try + if (c.code == VM.OpCode.TRY_L) { - var _addr = addrconv[c.srcaddr]; - Int32 addroff = (Int32)(_addr - c.addr); - c.bytes = BitConverter.GetBytes(addroff); - c.needfix = false; + var srcCatch = BitConverter.ToInt32(c.bytes, 0); + var srcFinal = BitConverter.ToInt32(c.bytes, 4); + var _addrCatch = addrconv[srcCatch]; + Int32 addroffCatch = (Int32)(_addrCatch - c.addr); + var _addrFinal = addrconv[srcFinal]; + Int32 addroffFinal = (Int32)(_addrFinal - c.addr); + var bytesCatch = BitConverter.GetBytes(addroffCatch); + var bytesFinal = BitConverter.GetBytes(addroffFinal); + Array.Copy(bytesCatch, 0, c.bytes, 0, 4); + Array.Copy(bytesFinal, 0, c.bytes, 4, 4); } - catch + else { - throw new Exception("cannot convert addr in: " + to.name + "\r\n"); + try + { + var _addr = addrconv[c.srcaddr]; + Int32 addroff = (Int32)(_addr - c.addr); + c.bytes = BitConverter.GetBytes(addroff); + c.needfix = false; + } + catch + { + throw new Exception("cannot convert addr in: " + to.name + "\r\n"); + } } } } @@ -538,6 +553,28 @@ private void ConvertAddrInMethod(NeoMethod to) private int ConvertCode(ILMethod method, OpCode src, NeoMethod to) { + //add try code + if (method.tryPositions.Contains(src.addr)) + { + foreach (var info in method.tryInfos) + { + if (info.addr_Try_Begin == src.addr) + { + var bytesFinally = BitConverter.GetBytes(info.addr_Finally_Begin); + if (info.catch_Infos.Count != 1) + throw new Exception("only support one catch for now."); + var first = info.catch_Infos.First().Value; + var bytesCatch = BitConverter.GetBytes(first.addrBegin); + var buf = new byte[8]; + Array.Copy(bytesCatch, 0, buf, 0, 4); + Array.Copy(bytesFinally, 0, buf, 4, 4); + var trycode = _Convert1by1(VM.OpCode.TRY_L, src, to, buf); + trycode.needfix = true; + + } + + } + } int skipcount = 0; switch (src.code) { @@ -654,14 +691,42 @@ private int ConvertCode(ILMethod method, OpCode src, NeoMethod to) //需要地址轉換的情況 case CodeEx.Br: case CodeEx.Br_S: - case CodeEx.Leave: - case CodeEx.Leave_S: { var code = _Convert1by1(VM.OpCode.JMP_L, src, to, new byte[] { 0, 0, 0, 0 }); code.needfix = true; code.srcaddr = src.tokenAddr_Index; } + break; + case CodeEx.Leave: + case CodeEx.Leave_S: + {//will support try catch + if (method.IsTryCode(src.addr)) + { + _Convert1by1(VM.OpCode.ENDT, src, to); + } + else + { + ILCatchInfo catchinfo = method.GetCatchInfo(src.addr); + if (catchinfo != null) + { + _Convert1by1(VM.OpCode.ENDC, src, to); + } + else + { + //maybe is in finally try ,just jump. + } + } + var code = _Convert1by1(VM.OpCode.JMP_L, src, to, new byte[] { 0, 0, 0, 0 }); + code.needfix = true; + code.srcaddr = src.tokenAddr_Index; + } + break; + case CodeEx.Endfinally: + { + //need vm add these opcodes + var code = _Convert1by1(VM.OpCode.ENDF, src, to); + } break; case CodeEx.Switch: { diff --git a/src/Neo.Compiler.MSIL/MSIL/ILModule.cs b/src/Neo.Compiler.MSIL/MSIL/ILModule.cs index cafc26fdd..a9f3d124e 100644 --- a/src/Neo.Compiler.MSIL/MSIL/ILModule.cs +++ b/src/Neo.Compiler.MSIL/MSIL/ILModule.cs @@ -196,6 +196,20 @@ public override string ToString() return type; } } + public class ILCatchInfo + { + public int addrBegin; + public int addrEnd; + public string catchType; + } + public class ILTryInfo + { + public int addr_Try_Begin = -1; + public int addr_Try_End = -1; + public Dictionary catch_Infos = new Dictionary(); + public int addr_Finally_Begin = -1; + public int addr_Finally_End = -1; + } public class ILMethod { @@ -207,7 +221,8 @@ public class ILMethod public List body_Variables = new List(); public SortedDictionary body_Codes = new SortedDictionary(); public string fail = null; - + public List tryInfos = new List(); + public List tryPositions = new List(); public ILMethod(ILType type, Mono.Cecil.MethodDefinition method, ILogger logger = null) { this.type = type; @@ -268,8 +283,160 @@ public ILMethod(ILType type, Mono.Cecil.MethodDefinition method, ILogger logger c.InitToken(code.Operand); this.body_Codes.Add(c.addr, c); } + if (method.Body.HasExceptionHandlers) + { + var mapTryInfos = new Dictionary(); + foreach (var e in method.Body.ExceptionHandlers) + { + if (e.HandlerType == Mono.Cecil.Cil.ExceptionHandlerType.Catch) + { + var key = e.TryStart.Offset + "_" + e.TryEnd.Offset; + if (mapTryInfos.ContainsKey(key) == false) + mapTryInfos[key] = new ILTryInfo(); + + var tryinfo = mapTryInfos[key]; + tryinfo.addr_Try_Begin = e.TryStart.Offset; + tryinfo.addr_Try_End = e.TryEnd.Offset; + + + var catchtypestr = e.CatchType.FullName; + + tryinfo.catch_Infos[catchtypestr] = new ILCatchInfo() + { + addrBegin = e.HandlerStart.Offset, + addrEnd = e.HandlerEnd.Offset, + catchType = catchtypestr + }; + + } + else if (e.HandlerType == Mono.Cecil.Cil.ExceptionHandlerType.Finally) + { + int start = e.TryStart.Offset; + int end = e.TryEnd.Offset; + Mono.Cecil.Cil.ExceptionHandler handler = null; + foreach (var tryinfocatch in method.Body.ExceptionHandlers) + { + if (tryinfocatch.HandlerType == Mono.Cecil.Cil.ExceptionHandlerType.Catch && tryinfocatch.TryStart.Offset == e.TryStart.Offset && tryinfocatch.TryEnd.Offset <= e.TryEnd.Offset) + {//find include catch element. + if (handler == null) + handler = tryinfocatch; + else if (handler.TryEnd.Offset < tryinfocatch.TryEnd.Offset) + handler = tryinfocatch; + } + } + if (handler != null) + { + start = handler.TryStart.Offset; + end = handler.TryEnd.Offset; + } + + var key = start + "_" + end; + + if (mapTryInfos.ContainsKey(key) == false) + mapTryInfos[key] = new ILTryInfo(); + + var tryinfo = mapTryInfos[key]; + tryinfo.addr_Try_Begin = start; + tryinfo.addr_Try_End = end; + + + tryinfo.addr_Finally_Begin = e.HandlerStart.Offset; + tryinfo.addr_Finally_End = e.HandlerEnd.Offset; + } + else + { + throw new Exception("not support yet." + e.HandlerType); + } + } + this.tryInfos = new List(mapTryInfos.Values); + foreach (var info in this.tryInfos) + { + if (this.tryPositions.Contains(info.addr_Try_Begin) == false) + this.tryPositions.Add(info.addr_Try_Begin); + } + } + } + } + } + public ILTryInfo GetTryInfo(int addr) + { + ILTryInfo last = null; + int begin = -1; + int end = -1; + foreach (var info in tryInfos) + { + //find match try + if (info.addr_Try_Begin <= addr && addr <= info.addr_Try_End) + { + if (last == null) + { + last = info; + begin = info.addr_Try_Begin; + end = last.addr_Try_End; + } + else if (begin <= info.addr_Try_Begin && last.addr_Try_End <= end) + { + last = info; + begin = info.addr_Try_Begin; + end = last.addr_Try_End; + } + } + //find match finally + if (info.addr_Finally_Begin <= addr && addr <= info.addr_Finally_End) + { + if (last == null) + { + last = info; + begin = info.addr_Finally_Begin; + end = last.addr_Finally_End; + } + else if (begin <= info.addr_Finally_Begin && last.addr_Finally_End <= end) + { + last = info; + begin = info.addr_Finally_Begin; + end = last.addr_Finally_End; + } + } + //find match catch + foreach (var c in info.catch_Infos) + { + if (c.Value.addrBegin <= addr && addr <= c.Value.addrEnd) + { + if (last == null) + { + last = info; + begin = c.Value.addrBegin; + end = c.Value.addrEnd; + } + else if (begin <= c.Value.addrBegin && c.Value.addrBegin <= end) + { + last = info; + begin = c.Value.addrBegin; + end = c.Value.addrEnd; + } + } } } + return last; + } + public bool IsTryCode(int addr) + { + ILTryInfo info = GetTryInfo(addr); + if (info == null) + return false; + return info.addr_Try_Begin <= addr && addr <= info.addr_Try_End; + } + public ILCatchInfo GetCatchInfo(int addr) + { + ILTryInfo info = GetTryInfo(addr); + if (info == null) + return null; + foreach (var c in info.catch_Infos) + { + if (c.Value.addrBegin <= addr && addr <= c.Value.addrEnd) + return c.Value; + } + return null; } public int GetLastCodeAddr(int srcaddr) { diff --git a/tests/Neo.Compiler.MSIL.UnitTests/TestClasses/Contract_TryCatch.cs b/tests/Neo.Compiler.MSIL.UnitTests/TestClasses/Contract_TryCatch.cs new file mode 100644 index 000000000..ac8d51a12 --- /dev/null +++ b/tests/Neo.Compiler.MSIL.UnitTests/TestClasses/Contract_TryCatch.cs @@ -0,0 +1,24 @@ +namespace Neo.Compiler.MSIL.TestClasses +{ + class Contract_shift : SmartContract.Framework.SmartContract + { + public static object Main(string method, object[] args) + { + int v = 0; + try + { + v = 2; + return v; + } + catch + { + v = 3; + } + finally + { + v++; + } + return v; + } + } +} diff --git a/tests/Neo.Compiler.MSIL.UnitTests/UnitTest_TryCatch.cs b/tests/Neo.Compiler.MSIL.UnitTests/UnitTest_TryCatch.cs new file mode 100644 index 000000000..ee896a911 --- /dev/null +++ b/tests/Neo.Compiler.MSIL.UnitTests/UnitTest_TryCatch.cs @@ -0,0 +1,28 @@ +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Neo.Compiler.MSIL.Utils; +using Neo.SmartContract; +using System; +using System.Collections.Generic; +using System.Numerics; + +namespace Neo.Compiler.MSIL +{ + [TestClass] + public class UnitTest_TryCatch + { + [TestMethod] + public void Test_TryCatch() + { + var testengine = new TestEngine(); + testengine.AddEntryScript("./TestClasses/Contract_TryCatch.cs"); + testengine.ScriptEntry.DumpNEF(); + var result = testengine.ExecuteTestCaseStandard("testfunc"); + Console.WriteLine("state=" + testengine.State + " result on stack= " + result.Count); + var value = result.Pop(); + Console.WriteLine("result:" + value.Type + " "+ value.ToString()); + + } + + + } +} From f4d9e682b77a4781d344164dc6d7c90a9951f178 Mon Sep 17 00:00:00 2001 From: lights Date: Tue, 21 Jan 2020 19:38:32 +0800 Subject: [PATCH 02/19] fix try endpos problem --- src/Neo.Compiler.MSIL/MSIL/ILModule.cs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Neo.Compiler.MSIL/MSIL/ILModule.cs b/src/Neo.Compiler.MSIL/MSIL/ILModule.cs index a9f3d124e..92ee3cc53 100644 --- a/src/Neo.Compiler.MSIL/MSIL/ILModule.cs +++ b/src/Neo.Compiler.MSIL/MSIL/ILModule.cs @@ -366,7 +366,7 @@ public ILTryInfo GetTryInfo(int addr) foreach (var info in tryInfos) { //find match try - if (info.addr_Try_Begin <= addr && addr <= info.addr_Try_End) + if (info.addr_Try_Begin <= addr && addr < info.addr_Try_End) { if (last == null) { @@ -382,7 +382,7 @@ public ILTryInfo GetTryInfo(int addr) } } //find match finally - if (info.addr_Finally_Begin <= addr && addr <= info.addr_Finally_End) + if (info.addr_Finally_Begin <= addr && addr < info.addr_Finally_End) { if (last == null) { @@ -390,7 +390,7 @@ public ILTryInfo GetTryInfo(int addr) begin = info.addr_Finally_Begin; end = last.addr_Finally_End; } - else if (begin <= info.addr_Finally_Begin && last.addr_Finally_End <= end) + else if (begin <= info.addr_Finally_Begin && last.addr_Finally_End < end) { last = info; begin = info.addr_Finally_Begin; @@ -400,7 +400,7 @@ public ILTryInfo GetTryInfo(int addr) //find match catch foreach (var c in info.catch_Infos) { - if (c.Value.addrBegin <= addr && addr <= c.Value.addrEnd) + if (c.Value.addrBegin <= addr && addr < c.Value.addrEnd) { if (last == null) { @@ -408,7 +408,7 @@ public ILTryInfo GetTryInfo(int addr) begin = c.Value.addrBegin; end = c.Value.addrEnd; } - else if (begin <= c.Value.addrBegin && c.Value.addrBegin <= end) + else if (begin <= c.Value.addrBegin && c.Value.addrBegin < end) { last = info; begin = c.Value.addrBegin; From ceb4bda30debc362abc646c1ebf7064c50ffdcdf Mon Sep 17 00:00:00 2001 From: lights Date: Tue, 21 Jan 2020 19:45:56 +0800 Subject: [PATCH 03/19] add parse code for no catch and no finally --- src/Neo.Compiler.MSIL/MSIL/Converter.cs | 32 ++++++++++++++++++------- 1 file changed, 24 insertions(+), 8 deletions(-) diff --git a/src/Neo.Compiler.MSIL/MSIL/Converter.cs b/src/Neo.Compiler.MSIL/MSIL/Converter.cs index 41fc14e1e..0013a4898 100644 --- a/src/Neo.Compiler.MSIL/MSIL/Converter.cs +++ b/src/Neo.Compiler.MSIL/MSIL/Converter.cs @@ -524,14 +524,30 @@ private void ConvertAddrInMethod(NeoMethod to) { var srcCatch = BitConverter.ToInt32(c.bytes, 0); var srcFinal = BitConverter.ToInt32(c.bytes, 4); - var _addrCatch = addrconv[srcCatch]; - Int32 addroffCatch = (Int32)(_addrCatch - c.addr); - var _addrFinal = addrconv[srcFinal]; - Int32 addroffFinal = (Int32)(_addrFinal - c.addr); - var bytesCatch = BitConverter.GetBytes(addroffCatch); - var bytesFinal = BitConverter.GetBytes(addroffFinal); - Array.Copy(bytesCatch, 0, c.bytes, 0, 4); - Array.Copy(bytesFinal, 0, c.bytes, 4, 4); + if(srcCatch==-1) + { + var bytesCatch = new byte[0, 0, 0, 0]; + Array.Copy(bytesCatch, 0, c.bytes, 0, 4); + } + else + { + var _addrCatch = addrconv[srcCatch]; + Int32 addroffCatch = (Int32)(_addrCatch - c.addr); + var bytesCatch = BitConverter.GetBytes(addroffCatch); + Array.Copy(bytesCatch, 0, c.bytes, 0, 4); + } + if (srcFinal == -1) + { + var bytesFinal = new byte[0, 0, 0, 0]; + Array.Copy(bytesFinal, 0, c.bytes, 4, 4); + } + else + { + var _addrFinal = addrconv[srcFinal]; + Int32 addroffFinal = (Int32)(_addrFinal - c.addr); + var bytesFinal = BitConverter.GetBytes(addroffFinal); + Array.Copy(bytesFinal, 0, c.bytes, 4, 4); + } } else { From b2bfc7987e552a533c247a2e5315c096ecb1914a Mon Sep 17 00:00:00 2001 From: lights Date: Mon, 17 Feb 2020 01:59:09 +0800 Subject: [PATCH 04/19] update trycatch --- src/Neo.Compiler.MSIL/MSIL/Conv_Multi.cs | 17 ++++++++++++-- .../Neo.Compiler.MSIL.csproj | 2 +- .../Neo.Compiler.MSIL.UnitTests.csproj | 12 +++++++++- .../TestClasses/Contract_TryCatch.cs | 22 +++++++++++++++++-- .../UnitTest_TryCatch.cs | 22 ++++++++++++++++--- .../Utils/TestEngine.cs | 5 +++++ 6 files changed, 71 insertions(+), 9 deletions(-) diff --git a/src/Neo.Compiler.MSIL/MSIL/Conv_Multi.cs b/src/Neo.Compiler.MSIL/MSIL/Conv_Multi.cs index 115d0d7a2..42713eda7 100644 --- a/src/Neo.Compiler.MSIL/MSIL/Conv_Multi.cs +++ b/src/Neo.Compiler.MSIL/MSIL/Conv_Multi.cs @@ -1348,11 +1348,24 @@ private int _ConvertNewObj(OpCode src, NeoMethod to) } else if (_type.DeclaringType.FullName.Contains("Exception")) { + //对异常对象要留一个,因为catch 会处理这个栈 _Convert1by1(VM.OpCode.NOP, src, to);//空白 var pcount = _type.Parameters.Count; - for (var i = 0; i < pcount; i++) + if (pcount == 0)//沒參數插一個 { - _Insert1(VM.OpCode.DROP, "", to); + var data = System.Text.Encoding.UTF8.GetBytes("usererror"); + _ConvertPush(data, src, to); + } + else if (pcount == 1) + { + + } + else + {//對異常對象保留第一個參數 + for (var i = 0; i < pcount - 1; i++) + { + _Insert1(VM.OpCode.DROP, "", to); + } } return 0; } diff --git a/src/Neo.Compiler.MSIL/Neo.Compiler.MSIL.csproj b/src/Neo.Compiler.MSIL/Neo.Compiler.MSIL.csproj index 79b0a2c4c..7e5f31ad2 100644 --- a/src/Neo.Compiler.MSIL/Neo.Compiler.MSIL.csproj +++ b/src/Neo.Compiler.MSIL/Neo.Compiler.MSIL.csproj @@ -26,10 +26,10 @@ - + diff --git a/tests/Neo.Compiler.MSIL.UnitTests/Neo.Compiler.MSIL.UnitTests.csproj b/tests/Neo.Compiler.MSIL.UnitTests/Neo.Compiler.MSIL.UnitTests.csproj index d2dbda3b9..844c97ada 100644 --- a/tests/Neo.Compiler.MSIL.UnitTests/Neo.Compiler.MSIL.UnitTests.csproj +++ b/tests/Neo.Compiler.MSIL.UnitTests/Neo.Compiler.MSIL.UnitTests.csproj @@ -1,4 +1,4 @@ - + netcoreapp3.1 @@ -25,4 +25,14 @@ + + + + + + + PreserveNewest + + + diff --git a/tests/Neo.Compiler.MSIL.UnitTests/TestClasses/Contract_TryCatch.cs b/tests/Neo.Compiler.MSIL.UnitTests/TestClasses/Contract_TryCatch.cs index ac8d51a12..06b8ceff1 100644 --- a/tests/Neo.Compiler.MSIL.UnitTests/TestClasses/Contract_TryCatch.cs +++ b/tests/Neo.Compiler.MSIL.UnitTests/TestClasses/Contract_TryCatch.cs @@ -2,13 +2,31 @@ namespace Neo.Compiler.MSIL.TestClasses { class Contract_shift : SmartContract.Framework.SmartContract { - public static object Main(string method, object[] args) + public static object try01() { int v = 0; try { v = 2; - return v; + } + catch + { + v = 3; + } + finally + { + v++; + } + return v; + } + + public static object try02() + { + int v = 0; + try + { + v = 2; + throw new System.Exception(); } catch { diff --git a/tests/Neo.Compiler.MSIL.UnitTests/UnitTest_TryCatch.cs b/tests/Neo.Compiler.MSIL.UnitTests/UnitTest_TryCatch.cs index ee896a911..084150e8a 100644 --- a/tests/Neo.Compiler.MSIL.UnitTests/UnitTest_TryCatch.cs +++ b/tests/Neo.Compiler.MSIL.UnitTests/UnitTest_TryCatch.cs @@ -11,18 +11,34 @@ namespace Neo.Compiler.MSIL public class UnitTest_TryCatch { [TestMethod] - public void Test_TryCatch() + public void Test_TryCatch_Succ() { var testengine = new TestEngine(); testengine.AddEntryScript("./TestClasses/Contract_TryCatch.cs"); testengine.ScriptEntry.DumpNEF(); - var result = testengine.ExecuteTestCaseStandard("testfunc"); + var result = testengine.ExecuteTestCaseStandard("try01"); Console.WriteLine("state=" + testengine.State + " result on stack= " + result.Count); var value = result.Pop(); Console.WriteLine("result:" + value.Type + " "+ value.ToString()); - + var num = value as Neo.VM.Types.Integer; + Console.WriteLine("result = " + num.ToBigInteger().ToString()); + Assert.AreEqual(num.ToBigInteger(), 3); } + [TestMethod] + public void Test_TryCatch_Throw() + { + var testengine = new TestEngine(); + testengine.AddEntryScript("./TestClasses/Contract_TryCatch.cs"); + testengine.ScriptEntry.DumpNEF(); + var result = testengine.ExecuteTestCaseStandard("try02"); + Console.WriteLine("state=" + testengine.State + " result on stack= " + result.Count); + var value = result.Pop(); + Console.WriteLine("result:" + value.Type + " " + value.ToString()); + var num = value as Neo.VM.Types.Integer; + Console.WriteLine("result = " + num.ToBigInteger().ToString()); + Assert.AreEqual(num.ToBigInteger(), 4); + } } } diff --git a/tests/Neo.Compiler.MSIL.UnitTests/Utils/TestEngine.cs b/tests/Neo.Compiler.MSIL.UnitTests/Utils/TestEngine.cs index 34d34695a..d2e133fcb 100644 --- a/tests/Neo.Compiler.MSIL.UnitTests/Utils/TestEngine.cs +++ b/tests/Neo.Compiler.MSIL.UnitTests/Utils/TestEngine.cs @@ -10,6 +10,11 @@ namespace Neo.Compiler.MSIL.Utils { public class TestEngine : ApplicationEngine { + protected override bool PreExecuteInstruction() + { + return true; + } + public static InteropDescriptor Native_Deploy; static TestEngine() From 827a8858718269dd88bc48b6c2e1badc39797dc5 Mon Sep 17 00:00:00 2001 From: lights Date: Wed, 26 Feb 2020 20:45:36 +0800 Subject: [PATCH 05/19] add a unittest --- .../TestClasses/Contract_TryCatch.cs | 22 +++++++++++++++++++ .../UnitTest_TryCatch.cs | 15 ++++++++++++- 2 files changed, 36 insertions(+), 1 deletion(-) diff --git a/tests/Neo.Compiler.MSIL.UnitTests/TestClasses/Contract_TryCatch.cs b/tests/Neo.Compiler.MSIL.UnitTests/TestClasses/Contract_TryCatch.cs index 06b8ceff1..b42e5d0f9 100644 --- a/tests/Neo.Compiler.MSIL.UnitTests/TestClasses/Contract_TryCatch.cs +++ b/tests/Neo.Compiler.MSIL.UnitTests/TestClasses/Contract_TryCatch.cs @@ -38,5 +38,27 @@ public static object try02() } return v; } + public static object throwcall() + { + throw new System.Exception(); + } + public static object try03() + { + int v = 0; + try + { + v = 2; + throwcall(); + } + catch + { + v = 3; + } + finally + { + v++; + } + return v; + } } } diff --git a/tests/Neo.Compiler.MSIL.UnitTests/UnitTest_TryCatch.cs b/tests/Neo.Compiler.MSIL.UnitTests/UnitTest_TryCatch.cs index 084150e8a..34cf96df1 100644 --- a/tests/Neo.Compiler.MSIL.UnitTests/UnitTest_TryCatch.cs +++ b/tests/Neo.Compiler.MSIL.UnitTests/UnitTest_TryCatch.cs @@ -24,7 +24,20 @@ public void Test_TryCatch_Succ() Console.WriteLine("result = " + num.ToBigInteger().ToString()); Assert.AreEqual(num.ToBigInteger(), 3); } - + [TestMethod] + public void Test_TryCatch_ThrowByCall() + { + var testengine = new TestEngine(); + testengine.AddEntryScript("./TestClasses/Contract_TryCatch.cs"); + testengine.ScriptEntry.DumpNEF(); + var result = testengine.ExecuteTestCaseStandard("try03"); + Console.WriteLine("state=" + testengine.State + " result on stack= " + result.Count); + var value = result.Pop(); + Console.WriteLine("result:" + value.Type + " " + value.ToString()); + var num = value as Neo.VM.Types.Integer; + Console.WriteLine("result = " + num.ToBigInteger().ToString()); + Assert.AreEqual(num.ToBigInteger(), 4); + } [TestMethod] public void Test_TryCatch_Throw() { From 782f62c67f10a41f023ea304226ce61e8a8e9d66 Mon Sep 17 00:00:00 2001 From: lights Date: Thu, 16 Apr 2020 09:51:23 +0800 Subject: [PATCH 06/19] fix compile error on compiler --- src/Neo.Compiler.MSIL/MSIL/Conv_Multi.cs | 3 +- src/Neo.Compiler.MSIL/MSIL/Converter.cs | 42 ++++++++++--------- .../Neo.Compiler.MSIL.csproj | 3 +- 3 files changed, 25 insertions(+), 23 deletions(-) diff --git a/src/Neo.Compiler.MSIL/MSIL/Conv_Multi.cs b/src/Neo.Compiler.MSIL/MSIL/Conv_Multi.cs index 7cdb2c495..84d2bc303 100644 --- a/src/Neo.Compiler.MSIL/MSIL/Conv_Multi.cs +++ b/src/Neo.Compiler.MSIL/MSIL/Conv_Multi.cs @@ -1317,8 +1317,7 @@ private int ConvertNewObj(ILMethod from, OpCode src, NeoMethod to) var pcount = _type.Parameters.Count; if (pcount == 0)//沒參數插一個 { - var data = System.Text.Encoding.UTF8.GetBytes("usererror"); - _ConvertPush(data, src, to); + ConvertPushString("usererror", src, to); } else if (pcount == 1) { diff --git a/src/Neo.Compiler.MSIL/MSIL/Converter.cs b/src/Neo.Compiler.MSIL/MSIL/Converter.cs index 40526c422..037c63698 100644 --- a/src/Neo.Compiler.MSIL/MSIL/Converter.cs +++ b/src/Neo.Compiler.MSIL/MSIL/Converter.cs @@ -534,7 +534,7 @@ private int ConvertCode(ILMethod method, OpCode src, NeoMethod to) var buf = new byte[8]; Array.Copy(bytesCatch, 0, buf, 0, 4); Array.Copy(bytesFinally, 0, buf, 4, 4); - var trycode = _Convert1by1(VM.OpCode.TRY_L, src, to, buf); + var trycode = Convert1by1(VM.OpCode.TRY_L, src, to, buf); trycode.needfix = true; } @@ -666,32 +666,36 @@ private int ConvertCode(ILMethod method, OpCode src, NeoMethod to) case CodeEx.Leave: case CodeEx.Leave_S: {//will support try catch - if (method.IsTryCode(src.addr)) - { - _Convert1by1(VM.OpCode.ENDT, src, to); - } - else - { - ILCatchInfo catchinfo = method.GetCatchInfo(src.addr); - if (catchinfo != null) - { - _Convert1by1(VM.OpCode.ENDC, src, to); - } - else - { - //maybe is in finally try ,just jump. - } - } - var code = _Convert1by1(VM.OpCode.JMP_L, src, to, new byte[] { 0, 0, 0, 0 }); + var code = Convert1by1(VM.OpCode.ENDTRY_L, src, to, new byte[] { 0, 0, 0, 0 }); code.needfix = true; code.srcaddr = src.tokenAddr_Index; + //if (method.IsTryCode(src.addr)) + //{ + + //} + //else + //{ + // ILCatchInfo catchinfo = method.GetCatchInfo(src.addr); + // if (catchinfo != null) + // { + // _Convert1by1(VM.OpCode.ENDC, src, to); + // } + // else + // { + // //maybe is in finally try ,just jump. + // } + //} + + //var code = _Convert1by1(VM.OpCode.JMP_L, src, to, new byte[] { 0, 0, 0, 0 }); + //code.needfix = true; + //code.srcaddr = src.tokenAddr_Index; } break; case CodeEx.Endfinally: { //need vm add these opcodes - var code = _Convert1by1(VM.OpCode.ENDF, src, to); + var code = Convert1by1(VM.OpCode.ENDFINALLY, src, to); } break; case CodeEx.Switch: diff --git a/src/Neo.Compiler.MSIL/Neo.Compiler.MSIL.csproj b/src/Neo.Compiler.MSIL/Neo.Compiler.MSIL.csproj index 38d496576..b9c827788 100644 --- a/src/Neo.Compiler.MSIL/Neo.Compiler.MSIL.csproj +++ b/src/Neo.Compiler.MSIL/Neo.Compiler.MSIL.csproj @@ -26,11 +26,10 @@ - + - From 61db134bde98e8cf280035e9c8cbef2c49c32d8a Mon Sep 17 00:00:00 2001 From: lights Date: Thu, 16 Apr 2020 10:11:51 +0800 Subject: [PATCH 07/19] fix compiler about trycatch --- src/Neo.Compiler.MSIL/MSIL/Converter.cs | 48 ++-- .../UnitTest_TryCatch.cs | 8 +- .../Services/Neo/ContractTest.cs | 224 +++++++++--------- 3 files changed, 142 insertions(+), 138 deletions(-) diff --git a/src/Neo.Compiler.MSIL/MSIL/Converter.cs b/src/Neo.Compiler.MSIL/MSIL/Converter.cs index 037c63698..11ffeb91f 100644 --- a/src/Neo.Compiler.MSIL/MSIL/Converter.cs +++ b/src/Neo.Compiler.MSIL/MSIL/Converter.cs @@ -474,7 +474,7 @@ private void ConvertAddrInMethod(NeoMethod to) { var srcCatch = BitConverter.ToInt32(c.bytes, 0); var srcFinal = BitConverter.ToInt32(c.bytes, 4); - if(srcCatch==-1) + if (srcCatch == -1) { var bytesCatch = new byte[0, 0, 0, 0]; Array.Copy(bytesCatch, 0, c.bytes, 0, 4); @@ -667,29 +667,31 @@ private int ConvertCode(ILMethod method, OpCode src, NeoMethod to) case CodeEx.Leave_S: {//will support try catch - var code = Convert1by1(VM.OpCode.ENDTRY_L, src, to, new byte[] { 0, 0, 0, 0 }); - code.needfix = true; - code.srcaddr = src.tokenAddr_Index; - //if (method.IsTryCode(src.addr)) - //{ - - //} - //else - //{ - // ILCatchInfo catchinfo = method.GetCatchInfo(src.addr); - // if (catchinfo != null) - // { - // _Convert1by1(VM.OpCode.ENDC, src, to); - // } - // else - // { - // //maybe is in finally try ,just jump. - // } - //} - //var code = _Convert1by1(VM.OpCode.JMP_L, src, to, new byte[] { 0, 0, 0, 0 }); - //code.needfix = true; - //code.srcaddr = src.tokenAddr_Index; + if (method.IsTryCode(src.addr)) + { + var code = Convert1by1(VM.OpCode.ENDTRY_L, src, to, new byte[] { 0, 0, 0, 0 }); + code.needfix = true; + code.srcaddr = src.tokenAddr_Index; + } + else + { + ILCatchInfo catchinfo = method.GetCatchInfo(src.addr); + if (catchinfo != null) + { + var code = Convert1by1(VM.OpCode.ENDTRY_L, src, to, new byte[] { 0, 0, 0, 0 }); + code.needfix = true; + code.srcaddr = src.tokenAddr_Index; + } + else + { + //maybe is in finally try ,just jump. + var code = Convert1by1(VM.OpCode.JMP_L, src, to, new byte[] { 0, 0, 0, 0 }); + code.needfix = true; + code.srcaddr = src.tokenAddr_Index; + } + } + } break; case CodeEx.Endfinally: diff --git a/tests/Neo.Compiler.MSIL.UnitTests/UnitTest_TryCatch.cs b/tests/Neo.Compiler.MSIL.UnitTests/UnitTest_TryCatch.cs index 34cf96df1..5d4c59266 100644 --- a/tests/Neo.Compiler.MSIL.UnitTests/UnitTest_TryCatch.cs +++ b/tests/Neo.Compiler.MSIL.UnitTests/UnitTest_TryCatch.cs @@ -1,5 +1,5 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; -using Neo.Compiler.MSIL.Utils; +using Neo.Compiler.MSIL.UnitTests.Utils; using Neo.SmartContract; using System; using System.Collections.Generic; @@ -14,7 +14,7 @@ public class UnitTest_TryCatch public void Test_TryCatch_Succ() { var testengine = new TestEngine(); - testengine.AddEntryScript("./TestClasses/Contract_TryCatch.cs"); + testengine.AddEntryScript("./TestClasses/Contract_TryCatch.cs",false,false); testengine.ScriptEntry.DumpNEF(); var result = testengine.ExecuteTestCaseStandard("try01"); Console.WriteLine("state=" + testengine.State + " result on stack= " + result.Count); @@ -28,7 +28,7 @@ public void Test_TryCatch_Succ() public void Test_TryCatch_ThrowByCall() { var testengine = new TestEngine(); - testengine.AddEntryScript("./TestClasses/Contract_TryCatch.cs"); + testengine.AddEntryScript("./TestClasses/Contract_TryCatch.cs", false, false); testengine.ScriptEntry.DumpNEF(); var result = testengine.ExecuteTestCaseStandard("try03"); Console.WriteLine("state=" + testengine.State + " result on stack= " + result.Count); @@ -42,7 +42,7 @@ public void Test_TryCatch_ThrowByCall() public void Test_TryCatch_Throw() { var testengine = new TestEngine(); - testengine.AddEntryScript("./TestClasses/Contract_TryCatch.cs"); + testengine.AddEntryScript("./TestClasses/Contract_TryCatch.cs", false, false); testengine.ScriptEntry.DumpNEF(); var result = testengine.ExecuteTestCaseStandard("try02"); Console.WriteLine("state=" + testengine.State + " result on stack= " + result.Count); diff --git a/tests/Neo.SmartContract.Framework.UnitTests/Services/Neo/ContractTest.cs b/tests/Neo.SmartContract.Framework.UnitTests/Services/Neo/ContractTest.cs index 08b232e46..ce2551a31 100644 --- a/tests/Neo.SmartContract.Framework.UnitTests/Services/Neo/ContractTest.cs +++ b/tests/Neo.SmartContract.Framework.UnitTests/Services/Neo/ContractTest.cs @@ -22,166 +22,168 @@ public void Init() [TestMethod] public void Test_CreateCallDestroy() { - // Create + throw new System.Exception("compiler error on ContractManifest.CreateDefault"); + //// Create - byte[] script; - using (var scriptBuilder = new ScriptBuilder()) - { - // Drop arguments + //byte[] script; + //using (var scriptBuilder = new ScriptBuilder()) + //{ + // // Drop arguments - scriptBuilder.Emit(VM.OpCode.DROP); - scriptBuilder.Emit(VM.OpCode.DROP); + // scriptBuilder.Emit(VM.OpCode.DROP); + // scriptBuilder.Emit(VM.OpCode.DROP); - // Return 123 + // // Return 123 - scriptBuilder.EmitPush(123); - script = scriptBuilder.ToArray(); - } + // scriptBuilder.EmitPush(123); + // script = scriptBuilder.ToArray(); + //} - var manifest = ContractManifest.CreateDefault(script.ToScriptHash()); + //var manifest = ContractManifest.CreateDefault(script.ToScriptHash()); - // Check first + //// Check first - _engine.Reset(); - var result = _engine.ExecuteTestCaseStandard("call", manifest.Hash.ToArray()); - Assert.AreEqual(VMState.FAULT, _engine.State); - Assert.AreEqual(0, result.Count); + //_engine.Reset(); + //var result = _engine.ExecuteTestCaseStandard("call", manifest.Hash.ToArray()); + //Assert.AreEqual(VMState.FAULT, _engine.State); + //Assert.AreEqual(0, result.Count); - // Create + //// Create - _engine.Reset(); - result = _engine.ExecuteTestCaseStandard("create", script, manifest.ToJson().ToString()); - Assert.AreEqual(VMState.HALT, _engine.State); - Assert.AreEqual(1, result.Count); + //_engine.Reset(); + //result = _engine.ExecuteTestCaseStandard("create", script, manifest.ToJson().ToString()); + //Assert.AreEqual(VMState.HALT, _engine.State); + //Assert.AreEqual(1, result.Count); - var item = result.Pop(); - Assert.IsTrue(item.Type == VM.Types.StackItemType.InteropInterface); - var ledger = (item as InteropInterface).GetInterface(); - Assert.AreEqual(manifest.Hash, ledger.ScriptHash); + //var item = result.Pop(); + //Assert.IsTrue(item.Type == VM.Types.StackItemType.InteropInterface); + //var ledger = (item as InteropInterface).GetInterface(); + //Assert.AreEqual(manifest.Hash, ledger.ScriptHash); - // Call + //// Call - _engine.Reset(); - result = _engine.ExecuteTestCaseStandard("call", manifest.Hash.ToArray(), Null.Null, Null.Null); - Assert.AreEqual(VMState.HALT, _engine.State); - Assert.AreEqual(1, result.Count); + //_engine.Reset(); + //result = _engine.ExecuteTestCaseStandard("call", manifest.Hash.ToArray(), Null.Null, Null.Null); + //Assert.AreEqual(VMState.HALT, _engine.State); + //Assert.AreEqual(1, result.Count); - item = result.Pop(); - Assert.IsInstanceOfType(item, typeof(Integer)); - Assert.AreEqual(123, item.GetBigInteger()); + //item = result.Pop(); + //Assert.IsInstanceOfType(item, typeof(Integer)); + //Assert.AreEqual(123, item.GetBigInteger()); - // Destroy + //// Destroy - _engine.Reset(); - result = _engine.ExecuteTestCaseStandard("destroy"); - Assert.AreEqual(VMState.HALT, _engine.State); - Assert.AreEqual(1, result.Count); + //_engine.Reset(); + //result = _engine.ExecuteTestCaseStandard("destroy"); + //Assert.AreEqual(VMState.HALT, _engine.State); + //Assert.AreEqual(1, result.Count); - item = result.Pop(); - Assert.IsInstanceOfType(item, typeof(Integer)); - Assert.AreEqual(0, item.GetByteLength()); + //item = result.Pop(); + //Assert.IsInstanceOfType(item, typeof(Integer)); + //Assert.AreEqual(0, item.GetByteLength()); - // Check again for failures + //// Check again for failures - _engine.Reset(); - result = _engine.ExecuteTestCaseStandard("call", manifest.Hash.ToArray()); - Assert.AreEqual(VMState.FAULT, _engine.State); - Assert.AreEqual(0, result.Count); + //_engine.Reset(); + //result = _engine.ExecuteTestCaseStandard("call", manifest.Hash.ToArray()); + //Assert.AreEqual(VMState.FAULT, _engine.State); + //Assert.AreEqual(0, result.Count); } [TestMethod] public void Test_Update() { - // Create + throw new System.Exception("compiler error on ContractManifest.CreateDefault"); + //// Create - byte[] scriptUpdate; - using (var scriptBuilder = new ScriptBuilder()) - { - // Drop arguments + //byte[] scriptUpdate; + //using (var scriptBuilder = new ScriptBuilder()) + //{ + // // Drop arguments - scriptBuilder.Emit(VM.OpCode.DROP); - scriptBuilder.Emit(VM.OpCode.DROP); + // scriptBuilder.Emit(VM.OpCode.DROP); + // scriptBuilder.Emit(VM.OpCode.DROP); - // Return 124 + // // Return 124 - scriptBuilder.EmitPush(123); - scriptBuilder.Emit(VM.OpCode.INC); - scriptUpdate = scriptBuilder.ToArray(); - } + // scriptBuilder.EmitPush(123); + // scriptBuilder.Emit(VM.OpCode.INC); + // scriptUpdate = scriptBuilder.ToArray(); + //} - var manifestUpdate = ContractManifest.CreateDefault(scriptUpdate.ToScriptHash()); + //var manifestUpdate = ContractManifest.CreateDefault(scriptUpdate.ToScriptHash()); - byte[] script; - using (var scriptBuilder = new ScriptBuilder()) - { - // Drop arguments + //byte[] script; + //using (var scriptBuilder = new ScriptBuilder()) + //{ + // // Drop arguments - scriptBuilder.Emit(VM.OpCode.DROP); - scriptBuilder.Emit(VM.OpCode.DROP); + // scriptBuilder.Emit(VM.OpCode.DROP); + // scriptBuilder.Emit(VM.OpCode.DROP); - // Return 123 + // // Return 123 - scriptBuilder.EmitPush(123); + // scriptBuilder.EmitPush(123); - // Update + // // Update - scriptBuilder.EmitSysCall(InteropService.Contract.Update, scriptUpdate, manifestUpdate.ToJson().ToString()); - script = scriptBuilder.ToArray(); - } + // scriptBuilder.EmitSysCall(InteropService.Contract.Update, scriptUpdate, manifestUpdate.ToJson().ToString()); + // script = scriptBuilder.ToArray(); + //} - var manifest = ContractManifest.CreateDefault(script.ToScriptHash()); + //var manifest = ContractManifest.CreateDefault(script.ToScriptHash()); - // Check first + //// Check first - _engine.Reset(); - var result = _engine.ExecuteTestCaseStandard("call", manifest.Hash.ToArray()); - Assert.AreEqual(VMState.FAULT, _engine.State); - Assert.AreEqual(0, result.Count); + //_engine.Reset(); + //var result = _engine.ExecuteTestCaseStandard("call", manifest.Hash.ToArray()); + //Assert.AreEqual(VMState.FAULT, _engine.State); + //Assert.AreEqual(0, result.Count); - _engine.Reset(); - _ = _engine.ExecuteTestCaseStandard("call", manifestUpdate.Hash.ToArray()); - Assert.AreEqual(VMState.FAULT, _engine.State); + //_engine.Reset(); + //_ = _engine.ExecuteTestCaseStandard("call", manifestUpdate.Hash.ToArray()); + //Assert.AreEqual(VMState.FAULT, _engine.State); - // Create + //// Create - _engine.Reset(); - result = _engine.ExecuteTestCaseStandard("create", script, manifest.ToJson().ToString()); - Assert.AreEqual(VMState.HALT, _engine.State); - Assert.AreEqual(1, result.Count); + //_engine.Reset(); + //result = _engine.ExecuteTestCaseStandard("create", script, manifest.ToJson().ToString()); + //Assert.AreEqual(VMState.HALT, _engine.State); + //Assert.AreEqual(1, result.Count); - var item = result.Pop(); - Assert.IsTrue(item.Type == VM.Types.StackItemType.InteropInterface); - var ledger = (item as InteropInterface).GetInterface(); - Assert.AreEqual(manifest.Hash, ledger.ScriptHash); + //var item = result.Pop(); + //Assert.IsTrue(item.Type == VM.Types.StackItemType.InteropInterface); + //var ledger = (item as InteropInterface).GetInterface(); + //Assert.AreEqual(manifest.Hash, ledger.ScriptHash); - // Call & Update + //// Call & Update - _engine.Reset(); - result = _engine.ExecuteTestCaseStandard("call", manifest.Hash.ToArray(), Null.Null, Null.Null); - Assert.AreEqual(VMState.HALT, _engine.State); - Assert.AreEqual(1, result.Count); + //_engine.Reset(); + //result = _engine.ExecuteTestCaseStandard("call", manifest.Hash.ToArray(), Null.Null, Null.Null); + //Assert.AreEqual(VMState.HALT, _engine.State); + //Assert.AreEqual(1, result.Count); - item = result.Pop(); - Assert.IsInstanceOfType(item, typeof(Integer)); - Assert.AreEqual(123, item.GetBigInteger()); + //item = result.Pop(); + //Assert.IsInstanceOfType(item, typeof(Integer)); + //Assert.AreEqual(123, item.GetBigInteger()); - // Call Again + //// Call Again - _engine.Reset(); - result = _engine.ExecuteTestCaseStandard("call", manifestUpdate.Hash.ToArray(), Null.Null, Null.Null); - Assert.AreEqual(VMState.HALT, _engine.State); - Assert.AreEqual(1, result.Count); + //_engine.Reset(); + //result = _engine.ExecuteTestCaseStandard("call", manifestUpdate.Hash.ToArray(), Null.Null, Null.Null); + //Assert.AreEqual(VMState.HALT, _engine.State); + //Assert.AreEqual(1, result.Count); - item = result.Pop(); - Assert.IsInstanceOfType(item, typeof(Integer)); - Assert.AreEqual(124, item.GetBigInteger()); + //item = result.Pop(); + //Assert.IsInstanceOfType(item, typeof(Integer)); + //Assert.AreEqual(124, item.GetBigInteger()); - // Check again for failures + //// Check again for failures - _engine.Reset(); - result = _engine.ExecuteTestCaseStandard("call", manifest.Hash.ToArray()); - Assert.AreEqual(VMState.FAULT, _engine.State); - Assert.AreEqual(0, result.Count); + //_engine.Reset(); + //result = _engine.ExecuteTestCaseStandard("call", manifest.Hash.ToArray()); + //Assert.AreEqual(VMState.FAULT, _engine.State); + //Assert.AreEqual(0, result.Count); } } } From 23b262dcbbdf441760f0255c9d1b0a722f0c4a76 Mon Sep 17 00:00:00 2001 From: lights Date: Thu, 16 Apr 2020 10:17:53 +0800 Subject: [PATCH 08/19] fix opcodes --- src/Neo.SmartContract.Framework/OpCode.cs | 29 +++++++++++++++++++---- 1 file changed, 24 insertions(+), 5 deletions(-) diff --git a/src/Neo.SmartContract.Framework/OpCode.cs b/src/Neo.SmartContract.Framework/OpCode.cs index 310c0f3e5..6c8e19032 100644 --- a/src/Neo.SmartContract.Framework/OpCode.cs +++ b/src/Neo.SmartContract.Framework/OpCode.cs @@ -4,6 +4,7 @@ public enum OpCode : byte { #region Constants + PUSHINT8 = 0x00, PUSHINT16 = 0x01, PUSHINT32 = 0x02, @@ -203,12 +204,30 @@ public enum OpCode : byte /// Pop the top value of the stack, if it false, then exit vm execution and set vm state to FAULT. /// ASSERT = 0x38, + /// + /// Pop the top value of the stack, and throw it. + /// THROW = 0x3A, - //TRY = 0x3B, - //TRY_L = 0x3C, - //ENDT = 0x3D, - //ENDC = 0x3E, - //ENDF = 0x3F, + /// + /// TRY CatchOffset(sbyte) FinallyOffset(sbyte). If there's no catch body, set CatchOffset 0. If there's no finally body, set FinallyOffset 0. + /// + TRY = 0x3B, + /// + /// TRY_L CatchOffset(int) FinallyOffset(int). If there's no catch body, set CatchOffset 0. If there's no finally body, set FinallyOffset 0. + /// + TRY_L = 0x3C, + /// + /// Ensures that the appropriate surrounding finally blocks are executed. And then unconditionally transfers control to the specific target instruction, represented as a 1-byte signed offset from the beginning of the current instruction. + /// + ENDTRY = 0x3D, + /// + /// Ensures that the appropriate surrounding finally blocks are executed. And then unconditionally transfers control to the specific target instruction, represented as a 4-byte signed offset from the beginning of the current instruction. + /// + ENDTRY_L = 0x3E, + /// + /// End finally, If no exception happen or be catched, vm will jump to the target instruction of ENDTRY/ENDTRY_L. Otherwise vm will rethrow the exception to upper layer. + /// + ENDFINALLY = 0x3F, /// /// Returns from the current method. /// From cc9a64aba2d027074d7ba1abf5804673057044a2 Mon Sep 17 00:00:00 2001 From: lights Date: Thu, 16 Apr 2020 10:46:00 +0800 Subject: [PATCH 09/19] fix optimizer for try catch --- .../Optimizer/NefInstruction.cs | 26 ++++++++++++++++++- .../Optimizer/Parser_DeleteDeadCode.cs | 7 ++++- .../Optimizer/Parser_UseShortAddress.cs | 4 +++ .../UnitTest_TryCatch.cs | 2 +- 4 files changed, 36 insertions(+), 3 deletions(-) diff --git a/src/Neo.Compiler.MSIL/Optimizer/NefInstruction.cs b/src/Neo.Compiler.MSIL/Optimizer/NefInstruction.cs index 8e0551320..c44b31714 100644 --- a/src/Neo.Compiler.MSIL/Optimizer/NefInstruction.cs +++ b/src/Neo.Compiler.MSIL/Optimizer/NefInstruction.cs @@ -151,6 +151,7 @@ public void SetOpCode(OpCode opcode) case OpCode.JMPEQ_L: case OpCode.JMPGE_L: case OpCode.JMPGT_L: + case OpCode.ENDTRY_L: { Labels = new string[1]; // is an address if (oldlabels != null && oldlabels.Length >= 1) @@ -158,6 +159,17 @@ public void SetOpCode(OpCode opcode) AddressSize = 4; // 32 bit break; } + case OpCode.TRY_L: + { + Labels = new string[2]; // is an address + if (oldlabels != null && oldlabels.Length >= 2) + { + Labels[0] = oldlabels[0]; + Labels[1] = oldlabels[1]; + } + AddressSize = 4; // 32 bit + break; + } //TODO case OpCode.TRY_L: 32 + 32 bit //TODO case OpCode.TRY: 8 + 8 bit case OpCode.CALL: @@ -171,13 +183,25 @@ public void SetOpCode(OpCode opcode) case OpCode.JMPEQ: case OpCode.JMPGE: case OpCode.JMPGT: - { + case OpCode.ENDTRY: + { Labels = new string[1]; // an address if (oldlabels != null && oldlabels.Length >= 1) Labels[0] = oldlabels[0]; AddressSize = 1; //8 bit break; } + case OpCode.TRY: + { + Labels = new string[2]; // an address + if (oldlabels != null && oldlabels.Length >= 2) + { + Labels[0] = oldlabels[0]; + Labels[1] = oldlabels[1]; + } + AddressSize = 1; //8 bit + break; + } default: break; } } diff --git a/src/Neo.Compiler.MSIL/Optimizer/Parser_DeleteDeadCode.cs b/src/Neo.Compiler.MSIL/Optimizer/Parser_DeleteDeadCode.cs index b23c34f48..9ab2447c2 100644 --- a/src/Neo.Compiler.MSIL/Optimizer/Parser_DeleteDeadCode.cs +++ b/src/Neo.Compiler.MSIL/Optimizer/Parser_DeleteDeadCode.cs @@ -47,6 +47,8 @@ private static void Touch(List items, List reachableAddrs, int be { reachableAddrs.Add(inst.Offset); } + //try 不是线性的,遇到try,跳到catch段和final段继续扫, + //遇到endtry也应该跳过去扫 if (inst.AddressCountInData > 0) // The instruction may contain jmp addess { @@ -66,7 +68,10 @@ private static void Touch(List items, List reachableAddrs, int be if (inst.OpCode == OpCode.JMP || inst.OpCode == OpCode.JMP_L || inst.OpCode == OpCode.RET || - inst.OpCode == OpCode.THROW) + inst.OpCode == OpCode.THROW || + inst.OpCode == OpCode.ENDTRY || + inst.OpCode == OpCode.ENDTRY_L || + inst.OpCode == OpCode.ENDFINALLY) { return; } diff --git a/src/Neo.Compiler.MSIL/Optimizer/Parser_UseShortAddress.cs b/src/Neo.Compiler.MSIL/Optimizer/Parser_UseShortAddress.cs index 215428435..27eba3750 100644 --- a/src/Neo.Compiler.MSIL/Optimizer/Parser_UseShortAddress.cs +++ b/src/Neo.Compiler.MSIL/Optimizer/Parser_UseShortAddress.cs @@ -37,6 +37,10 @@ public void Parse(List items) for (int x = 0; x < items.Count; x++) { if (!(items[x] is NefInstruction inst)) continue; + if(inst.OpCode== OpCode.TRY_L) + { + + } if (inst.OpCode == OpCode.PUSHA) continue; //PUSHA is not 8 bits if (inst.AddressSize != 4) continue; diff --git a/tests/Neo.Compiler.MSIL.UnitTests/UnitTest_TryCatch.cs b/tests/Neo.Compiler.MSIL.UnitTests/UnitTest_TryCatch.cs index 5d4c59266..e2c14fc22 100644 --- a/tests/Neo.Compiler.MSIL.UnitTests/UnitTest_TryCatch.cs +++ b/tests/Neo.Compiler.MSIL.UnitTests/UnitTest_TryCatch.cs @@ -14,7 +14,7 @@ public class UnitTest_TryCatch public void Test_TryCatch_Succ() { var testengine = new TestEngine(); - testengine.AddEntryScript("./TestClasses/Contract_TryCatch.cs",false,false); + testengine.AddEntryScript("./TestClasses/Contract_TryCatch.cs"); testengine.ScriptEntry.DumpNEF(); var result = testengine.ExecuteTestCaseStandard("try01"); Console.WriteLine("state=" + testengine.State + " result on stack= " + result.Count); From 335d1cdf94e9d92e7c0175b23c5cbd0895909c7b Mon Sep 17 00:00:00 2001 From: lights Date: Thu, 16 Apr 2020 10:46:49 +0800 Subject: [PATCH 10/19] open optimize for trycatch unittest --- tests/Neo.Compiler.MSIL.UnitTests/UnitTest_TryCatch.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/Neo.Compiler.MSIL.UnitTests/UnitTest_TryCatch.cs b/tests/Neo.Compiler.MSIL.UnitTests/UnitTest_TryCatch.cs index e2c14fc22..ccb9e3a82 100644 --- a/tests/Neo.Compiler.MSIL.UnitTests/UnitTest_TryCatch.cs +++ b/tests/Neo.Compiler.MSIL.UnitTests/UnitTest_TryCatch.cs @@ -28,7 +28,7 @@ public void Test_TryCatch_Succ() public void Test_TryCatch_ThrowByCall() { var testengine = new TestEngine(); - testengine.AddEntryScript("./TestClasses/Contract_TryCatch.cs", false, false); + testengine.AddEntryScript("./TestClasses/Contract_TryCatch.cs"); testengine.ScriptEntry.DumpNEF(); var result = testengine.ExecuteTestCaseStandard("try03"); Console.WriteLine("state=" + testengine.State + " result on stack= " + result.Count); @@ -42,7 +42,7 @@ public void Test_TryCatch_ThrowByCall() public void Test_TryCatch_Throw() { var testengine = new TestEngine(); - testengine.AddEntryScript("./TestClasses/Contract_TryCatch.cs", false, false); + testengine.AddEntryScript("./TestClasses/Contract_TryCatch.cs"); testengine.ScriptEntry.DumpNEF(); var result = testengine.ExecuteTestCaseStandard("try02"); Console.WriteLine("state=" + testengine.State + " result on stack= " + result.Count); From ae81673e21c005a595f52ff66e3a91122e741292 Mon Sep 17 00:00:00 2001 From: Shargon Date: Thu, 16 Apr 2020 08:55:04 +0200 Subject: [PATCH 11/19] Fix format --- src/Neo.Compiler.MSIL/Optimizer/NefInstruction.cs | 2 +- src/Neo.Compiler.MSIL/Optimizer/Parser_UseShortAddress.cs | 2 +- src/Neo.SmartContract.Framework/OpCode.cs | 2 +- tests/Neo.Compiler.MSIL.UnitTests/UnitTest_TryCatch.cs | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Neo.Compiler.MSIL/Optimizer/NefInstruction.cs b/src/Neo.Compiler.MSIL/Optimizer/NefInstruction.cs index c44b31714..699be6c57 100644 --- a/src/Neo.Compiler.MSIL/Optimizer/NefInstruction.cs +++ b/src/Neo.Compiler.MSIL/Optimizer/NefInstruction.cs @@ -184,7 +184,7 @@ public void SetOpCode(OpCode opcode) case OpCode.JMPGE: case OpCode.JMPGT: case OpCode.ENDTRY: - { + { Labels = new string[1]; // an address if (oldlabels != null && oldlabels.Length >= 1) Labels[0] = oldlabels[0]; diff --git a/src/Neo.Compiler.MSIL/Optimizer/Parser_UseShortAddress.cs b/src/Neo.Compiler.MSIL/Optimizer/Parser_UseShortAddress.cs index 27eba3750..7d598baa3 100644 --- a/src/Neo.Compiler.MSIL/Optimizer/Parser_UseShortAddress.cs +++ b/src/Neo.Compiler.MSIL/Optimizer/Parser_UseShortAddress.cs @@ -37,7 +37,7 @@ public void Parse(List items) for (int x = 0; x < items.Count; x++) { if (!(items[x] is NefInstruction inst)) continue; - if(inst.OpCode== OpCode.TRY_L) + if (inst.OpCode == OpCode.TRY_L) { } diff --git a/src/Neo.SmartContract.Framework/OpCode.cs b/src/Neo.SmartContract.Framework/OpCode.cs index 6c8e19032..a8457fe00 100644 --- a/src/Neo.SmartContract.Framework/OpCode.cs +++ b/src/Neo.SmartContract.Framework/OpCode.cs @@ -4,7 +4,7 @@ public enum OpCode : byte { #region Constants - + PUSHINT8 = 0x00, PUSHINT16 = 0x01, PUSHINT32 = 0x02, diff --git a/tests/Neo.Compiler.MSIL.UnitTests/UnitTest_TryCatch.cs b/tests/Neo.Compiler.MSIL.UnitTests/UnitTest_TryCatch.cs index ccb9e3a82..01ee1a0a1 100644 --- a/tests/Neo.Compiler.MSIL.UnitTests/UnitTest_TryCatch.cs +++ b/tests/Neo.Compiler.MSIL.UnitTests/UnitTest_TryCatch.cs @@ -19,7 +19,7 @@ public void Test_TryCatch_Succ() var result = testengine.ExecuteTestCaseStandard("try01"); Console.WriteLine("state=" + testengine.State + " result on stack= " + result.Count); var value = result.Pop(); - Console.WriteLine("result:" + value.Type + " "+ value.ToString()); + Console.WriteLine("result:" + value.Type + " " + value.ToString()); var num = value as Neo.VM.Types.Integer; Console.WriteLine("result = " + num.ToBigInteger().ToString()); Assert.AreEqual(num.ToBigInteger(), 3); From f602eb83054a216257a2cb3dfc44055ea2242575 Mon Sep 17 00:00:00 2001 From: ShawnYun <42930111+ShawnYun@users.noreply.github.com> Date: Sun, 26 Apr 2020 16:37:48 +0800 Subject: [PATCH 12/19] fix UT (#255) --- .../Services/Neo/ContractTest.cs | 72 ++++++++++--------- 1 file changed, 37 insertions(+), 35 deletions(-) diff --git a/tests/Neo.SmartContract.Framework.UnitTests/Services/Neo/ContractTest.cs b/tests/Neo.SmartContract.Framework.UnitTests/Services/Neo/ContractTest.cs index a71af4819..df323a674 100644 --- a/tests/Neo.SmartContract.Framework.UnitTests/Services/Neo/ContractTest.cs +++ b/tests/Neo.SmartContract.Framework.UnitTests/Services/Neo/ContractTest.cs @@ -24,43 +24,43 @@ public void Init() [TestMethod] public void Test_CreateCallDestroy() { - throw new System.Exception("compiler error on ContractManifest.CreateDefault"); - //// Create + // Create + var script = _engine.Build("./TestClasses/Contract_Create.cs"); var manifest = ContractManifest.FromJson(JObject.Parse(script.finalManifest)); + // Check first - //// Check first _engine.Reset(); var result = _engine.ExecuteTestCaseStandard("call", manifest.Hash.ToArray(), "oldContract", new Array()); Assert.AreEqual(VMState.FAULT, _engine.State); Assert.AreEqual(0, result.Count); + // Create - //// Create _engine.Reset(); result = _engine.ExecuteTestCaseStandard("create", script.finalNEF, manifest.ToJson().ToString()); Assert.AreEqual(VMState.HALT, _engine.State); Assert.AreEqual(1, result.Count); + var item = result.Pop(); + Assert.IsTrue(item.Type == VM.Types.StackItemType.InteropInterface); + var ledger = (item as InteropInterface).GetInterface(); + Assert.AreEqual(manifest.Hash, ledger.ScriptHash); - //var item = result.Pop(); - //Assert.IsTrue(item.Type == VM.Types.StackItemType.InteropInterface); - //var ledger = (item as InteropInterface).GetInterface(); - //Assert.AreEqual(manifest.Hash, ledger.ScriptHash); + // Call - //// Call _engine.Reset(); result = _engine.ExecuteTestCaseStandard("call", manifest.Hash.ToArray(), "oldContract", new Array()); Assert.AreEqual(VMState.HALT, _engine.State); Assert.AreEqual(1, result.Count); - //item = result.Pop(); - //Assert.IsInstanceOfType(item, typeof(Integer)); - //Assert.AreEqual(123, item.GetBigInteger()); + item = result.Pop(); + Assert.IsInstanceOfType(item, typeof(Integer)); + Assert.AreEqual(123, item.GetBigInteger()); - //// Destroy + // Destroy _engine.Reset(); result = _engine.ExecuteTestCaseStandard("destroy"); @@ -68,20 +68,19 @@ public void Test_CreateCallDestroy() Assert.AreEqual(0, result.Count); - //// Check again for failures + // Check again for failures - //_engine.Reset(); - //result = _engine.ExecuteTestCaseStandard("call", manifest.Hash.ToArray()); - //Assert.AreEqual(VMState.FAULT, _engine.State); - //Assert.AreEqual(0, result.Count); + _engine.Reset(); + result = _engine.ExecuteTestCaseStandard("call", manifest.Hash.ToArray()); + Assert.AreEqual(VMState.FAULT, _engine.State); + Assert.AreEqual(0, result.Count); } [TestMethod] public void Test_Update() { - throw new System.Exception("compiler error on ContractManifest.CreateDefault"); - //// Create + // Create var script = _engine.Build("./TestClasses/Contract_CreateAndUpdate.cs"); var manifest = ContractManifest.FromJson(JObject.Parse(script.finalManifest)); @@ -89,8 +88,8 @@ public void Test_Update() var scriptUpdate = _engine.Build("./TestClasses/Contract_Update.cs"); var manifestUpdate = ContractManifest.FromJson(JObject.Parse(scriptUpdate.finalManifest)); + // Check first - //// Check first _engine.Reset(); var result = _engine.ExecuteTestCaseStandard("call", manifest.Hash.ToArray(), "oldContract", new Array()); Assert.AreEqual(VMState.FAULT, _engine.State); @@ -100,19 +99,20 @@ public void Test_Update() _ = _engine.ExecuteTestCaseStandard("call", manifestUpdate.Hash.ToArray(), "newContract", new Array()); Assert.AreEqual(VMState.FAULT, _engine.State); + // Create - //// Create _engine.Reset(); result = _engine.ExecuteTestCaseStandard("create", script.finalNEF, manifest.ToJson().ToString()); Assert.AreEqual(VMState.HALT, _engine.State); Assert.AreEqual(1, result.Count); - //var item = result.Pop(); - //Assert.IsTrue(item.Type == VM.Types.StackItemType.InteropInterface); - //var ledger = (item as InteropInterface).GetInterface(); - //Assert.AreEqual(manifest.Hash, ledger.ScriptHash); + var item = result.Pop(); + Assert.IsTrue(item.Type == VM.Types.StackItemType.InteropInterface); + var ledger = (item as InteropInterface).GetInterface(); + Assert.AreEqual(manifest.Hash, ledger.ScriptHash); + + // Call & Update - //// Call & Update _engine.Reset(); var args = new Array { @@ -123,21 +123,23 @@ public void Test_Update() Assert.AreEqual(VMState.HALT, _engine.State); Assert.AreEqual(1, result.Count); - //item = result.Pop(); - //Assert.IsInstanceOfType(item, typeof(Integer)); - //Assert.AreEqual(123, item.GetBigInteger()); + item = result.Pop(); + Assert.IsInstanceOfType(item, typeof(Integer)); + Assert.AreEqual(123, item.GetBigInteger()); + + // Call Again - //// Call Again _engine.Reset(); result = _engine.ExecuteTestCaseStandard("call", manifestUpdate.Hash.ToArray(), "newContract", new Array()); Assert.AreEqual(VMState.HALT, _engine.State); Assert.AreEqual(1, result.Count); - //item = result.Pop(); - //Assert.IsInstanceOfType(item, typeof(Integer)); - //Assert.AreEqual(124, item.GetBigInteger()); + item = result.Pop(); + Assert.IsInstanceOfType(item, typeof(Integer)); + Assert.AreEqual(124, item.GetBigInteger()); + + // Check again for failures - //// Check again for failures _engine.Reset(); result = _engine.ExecuteTestCaseStandard("call", manifest.Hash.ToArray(), "oldContract", new Array()); Assert.AreEqual(VMState.FAULT, _engine.State); From c462e25b2bb77f91c9dc6640d9cce555773515c9 Mon Sep 17 00:00:00 2001 From: Luchuan Date: Wed, 29 Apr 2020 18:07:14 +0800 Subject: [PATCH 13/19] add try-finally ut (#259) * add try-finally ut * format, translate * fix try-finally and add try-catch * refactor code * keep only one try-catch matched --- src/Neo.Compiler.MSIL/MSIL/Conv_Multi.cs | 10 +-- src/Neo.Compiler.MSIL/MSIL/Converter.cs | 24 ++++-- src/Neo.Compiler.MSIL/MSIL/ILModule.cs | 6 +- .../Optimizer/NefInstruction.cs | 2 - .../Optimizer/Parser_DeleteDeadCode.cs | 5 +- .../TestClasses/Contract_TryCatch.cs | 82 ++++++++++++++++++- .../UnitTest_TryCatch.cs | 60 +++++++++++++- 7 files changed, 163 insertions(+), 26 deletions(-) diff --git a/src/Neo.Compiler.MSIL/MSIL/Conv_Multi.cs b/src/Neo.Compiler.MSIL/MSIL/Conv_Multi.cs index c35b86d6d..0928d7e66 100644 --- a/src/Neo.Compiler.MSIL/MSIL/Conv_Multi.cs +++ b/src/Neo.Compiler.MSIL/MSIL/Conv_Multi.cs @@ -1308,14 +1308,14 @@ 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; + return 0; // donothing; } else if (_type.DeclaringType.FullName.Contains("Exception")) { - //对异常对象要留一个,因为catch 会处理这个栈 + // NeoVM `catch` instruction need one exception parameter Convert1by1(VM.OpCode.NOP, src, to); var pcount = _type.Parameters.Count; - if (pcount == 0)//沒參數插一個 + if (pcount == 0) // If there is no parameter, insert one pararmeter { ConvertPushString("usererror", src, to); } @@ -1325,7 +1325,7 @@ private int ConvertNewObj(ILMethod from, OpCode src, NeoMethod to) } else { - //對異常對象保留第一個參數 + // Keep the first exception parameter for (var i = 0; i < pcount - 1; i++) { Insert1(VM.OpCode.DROP, "", to); @@ -1335,7 +1335,7 @@ private int ConvertNewObj(ILMethod from, OpCode src, NeoMethod to) } var type = _type.Resolve(); - //Replace the New Array operation if there is an [OpCode] on the constructor + // Replace the New Array operation if there is an [OpCode] on the constructor foreach (var m in type.DeclaringType.Methods) { if (m.IsConstructor && m.HasCustomAttributes) diff --git a/src/Neo.Compiler.MSIL/MSIL/Converter.cs b/src/Neo.Compiler.MSIL/MSIL/Converter.cs index 135348ca4..a10f64352 100644 --- a/src/Neo.Compiler.MSIL/MSIL/Converter.cs +++ b/src/Neo.Compiler.MSIL/MSIL/Converter.cs @@ -1,4 +1,5 @@ using System; +using System.Buffers.Binary; using System.Collections.Generic; using System.Linq; using System.Numerics; @@ -352,7 +353,7 @@ private void ConvertAddrInMethod(NeoMethod to) var srcFinal = BitConverter.ToInt32(c.bytes, 4); if (srcCatch == -1) { - var bytesCatch = new byte[0, 0, 0, 0]; + var bytesCatch = new byte[] { 0, 0, 0, 0 }; Array.Copy(bytesCatch, 0, c.bytes, 0, 4); } else @@ -364,7 +365,7 @@ private void ConvertAddrInMethod(NeoMethod to) } if (srcFinal == -1) { - var bytesFinal = new byte[0, 0, 0, 0]; + var bytesFinal = new byte[] { 0, 0, 0, 0 }; Array.Copy(bytesFinal, 0, c.bytes, 4, 4); } else @@ -402,19 +403,25 @@ private int ConvertCode(ILMethod method, OpCode src, NeoMethod to) { if (info.addr_Try_Begin == src.addr) { - var bytesFinally = BitConverter.GetBytes(info.addr_Finally_Begin); - if (info.catch_Infos.Count != 1) + if (info.catch_Infos.Count > 1) throw new Exception("only support one catch for now."); - var first = info.catch_Infos.First().Value; - var bytesCatch = BitConverter.GetBytes(first.addrBegin); + var buf = new byte[8]; + var catchAddr = -1; + if (info.catch_Infos.Count == 1) + { + var first = info.catch_Infos.First().Value; + catchAddr = first.addrBegin; + } + var bytesCatch = BitConverter.GetBytes(catchAddr); + var bytesFinally = BitConverter.GetBytes(info.addr_Finally_Begin); + Array.Copy(bytesCatch, 0, buf, 0, 4); Array.Copy(bytesFinally, 0, buf, 4, 4); var trycode = Convert1by1(VM.OpCode.TRY_L, src, to, buf); trycode.needfix = true; - + break; } - } } int skipcount = 0; @@ -567,7 +574,6 @@ private int ConvertCode(ILMethod method, OpCode src, NeoMethod to) code.srcaddr = src.tokenAddr_Index; } } - } break; case CodeEx.Endfinally: diff --git a/src/Neo.Compiler.MSIL/MSIL/ILModule.cs b/src/Neo.Compiler.MSIL/MSIL/ILModule.cs index 486a77433..4014214bb 100644 --- a/src/Neo.Compiler.MSIL/MSIL/ILModule.cs +++ b/src/Neo.Compiler.MSIL/MSIL/ILModule.cs @@ -197,12 +197,14 @@ public override string ToString() return type; } } + public class ILCatchInfo { public int addrBegin; public int addrEnd; public string catchType; } + public class ILTryInfo { public int addr_Try_Begin = -1; @@ -308,7 +310,6 @@ public ILMethod(ILType type, Mono.Cecil.MethodDefinition method, ILogger logger addrEnd = e.HandlerEnd.Offset, catchType = catchtypestr }; - } else if (e.HandlerType == Mono.Cecil.Cil.ExceptionHandlerType.Finally) { @@ -359,6 +360,7 @@ public ILMethod(ILType type, Mono.Cecil.MethodDefinition method, ILogger logger } } } + public ILTryInfo GetTryInfo(int addr) { ILTryInfo last = null; @@ -420,6 +422,7 @@ public ILTryInfo GetTryInfo(int addr) } return last; } + public bool IsTryCode(int addr) { ILTryInfo info = GetTryInfo(addr); @@ -427,6 +430,7 @@ public bool IsTryCode(int addr) return false; return info.addr_Try_Begin <= addr && addr <= info.addr_Try_End; } + public ILCatchInfo GetCatchInfo(int addr) { ILTryInfo info = GetTryInfo(addr); diff --git a/src/Neo.Compiler.MSIL/Optimizer/NefInstruction.cs b/src/Neo.Compiler.MSIL/Optimizer/NefInstruction.cs index 163bdebbd..373bdbb4d 100644 --- a/src/Neo.Compiler.MSIL/Optimizer/NefInstruction.cs +++ b/src/Neo.Compiler.MSIL/Optimizer/NefInstruction.cs @@ -180,8 +180,6 @@ public void SetOpCode(OpCode opcode) AddressSize = 4; // 32 bit break; } - //TODO case OpCode.TRY_L: 32 + 32 bit - //TODO case OpCode.TRY: 8 + 8 bit case OpCode.CALL: case OpCode.JMP: diff --git a/src/Neo.Compiler.MSIL/Optimizer/Parser_DeleteDeadCode.cs b/src/Neo.Compiler.MSIL/Optimizer/Parser_DeleteDeadCode.cs index 9ab2447c2..45698f75a 100644 --- a/src/Neo.Compiler.MSIL/Optimizer/Parser_DeleteDeadCode.cs +++ b/src/Neo.Compiler.MSIL/Optimizer/Parser_DeleteDeadCode.cs @@ -47,8 +47,9 @@ private static void Touch(List items, List reachableAddrs, int be { reachableAddrs.Add(inst.Offset); } - //try 不是线性的,遇到try,跳到catch段和final段继续扫, - //遇到endtry也应该跳过去扫 + + // Try is not linear. If encounter a try, skip to the catch and finally segments to scan. + // If encounter endtry, will also skip to finally segment to scan if (inst.AddressCountInData > 0) // The instruction may contain jmp addess { diff --git a/tests/Neo.Compiler.MSIL.UnitTests/TestClasses/Contract_TryCatch.cs b/tests/Neo.Compiler.MSIL.UnitTests/TestClasses/Contract_TryCatch.cs index b42e5d0f9..e6b579335 100644 --- a/tests/Neo.Compiler.MSIL.UnitTests/TestClasses/Contract_TryCatch.cs +++ b/tests/Neo.Compiler.MSIL.UnitTests/TestClasses/Contract_TryCatch.cs @@ -38,10 +38,7 @@ public static object try02() } return v; } - public static object throwcall() - { - throw new System.Exception(); - } + public static object try03() { int v = 0; @@ -60,5 +57,82 @@ public static object try03() } return v; } + + public static object tryNest() + { + int v = 0; + try + { + try + { + v = 2; + throwcall(); + } + catch + { + v = 3; + throwcall(); + } + finally + { + throwcall(); + v++; + } + } + catch + { + v++; + } + return v; + } + + public static object tryFinally() + { + int v = 0; + try + { + v = 2; + } + finally + { + v++; + } + return v; + } + + public static object tryFinallyAndRethrow() + { + int v = 0; + try + { + v = 2; + throwcall(); + } + finally + { + v++; + } + return v; + } + + public static object tryCatch() + { + int v = 0; + try + { + v = 2; + throwcall(); + } + catch + { + v++; + } + return v; + } + + public static object throwcall() + { + throw new System.Exception(); + } } } diff --git a/tests/Neo.Compiler.MSIL.UnitTests/UnitTest_TryCatch.cs b/tests/Neo.Compiler.MSIL.UnitTests/UnitTest_TryCatch.cs index 01ee1a0a1..2e931ab66 100644 --- a/tests/Neo.Compiler.MSIL.UnitTests/UnitTest_TryCatch.cs +++ b/tests/Neo.Compiler.MSIL.UnitTests/UnitTest_TryCatch.cs @@ -1,9 +1,6 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; using Neo.Compiler.MSIL.UnitTests.Utils; -using Neo.SmartContract; using System; -using System.Collections.Generic; -using System.Numerics; namespace Neo.Compiler.MSIL { @@ -24,6 +21,7 @@ public void Test_TryCatch_Succ() Console.WriteLine("result = " + num.ToBigInteger().ToString()); Assert.AreEqual(num.ToBigInteger(), 3); } + [TestMethod] public void Test_TryCatch_ThrowByCall() { @@ -38,6 +36,7 @@ public void Test_TryCatch_ThrowByCall() Console.WriteLine("result = " + num.ToBigInteger().ToString()); Assert.AreEqual(num.ToBigInteger(), 4); } + [TestMethod] public void Test_TryCatch_Throw() { @@ -53,5 +52,60 @@ public void Test_TryCatch_Throw() Assert.AreEqual(num.ToBigInteger(), 4); } + [TestMethod] + public void Test_TryNest() + { + var testengine = new TestEngine(); + testengine.AddEntryScript("./TestClasses/Contract_TryCatch.cs"); + testengine.ScriptEntry.DumpNEF(); + var result = testengine.ExecuteTestCaseStandard("tryNest"); + Console.WriteLine("state=" + testengine.State + " result on stack= " + result.Count); + var value = result.Pop(); + Console.WriteLine("result:" + value.Type + " " + value.ToString()); + var num = value as Neo.VM.Types.Integer; + Console.WriteLine("result = " + num.ToBigInteger().ToString()); + Assert.AreEqual(num.ToBigInteger(), 4); + } + + [TestMethod] + public void Test_TryFinally() + { + var testengine = new TestEngine(); + testengine.AddEntryScript("./TestClasses/Contract_TryCatch.cs"); + testengine.ScriptEntry.DumpNEF(); + var result = testengine.ExecuteTestCaseStandard("tryFinally"); + Console.WriteLine("state=" + testengine.State + " result on stack= " + result.Count); + var value = result.Pop(); + Console.WriteLine("result:" + value.Type + " " + value.ToString()); + var num = value as Neo.VM.Types.Integer; + Console.WriteLine("result = " + num.ToBigInteger().ToString()); + Assert.AreEqual(num.ToBigInteger(), 3); + } + + [TestMethod] + public void Test_TryFinallyAndRethrow() + { + var testengine = new TestEngine(); + testengine.AddEntryScript("./TestClasses/Contract_TryCatch.cs"); + testengine.ScriptEntry.DumpNEF(); + var result = testengine.ExecuteTestCaseStandard("tryFinallyAndRethrow"); + Console.WriteLine("state=" + testengine.State + " result on stack= " + result.Count); + Assert.AreEqual(testengine.State, VM.VMState.FAULT); + } + + [TestMethod] + public void Test_TryCatch() + { + var testengine = new TestEngine(); + testengine.AddEntryScript("./TestClasses/Contract_TryCatch.cs"); + testengine.ScriptEntry.DumpNEF(); + var result = testengine.ExecuteTestCaseStandard("tryCatch"); + Console.WriteLine("state=" + testengine.State + " result on stack= " + result.Count); + var value = result.Pop(); + Console.WriteLine("result:" + value.Type + " " + value.ToString()); + var num = value as Neo.VM.Types.Integer; + Console.WriteLine("result = " + num.ToBigInteger().ToString()); + Assert.AreEqual(num.ToBigInteger(), 3); + } } } From bef47cbca345f339334050d71b5cd090fec3a94e Mon Sep 17 00:00:00 2001 From: lights Date: Thu, 30 Apr 2020 10:35:21 +0800 Subject: [PATCH 14/19] add commont for exception paramcount. --- src/Neo.Compiler.MSIL/MSIL/Conv_Multi.cs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Neo.Compiler.MSIL/MSIL/Conv_Multi.cs b/src/Neo.Compiler.MSIL/MSIL/Conv_Multi.cs index 0928d7e66..9eb505553 100644 --- a/src/Neo.Compiler.MSIL/MSIL/Conv_Multi.cs +++ b/src/Neo.Compiler.MSIL/MSIL/Conv_Multi.cs @@ -1314,16 +1314,16 @@ private int ConvertNewObj(ILMethod from, OpCode src, NeoMethod to) { // NeoVM `catch` instruction need one exception parameter Convert1by1(VM.OpCode.NOP, src, to); + var pcount = _type.Parameters.Count; + //pcount must be 1 + //if more then one, drop them. + //if pcount==0,add one. if (pcount == 0) // If there is no parameter, insert one pararmeter { ConvertPushString("usererror", src, to); } - else if (pcount == 1) - { - - } - else + else if (pcount > 1) { // Keep the first exception parameter for (var i = 0; i < pcount - 1; i++) From 5f97e0a4fcdee5c54143d99d2efc8dccc04d44ac Mon Sep 17 00:00:00 2001 From: Shargon Date: Thu, 30 Apr 2020 09:00:04 +0200 Subject: [PATCH 15/19] Update src/Neo.Compiler.MSIL/MSIL/Converter.cs --- src/Neo.Compiler.MSIL/MSIL/Converter.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Neo.Compiler.MSIL/MSIL/Converter.cs b/src/Neo.Compiler.MSIL/MSIL/Converter.cs index a10f64352..9d443a7c6 100644 --- a/src/Neo.Compiler.MSIL/MSIL/Converter.cs +++ b/src/Neo.Compiler.MSIL/MSIL/Converter.cs @@ -371,7 +371,7 @@ private void ConvertAddrInMethod(NeoMethod to) else { var _addrFinal = addrconv[srcFinal]; - Int32 addroffFinal = (Int32)(_addrFinal - c.addr); + int addroffFinal = (int)(_addrFinal - c.addr); var bytesFinal = BitConverter.GetBytes(addroffFinal); Array.Copy(bytesFinal, 0, c.bytes, 4, 4); } From 0ffbe6a02048beda9113f870e5785f60dddd6cc9 Mon Sep 17 00:00:00 2001 From: Shargon Date: Thu, 30 Apr 2020 09:00:13 +0200 Subject: [PATCH 16/19] Update src/Neo.Compiler.MSIL/MSIL/Converter.cs --- src/Neo.Compiler.MSIL/MSIL/Converter.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Neo.Compiler.MSIL/MSIL/Converter.cs b/src/Neo.Compiler.MSIL/MSIL/Converter.cs index 9d443a7c6..c67b97dc4 100644 --- a/src/Neo.Compiler.MSIL/MSIL/Converter.cs +++ b/src/Neo.Compiler.MSIL/MSIL/Converter.cs @@ -381,7 +381,7 @@ private void ConvertAddrInMethod(NeoMethod to) try { var _addr = addrconv[c.srcaddr]; - Int32 addroff = (Int32)(_addr - c.addr); + int addroff = (int)(_addr - c.addr); c.bytes = BitConverter.GetBytes(addroff); c.needfix = false; } From e891851348322107585faef2d037de0d6ec53046 Mon Sep 17 00:00:00 2001 From: Luchuan Date: Thu, 30 Apr 2020 19:07:04 +0800 Subject: [PATCH 17/19] add try-catch failure ut (#261) --- .../TestClasses/Contract_TryCatch.cs | 29 +++++++++++++++++++ .../UnitTest_TryCatch.cs | 15 ++++++++++ 2 files changed, 44 insertions(+) diff --git a/tests/Neo.Compiler.MSIL.UnitTests/TestClasses/Contract_TryCatch.cs b/tests/Neo.Compiler.MSIL.UnitTests/TestClasses/Contract_TryCatch.cs index e6b579335..c4b9d0e81 100644 --- a/tests/Neo.Compiler.MSIL.UnitTests/TestClasses/Contract_TryCatch.cs +++ b/tests/Neo.Compiler.MSIL.UnitTests/TestClasses/Contract_TryCatch.cs @@ -130,6 +130,35 @@ public static object tryCatch() return v; } + public static object tryWithTwoFinally() + { + int v = 0; + try + { + try + { + v++; + } + catch + { + v += 2; + } + finally + { + v += 3; + } + } + catch + { + v += 4; + } + finally + { + v += 5; + } + return v; + } + public static object throwcall() { throw new System.Exception(); diff --git a/tests/Neo.Compiler.MSIL.UnitTests/UnitTest_TryCatch.cs b/tests/Neo.Compiler.MSIL.UnitTests/UnitTest_TryCatch.cs index 2e931ab66..30c4b06e1 100644 --- a/tests/Neo.Compiler.MSIL.UnitTests/UnitTest_TryCatch.cs +++ b/tests/Neo.Compiler.MSIL.UnitTests/UnitTest_TryCatch.cs @@ -107,5 +107,20 @@ public void Test_TryCatch() Console.WriteLine("result = " + num.ToBigInteger().ToString()); Assert.AreEqual(num.ToBigInteger(), 3); } + + [TestMethod] + public void Test_TryWithTwoFinally() + { + var testengine = new TestEngine(); + testengine.AddEntryScript("./TestClasses/Contract_TryCatch.cs"); + testengine.ScriptEntry.DumpNEF(); + var result = testengine.ExecuteTestCaseStandard("tryWithTwoFinally"); + Console.WriteLine("state=" + testengine.State + " result on stack= " + result.Count); + var value = result.Pop(); + Console.WriteLine("result:" + value.Type + " " + value.ToString()); + var num = value as Neo.VM.Types.Integer; + Console.WriteLine("result = " + num.ToBigInteger().ToString()); + Assert.AreEqual(num.ToBigInteger(), 9); + } } } From 3089c6d2cf6c45e9c11415e42beceea227d1d9b1 Mon Sep 17 00:00:00 2001 From: lights Date: Sat, 2 May 2020 10:06:13 +0800 Subject: [PATCH 18/19] fix some skip leaves problem. --- src/Neo.Compiler.MSIL/MSIL/Converter.cs | 24 +++---- src/Neo.Compiler.MSIL/MSIL/ILModule.cs | 66 +++++++++++-------- .../Neo.Compiler.MSIL.UnitTests.csproj | 3 - 3 files changed, 48 insertions(+), 45 deletions(-) diff --git a/src/Neo.Compiler.MSIL/MSIL/Converter.cs b/src/Neo.Compiler.MSIL/MSIL/Converter.cs index c67b97dc4..b02f927a5 100644 --- a/src/Neo.Compiler.MSIL/MSIL/Converter.cs +++ b/src/Neo.Compiler.MSIL/MSIL/Converter.cs @@ -550,29 +550,21 @@ private int ConvertCode(ILMethod method, OpCode src, NeoMethod to) case CodeEx.Leave_S: {//will support try catch + var tryinfo = method.GetTryInfo(src.addr, out ILMethod.TryCodeType type); - if (method.IsTryCode(src.addr)) + //leaves in try + //leaves in catch + if (type == ILMethod.TryCodeType.Try || type == ILMethod.TryCodeType.Catch) { var code = Convert1by1(VM.OpCode.ENDTRY_L, src, to, new byte[] { 0, 0, 0, 0 }); code.needfix = true; code.srcaddr = src.tokenAddr_Index; } - else + else //or else just jmp { - ILCatchInfo catchinfo = method.GetCatchInfo(src.addr); - if (catchinfo != null) - { - var code = Convert1by1(VM.OpCode.ENDTRY_L, src, to, new byte[] { 0, 0, 0, 0 }); - code.needfix = true; - code.srcaddr = src.tokenAddr_Index; - } - else - { - //maybe is in finally try ,just jump. - var code = Convert1by1(VM.OpCode.JMP_L, src, to, new byte[] { 0, 0, 0, 0 }); - code.needfix = true; - code.srcaddr = src.tokenAddr_Index; - } + var code = Convert1by1(VM.OpCode.JMP_L, src, to, new byte[] { 0, 0, 0, 0 }); + code.needfix = true; + code.srcaddr = src.tokenAddr_Index; } } break; diff --git a/src/Neo.Compiler.MSIL/MSIL/ILModule.cs b/src/Neo.Compiler.MSIL/MSIL/ILModule.cs index 4014214bb..3acec93e5 100644 --- a/src/Neo.Compiler.MSIL/MSIL/ILModule.cs +++ b/src/Neo.Compiler.MSIL/MSIL/ILModule.cs @@ -209,6 +209,7 @@ public class ILTryInfo { public int addr_Try_Begin = -1; public int addr_Try_End = -1; + public int addr_Try_End_F = -1;//IL try catch,try final is 2 different Block,need to process that. public Dictionary catch_Infos = new Dictionary(); public int addr_Finally_Begin = -1; public int addr_Finally_End = -1; @@ -301,7 +302,6 @@ public ILMethod(ILType type, Mono.Cecil.MethodDefinition method, ILogger logger tryinfo.addr_Try_Begin = e.TryStart.Offset; tryinfo.addr_Try_End = e.TryEnd.Offset; - var catchtypestr = e.CatchType.FullName; tryinfo.catch_Infos[catchtypestr] = new ILCatchInfo() @@ -340,7 +340,7 @@ public ILMethod(ILType type, Mono.Cecil.MethodDefinition method, ILogger logger var tryinfo = mapTryInfos[key]; tryinfo.addr_Try_Begin = start; tryinfo.addr_Try_End = end; - + tryinfo.addr_Try_End_F = e.TryEnd.Offset; tryinfo.addr_Finally_Begin = e.HandlerStart.Offset; tryinfo.addr_Finally_End = e.HandlerEnd.Offset; @@ -361,40 +361,73 @@ public ILMethod(ILType type, Mono.Cecil.MethodDefinition method, ILogger logger } } - public ILTryInfo GetTryInfo(int addr) + public enum TryCodeType + { + None, + Try, + Try_Final, + Catch, + Final, + } + public ILTryInfo GetTryInfo(int addr, out TryCodeType type) { + type = TryCodeType.None; ILTryInfo last = null; int begin = -1; int end = -1; foreach (var info in tryInfos) { - //find match try + //check try first if (info.addr_Try_Begin <= addr && addr < info.addr_Try_End) { if (last == null) { + type = TryCodeType.Try; last = info; begin = info.addr_Try_Begin; end = last.addr_Try_End; } - else if (begin <= info.addr_Try_Begin && last.addr_Try_End <= end) + else if (begin <= info.addr_Try_Begin && last.addr_Try_End < end) { + type = TryCodeType.Try; last = info; begin = info.addr_Try_Begin; end = last.addr_Try_End; } } + + //then code in final but not in try + if (info.addr_Try_Begin <= addr && addr < info.addr_Try_End_F) + { + if (last == null) + { + type = TryCodeType.Try_Final; + last = info; + begin = info.addr_Try_Begin; + end = last.addr_Try_End_F; + } + else if (begin <= info.addr_Try_Begin && last.addr_Try_End_F < end) + { + type = TryCodeType.Try_Final; + last = info; + begin = info.addr_Try_Begin; + end = last.addr_Try_End_F; + } + } + //find match finally if (info.addr_Finally_Begin <= addr && addr < info.addr_Finally_End) { if (last == null) { + type = TryCodeType.Final; last = info; begin = info.addr_Finally_Begin; end = last.addr_Finally_End; } else if (begin <= info.addr_Finally_Begin && last.addr_Finally_End < end) { + type = TryCodeType.Final; last = info; begin = info.addr_Finally_Begin; end = last.addr_Finally_End; @@ -407,12 +440,14 @@ public ILTryInfo GetTryInfo(int addr) { if (last == null) { + type = TryCodeType.Catch; last = info; begin = c.Value.addrBegin; end = c.Value.addrEnd; } else if (begin <= c.Value.addrBegin && c.Value.addrBegin < end) { + type = TryCodeType.Catch; last = info; begin = c.Value.addrBegin; end = c.Value.addrEnd; @@ -423,27 +458,6 @@ public ILTryInfo GetTryInfo(int addr) return last; } - public bool IsTryCode(int addr) - { - ILTryInfo info = GetTryInfo(addr); - if (info == null) - return false; - return info.addr_Try_Begin <= addr && addr <= info.addr_Try_End; - } - - public ILCatchInfo GetCatchInfo(int addr) - { - ILTryInfo info = GetTryInfo(addr); - if (info == null) - return null; - foreach (var c in info.catch_Infos) - { - if (c.Value.addrBegin <= addr && addr <= c.Value.addrEnd) - return c.Value; - } - return null; - } - public int GetLastCodeAddr(int srcaddr) { int last = -1; diff --git a/tests/Neo.Compiler.MSIL.UnitTests/Neo.Compiler.MSIL.UnitTests.csproj b/tests/Neo.Compiler.MSIL.UnitTests/Neo.Compiler.MSIL.UnitTests.csproj index a60001096..c788f95b3 100644 --- a/tests/Neo.Compiler.MSIL.UnitTests/Neo.Compiler.MSIL.UnitTests.csproj +++ b/tests/Neo.Compiler.MSIL.UnitTests/Neo.Compiler.MSIL.UnitTests.csproj @@ -32,9 +32,6 @@ - - PreserveNewest - Never From a523a0213837195eab64158926b6880a9424a5fd Mon Sep 17 00:00:00 2001 From: Shargon Date: Sat, 2 May 2020 11:02:09 +0200 Subject: [PATCH 19/19] Reduce changes --- src/Neo.Compiler.MSIL/Optimizer/Parser_UseShortAddress.cs | 4 ---- src/Neo.SmartContract.Framework/OpCode.cs | 1 - .../Neo.Compiler.MSIL.UnitTests.csproj | 4 ---- .../Services/Neo/ContractTest.cs | 6 +++--- 4 files changed, 3 insertions(+), 12 deletions(-) diff --git a/src/Neo.Compiler.MSIL/Optimizer/Parser_UseShortAddress.cs b/src/Neo.Compiler.MSIL/Optimizer/Parser_UseShortAddress.cs index 7d598baa3..215428435 100644 --- a/src/Neo.Compiler.MSIL/Optimizer/Parser_UseShortAddress.cs +++ b/src/Neo.Compiler.MSIL/Optimizer/Parser_UseShortAddress.cs @@ -37,10 +37,6 @@ public void Parse(List items) for (int x = 0; x < items.Count; x++) { if (!(items[x] is NefInstruction inst)) continue; - if (inst.OpCode == OpCode.TRY_L) - { - - } if (inst.OpCode == OpCode.PUSHA) continue; //PUSHA is not 8 bits if (inst.AddressSize != 4) continue; diff --git a/src/Neo.SmartContract.Framework/OpCode.cs b/src/Neo.SmartContract.Framework/OpCode.cs index a8457fe00..e563f4701 100644 --- a/src/Neo.SmartContract.Framework/OpCode.cs +++ b/src/Neo.SmartContract.Framework/OpCode.cs @@ -4,7 +4,6 @@ public enum OpCode : byte { #region Constants - PUSHINT8 = 0x00, PUSHINT16 = 0x01, PUSHINT32 = 0x02, diff --git a/tests/Neo.Compiler.MSIL.UnitTests/Neo.Compiler.MSIL.UnitTests.csproj b/tests/Neo.Compiler.MSIL.UnitTests/Neo.Compiler.MSIL.UnitTests.csproj index c788f95b3..aafd4b64e 100644 --- a/tests/Neo.Compiler.MSIL.UnitTests/Neo.Compiler.MSIL.UnitTests.csproj +++ b/tests/Neo.Compiler.MSIL.UnitTests/Neo.Compiler.MSIL.UnitTests.csproj @@ -29,10 +29,7 @@ - - - Never @@ -45,7 +42,6 @@ PreserveNewest - diff --git a/tests/Neo.SmartContract.Framework.UnitTests/Services/Neo/ContractTest.cs b/tests/Neo.SmartContract.Framework.UnitTests/Services/Neo/ContractTest.cs index 40f261c40..959e2d90a 100644 --- a/tests/Neo.SmartContract.Framework.UnitTests/Services/Neo/ContractTest.cs +++ b/tests/Neo.SmartContract.Framework.UnitTests/Services/Neo/ContractTest.cs @@ -55,7 +55,6 @@ public void Test_CreateCallDestroy() Assert.AreEqual(VMState.HALT, _engine.State); Assert.AreEqual(1, result.Count); - item = result.Pop(); Assert.IsInstanceOfType(item, typeof(Integer)); Assert.AreEqual(123, item.GetBigInteger()); @@ -67,7 +66,6 @@ public void Test_CreateCallDestroy() Assert.AreEqual(VMState.HALT, _engine.State); Assert.AreEqual(0, result.Count); - // Check again for failures _engine.Reset(); @@ -79,7 +77,6 @@ public void Test_CreateCallDestroy() [TestMethod] public void Test_Update() { - // Create var script = _engine.Build("./TestClasses/Contract_CreateAndUpdate.cs"); @@ -150,6 +147,7 @@ public void Test_Update() public void Test_CreateStandardAccount() { // Wrong pubKey + _engine.Reset(); var result = _engine.ExecuteTestCaseStandard("createStandardAccount", new byte[] { 0x01, 0x02 }); Assert.AreEqual(VMState.FAULT, _engine.State); @@ -158,6 +156,7 @@ public void Test_CreateStandardAccount() _engine.Reset(); // Good pubKey (compressed) + _engine.Reset(); result = _engine.ExecuteTestCaseStandard("createStandardAccount", new byte[] { 0x02, 0x48, 0x6f, 0xd1, 0x57, 0x02, 0xc4, 0x49, 0x0a, 0x26, 0x70, 0x31, 0x12, 0xa5, 0xcc, 0x1d, 0x09, 0x23, 0xfd, 0x69, 0x7a, 0x33, 0x40, 0x6b, 0xd5, 0xa1, 0xc0, 0x0e, 0x00, 0x13, 0xb0, 0x9a, 0x70 }); Assert.AreEqual(VMState.HALT, _engine.State); @@ -168,6 +167,7 @@ public void Test_CreateStandardAccount() Assert.AreEqual("8b67a062c232ce87dc65cc69391ea909e721cd98", item.GetSpan().ToHexString()); // Good pubKey (uncompressed) + _engine.Reset(); result = _engine.ExecuteTestCaseStandard("createStandardAccount", new byte[] { 0x04, 0x48, 0x6f, 0xd1, 0x57, 0x02, 0xc4, 0x49, 0x0a, 0x26, 0x70, 0x31, 0x12, 0xa5, 0xcc, 0x1d, 0x09, 0x23, 0xfd, 0x69, 0x7a, 0x33, 0x40, 0x6b, 0xd5, 0xa1, 0xc0, 0x0e, 0x00, 0x13, 0xb0, 0x9a, 0x70, 0x05, 0x43, 0x6c, 0x08, 0x2c, 0x2c, 0x88, 0x08, 0x5b, 0x4b, 0x53, 0xd5, 0x4c, 0x55, 0x66, 0xba, 0x44, 0x8d, 0x5c, 0x3e, 0x2a, 0x2a, 0x5c, 0x3a, 0x3e, 0xa5, 0x00, 0xe1, 0x40, 0x77, 0x55, 0x9c }); Assert.AreEqual(VMState.HALT, _engine.State);