From f28363914fa23bb0bee11934aec3c3f4096cfa6c Mon Sep 17 00:00:00 2001 From: Hecate2 <2474101468@qq.com> Date: Mon, 21 Oct 2024 13:16:47 +0800 Subject: [PATCH 1/5] helper to get engine error info --- .../SmartContract/ApplicationEngine.Helper.cs | 58 +++++++++++++++++++ .../SmartContract/UT_ApplicationEngine.cs | 7 +++ 2 files changed, 65 insertions(+) create mode 100644 src/Neo/SmartContract/ApplicationEngine.Helper.cs diff --git a/src/Neo/SmartContract/ApplicationEngine.Helper.cs b/src/Neo/SmartContract/ApplicationEngine.Helper.cs new file mode 100644 index 0000000000..290acb838b --- /dev/null +++ b/src/Neo/SmartContract/ApplicationEngine.Helper.cs @@ -0,0 +1,58 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// ApplicationEngine.Helper.cs file belongs to the neo project and is free +// software distributed under the MIT software license, see the +// accompanying file LICENSE in the main directory of the +// repository or http://www.opensource.org/licenses/mit-license.php +// for more details. +// +// Redistribution and use in source and binary forms with or without +// modifications are permitted. + +using Neo.SmartContract.Native; +using Neo.VM; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace Neo.SmartContract +{ + public partial class ApplicationEngine : ExecutionEngine + { + public string GetEngineErrorInfo() + { + if (State != VMState.FAULT || FaultException == null) + return null; + StringBuilder traceback = new(); + try + { + if (CallingScriptHash != null) + traceback.AppendLine($"CallingScriptHash={CallingScriptHash}[{NativeContract.ContractManagement.GetContract(SnapshotCache, CallingScriptHash)?.Manifest.Name}]"); + } + catch { } + try + { + traceback.AppendLine($"CurrentScriptHash={CurrentScriptHash}[{NativeContract.ContractManagement.GetContract(SnapshotCache, CurrentScriptHash)?.Manifest.Name}]"); + } + catch { } + try + { + traceback.AppendLine($"EntryScriptHash={EntryScriptHash}"); + } + catch { } + + foreach (ExecutionContext context in InvocationStack.Reverse()) + { + UInt160 contextScriptHash = context.GetScriptHash(); + string contextContractName = NativeContract.ContractManagement.GetContract(SnapshotCache, contextScriptHash)?.Manifest.Name; + traceback.AppendLine($"\tInstructionPointer={context.InstructionPointer}, OpCode {context.CurrentInstruction?.OpCode}, Script Length={context.Script.Length} {contextScriptHash}[{contextContractName}]"); + } + Exception baseException = FaultException.GetBaseException(); + traceback.AppendLine(baseException.StackTrace); + traceback.AppendLine(baseException.Message); + + return traceback.ToString(); + } + } +} diff --git a/tests/Neo.UnitTests/SmartContract/UT_ApplicationEngine.cs b/tests/Neo.UnitTests/SmartContract/UT_ApplicationEngine.cs index a670e3b4b7..4166a7a914 100644 --- a/tests/Neo.UnitTests/SmartContract/UT_ApplicationEngine.cs +++ b/tests/Neo.UnitTests/SmartContract/UT_ApplicationEngine.cs @@ -167,8 +167,15 @@ public void TestSystem_Contract_Call_Permissions() }; var currentScriptHash = engine.EntryScriptHash; + Assert.IsNull(engine.GetEngineErrorInfo()); Assert.AreEqual(VMState.FAULT, engine.Execute()); Assert.IsTrue(engine.FaultException.ToString().Contains($"Cannot Call Method disallowed Of Contract {scriptHash.ToString()}")); + string traceback = engine.GetEngineErrorInfo(); + Assert.IsTrue(traceback.Contains($"Cannot Call Method disallowed Of Contract {scriptHash.ToString()}")); + Assert.IsTrue(traceback.Contains("CurrentScriptHash")); + Assert.IsTrue(traceback.Contains("EntryScriptHash")); + Assert.IsTrue(traceback.Contains("InstructionPointer")); + Assert.IsTrue(traceback.Contains("OpCode SYSCALL, Script Length=")); } // Allowed method call. From fb59cc63b87d59fc2113c607fd6d286755e322b3 Mon Sep 17 00:00:00 2001 From: Hecate2 <2474101468@qq.com> Date: Mon, 21 Oct 2024 13:35:01 +0800 Subject: [PATCH 2/5] cancel try --- .../SmartContract/ApplicationEngine.Helper.cs | 20 ++++--------------- 1 file changed, 4 insertions(+), 16 deletions(-) diff --git a/src/Neo/SmartContract/ApplicationEngine.Helper.cs b/src/Neo/SmartContract/ApplicationEngine.Helper.cs index 290acb838b..2fe58ca8cc 100644 --- a/src/Neo/SmartContract/ApplicationEngine.Helper.cs +++ b/src/Neo/SmartContract/ApplicationEngine.Helper.cs @@ -25,22 +25,10 @@ public string GetEngineErrorInfo() if (State != VMState.FAULT || FaultException == null) return null; StringBuilder traceback = new(); - try - { - if (CallingScriptHash != null) - traceback.AppendLine($"CallingScriptHash={CallingScriptHash}[{NativeContract.ContractManagement.GetContract(SnapshotCache, CallingScriptHash)?.Manifest.Name}]"); - } - catch { } - try - { - traceback.AppendLine($"CurrentScriptHash={CurrentScriptHash}[{NativeContract.ContractManagement.GetContract(SnapshotCache, CurrentScriptHash)?.Manifest.Name}]"); - } - catch { } - try - { - traceback.AppendLine($"EntryScriptHash={EntryScriptHash}"); - } - catch { } + if (CallingScriptHash != null) + traceback.AppendLine($"CallingScriptHash={CallingScriptHash}[{NativeContract.ContractManagement.GetContract(SnapshotCache, CallingScriptHash)?.Manifest.Name}]"); + traceback.AppendLine($"CurrentScriptHash={CurrentScriptHash}[{NativeContract.ContractManagement.GetContract(SnapshotCache, CurrentScriptHash)?.Manifest.Name}]"); + traceback.AppendLine($"EntryScriptHash={EntryScriptHash}"); foreach (ExecutionContext context in InvocationStack.Reverse()) { From 5cbc78c57627e9a44fec0bbab2f1557188277ee0 Mon Sep 17 00:00:00 2001 From: Jimmy Date: Mon, 21 Oct 2024 20:40:15 +0800 Subject: [PATCH 3/5] Update src/Neo/SmartContract/ApplicationEngine.Helper.cs Co-authored-by: Shargon --- src/Neo/SmartContract/ApplicationEngine.Helper.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Neo/SmartContract/ApplicationEngine.Helper.cs b/src/Neo/SmartContract/ApplicationEngine.Helper.cs index 2fe58ca8cc..687e8d84f3 100644 --- a/src/Neo/SmartContract/ApplicationEngine.Helper.cs +++ b/src/Neo/SmartContract/ApplicationEngine.Helper.cs @@ -20,7 +20,7 @@ namespace Neo.SmartContract { public partial class ApplicationEngine : ExecutionEngine { - public string GetEngineErrorInfo() + public string? GetEngineErrorInfo() { if (State != VMState.FAULT || FaultException == null) return null; From 3987e074174dc31d7ee80467dbaa33739a916cd6 Mon Sep 17 00:00:00 2001 From: Hecate2 <2474101468@qq.com> Date: Tue, 22 Oct 2024 10:25:08 +0800 Subject: [PATCH 4/5] standalone method to get exception stack trace and message --- .../SmartContract/ApplicationEngine.Helper.cs | 20 ++++++++++++++----- .../SmartContract/UT_ApplicationEngine.cs | 4 ++-- 2 files changed, 17 insertions(+), 7 deletions(-) diff --git a/src/Neo/SmartContract/ApplicationEngine.Helper.cs b/src/Neo/SmartContract/ApplicationEngine.Helper.cs index 687e8d84f3..8da61efb03 100644 --- a/src/Neo/SmartContract/ApplicationEngine.Helper.cs +++ b/src/Neo/SmartContract/ApplicationEngine.Helper.cs @@ -12,7 +12,6 @@ using Neo.SmartContract.Native; using Neo.VM; using System; -using System.Collections.Generic; using System.Linq; using System.Text; @@ -20,7 +19,7 @@ namespace Neo.SmartContract { public partial class ApplicationEngine : ExecutionEngine { - public string? GetEngineErrorInfo() + public string? GetEngineStackInfoOnFault(bool exceptionStackTrace = true, bool exceptionMessage = true) { if (State != VMState.FAULT || FaultException == null) return null; @@ -36,11 +35,22 @@ public partial class ApplicationEngine : ExecutionEngine string contextContractName = NativeContract.ContractManagement.GetContract(SnapshotCache, contextScriptHash)?.Manifest.Name; traceback.AppendLine($"\tInstructionPointer={context.InstructionPointer}, OpCode {context.CurrentInstruction?.OpCode}, Script Length={context.Script.Length} {contextScriptHash}[{contextContractName}]"); } - Exception baseException = FaultException.GetBaseException(); - traceback.AppendLine(baseException.StackTrace); - traceback.AppendLine(baseException.Message); + traceback.Append(GetEngineExceptionInfo(exceptionStackTrace: exceptionStackTrace, exceptionMessage: exceptionMessage)); return traceback.ToString(); } + + public string? GetEngineExceptionInfo(bool exceptionStackTrace = true, bool exceptionMessage = true) + { + if (State != VMState.FAULT || FaultException == null) + return null; + StringBuilder traceback = new(); + Exception baseException = FaultException.GetBaseException(); + if (exceptionStackTrace) + traceback.AppendLine(baseException.StackTrace); + if (exceptionMessage) + traceback.AppendLine(baseException.Message); + return traceback.ToString(); + } } } diff --git a/tests/Neo.UnitTests/SmartContract/UT_ApplicationEngine.cs b/tests/Neo.UnitTests/SmartContract/UT_ApplicationEngine.cs index 4166a7a914..7b379d5eb1 100644 --- a/tests/Neo.UnitTests/SmartContract/UT_ApplicationEngine.cs +++ b/tests/Neo.UnitTests/SmartContract/UT_ApplicationEngine.cs @@ -167,10 +167,10 @@ public void TestSystem_Contract_Call_Permissions() }; var currentScriptHash = engine.EntryScriptHash; - Assert.IsNull(engine.GetEngineErrorInfo()); + Assert.IsNull(engine.GetEngineStackInfoOnFault()); Assert.AreEqual(VMState.FAULT, engine.Execute()); Assert.IsTrue(engine.FaultException.ToString().Contains($"Cannot Call Method disallowed Of Contract {scriptHash.ToString()}")); - string traceback = engine.GetEngineErrorInfo(); + string traceback = engine.GetEngineStackInfoOnFault(); Assert.IsTrue(traceback.Contains($"Cannot Call Method disallowed Of Contract {scriptHash.ToString()}")); Assert.IsTrue(traceback.Contains("CurrentScriptHash")); Assert.IsTrue(traceback.Contains("EntryScriptHash")); From 416cc5b6da968007ce2d6788a393ea9abe08d5a1 Mon Sep 17 00:00:00 2001 From: Hecate2 <2474101468@qq.com> Date: Tue, 22 Oct 2024 10:32:29 +0800 Subject: [PATCH 5/5] always return string --- src/Neo/SmartContract/ApplicationEngine.Helper.cs | 8 ++++---- tests/Neo.UnitTests/SmartContract/UT_ApplicationEngine.cs | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Neo/SmartContract/ApplicationEngine.Helper.cs b/src/Neo/SmartContract/ApplicationEngine.Helper.cs index 8da61efb03..5d2976c288 100644 --- a/src/Neo/SmartContract/ApplicationEngine.Helper.cs +++ b/src/Neo/SmartContract/ApplicationEngine.Helper.cs @@ -19,10 +19,10 @@ namespace Neo.SmartContract { public partial class ApplicationEngine : ExecutionEngine { - public string? GetEngineStackInfoOnFault(bool exceptionStackTrace = true, bool exceptionMessage = true) + public string GetEngineStackInfoOnFault(bool exceptionStackTrace = true, bool exceptionMessage = true) { if (State != VMState.FAULT || FaultException == null) - return null; + return ""; StringBuilder traceback = new(); if (CallingScriptHash != null) traceback.AppendLine($"CallingScriptHash={CallingScriptHash}[{NativeContract.ContractManagement.GetContract(SnapshotCache, CallingScriptHash)?.Manifest.Name}]"); @@ -40,10 +40,10 @@ public partial class ApplicationEngine : ExecutionEngine return traceback.ToString(); } - public string? GetEngineExceptionInfo(bool exceptionStackTrace = true, bool exceptionMessage = true) + public string GetEngineExceptionInfo(bool exceptionStackTrace = true, bool exceptionMessage = true) { if (State != VMState.FAULT || FaultException == null) - return null; + return ""; StringBuilder traceback = new(); Exception baseException = FaultException.GetBaseException(); if (exceptionStackTrace) diff --git a/tests/Neo.UnitTests/SmartContract/UT_ApplicationEngine.cs b/tests/Neo.UnitTests/SmartContract/UT_ApplicationEngine.cs index 7b379d5eb1..def978596e 100644 --- a/tests/Neo.UnitTests/SmartContract/UT_ApplicationEngine.cs +++ b/tests/Neo.UnitTests/SmartContract/UT_ApplicationEngine.cs @@ -167,7 +167,7 @@ public void TestSystem_Contract_Call_Permissions() }; var currentScriptHash = engine.EntryScriptHash; - Assert.IsNull(engine.GetEngineStackInfoOnFault()); + Assert.AreEqual("", engine.GetEngineStackInfoOnFault()); Assert.AreEqual(VMState.FAULT, engine.Execute()); Assert.IsTrue(engine.FaultException.ToString().Contains($"Cannot Call Method disallowed Of Contract {scriptHash.ToString()}")); string traceback = engine.GetEngineStackInfoOnFault();