From f0fe8651e933a4248a1049f2d2d4acff9619d585 Mon Sep 17 00:00:00 2001 From: Fernando Diaz Toledano Date: Fri, 9 Feb 2024 20:31:23 +0100 Subject: [PATCH 001/106] Creating source from nef --- neo-devpack-dotnet.sln | 234 ++++++++++-------- src/Neo.Compiler.CSharp/CompilationResult.cs | 24 ++ src/Neo.Compiler.CSharp/Compiler.cs | 71 ++++++ .../templates/neocontractnep17/Contract1.cs | 28 ++- src/Neo.SmartContract.TestEngine/Artifacts.cs | 130 ++++++++++ .../CompilationResult.cs | 23 ++ .../Mocks/SmartContract.cs | 16 ++ .../Neo.SmartContract.TestEngine.csproj | 23 ++ .../TestEngine.cs | 92 +++++++ .../ArtifactsTests.cs | 48 ++++ .../GlobalUsings.cs | 1 + ....SmartContract.TestEngine.UnitTests.csproj | 26 ++ 12 files changed, 593 insertions(+), 123 deletions(-) create mode 100644 src/Neo.Compiler.CSharp/CompilationResult.cs create mode 100644 src/Neo.Compiler.CSharp/Compiler.cs create mode 100644 src/Neo.SmartContract.TestEngine/Artifacts.cs create mode 100644 src/Neo.SmartContract.TestEngine/CompilationResult.cs create mode 100644 src/Neo.SmartContract.TestEngine/Mocks/SmartContract.cs create mode 100644 src/Neo.SmartContract.TestEngine/Neo.SmartContract.TestEngine.csproj create mode 100644 src/Neo.SmartContract.TestEngine/TestEngine.cs create mode 100644 tests/Neo.SmartContract.TestEngine.UnitTests/ArtifactsTests.cs create mode 100644 tests/Neo.SmartContract.TestEngine.UnitTests/GlobalUsings.cs create mode 100644 tests/Neo.SmartContract.TestEngine.UnitTests/Neo.SmartContract.TestEngine.UnitTests.csproj diff --git a/neo-devpack-dotnet.sln b/neo-devpack-dotnet.sln index ab0501653..dd9d42b41 100644 --- a/neo-devpack-dotnet.sln +++ b/neo-devpack-dotnet.sln @@ -1,110 +1,124 @@ -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 16 -VisualStudioVersion = 16.0.28803.452 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Neo.SmartContract.Framework", "src\Neo.SmartContract.Framework\Neo.SmartContract.Framework.csproj", "{C30B5859-D4B9-46E8-A797-6B0A1B49B590}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Neo.Compiler.CSharp", "src\Neo.Compiler.CSharp\Neo.Compiler.CSharp.csproj", "{A2A3B687-A1EC-4221-B792-9BBA8DED09DA}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Neo.SmartContract.Template", "src\Neo.SmartContract.Template\Neo.SmartContract.Template.csproj", "{FC0CAF5A-30A7-4857-B1A4-486FAAA39E5A}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Neo.Compiler.CSharp.UnitTests", "tests\Neo.Compiler.CSharp.UnitTests\Neo.Compiler.CSharp.UnitTests.csproj", "{4C6B120B-99B5-4888-B8D5-45031458DD07}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Neo.SmartContract.Framework.UnitTests", "tests\Neo.SmartContract.Framework.UnitTests\Neo.SmartContract.Framework.UnitTests.csproj", "{93BEC5CC-BAFF-4389-89E7-84AAFF5D495D}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{79389FC0-C621-4CEA-AD2B-6074C32E7BCA}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{D5266066-0AFD-44D5-A83E-2F73668A63C8}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Neo.Compiler.CSharp.TestContracts", "tests\Neo.Compiler.CSharp.TestContracts\Neo.Compiler.CSharp.TestContracts.csproj", "{8D67DD5A-D683-481F-915E-98683EA38791}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Neo.SmartContract.Framework.TestContracts", "tests\Neo.SmartContract.Framework.TestContracts\Neo.SmartContract.Framework.TestContracts.csproj", "{A372F1D6-51FF-472C-9508-FDAF7E6FEB13}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Neo.SmartContract.TestEngine", "tests\Neo.SmartContract.TestEngine\Neo.SmartContract.TestEngine.csproj", "{D0153204-6AEF-4D94-B0E1-8124C38C91D4}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Neo", "neo\src\Neo\Neo.csproj", "{73223FBD-C562-4FA0-9722-C7F1C382A9DE}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Neo.Cryptography.BLS12_381", "neo\src\Neo.Cryptography.BLS12_381\Neo.Cryptography.BLS12_381.csproj", "{D541BCE9-65BC-475B-94E5-19B6BFFF2B8E}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Neo.Json", "neo\src\Neo.Json\Neo.Json.csproj", "{35A34EBD-F2BF-4D83-A096-D5F007B12732}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Neo.VM", "neo\src\Neo.VM\Neo.VM.csproj", "{D6D53889-5A10-46A4-BA66-E78B56EC1881}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Dependency", "Dependency", "{49D5873D-7B38-48A5-B853-85146F032091}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Release|Any CPU = Release|Any CPU - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {C30B5859-D4B9-46E8-A797-6B0A1B49B590}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {C30B5859-D4B9-46E8-A797-6B0A1B49B590}.Debug|Any CPU.Build.0 = Debug|Any CPU - {C30B5859-D4B9-46E8-A797-6B0A1B49B590}.Release|Any CPU.ActiveCfg = Release|Any CPU - {C30B5859-D4B9-46E8-A797-6B0A1B49B590}.Release|Any CPU.Build.0 = Release|Any CPU - {A2A3B687-A1EC-4221-B792-9BBA8DED09DA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {A2A3B687-A1EC-4221-B792-9BBA8DED09DA}.Debug|Any CPU.Build.0 = Debug|Any CPU - {A2A3B687-A1EC-4221-B792-9BBA8DED09DA}.Release|Any CPU.ActiveCfg = Release|Any CPU - {A2A3B687-A1EC-4221-B792-9BBA8DED09DA}.Release|Any CPU.Build.0 = Release|Any CPU - {FC0CAF5A-30A7-4857-B1A4-486FAAA39E5A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {FC0CAF5A-30A7-4857-B1A4-486FAAA39E5A}.Debug|Any CPU.Build.0 = Debug|Any CPU - {FC0CAF5A-30A7-4857-B1A4-486FAAA39E5A}.Release|Any CPU.ActiveCfg = Release|Any CPU - {FC0CAF5A-30A7-4857-B1A4-486FAAA39E5A}.Release|Any CPU.Build.0 = Release|Any CPU - {4C6B120B-99B5-4888-B8D5-45031458DD07}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {4C6B120B-99B5-4888-B8D5-45031458DD07}.Debug|Any CPU.Build.0 = Debug|Any CPU - {4C6B120B-99B5-4888-B8D5-45031458DD07}.Release|Any CPU.ActiveCfg = Release|Any CPU - {4C6B120B-99B5-4888-B8D5-45031458DD07}.Release|Any CPU.Build.0 = Release|Any CPU - {93BEC5CC-BAFF-4389-89E7-84AAFF5D495D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {93BEC5CC-BAFF-4389-89E7-84AAFF5D495D}.Debug|Any CPU.Build.0 = Debug|Any CPU - {93BEC5CC-BAFF-4389-89E7-84AAFF5D495D}.Release|Any CPU.ActiveCfg = Release|Any CPU - {93BEC5CC-BAFF-4389-89E7-84AAFF5D495D}.Release|Any CPU.Build.0 = Release|Any CPU - {8D67DD5A-D683-481F-915E-98683EA38791}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {8D67DD5A-D683-481F-915E-98683EA38791}.Debug|Any CPU.Build.0 = Debug|Any CPU - {8D67DD5A-D683-481F-915E-98683EA38791}.Release|Any CPU.ActiveCfg = Release|Any CPU - {8D67DD5A-D683-481F-915E-98683EA38791}.Release|Any CPU.Build.0 = Release|Any CPU - {A372F1D6-51FF-472C-9508-FDAF7E6FEB13}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {A372F1D6-51FF-472C-9508-FDAF7E6FEB13}.Debug|Any CPU.Build.0 = Debug|Any CPU - {A372F1D6-51FF-472C-9508-FDAF7E6FEB13}.Release|Any CPU.ActiveCfg = Release|Any CPU - {A372F1D6-51FF-472C-9508-FDAF7E6FEB13}.Release|Any CPU.Build.0 = Release|Any CPU - {D0153204-6AEF-4D94-B0E1-8124C38C91D4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {D0153204-6AEF-4D94-B0E1-8124C38C91D4}.Debug|Any CPU.Build.0 = Debug|Any CPU - {D0153204-6AEF-4D94-B0E1-8124C38C91D4}.Release|Any CPU.ActiveCfg = Release|Any CPU - {D0153204-6AEF-4D94-B0E1-8124C38C91D4}.Release|Any CPU.Build.0 = Release|Any CPU - {73223FBD-C562-4FA0-9722-C7F1C382A9DE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {73223FBD-C562-4FA0-9722-C7F1C382A9DE}.Debug|Any CPU.Build.0 = Debug|Any CPU - {73223FBD-C562-4FA0-9722-C7F1C382A9DE}.Release|Any CPU.ActiveCfg = Release|Any CPU - {73223FBD-C562-4FA0-9722-C7F1C382A9DE}.Release|Any CPU.Build.0 = Release|Any CPU - {D541BCE9-65BC-475B-94E5-19B6BFFF2B8E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {D541BCE9-65BC-475B-94E5-19B6BFFF2B8E}.Debug|Any CPU.Build.0 = Debug|Any CPU - {D541BCE9-65BC-475B-94E5-19B6BFFF2B8E}.Release|Any CPU.ActiveCfg = Release|Any CPU - {D541BCE9-65BC-475B-94E5-19B6BFFF2B8E}.Release|Any CPU.Build.0 = Release|Any CPU - {35A34EBD-F2BF-4D83-A096-D5F007B12732}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {35A34EBD-F2BF-4D83-A096-D5F007B12732}.Debug|Any CPU.Build.0 = Debug|Any CPU - {35A34EBD-F2BF-4D83-A096-D5F007B12732}.Release|Any CPU.ActiveCfg = Release|Any CPU - {35A34EBD-F2BF-4D83-A096-D5F007B12732}.Release|Any CPU.Build.0 = Release|Any CPU - {D6D53889-5A10-46A4-BA66-E78B56EC1881}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {D6D53889-5A10-46A4-BA66-E78B56EC1881}.Debug|Any CPU.Build.0 = Debug|Any CPU - {D6D53889-5A10-46A4-BA66-E78B56EC1881}.Release|Any CPU.ActiveCfg = Release|Any CPU - {D6D53889-5A10-46A4-BA66-E78B56EC1881}.Release|Any CPU.Build.0 = Release|Any CPU - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection - GlobalSection(NestedProjects) = preSolution - {C30B5859-D4B9-46E8-A797-6B0A1B49B590} = {79389FC0-C621-4CEA-AD2B-6074C32E7BCA} - {A2A3B687-A1EC-4221-B792-9BBA8DED09DA} = {79389FC0-C621-4CEA-AD2B-6074C32E7BCA} - {FC0CAF5A-30A7-4857-B1A4-486FAAA39E5A} = {79389FC0-C621-4CEA-AD2B-6074C32E7BCA} - {4C6B120B-99B5-4888-B8D5-45031458DD07} = {D5266066-0AFD-44D5-A83E-2F73668A63C8} - {93BEC5CC-BAFF-4389-89E7-84AAFF5D495D} = {D5266066-0AFD-44D5-A83E-2F73668A63C8} - {8D67DD5A-D683-481F-915E-98683EA38791} = {D5266066-0AFD-44D5-A83E-2F73668A63C8} - {A372F1D6-51FF-472C-9508-FDAF7E6FEB13} = {D5266066-0AFD-44D5-A83E-2F73668A63C8} - {D0153204-6AEF-4D94-B0E1-8124C38C91D4} = {D5266066-0AFD-44D5-A83E-2F73668A63C8} - {73223FBD-C562-4FA0-9722-C7F1C382A9DE} = {49D5873D-7B38-48A5-B853-85146F032091} - {D541BCE9-65BC-475B-94E5-19B6BFFF2B8E} = {49D5873D-7B38-48A5-B853-85146F032091} - {D6D53889-5A10-46A4-BA66-E78B56EC1881} = {49D5873D-7B38-48A5-B853-85146F032091} - {35A34EBD-F2BF-4D83-A096-D5F007B12732} = {49D5873D-7B38-48A5-B853-85146F032091} - EndGlobalSection - GlobalSection(ExtensibilityGlobals) = postSolution - SolutionGuid = {6DA935E1-C674-4364-B087-F1B511B79215} - EndGlobalSection -EndGlobal +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.7.34003.232 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Neo.SmartContract.Framework", "src\Neo.SmartContract.Framework\Neo.SmartContract.Framework.csproj", "{C30B5859-D4B9-46E8-A797-6B0A1B49B590}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Neo.Compiler.CSharp", "src\Neo.Compiler.CSharp\Neo.Compiler.CSharp.csproj", "{A2A3B687-A1EC-4221-B792-9BBA8DED09DA}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Neo.SmartContract.Template", "src\Neo.SmartContract.Template\Neo.SmartContract.Template.csproj", "{FC0CAF5A-30A7-4857-B1A4-486FAAA39E5A}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Neo.Compiler.CSharp.UnitTests", "tests\Neo.Compiler.CSharp.UnitTests\Neo.Compiler.CSharp.UnitTests.csproj", "{4C6B120B-99B5-4888-B8D5-45031458DD07}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Neo.SmartContract.Framework.UnitTests", "tests\Neo.SmartContract.Framework.UnitTests\Neo.SmartContract.Framework.UnitTests.csproj", "{93BEC5CC-BAFF-4389-89E7-84AAFF5D495D}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{79389FC0-C621-4CEA-AD2B-6074C32E7BCA}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{D5266066-0AFD-44D5-A83E-2F73668A63C8}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Neo.Compiler.CSharp.TestContracts", "tests\Neo.Compiler.CSharp.TestContracts\Neo.Compiler.CSharp.TestContracts.csproj", "{8D67DD5A-D683-481F-915E-98683EA38791}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Neo.SmartContract.Framework.TestContracts", "tests\Neo.SmartContract.Framework.TestContracts\Neo.SmartContract.Framework.TestContracts.csproj", "{A372F1D6-51FF-472C-9508-FDAF7E6FEB13}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Neo.SmartContract.TestEngine", "tests\Neo.SmartContract.TestEngine\Neo.SmartContract.TestEngine.csproj", "{D0153204-6AEF-4D94-B0E1-8124C38C91D4}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Neo", "neo\src\Neo\Neo.csproj", "{73223FBD-C562-4FA0-9722-C7F1C382A9DE}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Neo.Cryptography.BLS12_381", "neo\src\Neo.Cryptography.BLS12_381\Neo.Cryptography.BLS12_381.csproj", "{D541BCE9-65BC-475B-94E5-19B6BFFF2B8E}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Neo.Json", "neo\src\Neo.Json\Neo.Json.csproj", "{35A34EBD-F2BF-4D83-A096-D5F007B12732}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Neo.VM", "neo\src\Neo.VM\Neo.VM.csproj", "{D6D53889-5A10-46A4-BA66-E78B56EC1881}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Dependency", "Dependency", "{49D5873D-7B38-48A5-B853-85146F032091}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Neo.SmartContract.TestEngine", "src\Neo.SmartContract.TestEngine\Neo.SmartContract.TestEngine.csproj", "{648DCE6F-A0BA-4032-951B-20CF5BBFD998}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Neo.SmartContract.TestEngine.UnitTests", "tests\Neo.SmartContract.TestEngine.UnitTests\Neo.SmartContract.TestEngine.UnitTests.csproj", "{B772B8A9-9362-4C6F-A6D3-2A4138439B2C}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {C30B5859-D4B9-46E8-A797-6B0A1B49B590}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C30B5859-D4B9-46E8-A797-6B0A1B49B590}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C30B5859-D4B9-46E8-A797-6B0A1B49B590}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C30B5859-D4B9-46E8-A797-6B0A1B49B590}.Release|Any CPU.Build.0 = Release|Any CPU + {A2A3B687-A1EC-4221-B792-9BBA8DED09DA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {A2A3B687-A1EC-4221-B792-9BBA8DED09DA}.Debug|Any CPU.Build.0 = Debug|Any CPU + {A2A3B687-A1EC-4221-B792-9BBA8DED09DA}.Release|Any CPU.ActiveCfg = Release|Any CPU + {A2A3B687-A1EC-4221-B792-9BBA8DED09DA}.Release|Any CPU.Build.0 = Release|Any CPU + {FC0CAF5A-30A7-4857-B1A4-486FAAA39E5A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {FC0CAF5A-30A7-4857-B1A4-486FAAA39E5A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {FC0CAF5A-30A7-4857-B1A4-486FAAA39E5A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {FC0CAF5A-30A7-4857-B1A4-486FAAA39E5A}.Release|Any CPU.Build.0 = Release|Any CPU + {4C6B120B-99B5-4888-B8D5-45031458DD07}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {4C6B120B-99B5-4888-B8D5-45031458DD07}.Debug|Any CPU.Build.0 = Debug|Any CPU + {4C6B120B-99B5-4888-B8D5-45031458DD07}.Release|Any CPU.ActiveCfg = Release|Any CPU + {4C6B120B-99B5-4888-B8D5-45031458DD07}.Release|Any CPU.Build.0 = Release|Any CPU + {93BEC5CC-BAFF-4389-89E7-84AAFF5D495D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {93BEC5CC-BAFF-4389-89E7-84AAFF5D495D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {93BEC5CC-BAFF-4389-89E7-84AAFF5D495D}.Release|Any CPU.ActiveCfg = Release|Any CPU + {93BEC5CC-BAFF-4389-89E7-84AAFF5D495D}.Release|Any CPU.Build.0 = Release|Any CPU + {8D67DD5A-D683-481F-915E-98683EA38791}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {8D67DD5A-D683-481F-915E-98683EA38791}.Debug|Any CPU.Build.0 = Debug|Any CPU + {8D67DD5A-D683-481F-915E-98683EA38791}.Release|Any CPU.ActiveCfg = Release|Any CPU + {8D67DD5A-D683-481F-915E-98683EA38791}.Release|Any CPU.Build.0 = Release|Any CPU + {A372F1D6-51FF-472C-9508-FDAF7E6FEB13}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {A372F1D6-51FF-472C-9508-FDAF7E6FEB13}.Debug|Any CPU.Build.0 = Debug|Any CPU + {A372F1D6-51FF-472C-9508-FDAF7E6FEB13}.Release|Any CPU.ActiveCfg = Release|Any CPU + {A372F1D6-51FF-472C-9508-FDAF7E6FEB13}.Release|Any CPU.Build.0 = Release|Any CPU + {D0153204-6AEF-4D94-B0E1-8124C38C91D4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D0153204-6AEF-4D94-B0E1-8124C38C91D4}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D0153204-6AEF-4D94-B0E1-8124C38C91D4}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D0153204-6AEF-4D94-B0E1-8124C38C91D4}.Release|Any CPU.Build.0 = Release|Any CPU + {73223FBD-C562-4FA0-9722-C7F1C382A9DE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {73223FBD-C562-4FA0-9722-C7F1C382A9DE}.Debug|Any CPU.Build.0 = Debug|Any CPU + {73223FBD-C562-4FA0-9722-C7F1C382A9DE}.Release|Any CPU.ActiveCfg = Release|Any CPU + {73223FBD-C562-4FA0-9722-C7F1C382A9DE}.Release|Any CPU.Build.0 = Release|Any CPU + {D541BCE9-65BC-475B-94E5-19B6BFFF2B8E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D541BCE9-65BC-475B-94E5-19B6BFFF2B8E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D541BCE9-65BC-475B-94E5-19B6BFFF2B8E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D541BCE9-65BC-475B-94E5-19B6BFFF2B8E}.Release|Any CPU.Build.0 = Release|Any CPU + {35A34EBD-F2BF-4D83-A096-D5F007B12732}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {35A34EBD-F2BF-4D83-A096-D5F007B12732}.Debug|Any CPU.Build.0 = Debug|Any CPU + {35A34EBD-F2BF-4D83-A096-D5F007B12732}.Release|Any CPU.ActiveCfg = Release|Any CPU + {35A34EBD-F2BF-4D83-A096-D5F007B12732}.Release|Any CPU.Build.0 = Release|Any CPU + {D6D53889-5A10-46A4-BA66-E78B56EC1881}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D6D53889-5A10-46A4-BA66-E78B56EC1881}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D6D53889-5A10-46A4-BA66-E78B56EC1881}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D6D53889-5A10-46A4-BA66-E78B56EC1881}.Release|Any CPU.Build.0 = Release|Any CPU + {648DCE6F-A0BA-4032-951B-20CF5BBFD998}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {648DCE6F-A0BA-4032-951B-20CF5BBFD998}.Debug|Any CPU.Build.0 = Debug|Any CPU + {648DCE6F-A0BA-4032-951B-20CF5BBFD998}.Release|Any CPU.ActiveCfg = Release|Any CPU + {648DCE6F-A0BA-4032-951B-20CF5BBFD998}.Release|Any CPU.Build.0 = Release|Any CPU + {B772B8A9-9362-4C6F-A6D3-2A4138439B2C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B772B8A9-9362-4C6F-A6D3-2A4138439B2C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B772B8A9-9362-4C6F-A6D3-2A4138439B2C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B772B8A9-9362-4C6F-A6D3-2A4138439B2C}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {C30B5859-D4B9-46E8-A797-6B0A1B49B590} = {79389FC0-C621-4CEA-AD2B-6074C32E7BCA} + {A2A3B687-A1EC-4221-B792-9BBA8DED09DA} = {79389FC0-C621-4CEA-AD2B-6074C32E7BCA} + {FC0CAF5A-30A7-4857-B1A4-486FAAA39E5A} = {79389FC0-C621-4CEA-AD2B-6074C32E7BCA} + {4C6B120B-99B5-4888-B8D5-45031458DD07} = {D5266066-0AFD-44D5-A83E-2F73668A63C8} + {93BEC5CC-BAFF-4389-89E7-84AAFF5D495D} = {D5266066-0AFD-44D5-A83E-2F73668A63C8} + {8D67DD5A-D683-481F-915E-98683EA38791} = {D5266066-0AFD-44D5-A83E-2F73668A63C8} + {A372F1D6-51FF-472C-9508-FDAF7E6FEB13} = {D5266066-0AFD-44D5-A83E-2F73668A63C8} + {D0153204-6AEF-4D94-B0E1-8124C38C91D4} = {D5266066-0AFD-44D5-A83E-2F73668A63C8} + {73223FBD-C562-4FA0-9722-C7F1C382A9DE} = {49D5873D-7B38-48A5-B853-85146F032091} + {D541BCE9-65BC-475B-94E5-19B6BFFF2B8E} = {49D5873D-7B38-48A5-B853-85146F032091} + {35A34EBD-F2BF-4D83-A096-D5F007B12732} = {49D5873D-7B38-48A5-B853-85146F032091} + {D6D53889-5A10-46A4-BA66-E78B56EC1881} = {49D5873D-7B38-48A5-B853-85146F032091} + {648DCE6F-A0BA-4032-951B-20CF5BBFD998} = {79389FC0-C621-4CEA-AD2B-6074C32E7BCA} + {B772B8A9-9362-4C6F-A6D3-2A4138439B2C} = {D5266066-0AFD-44D5-A83E-2F73668A63C8} + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {6DA935E1-C674-4364-B087-F1B511B79215} + EndGlobalSection +EndGlobal diff --git a/src/Neo.Compiler.CSharp/CompilationResult.cs b/src/Neo.Compiler.CSharp/CompilationResult.cs new file mode 100644 index 000000000..5f9e3bd67 --- /dev/null +++ b/src/Neo.Compiler.CSharp/CompilationResult.cs @@ -0,0 +1,24 @@ +using Neo.Json; +using Neo.SmartContract; +using Neo.SmartContract.Manifest; + +namespace Neo.Compiler +{ + public class CompilationResult + { + /// + /// Nef + /// + public required NefFile Nef { get; init; } + + /// + /// Contract Manifest + /// + public required ContractManifest Manifest { get; init; } + + /// + /// Debug Info + /// + public required JObject DebugInfo { get; init; } + } +} diff --git a/src/Neo.Compiler.CSharp/Compiler.cs b/src/Neo.Compiler.CSharp/Compiler.cs new file mode 100644 index 000000000..c6be3a102 --- /dev/null +++ b/src/Neo.Compiler.CSharp/Compiler.cs @@ -0,0 +1,71 @@ +using Akka.Util.Internal; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.IO; +using System.Linq; +using System.Numerics; + +namespace Neo.Compiler +{ + public class Compiler + { + private static readonly List references = new(); + + /// + /// Static constructor + /// + static Compiler() + { + string coreDir = Path.GetDirectoryName(typeof(object).Assembly.Location)!; + references.Add(MetadataReference.CreateFromFile(Path.Combine(coreDir, "System.Runtime.dll"))); + references.Add(MetadataReference.CreateFromFile(Path.Combine(coreDir, "System.Runtime.InteropServices.dll"))); + references.Add(MetadataReference.CreateFromFile(typeof(string).Assembly.Location)); + references.Add(MetadataReference.CreateFromFile(typeof(DisplayNameAttribute).Assembly.Location)); + references.Add(MetadataReference.CreateFromFile(typeof(BigInteger).Assembly.Location)); + string folder = Path.GetFullPath("../../../../../src/Neo.SmartContract.Framework/"); + string obj = Path.Combine(folder, "obj"); + IEnumerable st = Directory.EnumerateFiles(folder, "*.cs", SearchOption.AllDirectories) + .Where(p => !p.StartsWith(obj)) + .OrderBy(p => p) + .Select(p => CSharpSyntaxTree.ParseText(File.ReadAllText(p), path: p)); + CSharpCompilationOptions options = new(OutputKind.DynamicallyLinkedLibrary); + CSharpCompilation cr = CSharpCompilation.Create(null, st, references, options); + references.Add(cr.ToMetadataReference()); + } + + /// + /// Compile c# source + /// + /// Optimize + /// Debug + /// Files + /// Compilation Result + public static CompilationResult Compile(bool optimize = true, bool debug = true, params string[] files) + { + CompilationContext context = CompilationContext.Compile(files, references, new Options + { + AddressVersion = ProtocolSettings.Default.AddressVersion, + Debug = debug, + NoOptimize = !optimize + }); + if (context.Success) + { + return new CompilationResult() + { + Nef = context.CreateExecutable(), + Manifest = context.CreateManifest(), + DebugInfo = context.CreateDebugInformation() + }; + } + else + { + context.Diagnostics.ForEach(Console.Error.WriteLine); + + throw new ApplicationException("Error while compiling"); + } + } + } +} diff --git a/src/Neo.SmartContract.Template/templates/neocontractnep17/Contract1.cs b/src/Neo.SmartContract.Template/templates/neocontractnep17/Contract1.cs index c05084d54..4b571e73c 100644 --- a/src/Neo.SmartContract.Template/templates/neocontractnep17/Contract1.cs +++ b/src/Neo.SmartContract.Template/templates/neocontractnep17/Contract1.cs @@ -1,5 +1,4 @@ using Neo; -using Neo.SmartContract; using Neo.SmartContract.Framework; using Neo.SmartContract.Framework.Attributes; using Neo.SmartContract.Framework.Native; @@ -29,15 +28,20 @@ public class Contract1 : Nep17Token [InitialValue("", Neo.SmartContract.ContractParameterType.Hash160)] private static readonly UInt160 InitialOwner = default; - [Safe] - public static UInt160 GetOwner() + // Init method + public static void _deploy(object data) { - var currentOwner = Storage.Get(new[] { Prefix_Owner }); + UInt160 initialOwner = (UInt160)data; + ExecutionEngine.Assert(initialOwner.IsValid && !initialOwner.IsZero, "owner must exists"); - if (currentOwner == null) - return InitialOwner; + Storage.Put(new[] { Prefix_Owner }, initialOwner); + OnSetOwner(initialOwner); + } - return (UInt160)currentOwner; + [Safe] + public static UInt160 GetOwner() + { + return (UInt160)Storage.Get(new[] { Prefix_Owner }); } private static bool IsOwner() => @@ -63,13 +67,11 @@ public static void SetOwner(UInt160 newOwner) #region NEP17 - // NOTE: Valid Range 0-31 - [Safe] - public override byte Decimals() => 8; - // TODO: Replace "EXAMPLE" with a short name all UPPERCASE 3-8 characters - [Safe] - public override string Symbol() => "EXAMPLE"; + public override string Symbol { [Safe] get => "EXAMPLE"; } + + // NOTE: Valid Range 0-31 + public override byte Decimals { [Safe] get => 8; } public static new void Burn(UInt160 account, BigInteger amount) { diff --git a/src/Neo.SmartContract.TestEngine/Artifacts.cs b/src/Neo.SmartContract.TestEngine/Artifacts.cs new file mode 100644 index 000000000..9a9525964 --- /dev/null +++ b/src/Neo.SmartContract.TestEngine/Artifacts.cs @@ -0,0 +1,130 @@ +using Microsoft.CodeDom.Providers.DotNetCompilerPlatform; +using Neo.SmartContract.Manifest; +using System; +using System.CodeDom.Compiler; +using System.IO; +using System.Numerics; +using System.Text; + +namespace Neo.SmartContract.TestEngine +{ + public class Artifacts + { + /// + /// Create artifacts for NefFile + /// + /// Contract manifest + /// Ouptut path for artifacts + public static void CreateArtifacts(ContractManifest manifest, string outputPath) + { + var dependencies = new string[] { + Path.GetFullPath(typeof(Artifacts).Assembly.Location), + Path.GetFullPath(typeof(UInt160).Assembly.Location), + Path.GetFullPath(typeof(BigInteger).Assembly.Location) + }; + + // Compose source code + var sourceCode = CreateSourceFromManifest(manifest); + + // Create a C# Code Provider + CSharpCodeProvider codeProvider = new(); + + // Set compiler parameters + CompilerParameters parameters = new() + { + GenerateExecutable = false, // We want a DLL, not an executable + OutputAssembly = outputPath // Set the output path for the DLL + }; + + // Add referenced assemblies, if any + foreach (var dependency in dependencies) + { + parameters.ReferencedAssemblies.Add(dependency); + } + + // Compile the code + CompilerResults results = codeProvider.CompileAssemblyFromSource(parameters, sourceCode); + + // Check for compilation errors + if (results.Errors.Count > 0) + { + foreach (CompilerError error in results.Errors) + { + Console.WriteLine("Error ({0}): {1}", error.ErrorNumber, error.ErrorText); + } + throw new InvalidOperationException("Compilation failed with errors."); + } + } + + /// + /// Create source code from manifest + /// + /// Manifest + /// Source + public static string CreateSourceFromManifest(ContractManifest manifest) + { + StringBuilder sourceCode = new(); + + sourceCode.AppendLine("using Neo"); + sourceCode.AppendLine("using System.Numerics;"); + sourceCode.AppendLine(""); + sourceCode.AppendLine("namespace Neo.TestEngine.Contracts;"); + sourceCode.AppendLine(""); + sourceCode.AppendLine($"public class {manifest.Name} : Neo.SmartContract.TestEngine.Mocks.SmartContract"); + sourceCode.AppendLine("{"); + + // Create constructor + + sourceCode.AppendLine($" internal {manifest.Name}(Neo.SmartContract.TestEngine.Mocks.SmartContract.TestEngine testEngine) : base(testEngine) {{}}"); + + // Crete methods + + foreach (var method in manifest.Abi.Methods) + { + sourceCode.Append(CreateSourceMethodFromManifest(method)); + } + + sourceCode.AppendLine("}"); + + return sourceCode.ToString(); + } + + /// + /// Create source code from manifest method + /// + /// Contract method + /// Source + private static string CreateSourceMethodFromManifest(ContractMethodDescriptor method) + { + StringBuilder sourceCode = new(); + + sourceCode.AppendLine($" public abstract {TypeToSource(method.ReturnType)} {method.Name} ();"); + + return sourceCode.ToString(); + } + + /// + /// Type to source + /// + /// Type + /// c# type + private static string TypeToSource(ContractParameterType type) + { + return type switch + { + ContractParameterType.Boolean => "bool", + ContractParameterType.Integer => "BigInteger", + ContractParameterType.String => "string", + ContractParameterType.Hash160 => "UInt160", + ContractParameterType.Hash256 => "UInt256", + ContractParameterType.PublicKey => "ECPoint", + ContractParameterType.ByteArray => "byte[]", + ContractParameterType.Signature => "byte[]", + ContractParameterType.Array => "List", + ContractParameterType.Map => "IDictionary", + ContractParameterType.Void => "void", + _ => "object", + }; + } + } +} diff --git a/src/Neo.SmartContract.TestEngine/CompilationResult.cs b/src/Neo.SmartContract.TestEngine/CompilationResult.cs new file mode 100644 index 000000000..b511cded5 --- /dev/null +++ b/src/Neo.SmartContract.TestEngine/CompilationResult.cs @@ -0,0 +1,23 @@ +using Neo.Json; +using Neo.SmartContract.Manifest; + +namespace Neo.SmartContract.TestEngine +{ + public class CompilationResult + { + /// + /// Nef + /// + public required NefFile Nef { get; init; } + + /// + /// Contract Manifest + /// + public required ContractManifest Manifest { get; init; } + + /// + /// Debug Info + /// + public required JObject DebugInfo { get; init; } + } +} diff --git a/src/Neo.SmartContract.TestEngine/Mocks/SmartContract.cs b/src/Neo.SmartContract.TestEngine/Mocks/SmartContract.cs new file mode 100644 index 000000000..e5f183e74 --- /dev/null +++ b/src/Neo.SmartContract.TestEngine/Mocks/SmartContract.cs @@ -0,0 +1,16 @@ +namespace Neo.SmartContract.TestEngine.Mocks +{ + public class SmartContract + { + private readonly TestEngine _engine; + + /// + /// Constructor + /// + /// TestEngine + protected SmartContract(TestEngine testEngine) + { + _engine = testEngine; + } + } +} diff --git a/src/Neo.SmartContract.TestEngine/Neo.SmartContract.TestEngine.csproj b/src/Neo.SmartContract.TestEngine/Neo.SmartContract.TestEngine.csproj new file mode 100644 index 000000000..7cd463ead --- /dev/null +++ b/src/Neo.SmartContract.TestEngine/Neo.SmartContract.TestEngine.csproj @@ -0,0 +1,23 @@ + + + + Neo.SmartContract.TestEngine + Neo.SmartContract.TestEngine + NEO;Blockchain;Smart Contract + TestEngine for NEO smart contract testing. + true + false + content + $(NoWarn);NU5128 + + + + + + + + + + + + diff --git a/src/Neo.SmartContract.TestEngine/TestEngine.cs b/src/Neo.SmartContract.TestEngine/TestEngine.cs new file mode 100644 index 000000000..aa5f5ad85 --- /dev/null +++ b/src/Neo.SmartContract.TestEngine/TestEngine.cs @@ -0,0 +1,92 @@ +using Neo.Cryptography.ECC; +using Neo.Persistence; +using System; +using System.Reflection; + +namespace Neo.SmartContract.TestEngine +{ + public class TestEngine + { + /// + /// Default Protocol Settings + /// + public static readonly ProtocolSettings Default = new() + { + Network = 0x334F454Eu, + AddressVersion = ProtocolSettings.Default.AddressVersion, + StandbyCommittee = new[] + { + //Validators + ECPoint.Parse("03b209fd4f53a7170ea4444e0cb0a6bb6a53c2bd016926989cf85f9b0fba17a70c", ECCurve.Secp256r1), + ECPoint.Parse("02df48f60e8f3e01c48ff40b9b7f1310d7a8b2a193188befe1c2e3df740e895093", ECCurve.Secp256r1), + ECPoint.Parse("03b8d9d5771d8f513aa0869b9cc8d50986403b78c6da36890638c3d46a5adce04a", ECCurve.Secp256r1), + ECPoint.Parse("02ca0e27697b9c248f6f16e085fd0061e26f44da85b58ee835c110caa5ec3ba554", ECCurve.Secp256r1), + ECPoint.Parse("024c7b7fb6c310fccf1ba33b082519d82964ea93868d676662d4a59ad548df0e7d", ECCurve.Secp256r1), + ECPoint.Parse("02aaec38470f6aad0042c6e877cfd8087d2676b0f516fddd362801b9bd3936399e", ECCurve.Secp256r1), + ECPoint.Parse("02486fd15702c4490a26703112a5cc1d0923fd697a33406bd5a1c00e0013b09a70", ECCurve.Secp256r1), + //Other Members + ECPoint.Parse("023a36c72844610b4d34d1968662424011bf783ca9d984efa19a20babf5582f3fe", ECCurve.Secp256r1), + ECPoint.Parse("03708b860c1de5d87f5b151a12c2a99feebd2e8b315ee8e7cf8aa19692a9e18379", ECCurve.Secp256r1), + ECPoint.Parse("03c6aa6e12638b36e88adc1ccdceac4db9929575c3e03576c617c49cce7114a050", ECCurve.Secp256r1), + ECPoint.Parse("03204223f8c86b8cd5c89ef12e4f0dbb314172e9241e30c9ef2293790793537cf0", ECCurve.Secp256r1), + ECPoint.Parse("02a62c915cf19c7f19a50ec217e79fac2439bbaad658493de0c7d8ffa92ab0aa62", ECCurve.Secp256r1), + ECPoint.Parse("03409f31f0d66bdc2f70a9730b66fe186658f84a8018204db01c106edc36553cd0", ECCurve.Secp256r1), + ECPoint.Parse("0288342b141c30dc8ffcde0204929bb46aed5756b41ef4a56778d15ada8f0c6654", ECCurve.Secp256r1), + ECPoint.Parse("020f2887f41474cfeb11fd262e982051c1541418137c02a0f4961af911045de639", ECCurve.Secp256r1), + ECPoint.Parse("0222038884bbd1d8ff109ed3bdef3542e768eef76c1247aea8bc8171f532928c30", ECCurve.Secp256r1), + ECPoint.Parse("03d281b42002647f0113f36c7b8efb30db66078dfaaa9ab3ff76d043a98d512fde", ECCurve.Secp256r1), + ECPoint.Parse("02504acbc1f4b3bdad1d86d6e1a08603771db135a73e61c9d565ae06a1938cd2ad", ECCurve.Secp256r1), + ECPoint.Parse("0226933336f1b75baa42d42b71d9091508b638046d19abd67f4e119bf64a7cfb4d", ECCurve.Secp256r1), + ECPoint.Parse("03cdcea66032b82f5c30450e381e5295cae85c5e6943af716cc6b646352a6067dc", ECCurve.Secp256r1), + ECPoint.Parse("02cd5a5547119e24feaa7c2a0f37b8c9366216bab7054de0065c9be42084003c8a", ECCurve.Secp256r1) + }, + ValidatorsCount = 7, + SeedList = new[] + { + "seed1.neo.org:10333", + "seed2.neo.org:10333", + "seed3.neo.org:10333", + "seed4.neo.org:10333", + "seed5.neo.org:10333" + }, + MillisecondsPerBlock = ProtocolSettings.Default.MillisecondsPerBlock, + MaxTransactionsPerBlock = ProtocolSettings.Default.MaxTransactionsPerBlock, + MemoryPoolMaxTransactions = ProtocolSettings.Default.MemoryPoolMaxTransactions, + MaxTraceableBlocks = ProtocolSettings.Default.MaxTraceableBlocks, + InitialGasDistribution = ProtocolSettings.Default.InitialGasDistribution, + Hardforks = ProtocolSettings.Default.Hardforks + }; + + /// + /// Store + /// + public IStore Store { get; init; } = new MemoryStore(); + + /// + /// Protocol Settings + /// + public ProtocolSettings ProtocolSettings { get; init; } = Default; + + /// + /// Create Smart contract + /// + /// Type + /// Mocked Smart Contract + public T CreateSmartContract() where T : Mocks.SmartContract + { + Type classType = typeof(T); + + ConstructorInfo internalConstructor = classType.GetConstructor( + BindingFlags.Instance | BindingFlags.NonPublic, + null, new Type[] { typeof(TestEngine) }, null); + + T sc = (T)internalConstructor.Invoke(new object[] { this }); + + // TODO: Mock sc here + + // return mocked sc + + return sc; + } + } +} diff --git a/tests/Neo.SmartContract.TestEngine.UnitTests/ArtifactsTests.cs b/tests/Neo.SmartContract.TestEngine.UnitTests/ArtifactsTests.cs new file mode 100644 index 000000000..a95d578d0 --- /dev/null +++ b/tests/Neo.SmartContract.TestEngine.UnitTests/ArtifactsTests.cs @@ -0,0 +1,48 @@ +namespace Neo.SmartContract.TestEngine.UnitTests +{ + public class ArtifactsTests + { + [Test] + public void TestCreateSourceFromManifest() + { + // Compile + + string source = "../../../../../src/Neo.SmartContract.Template/templates/neocontractnep17/Contract1.cs"; + var result = Compiler.Compiler.Compile(optimize: false, debug: true, files: source); + + // Create artifacts + + source = Artifacts.CreateSourceFromManifest(result.Manifest).Replace("\r\n", "\n").Trim(); + + Assert.That(source, Is.EqualTo(@" +using Neo +using System.Numerics; + +namespace Neo.TestEngine.Contracts; + +public class Contract1 : Neo.SmartContract.TestEngine.Mocks.SmartContract +{ + internal Contract1(Neo.SmartContract.TestEngine.Mocks.SmartContract.TestEngine testEngine) : base(testEngine) {} + public abstract string symbol (); + public abstract BigInteger decimals (); + public abstract BigInteger totalSupply (); + public abstract BigInteger balanceOf (); + public abstract bool transfer (); + public abstract void _deploy (); + public abstract UInt160 getOwner (); + public abstract void setOwner (); + public abstract void burn (); + public abstract void mint (); + public abstract bool withdraw (); + public abstract void onNEP17Payment (); + public abstract bool verify (); + public abstract string myMethod (); + public abstract void _deploy (); + public abstract void update (); + public abstract void _initialize (); +} + +".Replace("\r\n", "\n").Trim())); + } + } +} diff --git a/tests/Neo.SmartContract.TestEngine.UnitTests/GlobalUsings.cs b/tests/Neo.SmartContract.TestEngine.UnitTests/GlobalUsings.cs new file mode 100644 index 000000000..cefced496 --- /dev/null +++ b/tests/Neo.SmartContract.TestEngine.UnitTests/GlobalUsings.cs @@ -0,0 +1 @@ +global using NUnit.Framework; \ No newline at end of file diff --git a/tests/Neo.SmartContract.TestEngine.UnitTests/Neo.SmartContract.TestEngine.UnitTests.csproj b/tests/Neo.SmartContract.TestEngine.UnitTests/Neo.SmartContract.TestEngine.UnitTests.csproj new file mode 100644 index 000000000..ec7322001 --- /dev/null +++ b/tests/Neo.SmartContract.TestEngine.UnitTests/Neo.SmartContract.TestEngine.UnitTests.csproj @@ -0,0 +1,26 @@ + + + + net7.0 + enable + enable + + false + true + + + + + + + + + + + + + + + + + From 93a56460e166f39681d7534cfeda6e3cafc197c0 Mon Sep 17 00:00:00 2001 From: Fernando Diaz Toledano Date: Fri, 9 Feb 2024 20:32:56 +0100 Subject: [PATCH 002/106] change to LF --- neo-devpack-dotnet.sln | 248 ++++++++++++++++++++--------------------- 1 file changed, 124 insertions(+), 124 deletions(-) diff --git a/neo-devpack-dotnet.sln b/neo-devpack-dotnet.sln index dd9d42b41..796ed203e 100644 --- a/neo-devpack-dotnet.sln +++ b/neo-devpack-dotnet.sln @@ -1,124 +1,124 @@ -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 17 -VisualStudioVersion = 17.7.34003.232 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Neo.SmartContract.Framework", "src\Neo.SmartContract.Framework\Neo.SmartContract.Framework.csproj", "{C30B5859-D4B9-46E8-A797-6B0A1B49B590}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Neo.Compiler.CSharp", "src\Neo.Compiler.CSharp\Neo.Compiler.CSharp.csproj", "{A2A3B687-A1EC-4221-B792-9BBA8DED09DA}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Neo.SmartContract.Template", "src\Neo.SmartContract.Template\Neo.SmartContract.Template.csproj", "{FC0CAF5A-30A7-4857-B1A4-486FAAA39E5A}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Neo.Compiler.CSharp.UnitTests", "tests\Neo.Compiler.CSharp.UnitTests\Neo.Compiler.CSharp.UnitTests.csproj", "{4C6B120B-99B5-4888-B8D5-45031458DD07}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Neo.SmartContract.Framework.UnitTests", "tests\Neo.SmartContract.Framework.UnitTests\Neo.SmartContract.Framework.UnitTests.csproj", "{93BEC5CC-BAFF-4389-89E7-84AAFF5D495D}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{79389FC0-C621-4CEA-AD2B-6074C32E7BCA}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{D5266066-0AFD-44D5-A83E-2F73668A63C8}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Neo.Compiler.CSharp.TestContracts", "tests\Neo.Compiler.CSharp.TestContracts\Neo.Compiler.CSharp.TestContracts.csproj", "{8D67DD5A-D683-481F-915E-98683EA38791}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Neo.SmartContract.Framework.TestContracts", "tests\Neo.SmartContract.Framework.TestContracts\Neo.SmartContract.Framework.TestContracts.csproj", "{A372F1D6-51FF-472C-9508-FDAF7E6FEB13}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Neo.SmartContract.TestEngine", "tests\Neo.SmartContract.TestEngine\Neo.SmartContract.TestEngine.csproj", "{D0153204-6AEF-4D94-B0E1-8124C38C91D4}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Neo", "neo\src\Neo\Neo.csproj", "{73223FBD-C562-4FA0-9722-C7F1C382A9DE}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Neo.Cryptography.BLS12_381", "neo\src\Neo.Cryptography.BLS12_381\Neo.Cryptography.BLS12_381.csproj", "{D541BCE9-65BC-475B-94E5-19B6BFFF2B8E}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Neo.Json", "neo\src\Neo.Json\Neo.Json.csproj", "{35A34EBD-F2BF-4D83-A096-D5F007B12732}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Neo.VM", "neo\src\Neo.VM\Neo.VM.csproj", "{D6D53889-5A10-46A4-BA66-E78B56EC1881}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Dependency", "Dependency", "{49D5873D-7B38-48A5-B853-85146F032091}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Neo.SmartContract.TestEngine", "src\Neo.SmartContract.TestEngine\Neo.SmartContract.TestEngine.csproj", "{648DCE6F-A0BA-4032-951B-20CF5BBFD998}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Neo.SmartContract.TestEngine.UnitTests", "tests\Neo.SmartContract.TestEngine.UnitTests\Neo.SmartContract.TestEngine.UnitTests.csproj", "{B772B8A9-9362-4C6F-A6D3-2A4138439B2C}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Release|Any CPU = Release|Any CPU - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {C30B5859-D4B9-46E8-A797-6B0A1B49B590}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {C30B5859-D4B9-46E8-A797-6B0A1B49B590}.Debug|Any CPU.Build.0 = Debug|Any CPU - {C30B5859-D4B9-46E8-A797-6B0A1B49B590}.Release|Any CPU.ActiveCfg = Release|Any CPU - {C30B5859-D4B9-46E8-A797-6B0A1B49B590}.Release|Any CPU.Build.0 = Release|Any CPU - {A2A3B687-A1EC-4221-B792-9BBA8DED09DA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {A2A3B687-A1EC-4221-B792-9BBA8DED09DA}.Debug|Any CPU.Build.0 = Debug|Any CPU - {A2A3B687-A1EC-4221-B792-9BBA8DED09DA}.Release|Any CPU.ActiveCfg = Release|Any CPU - {A2A3B687-A1EC-4221-B792-9BBA8DED09DA}.Release|Any CPU.Build.0 = Release|Any CPU - {FC0CAF5A-30A7-4857-B1A4-486FAAA39E5A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {FC0CAF5A-30A7-4857-B1A4-486FAAA39E5A}.Debug|Any CPU.Build.0 = Debug|Any CPU - {FC0CAF5A-30A7-4857-B1A4-486FAAA39E5A}.Release|Any CPU.ActiveCfg = Release|Any CPU - {FC0CAF5A-30A7-4857-B1A4-486FAAA39E5A}.Release|Any CPU.Build.0 = Release|Any CPU - {4C6B120B-99B5-4888-B8D5-45031458DD07}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {4C6B120B-99B5-4888-B8D5-45031458DD07}.Debug|Any CPU.Build.0 = Debug|Any CPU - {4C6B120B-99B5-4888-B8D5-45031458DD07}.Release|Any CPU.ActiveCfg = Release|Any CPU - {4C6B120B-99B5-4888-B8D5-45031458DD07}.Release|Any CPU.Build.0 = Release|Any CPU - {93BEC5CC-BAFF-4389-89E7-84AAFF5D495D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {93BEC5CC-BAFF-4389-89E7-84AAFF5D495D}.Debug|Any CPU.Build.0 = Debug|Any CPU - {93BEC5CC-BAFF-4389-89E7-84AAFF5D495D}.Release|Any CPU.ActiveCfg = Release|Any CPU - {93BEC5CC-BAFF-4389-89E7-84AAFF5D495D}.Release|Any CPU.Build.0 = Release|Any CPU - {8D67DD5A-D683-481F-915E-98683EA38791}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {8D67DD5A-D683-481F-915E-98683EA38791}.Debug|Any CPU.Build.0 = Debug|Any CPU - {8D67DD5A-D683-481F-915E-98683EA38791}.Release|Any CPU.ActiveCfg = Release|Any CPU - {8D67DD5A-D683-481F-915E-98683EA38791}.Release|Any CPU.Build.0 = Release|Any CPU - {A372F1D6-51FF-472C-9508-FDAF7E6FEB13}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {A372F1D6-51FF-472C-9508-FDAF7E6FEB13}.Debug|Any CPU.Build.0 = Debug|Any CPU - {A372F1D6-51FF-472C-9508-FDAF7E6FEB13}.Release|Any CPU.ActiveCfg = Release|Any CPU - {A372F1D6-51FF-472C-9508-FDAF7E6FEB13}.Release|Any CPU.Build.0 = Release|Any CPU - {D0153204-6AEF-4D94-B0E1-8124C38C91D4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {D0153204-6AEF-4D94-B0E1-8124C38C91D4}.Debug|Any CPU.Build.0 = Debug|Any CPU - {D0153204-6AEF-4D94-B0E1-8124C38C91D4}.Release|Any CPU.ActiveCfg = Release|Any CPU - {D0153204-6AEF-4D94-B0E1-8124C38C91D4}.Release|Any CPU.Build.0 = Release|Any CPU - {73223FBD-C562-4FA0-9722-C7F1C382A9DE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {73223FBD-C562-4FA0-9722-C7F1C382A9DE}.Debug|Any CPU.Build.0 = Debug|Any CPU - {73223FBD-C562-4FA0-9722-C7F1C382A9DE}.Release|Any CPU.ActiveCfg = Release|Any CPU - {73223FBD-C562-4FA0-9722-C7F1C382A9DE}.Release|Any CPU.Build.0 = Release|Any CPU - {D541BCE9-65BC-475B-94E5-19B6BFFF2B8E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {D541BCE9-65BC-475B-94E5-19B6BFFF2B8E}.Debug|Any CPU.Build.0 = Debug|Any CPU - {D541BCE9-65BC-475B-94E5-19B6BFFF2B8E}.Release|Any CPU.ActiveCfg = Release|Any CPU - {D541BCE9-65BC-475B-94E5-19B6BFFF2B8E}.Release|Any CPU.Build.0 = Release|Any CPU - {35A34EBD-F2BF-4D83-A096-D5F007B12732}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {35A34EBD-F2BF-4D83-A096-D5F007B12732}.Debug|Any CPU.Build.0 = Debug|Any CPU - {35A34EBD-F2BF-4D83-A096-D5F007B12732}.Release|Any CPU.ActiveCfg = Release|Any CPU - {35A34EBD-F2BF-4D83-A096-D5F007B12732}.Release|Any CPU.Build.0 = Release|Any CPU - {D6D53889-5A10-46A4-BA66-E78B56EC1881}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {D6D53889-5A10-46A4-BA66-E78B56EC1881}.Debug|Any CPU.Build.0 = Debug|Any CPU - {D6D53889-5A10-46A4-BA66-E78B56EC1881}.Release|Any CPU.ActiveCfg = Release|Any CPU - {D6D53889-5A10-46A4-BA66-E78B56EC1881}.Release|Any CPU.Build.0 = Release|Any CPU - {648DCE6F-A0BA-4032-951B-20CF5BBFD998}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {648DCE6F-A0BA-4032-951B-20CF5BBFD998}.Debug|Any CPU.Build.0 = Debug|Any CPU - {648DCE6F-A0BA-4032-951B-20CF5BBFD998}.Release|Any CPU.ActiveCfg = Release|Any CPU - {648DCE6F-A0BA-4032-951B-20CF5BBFD998}.Release|Any CPU.Build.0 = Release|Any CPU - {B772B8A9-9362-4C6F-A6D3-2A4138439B2C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {B772B8A9-9362-4C6F-A6D3-2A4138439B2C}.Debug|Any CPU.Build.0 = Debug|Any CPU - {B772B8A9-9362-4C6F-A6D3-2A4138439B2C}.Release|Any CPU.ActiveCfg = Release|Any CPU - {B772B8A9-9362-4C6F-A6D3-2A4138439B2C}.Release|Any CPU.Build.0 = Release|Any CPU - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection - GlobalSection(NestedProjects) = preSolution - {C30B5859-D4B9-46E8-A797-6B0A1B49B590} = {79389FC0-C621-4CEA-AD2B-6074C32E7BCA} - {A2A3B687-A1EC-4221-B792-9BBA8DED09DA} = {79389FC0-C621-4CEA-AD2B-6074C32E7BCA} - {FC0CAF5A-30A7-4857-B1A4-486FAAA39E5A} = {79389FC0-C621-4CEA-AD2B-6074C32E7BCA} - {4C6B120B-99B5-4888-B8D5-45031458DD07} = {D5266066-0AFD-44D5-A83E-2F73668A63C8} - {93BEC5CC-BAFF-4389-89E7-84AAFF5D495D} = {D5266066-0AFD-44D5-A83E-2F73668A63C8} - {8D67DD5A-D683-481F-915E-98683EA38791} = {D5266066-0AFD-44D5-A83E-2F73668A63C8} - {A372F1D6-51FF-472C-9508-FDAF7E6FEB13} = {D5266066-0AFD-44D5-A83E-2F73668A63C8} - {D0153204-6AEF-4D94-B0E1-8124C38C91D4} = {D5266066-0AFD-44D5-A83E-2F73668A63C8} - {73223FBD-C562-4FA0-9722-C7F1C382A9DE} = {49D5873D-7B38-48A5-B853-85146F032091} - {D541BCE9-65BC-475B-94E5-19B6BFFF2B8E} = {49D5873D-7B38-48A5-B853-85146F032091} - {35A34EBD-F2BF-4D83-A096-D5F007B12732} = {49D5873D-7B38-48A5-B853-85146F032091} - {D6D53889-5A10-46A4-BA66-E78B56EC1881} = {49D5873D-7B38-48A5-B853-85146F032091} - {648DCE6F-A0BA-4032-951B-20CF5BBFD998} = {79389FC0-C621-4CEA-AD2B-6074C32E7BCA} - {B772B8A9-9362-4C6F-A6D3-2A4138439B2C} = {D5266066-0AFD-44D5-A83E-2F73668A63C8} - EndGlobalSection - GlobalSection(ExtensibilityGlobals) = postSolution - SolutionGuid = {6DA935E1-C674-4364-B087-F1B511B79215} - EndGlobalSection -EndGlobal +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.7.34003.232 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Neo.SmartContract.Framework", "src\Neo.SmartContract.Framework\Neo.SmartContract.Framework.csproj", "{C30B5859-D4B9-46E8-A797-6B0A1B49B590}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Neo.Compiler.CSharp", "src\Neo.Compiler.CSharp\Neo.Compiler.CSharp.csproj", "{A2A3B687-A1EC-4221-B792-9BBA8DED09DA}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Neo.SmartContract.Template", "src\Neo.SmartContract.Template\Neo.SmartContract.Template.csproj", "{FC0CAF5A-30A7-4857-B1A4-486FAAA39E5A}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Neo.Compiler.CSharp.UnitTests", "tests\Neo.Compiler.CSharp.UnitTests\Neo.Compiler.CSharp.UnitTests.csproj", "{4C6B120B-99B5-4888-B8D5-45031458DD07}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Neo.SmartContract.Framework.UnitTests", "tests\Neo.SmartContract.Framework.UnitTests\Neo.SmartContract.Framework.UnitTests.csproj", "{93BEC5CC-BAFF-4389-89E7-84AAFF5D495D}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{79389FC0-C621-4CEA-AD2B-6074C32E7BCA}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{D5266066-0AFD-44D5-A83E-2F73668A63C8}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Neo.Compiler.CSharp.TestContracts", "tests\Neo.Compiler.CSharp.TestContracts\Neo.Compiler.CSharp.TestContracts.csproj", "{8D67DD5A-D683-481F-915E-98683EA38791}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Neo.SmartContract.Framework.TestContracts", "tests\Neo.SmartContract.Framework.TestContracts\Neo.SmartContract.Framework.TestContracts.csproj", "{A372F1D6-51FF-472C-9508-FDAF7E6FEB13}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Neo.SmartContract.TestEngine", "tests\Neo.SmartContract.TestEngine\Neo.SmartContract.TestEngine.csproj", "{D0153204-6AEF-4D94-B0E1-8124C38C91D4}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Neo", "neo\src\Neo\Neo.csproj", "{73223FBD-C562-4FA0-9722-C7F1C382A9DE}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Neo.Cryptography.BLS12_381", "neo\src\Neo.Cryptography.BLS12_381\Neo.Cryptography.BLS12_381.csproj", "{D541BCE9-65BC-475B-94E5-19B6BFFF2B8E}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Neo.Json", "neo\src\Neo.Json\Neo.Json.csproj", "{35A34EBD-F2BF-4D83-A096-D5F007B12732}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Neo.VM", "neo\src\Neo.VM\Neo.VM.csproj", "{D6D53889-5A10-46A4-BA66-E78B56EC1881}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Dependency", "Dependency", "{49D5873D-7B38-48A5-B853-85146F032091}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Neo.SmartContract.TestEngine", "src\Neo.SmartContract.TestEngine\Neo.SmartContract.TestEngine.csproj", "{648DCE6F-A0BA-4032-951B-20CF5BBFD998}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Neo.SmartContract.TestEngine.UnitTests", "tests\Neo.SmartContract.TestEngine.UnitTests\Neo.SmartContract.TestEngine.UnitTests.csproj", "{B772B8A9-9362-4C6F-A6D3-2A4138439B2C}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {C30B5859-D4B9-46E8-A797-6B0A1B49B590}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C30B5859-D4B9-46E8-A797-6B0A1B49B590}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C30B5859-D4B9-46E8-A797-6B0A1B49B590}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C30B5859-D4B9-46E8-A797-6B0A1B49B590}.Release|Any CPU.Build.0 = Release|Any CPU + {A2A3B687-A1EC-4221-B792-9BBA8DED09DA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {A2A3B687-A1EC-4221-B792-9BBA8DED09DA}.Debug|Any CPU.Build.0 = Debug|Any CPU + {A2A3B687-A1EC-4221-B792-9BBA8DED09DA}.Release|Any CPU.ActiveCfg = Release|Any CPU + {A2A3B687-A1EC-4221-B792-9BBA8DED09DA}.Release|Any CPU.Build.0 = Release|Any CPU + {FC0CAF5A-30A7-4857-B1A4-486FAAA39E5A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {FC0CAF5A-30A7-4857-B1A4-486FAAA39E5A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {FC0CAF5A-30A7-4857-B1A4-486FAAA39E5A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {FC0CAF5A-30A7-4857-B1A4-486FAAA39E5A}.Release|Any CPU.Build.0 = Release|Any CPU + {4C6B120B-99B5-4888-B8D5-45031458DD07}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {4C6B120B-99B5-4888-B8D5-45031458DD07}.Debug|Any CPU.Build.0 = Debug|Any CPU + {4C6B120B-99B5-4888-B8D5-45031458DD07}.Release|Any CPU.ActiveCfg = Release|Any CPU + {4C6B120B-99B5-4888-B8D5-45031458DD07}.Release|Any CPU.Build.0 = Release|Any CPU + {93BEC5CC-BAFF-4389-89E7-84AAFF5D495D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {93BEC5CC-BAFF-4389-89E7-84AAFF5D495D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {93BEC5CC-BAFF-4389-89E7-84AAFF5D495D}.Release|Any CPU.ActiveCfg = Release|Any CPU + {93BEC5CC-BAFF-4389-89E7-84AAFF5D495D}.Release|Any CPU.Build.0 = Release|Any CPU + {8D67DD5A-D683-481F-915E-98683EA38791}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {8D67DD5A-D683-481F-915E-98683EA38791}.Debug|Any CPU.Build.0 = Debug|Any CPU + {8D67DD5A-D683-481F-915E-98683EA38791}.Release|Any CPU.ActiveCfg = Release|Any CPU + {8D67DD5A-D683-481F-915E-98683EA38791}.Release|Any CPU.Build.0 = Release|Any CPU + {A372F1D6-51FF-472C-9508-FDAF7E6FEB13}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {A372F1D6-51FF-472C-9508-FDAF7E6FEB13}.Debug|Any CPU.Build.0 = Debug|Any CPU + {A372F1D6-51FF-472C-9508-FDAF7E6FEB13}.Release|Any CPU.ActiveCfg = Release|Any CPU + {A372F1D6-51FF-472C-9508-FDAF7E6FEB13}.Release|Any CPU.Build.0 = Release|Any CPU + {D0153204-6AEF-4D94-B0E1-8124C38C91D4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D0153204-6AEF-4D94-B0E1-8124C38C91D4}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D0153204-6AEF-4D94-B0E1-8124C38C91D4}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D0153204-6AEF-4D94-B0E1-8124C38C91D4}.Release|Any CPU.Build.0 = Release|Any CPU + {73223FBD-C562-4FA0-9722-C7F1C382A9DE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {73223FBD-C562-4FA0-9722-C7F1C382A9DE}.Debug|Any CPU.Build.0 = Debug|Any CPU + {73223FBD-C562-4FA0-9722-C7F1C382A9DE}.Release|Any CPU.ActiveCfg = Release|Any CPU + {73223FBD-C562-4FA0-9722-C7F1C382A9DE}.Release|Any CPU.Build.0 = Release|Any CPU + {D541BCE9-65BC-475B-94E5-19B6BFFF2B8E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D541BCE9-65BC-475B-94E5-19B6BFFF2B8E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D541BCE9-65BC-475B-94E5-19B6BFFF2B8E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D541BCE9-65BC-475B-94E5-19B6BFFF2B8E}.Release|Any CPU.Build.0 = Release|Any CPU + {35A34EBD-F2BF-4D83-A096-D5F007B12732}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {35A34EBD-F2BF-4D83-A096-D5F007B12732}.Debug|Any CPU.Build.0 = Debug|Any CPU + {35A34EBD-F2BF-4D83-A096-D5F007B12732}.Release|Any CPU.ActiveCfg = Release|Any CPU + {35A34EBD-F2BF-4D83-A096-D5F007B12732}.Release|Any CPU.Build.0 = Release|Any CPU + {D6D53889-5A10-46A4-BA66-E78B56EC1881}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D6D53889-5A10-46A4-BA66-E78B56EC1881}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D6D53889-5A10-46A4-BA66-E78B56EC1881}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D6D53889-5A10-46A4-BA66-E78B56EC1881}.Release|Any CPU.Build.0 = Release|Any CPU + {648DCE6F-A0BA-4032-951B-20CF5BBFD998}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {648DCE6F-A0BA-4032-951B-20CF5BBFD998}.Debug|Any CPU.Build.0 = Debug|Any CPU + {648DCE6F-A0BA-4032-951B-20CF5BBFD998}.Release|Any CPU.ActiveCfg = Release|Any CPU + {648DCE6F-A0BA-4032-951B-20CF5BBFD998}.Release|Any CPU.Build.0 = Release|Any CPU + {B772B8A9-9362-4C6F-A6D3-2A4138439B2C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B772B8A9-9362-4C6F-A6D3-2A4138439B2C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B772B8A9-9362-4C6F-A6D3-2A4138439B2C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B772B8A9-9362-4C6F-A6D3-2A4138439B2C}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {C30B5859-D4B9-46E8-A797-6B0A1B49B590} = {79389FC0-C621-4CEA-AD2B-6074C32E7BCA} + {A2A3B687-A1EC-4221-B792-9BBA8DED09DA} = {79389FC0-C621-4CEA-AD2B-6074C32E7BCA} + {FC0CAF5A-30A7-4857-B1A4-486FAAA39E5A} = {79389FC0-C621-4CEA-AD2B-6074C32E7BCA} + {4C6B120B-99B5-4888-B8D5-45031458DD07} = {D5266066-0AFD-44D5-A83E-2F73668A63C8} + {93BEC5CC-BAFF-4389-89E7-84AAFF5D495D} = {D5266066-0AFD-44D5-A83E-2F73668A63C8} + {8D67DD5A-D683-481F-915E-98683EA38791} = {D5266066-0AFD-44D5-A83E-2F73668A63C8} + {A372F1D6-51FF-472C-9508-FDAF7E6FEB13} = {D5266066-0AFD-44D5-A83E-2F73668A63C8} + {D0153204-6AEF-4D94-B0E1-8124C38C91D4} = {D5266066-0AFD-44D5-A83E-2F73668A63C8} + {73223FBD-C562-4FA0-9722-C7F1C382A9DE} = {49D5873D-7B38-48A5-B853-85146F032091} + {D541BCE9-65BC-475B-94E5-19B6BFFF2B8E} = {49D5873D-7B38-48A5-B853-85146F032091} + {35A34EBD-F2BF-4D83-A096-D5F007B12732} = {49D5873D-7B38-48A5-B853-85146F032091} + {D6D53889-5A10-46A4-BA66-E78B56EC1881} = {49D5873D-7B38-48A5-B853-85146F032091} + {648DCE6F-A0BA-4032-951B-20CF5BBFD998} = {79389FC0-C621-4CEA-AD2B-6074C32E7BCA} + {B772B8A9-9362-4C6F-A6D3-2A4138439B2C} = {D5266066-0AFD-44D5-A83E-2F73668A63C8} + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {6DA935E1-C674-4364-B087-F1B511B79215} + EndGlobalSection +EndGlobal From 2e3655f72e897a69c8ceb111adcf3449c96b93dc Mon Sep 17 00:00:00 2001 From: Fernando Diaz Toledano Date: Fri, 9 Feb 2024 20:35:51 +0100 Subject: [PATCH 003/106] Fix _deploy in NEP17 template --- .../templates/neocontractnep17/Contract1.cs | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/Neo.SmartContract.Template/templates/neocontractnep17/Contract1.cs b/src/Neo.SmartContract.Template/templates/neocontractnep17/Contract1.cs index 4b571e73c..120a38f85 100644 --- a/src/Neo.SmartContract.Template/templates/neocontractnep17/Contract1.cs +++ b/src/Neo.SmartContract.Template/templates/neocontractnep17/Contract1.cs @@ -24,14 +24,13 @@ public class Contract1 : Nep17Token private const byte Prefix_Owner = 0xff; - // TODO: Replace it with your own address. - [InitialValue("", Neo.SmartContract.ContractParameterType.Hash160)] - private static readonly UInt160 InitialOwner = default; - - // Init method + // Init method, you must call it with the owner or it will take the sender public static void _deploy(object data) { + if (data is null) data = Runtime.Transaction.Sender; + UInt160 initialOwner = (UInt160)data; + ExecutionEngine.Assert(initialOwner.IsValid && !initialOwner.IsZero, "owner must exists"); Storage.Put(new[] { Prefix_Owner }, initialOwner); From fd567ea25174ff9c3731c502e531879b9d109452 Mon Sep 17 00:00:00 2001 From: Fernando Diaz Toledano Date: Fri, 9 Feb 2024 20:36:41 +0100 Subject: [PATCH 004/106] change comment --- .../templates/neocontractnep17/Contract1.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Neo.SmartContract.Template/templates/neocontractnep17/Contract1.cs b/src/Neo.SmartContract.Template/templates/neocontractnep17/Contract1.cs index 120a38f85..f390ec8d9 100644 --- a/src/Neo.SmartContract.Template/templates/neocontractnep17/Contract1.cs +++ b/src/Neo.SmartContract.Template/templates/neocontractnep17/Contract1.cs @@ -24,7 +24,7 @@ public class Contract1 : Nep17Token private const byte Prefix_Owner = 0xff; - // Init method, you must call it with the owner or it will take the sender + // Init method, you must deploy the contract with the owner as an argument, or it will take the sender public static void _deploy(object data) { if (data is null) data = Runtime.Transaction.Sender; From 6d897da84e0c950f75785f7e1fef41f8737801ae Mon Sep 17 00:00:00 2001 From: Fernando Diaz Toledano Date: Fri, 9 Feb 2024 20:37:42 +0100 Subject: [PATCH 005/106] Replace SetOwner --- .../templates/neocontractnep17/Contract1.cs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Neo.SmartContract.Template/templates/neocontractnep17/Contract1.cs b/src/Neo.SmartContract.Template/templates/neocontractnep17/Contract1.cs index f390ec8d9..4f423f5f0 100644 --- a/src/Neo.SmartContract.Template/templates/neocontractnep17/Contract1.cs +++ b/src/Neo.SmartContract.Template/templates/neocontractnep17/Contract1.cs @@ -55,11 +55,11 @@ public static void SetOwner(UInt160 newOwner) { if (IsOwner() == false) throw new InvalidOperationException("No Authorization!"); - if (newOwner != null && newOwner.IsValid) - { - Storage.Put(new[] { Prefix_Owner }, newOwner); - OnSetOwner(newOwner); - } + + ExecutionEngine.Assert(newOwner.IsValid && !newOwner.IsZero, "owner must be valid"); + + Storage.Put(new[] { Prefix_Owner }, newOwner); + OnSetOwner(newOwner); } #endregion From a8a28cb2f553dc81b33c84f176c3e22395876feb Mon Sep 17 00:00:00 2001 From: Fernando Diaz Toledano Date: Fri, 9 Feb 2024 20:38:48 +0100 Subject: [PATCH 006/106] Remove extra file --- .../CompilationResult.cs | 23 ------------------- 1 file changed, 23 deletions(-) delete mode 100644 src/Neo.SmartContract.TestEngine/CompilationResult.cs diff --git a/src/Neo.SmartContract.TestEngine/CompilationResult.cs b/src/Neo.SmartContract.TestEngine/CompilationResult.cs deleted file mode 100644 index b511cded5..000000000 --- a/src/Neo.SmartContract.TestEngine/CompilationResult.cs +++ /dev/null @@ -1,23 +0,0 @@ -using Neo.Json; -using Neo.SmartContract.Manifest; - -namespace Neo.SmartContract.TestEngine -{ - public class CompilationResult - { - /// - /// Nef - /// - public required NefFile Nef { get; init; } - - /// - /// Contract Manifest - /// - public required ContractManifest Manifest { get; init; } - - /// - /// Debug Info - /// - public required JObject DebugInfo { get; init; } - } -} From e8271e7bc423b19083ca2997cdb9cc6db71d71bb Mon Sep 17 00:00:00 2001 From: Fernando Diaz Toledano Date: Fri, 9 Feb 2024 20:41:47 +0100 Subject: [PATCH 007/106] Remove _deploy and _initialize --- .../templates/neocontractnep17/Contract1.cs | 23 ++++++++----------- src/Neo.SmartContract.TestEngine/Artifacts.cs | 5 ++++ .../ArtifactsTests.cs | 3 --- 3 files changed, 15 insertions(+), 16 deletions(-) diff --git a/src/Neo.SmartContract.Template/templates/neocontractnep17/Contract1.cs b/src/Neo.SmartContract.Template/templates/neocontractnep17/Contract1.cs index 4f423f5f0..09c77719e 100644 --- a/src/Neo.SmartContract.Template/templates/neocontractnep17/Contract1.cs +++ b/src/Neo.SmartContract.Template/templates/neocontractnep17/Contract1.cs @@ -24,19 +24,6 @@ public class Contract1 : Nep17Token private const byte Prefix_Owner = 0xff; - // Init method, you must deploy the contract with the owner as an argument, or it will take the sender - public static void _deploy(object data) - { - if (data is null) data = Runtime.Transaction.Sender; - - UInt160 initialOwner = (UInt160)data; - - ExecutionEngine.Assert(initialOwner.IsValid && !initialOwner.IsZero, "owner must exists"); - - Storage.Put(new[] { Prefix_Owner }, initialOwner); - OnSetOwner(initialOwner); - } - [Safe] public static UInt160 GetOwner() { @@ -142,6 +129,16 @@ public static void _deploy(object data, bool update) return; } + // Init method, you must deploy the contract with the owner as an argument, or it will take the sender + if (data is null) data = Runtime.Transaction.Sender; + + UInt160 initialOwner = (UInt160)data; + + ExecutionEngine.Assert(initialOwner.IsValid && !initialOwner.IsZero, "owner must exists"); + + Storage.Put(new[] { Prefix_Owner }, initialOwner); + OnSetOwner(initialOwner); + // This will be executed during deploy Storage.Put(Storage.CurrentContext, "Hello", "World"); } diff --git a/src/Neo.SmartContract.TestEngine/Artifacts.cs b/src/Neo.SmartContract.TestEngine/Artifacts.cs index 9a9525964..a42153ddd 100644 --- a/src/Neo.SmartContract.TestEngine/Artifacts.cs +++ b/src/Neo.SmartContract.TestEngine/Artifacts.cs @@ -81,6 +81,11 @@ public static string CreateSourceFromManifest(ContractManifest manifest) foreach (var method in manifest.Abi.Methods) { + // This method can't be called, so avoid them + + if (method.Name == "_deploy") continue; + if (method.Name == "_initialize") continue; + sourceCode.Append(CreateSourceMethodFromManifest(method)); } diff --git a/tests/Neo.SmartContract.TestEngine.UnitTests/ArtifactsTests.cs b/tests/Neo.SmartContract.TestEngine.UnitTests/ArtifactsTests.cs index a95d578d0..129ea344f 100644 --- a/tests/Neo.SmartContract.TestEngine.UnitTests/ArtifactsTests.cs +++ b/tests/Neo.SmartContract.TestEngine.UnitTests/ArtifactsTests.cs @@ -28,7 +28,6 @@ internal Contract1(Neo.SmartContract.TestEngine.Mocks.SmartContract.TestEngine t public abstract BigInteger totalSupply (); public abstract BigInteger balanceOf (); public abstract bool transfer (); - public abstract void _deploy (); public abstract UInt160 getOwner (); public abstract void setOwner (); public abstract void burn (); @@ -37,9 +36,7 @@ internal Contract1(Neo.SmartContract.TestEngine.Mocks.SmartContract.TestEngine t public abstract void onNEP17Payment (); public abstract bool verify (); public abstract string myMethod (); - public abstract void _deploy (); public abstract void update (); - public abstract void _initialize (); } ".Replace("\r\n", "\n").Trim())); From 3b62d7a622f6b63fbbcc23879b449783fba71afa Mon Sep 17 00:00:00 2001 From: Fernando Diaz Toledano Date: Fri, 9 Feb 2024 20:42:54 +0100 Subject: [PATCH 008/106] change to _ --- src/Neo.SmartContract.TestEngine/Artifacts.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Neo.SmartContract.TestEngine/Artifacts.cs b/src/Neo.SmartContract.TestEngine/Artifacts.cs index a42153ddd..5806be9b0 100644 --- a/src/Neo.SmartContract.TestEngine/Artifacts.cs +++ b/src/Neo.SmartContract.TestEngine/Artifacts.cs @@ -83,8 +83,7 @@ public static string CreateSourceFromManifest(ContractManifest manifest) { // This method can't be called, so avoid them - if (method.Name == "_deploy") continue; - if (method.Name == "_initialize") continue; + if (method.Name.StartsWith("_")) continue; sourceCode.Append(CreateSourceMethodFromManifest(method)); } From 3de58e0cc81ce8108f48a89c648f221cd8bd1a1a Mon Sep 17 00:00:00 2001 From: Fernando Diaz Toledano Date: Fri, 9 Feb 2024 20:47:03 +0100 Subject: [PATCH 009/106] Add args --- src/Neo.SmartContract.TestEngine/Artifacts.cs | 13 ++++++++++++- .../ArtifactsTests.cs | 16 ++++++++-------- 2 files changed, 20 insertions(+), 9 deletions(-) diff --git a/src/Neo.SmartContract.TestEngine/Artifacts.cs b/src/Neo.SmartContract.TestEngine/Artifacts.cs index 5806be9b0..41197a43c 100644 --- a/src/Neo.SmartContract.TestEngine/Artifacts.cs +++ b/src/Neo.SmartContract.TestEngine/Artifacts.cs @@ -102,7 +102,18 @@ private static string CreateSourceMethodFromManifest(ContractMethodDescriptor me { StringBuilder sourceCode = new(); - sourceCode.AppendLine($" public abstract {TypeToSource(method.ReturnType)} {method.Name} ();"); + sourceCode.Append($" public abstract {TypeToSource(method.ReturnType)} {method.Name} ("); + + bool isFirst = true; + foreach (var arg in method.Parameters) + { + if (!isFirst) sourceCode.Append(", "); + else isFirst = false; + + sourceCode.Append($"{TypeToSource(arg.Type)} {arg.Name}"); + } + + sourceCode.AppendLine(");"); return sourceCode.ToString(); } diff --git a/tests/Neo.SmartContract.TestEngine.UnitTests/ArtifactsTests.cs b/tests/Neo.SmartContract.TestEngine.UnitTests/ArtifactsTests.cs index 129ea344f..2084f502d 100644 --- a/tests/Neo.SmartContract.TestEngine.UnitTests/ArtifactsTests.cs +++ b/tests/Neo.SmartContract.TestEngine.UnitTests/ArtifactsTests.cs @@ -26,17 +26,17 @@ internal Contract1(Neo.SmartContract.TestEngine.Mocks.SmartContract.TestEngine t public abstract string symbol (); public abstract BigInteger decimals (); public abstract BigInteger totalSupply (); - public abstract BigInteger balanceOf (); - public abstract bool transfer (); + public abstract BigInteger balanceOf (UInt160 owner); + public abstract bool transfer (UInt160 from, UInt160 to, BigInteger amount, object data); public abstract UInt160 getOwner (); - public abstract void setOwner (); - public abstract void burn (); - public abstract void mint (); - public abstract bool withdraw (); - public abstract void onNEP17Payment (); + public abstract void setOwner (UInt160 newOwner); + public abstract void burn (UInt160 account, BigInteger amount); + public abstract void mint (UInt160 to, BigInteger amount); + public abstract bool withdraw (UInt160 token, UInt160 to, BigInteger amount); + public abstract void onNEP17Payment (UInt160 from, BigInteger amount, object data); public abstract bool verify (); public abstract string myMethod (); - public abstract void update (); + public abstract void update (byte[] nefFile, string manifest); } ".Replace("\r\n", "\n").Trim())); From 165cac4a483e4e04f7ea173a5e9b3d9d5e48d191 Mon Sep 17 00:00:00 2001 From: Fernando Diaz Toledano Date: Fri, 9 Feb 2024 20:51:57 +0100 Subject: [PATCH 010/106] Separate safe from unsafe --- src/Neo.SmartContract.TestEngine/Artifacts.cs | 33 ++++++++++++++++--- .../ArtifactsTests.cs | 23 ++++++++----- 2 files changed, 43 insertions(+), 13 deletions(-) diff --git a/src/Neo.SmartContract.TestEngine/Artifacts.cs b/src/Neo.SmartContract.TestEngine/Artifacts.cs index 41197a43c..4b3cccd17 100644 --- a/src/Neo.SmartContract.TestEngine/Artifacts.cs +++ b/src/Neo.SmartContract.TestEngine/Artifacts.cs @@ -3,6 +3,7 @@ using System; using System.CodeDom.Compiler; using System.IO; +using System.Linq; using System.Numerics; using System.Text; @@ -75,17 +76,41 @@ public static string CreateSourceFromManifest(ContractManifest manifest) // Create constructor + sourceCode.AppendLine("#region Constructor for internal use only"); sourceCode.AppendLine($" internal {manifest.Name}(Neo.SmartContract.TestEngine.Mocks.SmartContract.TestEngine testEngine) : base(testEngine) {{}}"); + sourceCode.AppendLine("#endregion"); // Crete methods - foreach (var method in manifest.Abi.Methods) + if (manifest.Abi.Methods.Any(u => u.Safe)) { - // This method can't be called, so avoid them + sourceCode.AppendLine("#region Safe methods"); - if (method.Name.StartsWith("_")) continue; + foreach (var method in manifest.Abi.Methods.Where(u => u.Safe).OrderBy(u => u.Name)) + { + // This method can't be called, so avoid them + + if (method.Name.StartsWith("_")) continue; + + sourceCode.Append(CreateSourceMethodFromManifest(method)); + } + + sourceCode.AppendLine("#endregion"); + } - sourceCode.Append(CreateSourceMethodFromManifest(method)); + if (manifest.Abi.Methods.Any(u => !u.Safe)) + { + sourceCode.AppendLine("#region Unsafe methods"); + + foreach (var method in manifest.Abi.Methods.Where(u => !u.Safe).OrderBy(u => u.Name)) + { + // This method can't be called, so avoid them + + if (method.Name.StartsWith("_")) continue; + + sourceCode.Append(CreateSourceMethodFromManifest(method)); + } + sourceCode.AppendLine("#endregion"); } sourceCode.AppendLine("}"); diff --git a/tests/Neo.SmartContract.TestEngine.UnitTests/ArtifactsTests.cs b/tests/Neo.SmartContract.TestEngine.UnitTests/ArtifactsTests.cs index 2084f502d..a9c52f9cc 100644 --- a/tests/Neo.SmartContract.TestEngine.UnitTests/ArtifactsTests.cs +++ b/tests/Neo.SmartContract.TestEngine.UnitTests/ArtifactsTests.cs @@ -22,23 +22,28 @@ namespace Neo.TestEngine.Contracts; public class Contract1 : Neo.SmartContract.TestEngine.Mocks.SmartContract { +#region Constructor for internal use only internal Contract1(Neo.SmartContract.TestEngine.Mocks.SmartContract.TestEngine testEngine) : base(testEngine) {} - public abstract string symbol (); - public abstract BigInteger decimals (); - public abstract BigInteger totalSupply (); +#endregion +#region Safe methods public abstract BigInteger balanceOf (UInt160 owner); - public abstract bool transfer (UInt160 from, UInt160 to, BigInteger amount, object data); + public abstract BigInteger decimals (); public abstract UInt160 getOwner (); - public abstract void setOwner (UInt160 newOwner); + public abstract string symbol (); + public abstract BigInteger totalSupply (); + public abstract bool verify (); +#endregion +#region Unsafe methods public abstract void burn (UInt160 account, BigInteger amount); public abstract void mint (UInt160 to, BigInteger amount); - public abstract bool withdraw (UInt160 token, UInt160 to, BigInteger amount); - public abstract void onNEP17Payment (UInt160 from, BigInteger amount, object data); - public abstract bool verify (); public abstract string myMethod (); + public abstract void onNEP17Payment (UInt160 from, BigInteger amount, object data); + public abstract void setOwner (UInt160 newOwner); + public abstract bool transfer (UInt160 from, UInt160 to, BigInteger amount, object data); public abstract void update (byte[] nefFile, string manifest); + public abstract bool withdraw (UInt160 token, UInt160 to, BigInteger amount); +#endregion } - ".Replace("\r\n", "\n").Trim())); } } From 10a363f9ebb2e5986c6d29c53e3b40457674a5fc Mon Sep 17 00:00:00 2001 From: Fernando Diaz Toledano Date: Fri, 9 Feb 2024 20:55:59 +0100 Subject: [PATCH 011/106] abstract Class --- src/Neo.SmartContract.TestEngine/Artifacts.cs | 2 +- tests/Neo.SmartContract.TestEngine.UnitTests/ArtifactsTests.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Neo.SmartContract.TestEngine/Artifacts.cs b/src/Neo.SmartContract.TestEngine/Artifacts.cs index 4b3cccd17..e960ed5af 100644 --- a/src/Neo.SmartContract.TestEngine/Artifacts.cs +++ b/src/Neo.SmartContract.TestEngine/Artifacts.cs @@ -71,7 +71,7 @@ public static string CreateSourceFromManifest(ContractManifest manifest) sourceCode.AppendLine(""); sourceCode.AppendLine("namespace Neo.TestEngine.Contracts;"); sourceCode.AppendLine(""); - sourceCode.AppendLine($"public class {manifest.Name} : Neo.SmartContract.TestEngine.Mocks.SmartContract"); + sourceCode.AppendLine($"public abstract class {manifest.Name} : Neo.SmartContract.TestEngine.Mocks.SmartContract"); sourceCode.AppendLine("{"); // Create constructor diff --git a/tests/Neo.SmartContract.TestEngine.UnitTests/ArtifactsTests.cs b/tests/Neo.SmartContract.TestEngine.UnitTests/ArtifactsTests.cs index a9c52f9cc..f7b4781ad 100644 --- a/tests/Neo.SmartContract.TestEngine.UnitTests/ArtifactsTests.cs +++ b/tests/Neo.SmartContract.TestEngine.UnitTests/ArtifactsTests.cs @@ -20,7 +20,7 @@ public void TestCreateSourceFromManifest() namespace Neo.TestEngine.Contracts; -public class Contract1 : Neo.SmartContract.TestEngine.Mocks.SmartContract +public abstract class Contract1 : Neo.SmartContract.TestEngine.Mocks.SmartContract { #region Constructor for internal use only internal Contract1(Neo.SmartContract.TestEngine.Mocks.SmartContract.TestEngine testEngine) : base(testEngine) {} From 633cbe11863720f911912120d14da1f9c8bb7586 Mon Sep 17 00:00:00 2001 From: Fernando Diaz Toledano Date: Fri, 9 Feb 2024 21:00:59 +0100 Subject: [PATCH 012/106] format --- src/Neo.Compiler.CSharp/Compiler.cs | 2 +- tests/Neo.SmartContract.TestEngine.UnitTests/GlobalUsings.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Neo.Compiler.CSharp/Compiler.cs b/src/Neo.Compiler.CSharp/Compiler.cs index c6be3a102..ce0bc1e33 100644 --- a/src/Neo.Compiler.CSharp/Compiler.cs +++ b/src/Neo.Compiler.CSharp/Compiler.cs @@ -1,4 +1,4 @@ -using Akka.Util.Internal; +using Akka.Util.Internal; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using System; diff --git a/tests/Neo.SmartContract.TestEngine.UnitTests/GlobalUsings.cs b/tests/Neo.SmartContract.TestEngine.UnitTests/GlobalUsings.cs index cefced496..324456763 100644 --- a/tests/Neo.SmartContract.TestEngine.UnitTests/GlobalUsings.cs +++ b/tests/Neo.SmartContract.TestEngine.UnitTests/GlobalUsings.cs @@ -1 +1 @@ -global using NUnit.Framework; \ No newline at end of file +global using NUnit.Framework; From e4a71d87aa9871611fd5a61f955c1b244a4ba368 Mon Sep 17 00:00:00 2001 From: Fernando Diaz Toledano Date: Sat, 10 Feb 2024 09:52:24 +0100 Subject: [PATCH 013/106] Only source --- src/Neo.Compiler.CSharp/CompilationResult.cs | 24 ------- src/Neo.Compiler.CSharp/Compiler.cs | 71 ------------------- .../Neo.Compiler.CSharp.csproj | 1 + src/Neo.Compiler.CSharp/Program.cs | 7 ++ src/Neo.SmartContract.TestEngine/Artifacts.cs | 70 +++--------------- .../Neo.SmartContract.TestEngine.csproj | 5 -- .../ArtifactsTests.cs | 11 +-- ....SmartContract.TestEngine.UnitTests.csproj | 2 - 8 files changed, 24 insertions(+), 167 deletions(-) delete mode 100644 src/Neo.Compiler.CSharp/CompilationResult.cs delete mode 100644 src/Neo.Compiler.CSharp/Compiler.cs diff --git a/src/Neo.Compiler.CSharp/CompilationResult.cs b/src/Neo.Compiler.CSharp/CompilationResult.cs deleted file mode 100644 index 5f9e3bd67..000000000 --- a/src/Neo.Compiler.CSharp/CompilationResult.cs +++ /dev/null @@ -1,24 +0,0 @@ -using Neo.Json; -using Neo.SmartContract; -using Neo.SmartContract.Manifest; - -namespace Neo.Compiler -{ - public class CompilationResult - { - /// - /// Nef - /// - public required NefFile Nef { get; init; } - - /// - /// Contract Manifest - /// - public required ContractManifest Manifest { get; init; } - - /// - /// Debug Info - /// - public required JObject DebugInfo { get; init; } - } -} diff --git a/src/Neo.Compiler.CSharp/Compiler.cs b/src/Neo.Compiler.CSharp/Compiler.cs deleted file mode 100644 index ce0bc1e33..000000000 --- a/src/Neo.Compiler.CSharp/Compiler.cs +++ /dev/null @@ -1,71 +0,0 @@ -using Akka.Util.Internal; -using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.CSharp; -using System; -using System.Collections.Generic; -using System.ComponentModel; -using System.IO; -using System.Linq; -using System.Numerics; - -namespace Neo.Compiler -{ - public class Compiler - { - private static readonly List references = new(); - - /// - /// Static constructor - /// - static Compiler() - { - string coreDir = Path.GetDirectoryName(typeof(object).Assembly.Location)!; - references.Add(MetadataReference.CreateFromFile(Path.Combine(coreDir, "System.Runtime.dll"))); - references.Add(MetadataReference.CreateFromFile(Path.Combine(coreDir, "System.Runtime.InteropServices.dll"))); - references.Add(MetadataReference.CreateFromFile(typeof(string).Assembly.Location)); - references.Add(MetadataReference.CreateFromFile(typeof(DisplayNameAttribute).Assembly.Location)); - references.Add(MetadataReference.CreateFromFile(typeof(BigInteger).Assembly.Location)); - string folder = Path.GetFullPath("../../../../../src/Neo.SmartContract.Framework/"); - string obj = Path.Combine(folder, "obj"); - IEnumerable st = Directory.EnumerateFiles(folder, "*.cs", SearchOption.AllDirectories) - .Where(p => !p.StartsWith(obj)) - .OrderBy(p => p) - .Select(p => CSharpSyntaxTree.ParseText(File.ReadAllText(p), path: p)); - CSharpCompilationOptions options = new(OutputKind.DynamicallyLinkedLibrary); - CSharpCompilation cr = CSharpCompilation.Create(null, st, references, options); - references.Add(cr.ToMetadataReference()); - } - - /// - /// Compile c# source - /// - /// Optimize - /// Debug - /// Files - /// Compilation Result - public static CompilationResult Compile(bool optimize = true, bool debug = true, params string[] files) - { - CompilationContext context = CompilationContext.Compile(files, references, new Options - { - AddressVersion = ProtocolSettings.Default.AddressVersion, - Debug = debug, - NoOptimize = !optimize - }); - if (context.Success) - { - return new CompilationResult() - { - Nef = context.CreateExecutable(), - Manifest = context.CreateManifest(), - DebugInfo = context.CreateDebugInformation() - }; - } - else - { - context.Diagnostics.ForEach(Console.Error.WriteLine); - - throw new ApplicationException("Error while compiling"); - } - } - } -} diff --git a/src/Neo.Compiler.CSharp/Neo.Compiler.CSharp.csproj b/src/Neo.Compiler.CSharp/Neo.Compiler.CSharp.csproj index 815ad92bc..b86759bca 100644 --- a/src/Neo.Compiler.CSharp/Neo.Compiler.CSharp.csproj +++ b/src/Neo.Compiler.CSharp/Neo.Compiler.CSharp.csproj @@ -28,6 +28,7 @@ scfx + diff --git a/src/Neo.Compiler.CSharp/Program.cs b/src/Neo.Compiler.CSharp/Program.cs index dc1924bfd..4af6bdde1 100644 --- a/src/Neo.Compiler.CSharp/Program.cs +++ b/src/Neo.Compiler.CSharp/Program.cs @@ -14,6 +14,7 @@ using Neo.Optimizer; using Neo.SmartContract; using Neo.SmartContract.Manifest; +using Neo.SmartContract.TestEngine; using System; using System.CommandLine; using System.CommandLine.Invocation; @@ -176,6 +177,12 @@ private static int ProcessOutputs(Options options, string folder, CompilationCon return 1; } Console.WriteLine($"Created {path}"); + // Create artifacts + { + path = Path.Combine(outputFolder, $"{baseName}.artifacts.cs"); + File.WriteAllText(path, Artifacts.CreateSourceFromManifest(baseName, manifest.Abi)); + Console.WriteLine($"Created {path}"); + } if (options.Debug) { path = Path.Combine(outputFolder, $"{baseName}.nefdbgnfo"); diff --git a/src/Neo.SmartContract.TestEngine/Artifacts.cs b/src/Neo.SmartContract.TestEngine/Artifacts.cs index e960ed5af..ba4680560 100644 --- a/src/Neo.SmartContract.TestEngine/Artifacts.cs +++ b/src/Neo.SmartContract.TestEngine/Artifacts.cs @@ -1,10 +1,5 @@ -using Microsoft.CodeDom.Providers.DotNetCompilerPlatform; using Neo.SmartContract.Manifest; -using System; -using System.CodeDom.Compiler; -using System.IO; using System.Linq; -using System.Numerics; using System.Text; namespace Neo.SmartContract.TestEngine @@ -12,57 +7,12 @@ namespace Neo.SmartContract.TestEngine public class Artifacts { /// - /// Create artifacts for NefFile + /// Create source code from contract Abi /// - /// Contract manifest - /// Ouptut path for artifacts - public static void CreateArtifacts(ContractManifest manifest, string outputPath) - { - var dependencies = new string[] { - Path.GetFullPath(typeof(Artifacts).Assembly.Location), - Path.GetFullPath(typeof(UInt160).Assembly.Location), - Path.GetFullPath(typeof(BigInteger).Assembly.Location) - }; - - // Compose source code - var sourceCode = CreateSourceFromManifest(manifest); - - // Create a C# Code Provider - CSharpCodeProvider codeProvider = new(); - - // Set compiler parameters - CompilerParameters parameters = new() - { - GenerateExecutable = false, // We want a DLL, not an executable - OutputAssembly = outputPath // Set the output path for the DLL - }; - - // Add referenced assemblies, if any - foreach (var dependency in dependencies) - { - parameters.ReferencedAssemblies.Add(dependency); - } - - // Compile the code - CompilerResults results = codeProvider.CompileAssemblyFromSource(parameters, sourceCode); - - // Check for compilation errors - if (results.Errors.Count > 0) - { - foreach (CompilerError error in results.Errors) - { - Console.WriteLine("Error ({0}): {1}", error.ErrorNumber, error.ErrorText); - } - throw new InvalidOperationException("Compilation failed with errors."); - } - } - - /// - /// Create source code from manifest - /// - /// Manifest + /// Contract name + /// Abi /// Source - public static string CreateSourceFromManifest(ContractManifest manifest) + public static string CreateSourceFromManifest(string name, ContractAbi abi) { StringBuilder sourceCode = new(); @@ -71,22 +21,22 @@ public static string CreateSourceFromManifest(ContractManifest manifest) sourceCode.AppendLine(""); sourceCode.AppendLine("namespace Neo.TestEngine.Contracts;"); sourceCode.AppendLine(""); - sourceCode.AppendLine($"public abstract class {manifest.Name} : Neo.SmartContract.TestEngine.Mocks.SmartContract"); + sourceCode.AppendLine($"public abstract class {name} : Neo.SmartContract.TestEngine.Mocks.SmartContract"); sourceCode.AppendLine("{"); // Create constructor sourceCode.AppendLine("#region Constructor for internal use only"); - sourceCode.AppendLine($" internal {manifest.Name}(Neo.SmartContract.TestEngine.Mocks.SmartContract.TestEngine testEngine) : base(testEngine) {{}}"); + sourceCode.AppendLine($" internal {name}(Neo.SmartContract.TestEngine.Mocks.SmartContract.TestEngine testEngine) : base(testEngine) {{}}"); sourceCode.AppendLine("#endregion"); // Crete methods - if (manifest.Abi.Methods.Any(u => u.Safe)) + if (abi.Methods.Any(u => u.Safe)) { sourceCode.AppendLine("#region Safe methods"); - foreach (var method in manifest.Abi.Methods.Where(u => u.Safe).OrderBy(u => u.Name)) + foreach (var method in abi.Methods.Where(u => u.Safe).OrderBy(u => u.Name)) { // This method can't be called, so avoid them @@ -98,11 +48,11 @@ public static string CreateSourceFromManifest(ContractManifest manifest) sourceCode.AppendLine("#endregion"); } - if (manifest.Abi.Methods.Any(u => !u.Safe)) + if (abi.Methods.Any(u => !u.Safe)) { sourceCode.AppendLine("#region Unsafe methods"); - foreach (var method in manifest.Abi.Methods.Where(u => !u.Safe).OrderBy(u => u.Name)) + foreach (var method in abi.Methods.Where(u => !u.Safe).OrderBy(u => u.Name)) { // This method can't be called, so avoid them diff --git a/src/Neo.SmartContract.TestEngine/Neo.SmartContract.TestEngine.csproj b/src/Neo.SmartContract.TestEngine/Neo.SmartContract.TestEngine.csproj index 7cd463ead..8a3774cb0 100644 --- a/src/Neo.SmartContract.TestEngine/Neo.SmartContract.TestEngine.csproj +++ b/src/Neo.SmartContract.TestEngine/Neo.SmartContract.TestEngine.csproj @@ -11,11 +11,6 @@ $(NoWarn);NU5128 - - - - - diff --git a/tests/Neo.SmartContract.TestEngine.UnitTests/ArtifactsTests.cs b/tests/Neo.SmartContract.TestEngine.UnitTests/ArtifactsTests.cs index f7b4781ad..ffbbff11b 100644 --- a/tests/Neo.SmartContract.TestEngine.UnitTests/ArtifactsTests.cs +++ b/tests/Neo.SmartContract.TestEngine.UnitTests/ArtifactsTests.cs @@ -1,3 +1,6 @@ +using Neo.Json; +using Neo.SmartContract.Manifest; + namespace Neo.SmartContract.TestEngine.UnitTests { public class ArtifactsTests @@ -5,14 +8,12 @@ public class ArtifactsTests [Test] public void TestCreateSourceFromManifest() { - // Compile - - string source = "../../../../../src/Neo.SmartContract.Template/templates/neocontractnep17/Contract1.cs"; - var result = Compiler.Compiler.Compile(optimize: false, debug: true, files: source); + var manifest = ContractManifest.FromJson(JToken.Parse( + @"{""name"":""Contract1"",""groups"":[],""features"":{},""supportedstandards"":[""NEP-17""],""abi"":{""methods"":[{""name"":""symbol"",""parameters"":[],""returntype"":""String"",""offset"":1406,""safe"":true},{""name"":""decimals"",""parameters"":[],""returntype"":""Integer"",""offset"":1421,""safe"":true},{""name"":""totalSupply"",""parameters"":[],""returntype"":""Integer"",""offset"":43,""safe"":true},{""name"":""balanceOf"",""parameters"":[{""name"":""owner"",""type"":""Hash160""}],""returntype"":""Integer"",""offset"":85,""safe"":true},{""name"":""transfer"",""parameters"":[{""name"":""from"",""type"":""Hash160""},{""name"":""to"",""type"":""Hash160""},{""name"":""amount"",""type"":""Integer""},{""name"":""data"",""type"":""Any""}],""returntype"":""Boolean"",""offset"":281,""safe"":false},{""name"":""getOwner"",""parameters"":[],""returntype"":""Hash160"",""offset"":711,""safe"":true},{""name"":""setOwner"",""parameters"":[{""name"":""newOwner"",""type"":""Hash160""}],""returntype"":""Void"",""offset"":755,""safe"":false},{""name"":""burn"",""parameters"":[{""name"":""account"",""type"":""Hash160""},{""name"":""amount"",""type"":""Integer""}],""returntype"":""Void"",""offset"":873,""safe"":false},{""name"":""mint"",""parameters"":[{""name"":""to"",""type"":""Hash160""},{""name"":""amount"",""type"":""Integer""}],""returntype"":""Void"",""offset"":915,""safe"":false},{""name"":""withdraw"",""parameters"":[{""name"":""token"",""type"":""Hash160""},{""name"":""to"",""type"":""Hash160""},{""name"":""amount"",""type"":""Integer""}],""returntype"":""Boolean"",""offset"":957,""safe"":false},{""name"":""onNEP17Payment"",""parameters"":[{""name"":""from"",""type"":""Hash160""},{""name"":""amount"",""type"":""Integer""},{""name"":""data"",""type"":""Any""}],""returntype"":""Void"",""offset"":1139,""safe"":false},{""name"":""verify"",""parameters"":[],""returntype"":""Boolean"",""offset"":1203,""safe"":true},{""name"":""myMethod"",""parameters"":[],""returntype"":""String"",""offset"":1209,""safe"":false},{""name"":""_deploy"",""parameters"":[{""name"":""data"",""type"":""Any""},{""name"":""update"",""type"":""Boolean""}],""returntype"":""Void"",""offset"":1229,""safe"":false},{""name"":""update"",""parameters"":[{""name"":""nefFile"",""type"":""ByteArray""},{""name"":""manifest"",""type"":""String""}],""returntype"":""Void"",""offset"":1352,""safe"":false},{""name"":""_initialize"",""parameters"":[],""returntype"":""Void"",""offset"":1390,""safe"":false}],""events"":[{""name"":""Transfer"",""parameters"":[{""name"":""from"",""type"":""Hash160""},{""name"":""to"",""type"":""Hash160""},{""name"":""amount"",""type"":""Integer""}]},{""name"":""SetOwner"",""parameters"":[{""name"":""newOwner"",""type"":""Hash160""}]}]},""permissions"":[{""contract"":""*"",""methods"":""*""}],""trusts"":[],""extra"":{""Author"":""\u003CYour Name Or Company Here\u003E"",""Description"":""\u003CDescription Here\u003E"",""Email"":""\u003CYour Public Email Here\u003E"",""Version"":""\u003CVersion String Here\u003E""}}") as JObject); // Create artifacts - source = Artifacts.CreateSourceFromManifest(result.Manifest).Replace("\r\n", "\n").Trim(); + var source = Artifacts.CreateSourceFromManifest(manifest.Name, manifest.Abi).Replace("\r\n", "\n").Trim(); Assert.That(source, Is.EqualTo(@" using Neo diff --git a/tests/Neo.SmartContract.TestEngine.UnitTests/Neo.SmartContract.TestEngine.UnitTests.csproj b/tests/Neo.SmartContract.TestEngine.UnitTests/Neo.SmartContract.TestEngine.UnitTests.csproj index ec7322001..74e5da66d 100644 --- a/tests/Neo.SmartContract.TestEngine.UnitTests/Neo.SmartContract.TestEngine.UnitTests.csproj +++ b/tests/Neo.SmartContract.TestEngine.UnitTests/Neo.SmartContract.TestEngine.UnitTests.csproj @@ -18,8 +18,6 @@ - - From eb93622359a4628515bf6aa6ba4aef4fd8699f03 Mon Sep 17 00:00:00 2001 From: Fernando Diaz Toledano Date: Sat, 10 Feb 2024 10:09:37 +0100 Subject: [PATCH 014/106] Generate events --- src/Neo.SmartContract.TestEngine/Artifacts.cs | 51 +++++++++++++++++-- .../Mocks/SmartContract.cs | 9 +++- .../TestEngine.cs | 41 +++++++++++++-- .../ArtifactsTests.cs | 38 ++++++++------ 4 files changed, 113 insertions(+), 26 deletions(-) diff --git a/src/Neo.SmartContract.TestEngine/Artifacts.cs b/src/Neo.SmartContract.TestEngine/Artifacts.cs index ba4680560..b60f3a239 100644 --- a/src/Neo.SmartContract.TestEngine/Artifacts.cs +++ b/src/Neo.SmartContract.TestEngine/Artifacts.cs @@ -1,4 +1,5 @@ using Neo.SmartContract.Manifest; +using System; using System.Linq; using System.Text; @@ -24,11 +25,19 @@ public static string CreateSourceFromManifest(string name, ContractAbi abi) sourceCode.AppendLine($"public abstract class {name} : Neo.SmartContract.TestEngine.Mocks.SmartContract"); sourceCode.AppendLine("{"); - // Create constructor + // Crete events - sourceCode.AppendLine("#region Constructor for internal use only"); - sourceCode.AppendLine($" internal {name}(Neo.SmartContract.TestEngine.Mocks.SmartContract.TestEngine testEngine) : base(testEngine) {{}}"); - sourceCode.AppendLine("#endregion"); + if (abi.Events.Any()) + { + sourceCode.AppendLine("#region Events"); + + foreach (var ev in abi.Events.OrderBy(u => u.Name)) + { + sourceCode.Append(CreateSourceEventFromManifest(ev)); + } + + sourceCode.AppendLine("#endregion"); + } // Crete methods @@ -63,11 +72,43 @@ public static string CreateSourceFromManifest(string name, ContractAbi abi) sourceCode.AppendLine("#endregion"); } + // Create constructor + + sourceCode.AppendLine("#region Constructor for internal use only"); + sourceCode.AppendLine($" internal {name}(Neo.SmartContract.TestEngine.Mocks.SmartContract.TestEngine testEngine, Neo.UInt160 hash) : base(testEngine, hash) {{}}"); + sourceCode.AppendLine("#endregion"); + sourceCode.AppendLine("}"); return sourceCode.ToString(); } + /// + /// Create source code from event + /// + /// Event + /// Source + private static string CreateSourceEventFromManifest(ContractEventDescriptor ev) + { + StringBuilder sourceCode = new(); + + sourceCode.Append($" public delegate void del{ev.Name}("); + + bool isFirst = true; + foreach (var arg in ev.Parameters) + { + if (!isFirst) sourceCode.Append(", "); + else isFirst = false; + + sourceCode.Append($"{TypeToSource(arg.Type)} {arg.Name}"); + } + + sourceCode.AppendLine(");"); + sourceCode.AppendLine($" public event del{ev.Name} {ev.Name};"); + + return sourceCode.ToString(); + } + /// /// Create source code from manifest method /// @@ -77,7 +118,7 @@ private static string CreateSourceMethodFromManifest(ContractMethodDescriptor me { StringBuilder sourceCode = new(); - sourceCode.Append($" public abstract {TypeToSource(method.ReturnType)} {method.Name} ("); + sourceCode.Append($" public abstract {TypeToSource(method.ReturnType)} {method.Name}("); bool isFirst = true; foreach (var arg in method.Parameters) diff --git a/src/Neo.SmartContract.TestEngine/Mocks/SmartContract.cs b/src/Neo.SmartContract.TestEngine/Mocks/SmartContract.cs index e5f183e74..36ae6483e 100644 --- a/src/Neo.SmartContract.TestEngine/Mocks/SmartContract.cs +++ b/src/Neo.SmartContract.TestEngine/Mocks/SmartContract.cs @@ -4,13 +4,20 @@ public class SmartContract { private readonly TestEngine _engine; + /// + /// Contract hash + /// + public UInt160 Hash { get; } + /// /// Constructor /// /// TestEngine - protected SmartContract(TestEngine testEngine) + /// Contract hash + protected SmartContract(TestEngine testEngine, UInt160 hash) { _engine = testEngine; + Hash = hash; } } } diff --git a/src/Neo.SmartContract.TestEngine/TestEngine.cs b/src/Neo.SmartContract.TestEngine/TestEngine.cs index aa5f5ad85..2105317cf 100644 --- a/src/Neo.SmartContract.TestEngine/TestEngine.cs +++ b/src/Neo.SmartContract.TestEngine/TestEngine.cs @@ -1,5 +1,6 @@ using Neo.Cryptography.ECC; using Neo.Persistence; +using Neo.SmartContract.Manifest; using System; using System.Reflection; @@ -68,19 +69,51 @@ public class TestEngine public ProtocolSettings ProtocolSettings { get; init; } = Default; /// - /// Create Smart contract + /// Sender + /// + public UInt160 Sender { get; } = UInt160.Zero; + + /// + /// Deploy Smart contract /// /// Type + /// Nef file + /// Contract manifest + /// Construction data /// Mocked Smart Contract - public T CreateSmartContract() where T : Mocks.SmartContract + public T Deploy(NefFile nef, ContractManifest manifest, object data) where T : Mocks.SmartContract { + // Deploy and get the hash + + UInt160 hash = Helper.GetContractHash(Sender, nef.CheckSum, manifest.Name); + + // Mock contract + + return MockContract(hash); + } + + /// + /// Deploy Smart contract + /// + /// Type + /// Contract hash + /// Mocked Smart Contract + public T FromHash(UInt160 hash) where T : Mocks.SmartContract + { + return MockContract(hash); + } + + private T MockContract(UInt160 hash) where T : Mocks.SmartContract + { + // Create object + Type classType = typeof(T); ConstructorInfo internalConstructor = classType.GetConstructor( BindingFlags.Instance | BindingFlags.NonPublic, - null, new Type[] { typeof(TestEngine) }, null); + null, new Type[] { typeof(TestEngine), typeof(UInt160) }, null); - T sc = (T)internalConstructor.Invoke(new object[] { this }); + T sc = (T)internalConstructor.Invoke(new object[] { this, hash }); // TODO: Mock sc here diff --git a/tests/Neo.SmartContract.TestEngine.UnitTests/ArtifactsTests.cs b/tests/Neo.SmartContract.TestEngine.UnitTests/ArtifactsTests.cs index ffbbff11b..218712b74 100644 --- a/tests/Neo.SmartContract.TestEngine.UnitTests/ArtifactsTests.cs +++ b/tests/Neo.SmartContract.TestEngine.UnitTests/ArtifactsTests.cs @@ -23,26 +23,32 @@ namespace Neo.TestEngine.Contracts; public abstract class Contract1 : Neo.SmartContract.TestEngine.Mocks.SmartContract { -#region Constructor for internal use only - internal Contract1(Neo.SmartContract.TestEngine.Mocks.SmartContract.TestEngine testEngine) : base(testEngine) {} +#region Events + public delegate void delSetOwner(UInt160 newOwner); + public event delSetOwner SetOwner; + public delegate void delTransfer(UInt160 from, UInt160 to, BigInteger amount); + public event delTransfer Transfer; #endregion #region Safe methods - public abstract BigInteger balanceOf (UInt160 owner); - public abstract BigInteger decimals (); - public abstract UInt160 getOwner (); - public abstract string symbol (); - public abstract BigInteger totalSupply (); - public abstract bool verify (); + public abstract BigInteger balanceOf(UInt160 owner); + public abstract BigInteger decimals(); + public abstract UInt160 getOwner(); + public abstract string symbol(); + public abstract BigInteger totalSupply(); + public abstract bool verify(); #endregion #region Unsafe methods - public abstract void burn (UInt160 account, BigInteger amount); - public abstract void mint (UInt160 to, BigInteger amount); - public abstract string myMethod (); - public abstract void onNEP17Payment (UInt160 from, BigInteger amount, object data); - public abstract void setOwner (UInt160 newOwner); - public abstract bool transfer (UInt160 from, UInt160 to, BigInteger amount, object data); - public abstract void update (byte[] nefFile, string manifest); - public abstract bool withdraw (UInt160 token, UInt160 to, BigInteger amount); + public abstract void burn(UInt160 account, BigInteger amount); + public abstract void mint(UInt160 to, BigInteger amount); + public abstract string myMethod(); + public abstract void onNEP17Payment(UInt160 from, BigInteger amount, object data); + public abstract void setOwner(UInt160 newOwner); + public abstract bool transfer(UInt160 from, UInt160 to, BigInteger amount, object data); + public abstract void update(byte[] nefFile, string manifest); + public abstract bool withdraw(UInt160 token, UInt160 to, BigInteger amount); +#endregion +#region Constructor for internal use only + internal Contract1(Neo.SmartContract.TestEngine.Mocks.SmartContract.TestEngine testEngine, Neo.UInt160 hash) : base(testEngine, hash) {} #endregion } ".Replace("\r\n", "\n").Trim())); From a3f9aedeccaef5edfa5adece339da2a2af9fc5c6 Mon Sep 17 00:00:00 2001 From: Fernando Diaz Toledano Date: Sat, 10 Feb 2024 10:24:15 +0100 Subject: [PATCH 015/106] Mock --- src/Neo.SmartContract.TestEngine/Artifacts.cs | 6 +++--- .../Neo.SmartContract.TestEngine.csproj | 4 ++++ .../TestEngine.cs | 10 ++++++++-- .../ArtifactsTests.cs | 20 +++++++++++++++---- 4 files changed, 31 insertions(+), 9 deletions(-) diff --git a/src/Neo.SmartContract.TestEngine/Artifacts.cs b/src/Neo.SmartContract.TestEngine/Artifacts.cs index b60f3a239..3f43b89c5 100644 --- a/src/Neo.SmartContract.TestEngine/Artifacts.cs +++ b/src/Neo.SmartContract.TestEngine/Artifacts.cs @@ -17,7 +17,7 @@ public static string CreateSourceFromManifest(string name, ContractAbi abi) { StringBuilder sourceCode = new(); - sourceCode.AppendLine("using Neo"); + sourceCode.AppendLine("using Neo;"); sourceCode.AppendLine("using System.Numerics;"); sourceCode.AppendLine(""); sourceCode.AppendLine("namespace Neo.TestEngine.Contracts;"); @@ -75,7 +75,7 @@ public static string CreateSourceFromManifest(string name, ContractAbi abi) // Create constructor sourceCode.AppendLine("#region Constructor for internal use only"); - sourceCode.AppendLine($" internal {name}(Neo.SmartContract.TestEngine.Mocks.SmartContract.TestEngine testEngine, Neo.UInt160 hash) : base(testEngine, hash) {{}}"); + sourceCode.AppendLine($" protected {name}(Neo.SmartContract.TestEngine.TestEngine testEngine, Neo.UInt160 hash) : base(testEngine, hash) {{}}"); sourceCode.AppendLine("#endregion"); sourceCode.AppendLine("}"); @@ -104,7 +104,7 @@ private static string CreateSourceEventFromManifest(ContractEventDescriptor ev) } sourceCode.AppendLine(");"); - sourceCode.AppendLine($" public event del{ev.Name} {ev.Name};"); + sourceCode.AppendLine($" public event del{ev.Name}? {ev.Name};"); return sourceCode.ToString(); } diff --git a/src/Neo.SmartContract.TestEngine/Neo.SmartContract.TestEngine.csproj b/src/Neo.SmartContract.TestEngine/Neo.SmartContract.TestEngine.csproj index 8a3774cb0..884907785 100644 --- a/src/Neo.SmartContract.TestEngine/Neo.SmartContract.TestEngine.csproj +++ b/src/Neo.SmartContract.TestEngine/Neo.SmartContract.TestEngine.csproj @@ -11,6 +11,10 @@ $(NoWarn);NU5128 + + + + diff --git a/src/Neo.SmartContract.TestEngine/TestEngine.cs b/src/Neo.SmartContract.TestEngine/TestEngine.cs index 2105317cf..e7d425038 100644 --- a/src/Neo.SmartContract.TestEngine/TestEngine.cs +++ b/src/Neo.SmartContract.TestEngine/TestEngine.cs @@ -1,3 +1,4 @@ +using Moq; using Neo.Cryptography.ECC; using Neo.Persistence; using Neo.SmartContract.Manifest; @@ -113,13 +114,18 @@ private T MockContract(UInt160 hash) where T : Mocks.SmartContract BindingFlags.Instance | BindingFlags.NonPublic, null, new Type[] { typeof(TestEngine), typeof(UInt160) }, null); - T sc = (T)internalConstructor.Invoke(new object[] { this, hash }); + //T sc = (T)internalConstructor.Invoke(new object[] { this, hash }); // TODO: Mock sc here + var mock = new Mock(this, hash) + { + CallBase = true + }; + // return mocked sc - return sc; + return mock.Object; } } } diff --git a/tests/Neo.SmartContract.TestEngine.UnitTests/ArtifactsTests.cs b/tests/Neo.SmartContract.TestEngine.UnitTests/ArtifactsTests.cs index 218712b74..e220f13f7 100644 --- a/tests/Neo.SmartContract.TestEngine.UnitTests/ArtifactsTests.cs +++ b/tests/Neo.SmartContract.TestEngine.UnitTests/ArtifactsTests.cs @@ -1,5 +1,6 @@ using Neo.Json; using Neo.SmartContract.Manifest; +using Neo.TestEngine.Contracts; namespace Neo.SmartContract.TestEngine.UnitTests { @@ -16,7 +17,7 @@ public void TestCreateSourceFromManifest() var source = Artifacts.CreateSourceFromManifest(manifest.Name, manifest.Abi).Replace("\r\n", "\n").Trim(); Assert.That(source, Is.EqualTo(@" -using Neo +using Neo; using System.Numerics; namespace Neo.TestEngine.Contracts; @@ -25,9 +26,9 @@ public abstract class Contract1 : Neo.SmartContract.TestEngine.Mocks.SmartContra { #region Events public delegate void delSetOwner(UInt160 newOwner); - public event delSetOwner SetOwner; + public event delSetOwner? SetOwner; public delegate void delTransfer(UInt160 from, UInt160 to, BigInteger amount); - public event delTransfer Transfer; + public event delTransfer? Transfer; #endregion #region Safe methods public abstract BigInteger balanceOf(UInt160 owner); @@ -48,10 +49,21 @@ public abstract class Contract1 : Neo.SmartContract.TestEngine.Mocks.SmartContra public abstract bool withdraw(UInt160 token, UInt160 to, BigInteger amount); #endregion #region Constructor for internal use only - internal Contract1(Neo.SmartContract.TestEngine.Mocks.SmartContract.TestEngine testEngine, Neo.UInt160 hash) : base(testEngine, hash) {} + protected Contract1(Neo.SmartContract.TestEngine.TestEngine testEngine, Neo.UInt160 hash) : base(testEngine, hash) {} #endregion } ".Replace("\r\n", "\n").Trim())); } + + [Test] + public void FromHashTest() + { + UInt160 hash = UInt160.Parse("0x1230000000000000000000000000000000000000"); + TestEngine engine = new(); + + var contract = engine.FromHash(hash); + + Assert.That(contract.Hash, Is.EqualTo(hash)); + } } } From fcc0bf9f6537e3e54bb0646330beca4f8201e8e0 Mon Sep 17 00:00:00 2001 From: Fernando Diaz Toledano Date: Sat, 10 Feb 2024 10:43:22 +0100 Subject: [PATCH 016/106] starting native artifacts --- src/Neo.SmartContract.TestEngine/Artifacts.cs | 2 +- .../NativeArtifacts.cs | 31 +++++++++++++++++ .../NativeArtifacts/ContractManagement.cs | 34 +++++++++++++++++++ .../Neo.SmartContract.TestEngine.csproj | 3 +- .../TestEngine.cs | 28 ++++++++------- .../ArtifactsTests.cs | 18 ++++++++-- ....SmartContract.TestEngine.UnitTests.csproj | 6 +--- .../UtArtifacts/Contract1.cs | 34 +++++++++++++++++++ 8 files changed, 135 insertions(+), 21 deletions(-) create mode 100644 src/Neo.SmartContract.TestEngine/NativeArtifacts.cs create mode 100644 src/Neo.SmartContract.TestEngine/NativeArtifacts/ContractManagement.cs create mode 100644 tests/Neo.SmartContract.TestEngine.UnitTests/UtArtifacts/Contract1.cs diff --git a/src/Neo.SmartContract.TestEngine/Artifacts.cs b/src/Neo.SmartContract.TestEngine/Artifacts.cs index 3f43b89c5..116860223 100644 --- a/src/Neo.SmartContract.TestEngine/Artifacts.cs +++ b/src/Neo.SmartContract.TestEngine/Artifacts.cs @@ -17,7 +17,7 @@ public static string CreateSourceFromManifest(string name, ContractAbi abi) { StringBuilder sourceCode = new(); - sourceCode.AppendLine("using Neo;"); + sourceCode.AppendLine("using System.Collections.Generic;"); sourceCode.AppendLine("using System.Numerics;"); sourceCode.AppendLine(""); sourceCode.AppendLine("namespace Neo.TestEngine.Contracts;"); diff --git a/src/Neo.SmartContract.TestEngine/NativeArtifacts.cs b/src/Neo.SmartContract.TestEngine/NativeArtifacts.cs new file mode 100644 index 000000000..f9c96d44c --- /dev/null +++ b/src/Neo.SmartContract.TestEngine/NativeArtifacts.cs @@ -0,0 +1,31 @@ +using Neo.TestEngine.Contracts; + +namespace Neo.SmartContract.TestEngine +{ + public class NativeArtifacts + { + private readonly TestEngine _engine; + private ContractManagement? _contractManagement; + + /// + /// ContractManagement + /// + public ContractManagement ContractManagement + { + get + { + _contractManagement ??= _engine.FromHash(Native.NativeContract.ContractManagement.Hash); + return _contractManagement; + } + } + + /// + /// Constructor + /// + /// Engine + public NativeArtifacts(TestEngine engine) + { + _engine = engine; + } + } +} diff --git a/src/Neo.SmartContract.TestEngine/NativeArtifacts/ContractManagement.cs b/src/Neo.SmartContract.TestEngine/NativeArtifacts/ContractManagement.cs new file mode 100644 index 000000000..7d03207b8 --- /dev/null +++ b/src/Neo.SmartContract.TestEngine/NativeArtifacts/ContractManagement.cs @@ -0,0 +1,34 @@ +using System.Collections.Generic; +using System.Numerics; + +namespace Neo.TestEngine.Contracts; + +public abstract class ContractManagement : Neo.SmartContract.TestEngine.Mocks.SmartContract +{ + #region Events + public delegate void delDeploy(UInt160 Hash); + public event delDeploy? Deploy; + public delegate void delDestroy(UInt160 Hash); + public event delDestroy? Destroy; + public delegate void delUpdate(UInt160 Hash); + public event delUpdate? Update; + #endregion + #region Safe methods + public abstract List getContract(UInt160 hash); + public abstract List getContractById(BigInteger id); + public abstract object getContractHashes(); + public abstract BigInteger getMinimumDeploymentFee(); + public abstract bool hasMethod(UInt160 hash, string method, BigInteger pcount); + #endregion + #region Unsafe methods + public abstract List deploy(byte[] nefFile, byte[] manifest); + public abstract List deploy(byte[] nefFile, byte[] manifest, object data); + public abstract void destroy(); + public abstract void setMinimumDeploymentFee(BigInteger value); + public abstract void update(byte[] nefFile, byte[] manifest); + public abstract void update(byte[] nefFile, byte[] manifest, object data); + #endregion + #region Constructor for internal use only + protected ContractManagement(Neo.SmartContract.TestEngine.TestEngine testEngine, Neo.UInt160 hash) : base(testEngine, hash) { } + #endregion +} diff --git a/src/Neo.SmartContract.TestEngine/Neo.SmartContract.TestEngine.csproj b/src/Neo.SmartContract.TestEngine/Neo.SmartContract.TestEngine.csproj index 884907785..8e782e03a 100644 --- a/src/Neo.SmartContract.TestEngine/Neo.SmartContract.TestEngine.csproj +++ b/src/Neo.SmartContract.TestEngine/Neo.SmartContract.TestEngine.csproj @@ -7,7 +7,8 @@ TestEngine for NEO smart contract testing. true false - content + content + enable $(NoWarn);NU5128 diff --git a/src/Neo.SmartContract.TestEngine/TestEngine.cs b/src/Neo.SmartContract.TestEngine/TestEngine.cs index e7d425038..00c2b570b 100644 --- a/src/Neo.SmartContract.TestEngine/TestEngine.cs +++ b/src/Neo.SmartContract.TestEngine/TestEngine.cs @@ -2,8 +2,6 @@ using Neo.Cryptography.ECC; using Neo.Persistence; using Neo.SmartContract.Manifest; -using System; -using System.Reflection; namespace Neo.SmartContract.TestEngine { @@ -74,6 +72,20 @@ public class TestEngine /// public UInt160 Sender { get; } = UInt160.Zero; + private NativeArtifacts? _native; + + /// + /// Native artifacts + /// + public NativeArtifacts Native + { + get + { + _native ??= new NativeArtifacts(this); + return _native; + } + } + /// /// Deploy Smart contract /// @@ -101,21 +113,13 @@ public T Deploy(NefFile nef, ContractManifest manifest, object data) where T /// Mocked Smart Contract public T FromHash(UInt160 hash) where T : Mocks.SmartContract { + // TODO: Ensure that the contract exists + return MockContract(hash); } private T MockContract(UInt160 hash) where T : Mocks.SmartContract { - // Create object - - Type classType = typeof(T); - - ConstructorInfo internalConstructor = classType.GetConstructor( - BindingFlags.Instance | BindingFlags.NonPublic, - null, new Type[] { typeof(TestEngine), typeof(UInt160) }, null); - - //T sc = (T)internalConstructor.Invoke(new object[] { this, hash }); - // TODO: Mock sc here var mock = new Mock(this, hash) diff --git a/tests/Neo.SmartContract.TestEngine.UnitTests/ArtifactsTests.cs b/tests/Neo.SmartContract.TestEngine.UnitTests/ArtifactsTests.cs index e220f13f7..a7b466f22 100644 --- a/tests/Neo.SmartContract.TestEngine.UnitTests/ArtifactsTests.cs +++ b/tests/Neo.SmartContract.TestEngine.UnitTests/ArtifactsTests.cs @@ -6,6 +6,20 @@ namespace Neo.SmartContract.TestEngine.UnitTests { public class ArtifactsTests { + //[Test] + public void GenerateNativeArtifacts() + { + var manifest = Native.NativeContract.ContractManagement.Manifest; + var source = Artifacts.CreateSourceFromManifest(manifest.Name, manifest.Abi).Replace("\r\n", "\n").Trim(); + } + + [Test] + public void TestNativeContracts() + { + TestEngine engine = new(); + Assert.That(engine.Native.ContractManagement.Hash, Is.EqualTo(Native.NativeContract.ContractManagement.Hash)); + } + [Test] public void TestCreateSourceFromManifest() { @@ -17,7 +31,7 @@ public void TestCreateSourceFromManifest() var source = Artifacts.CreateSourceFromManifest(manifest.Name, manifest.Abi).Replace("\r\n", "\n").Trim(); Assert.That(source, Is.EqualTo(@" -using Neo; +using System.Collections.Generic; using System.Numerics; namespace Neo.TestEngine.Contracts; @@ -62,7 +76,7 @@ public void FromHashTest() TestEngine engine = new(); var contract = engine.FromHash(hash); - + Assert.That(contract.Hash, Is.EqualTo(hash)); } } diff --git a/tests/Neo.SmartContract.TestEngine.UnitTests/Neo.SmartContract.TestEngine.UnitTests.csproj b/tests/Neo.SmartContract.TestEngine.UnitTests/Neo.SmartContract.TestEngine.UnitTests.csproj index 74e5da66d..bb557fbc8 100644 --- a/tests/Neo.SmartContract.TestEngine.UnitTests/Neo.SmartContract.TestEngine.UnitTests.csproj +++ b/tests/Neo.SmartContract.TestEngine.UnitTests/Neo.SmartContract.TestEngine.UnitTests.csproj @@ -10,11 +10,7 @@ - - - - - + diff --git a/tests/Neo.SmartContract.TestEngine.UnitTests/UtArtifacts/Contract1.cs b/tests/Neo.SmartContract.TestEngine.UnitTests/UtArtifacts/Contract1.cs new file mode 100644 index 000000000..375096f59 --- /dev/null +++ b/tests/Neo.SmartContract.TestEngine.UnitTests/UtArtifacts/Contract1.cs @@ -0,0 +1,34 @@ +using System.Numerics; + +namespace Neo.TestEngine.Contracts; + +public abstract class Contract1 : Neo.SmartContract.TestEngine.Mocks.SmartContract +{ + #region Events + public delegate void delSetOwner(UInt160 newOwner); + public event delSetOwner? SetOwner; + public delegate void delTransfer(UInt160 from, UInt160 to, BigInteger amount); + public event delTransfer? Transfer; + #endregion + #region Safe methods + public abstract BigInteger balanceOf(UInt160 owner); + public abstract BigInteger decimals(); + public abstract UInt160 getOwner(); + public abstract string symbol(); + public abstract BigInteger totalSupply(); + public abstract bool verify(); + #endregion + #region Unsafe methods + public abstract void burn(UInt160 account, BigInteger amount); + public abstract void mint(UInt160 to, BigInteger amount); + public abstract string myMethod(); + public abstract void onNEP17Payment(UInt160 from, BigInteger amount, object data); + public abstract void setOwner(UInt160 newOwner); + public abstract bool transfer(UInt160 from, UInt160 to, BigInteger amount, object data); + public abstract void update(byte[] nefFile, string manifest); + public abstract bool withdraw(UInt160 token, UInt160 to, BigInteger amount); + #endregion + #region Constructor for internal use only + protected Contract1(Neo.SmartContract.TestEngine.TestEngine testEngine, Neo.UInt160 hash) : base(testEngine, hash) { } + #endregion +} From bae9a3221d823ecd0f8c259af969e02883c63dae Mon Sep 17 00:00:00 2001 From: Fernando Diaz Toledano Date: Sat, 10 Feb 2024 11:11:03 +0100 Subject: [PATCH 017/106] CryptoLib --- src/Neo.SmartContract.TestEngine/Artifacts.cs | 1 - .../{TestEngine.cs => Engine.cs} | 2 +- .../Mocks/SmartContract.cs | 4 +-- .../ContractManagement.cs | 2 +- .../Native/CryptoLib.cs | 23 ++++++++++++++ .../NativeArtifacts.cs | 17 ++++++++-- .../ArtifactsTests.cs | 29 +++++++++-------- .../GlobalUsings.cs | 1 - ....SmartContract.TestEngine.UnitTests.csproj | 31 +++++++------------ .../UtArtifacts/Contract1.cs | 4 +-- 10 files changed, 71 insertions(+), 43 deletions(-) rename src/Neo.SmartContract.TestEngine/{TestEngine.cs => Engine.cs} (99%) rename src/Neo.SmartContract.TestEngine/{NativeArtifacts => Native}/ContractManagement.cs (91%) create mode 100644 src/Neo.SmartContract.TestEngine/Native/CryptoLib.cs delete mode 100644 tests/Neo.SmartContract.TestEngine.UnitTests/GlobalUsings.cs diff --git a/src/Neo.SmartContract.TestEngine/Artifacts.cs b/src/Neo.SmartContract.TestEngine/Artifacts.cs index 116860223..81fab39b6 100644 --- a/src/Neo.SmartContract.TestEngine/Artifacts.cs +++ b/src/Neo.SmartContract.TestEngine/Artifacts.cs @@ -1,5 +1,4 @@ using Neo.SmartContract.Manifest; -using System; using System.Linq; using System.Text; diff --git a/src/Neo.SmartContract.TestEngine/TestEngine.cs b/src/Neo.SmartContract.TestEngine/Engine.cs similarity index 99% rename from src/Neo.SmartContract.TestEngine/TestEngine.cs rename to src/Neo.SmartContract.TestEngine/Engine.cs index 00c2b570b..4a12c0267 100644 --- a/src/Neo.SmartContract.TestEngine/TestEngine.cs +++ b/src/Neo.SmartContract.TestEngine/Engine.cs @@ -5,7 +5,7 @@ namespace Neo.SmartContract.TestEngine { - public class TestEngine + public class Engine { /// /// Default Protocol Settings diff --git a/src/Neo.SmartContract.TestEngine/Mocks/SmartContract.cs b/src/Neo.SmartContract.TestEngine/Mocks/SmartContract.cs index 36ae6483e..fb1ec90f2 100644 --- a/src/Neo.SmartContract.TestEngine/Mocks/SmartContract.cs +++ b/src/Neo.SmartContract.TestEngine/Mocks/SmartContract.cs @@ -2,7 +2,7 @@ namespace Neo.SmartContract.TestEngine.Mocks { public class SmartContract { - private readonly TestEngine _engine; + private readonly Engine _engine; /// /// Contract hash @@ -14,7 +14,7 @@ public class SmartContract /// /// TestEngine /// Contract hash - protected SmartContract(TestEngine testEngine, UInt160 hash) + protected SmartContract(Engine testEngine, UInt160 hash) { _engine = testEngine; Hash = hash; diff --git a/src/Neo.SmartContract.TestEngine/NativeArtifacts/ContractManagement.cs b/src/Neo.SmartContract.TestEngine/Native/ContractManagement.cs similarity index 91% rename from src/Neo.SmartContract.TestEngine/NativeArtifacts/ContractManagement.cs rename to src/Neo.SmartContract.TestEngine/Native/ContractManagement.cs index 7d03207b8..3bbd7c910 100644 --- a/src/Neo.SmartContract.TestEngine/NativeArtifacts/ContractManagement.cs +++ b/src/Neo.SmartContract.TestEngine/Native/ContractManagement.cs @@ -29,6 +29,6 @@ public abstract class ContractManagement : Neo.SmartContract.TestEngine.Mocks.Sm public abstract void update(byte[] nefFile, byte[] manifest, object data); #endregion #region Constructor for internal use only - protected ContractManagement(Neo.SmartContract.TestEngine.TestEngine testEngine, Neo.UInt160 hash) : base(testEngine, hash) { } + protected ContractManagement(Neo.SmartContract.TestEngine.Engine testEngine, Neo.UInt160 hash) : base(testEngine, hash) { } #endregion } diff --git a/src/Neo.SmartContract.TestEngine/Native/CryptoLib.cs b/src/Neo.SmartContract.TestEngine/Native/CryptoLib.cs new file mode 100644 index 000000000..a86c68ebf --- /dev/null +++ b/src/Neo.SmartContract.TestEngine/Native/CryptoLib.cs @@ -0,0 +1,23 @@ +using System.Collections.Generic; +using System.Numerics; + +namespace Neo.TestEngine.Contracts; + +public abstract class CryptoLib : Neo.SmartContract.TestEngine.Mocks.SmartContract +{ + #region Safe methods + public abstract object bls12381Add(object x, object y); + public abstract object bls12381Deserialize(byte[] data); + public abstract bool bls12381Equal(object x, object y); + public abstract object bls12381Mul(object x, byte[] mul, bool neg); + public abstract object bls12381Pairing(object g1, object g2); + public abstract byte[] bls12381Serialize(object g); + public abstract byte[] murmur32(byte[] data, BigInteger seed); + public abstract byte[] ripemd160(byte[] data); + public abstract byte[] sha256(byte[] data); + public abstract bool verifyWithECDsa(byte[] message, byte[] pubkey, byte[] signature, BigInteger curve); + #endregion + #region Constructor for internal use only + protected CryptoLib(Neo.SmartContract.TestEngine.Engine testEngine, Neo.UInt160 hash) : base(testEngine, hash) { } + #endregion +} diff --git a/src/Neo.SmartContract.TestEngine/NativeArtifacts.cs b/src/Neo.SmartContract.TestEngine/NativeArtifacts.cs index f9c96d44c..8f65972cc 100644 --- a/src/Neo.SmartContract.TestEngine/NativeArtifacts.cs +++ b/src/Neo.SmartContract.TestEngine/NativeArtifacts.cs @@ -4,8 +4,9 @@ namespace Neo.SmartContract.TestEngine { public class NativeArtifacts { - private readonly TestEngine _engine; + private readonly Engine _engine; private ContractManagement? _contractManagement; + private CryptoLib? _cryptoLib; /// /// ContractManagement @@ -19,11 +20,23 @@ public ContractManagement ContractManagement } } + /// + /// CryptoLib + /// + public CryptoLib CryptoLib + { + get + { + _cryptoLib ??= _engine.FromHash(Native.NativeContract.CryptoLib.Hash); + return _cryptoLib; + } + } + /// /// Constructor /// /// Engine - public NativeArtifacts(TestEngine engine) + public NativeArtifacts(Engine engine) { _engine = engine; } diff --git a/tests/Neo.SmartContract.TestEngine.UnitTests/ArtifactsTests.cs b/tests/Neo.SmartContract.TestEngine.UnitTests/ArtifactsTests.cs index a7b466f22..0c2f232ab 100644 --- a/tests/Neo.SmartContract.TestEngine.UnitTests/ArtifactsTests.cs +++ b/tests/Neo.SmartContract.TestEngine.UnitTests/ArtifactsTests.cs @@ -1,26 +1,29 @@ +using Microsoft.VisualStudio.TestTools.UnitTesting; using Neo.Json; using Neo.SmartContract.Manifest; -using Neo.TestEngine.Contracts; namespace Neo.SmartContract.TestEngine.UnitTests { + [TestClass] public class ArtifactsTests { - //[Test] + [TestMethod] public void GenerateNativeArtifacts() { - var manifest = Native.NativeContract.ContractManagement.Manifest; - var source = Artifacts.CreateSourceFromManifest(manifest.Name, manifest.Abi).Replace("\r\n", "\n").Trim(); + var manifest = SmartContract.Native.NativeContract.ContractManagement.Manifest; + var contractManagement = Artifacts.CreateSourceFromManifest(manifest.Name, manifest.Abi).Replace("\r\n", "\n").Trim(); + + manifest = SmartContract.Native.NativeContract.CryptoLib.Manifest; + var cryptoLib = Artifacts.CreateSourceFromManifest(manifest.Name, manifest.Abi).Replace("\r\n", "\n").Trim(); } - [Test] public void TestNativeContracts() { - TestEngine engine = new(); - Assert.That(engine.Native.ContractManagement.Hash, Is.EqualTo(Native.NativeContract.ContractManagement.Hash)); + Engine engine = new(); + Assert.Equals(engine.Native.ContractManagement.Hash, SmartContract.Native.NativeContract.ContractManagement.Hash); } - [Test] + [TestMethod] public void TestCreateSourceFromManifest() { var manifest = ContractManifest.FromJson(JToken.Parse( @@ -30,7 +33,7 @@ public void TestCreateSourceFromManifest() var source = Artifacts.CreateSourceFromManifest(manifest.Name, manifest.Abi).Replace("\r\n", "\n").Trim(); - Assert.That(source, Is.EqualTo(@" + Assert.AreEqual(source, @" using System.Collections.Generic; using System.Numerics; @@ -66,18 +69,18 @@ public abstract class Contract1 : Neo.SmartContract.TestEngine.Mocks.SmartContra protected Contract1(Neo.SmartContract.TestEngine.TestEngine testEngine, Neo.UInt160 hash) : base(testEngine, hash) {} #endregion } -".Replace("\r\n", "\n").Trim())); +".Replace("\r\n", "\n").Trim()); } - [Test] + [TestMethod] public void FromHashTest() { UInt160 hash = UInt160.Parse("0x1230000000000000000000000000000000000000"); - TestEngine engine = new(); + Engine engine = new(); var contract = engine.FromHash(hash); - Assert.That(contract.Hash, Is.EqualTo(hash)); + Assert.Equals(contract.Hash, hash); } } } diff --git a/tests/Neo.SmartContract.TestEngine.UnitTests/GlobalUsings.cs b/tests/Neo.SmartContract.TestEngine.UnitTests/GlobalUsings.cs deleted file mode 100644 index 324456763..000000000 --- a/tests/Neo.SmartContract.TestEngine.UnitTests/GlobalUsings.cs +++ /dev/null @@ -1 +0,0 @@ -global using NUnit.Framework; diff --git a/tests/Neo.SmartContract.TestEngine.UnitTests/Neo.SmartContract.TestEngine.UnitTests.csproj b/tests/Neo.SmartContract.TestEngine.UnitTests/Neo.SmartContract.TestEngine.UnitTests.csproj index bb557fbc8..cdb30c0fd 100644 --- a/tests/Neo.SmartContract.TestEngine.UnitTests/Neo.SmartContract.TestEngine.UnitTests.csproj +++ b/tests/Neo.SmartContract.TestEngine.UnitTests/Neo.SmartContract.TestEngine.UnitTests.csproj @@ -1,20 +1,11 @@ - - - - net7.0 - enable - enable - - false - true - - - - - - - - - - - + + + + Neo.SmartContract.TestEngine.UnitTests + + + + + + + diff --git a/tests/Neo.SmartContract.TestEngine.UnitTests/UtArtifacts/Contract1.cs b/tests/Neo.SmartContract.TestEngine.UnitTests/UtArtifacts/Contract1.cs index 375096f59..85c926d40 100644 --- a/tests/Neo.SmartContract.TestEngine.UnitTests/UtArtifacts/Contract1.cs +++ b/tests/Neo.SmartContract.TestEngine.UnitTests/UtArtifacts/Contract1.cs @@ -1,6 +1,6 @@ using System.Numerics; -namespace Neo.TestEngine.Contracts; +namespace Neo.SmartContract.TestEngine.UnitTests; public abstract class Contract1 : Neo.SmartContract.TestEngine.Mocks.SmartContract { @@ -29,6 +29,6 @@ public abstract class Contract1 : Neo.SmartContract.TestEngine.Mocks.SmartContra public abstract bool withdraw(UInt160 token, UInt160 to, BigInteger amount); #endregion #region Constructor for internal use only - protected Contract1(Neo.SmartContract.TestEngine.TestEngine testEngine, Neo.UInt160 hash) : base(testEngine, hash) { } + protected Contract1(Neo.SmartContract.TestEngine.Engine testEngine, Neo.UInt160 hash) : base(testEngine, hash) { } #endregion } From 1cdf7064a1cc9dc9a22547dbeb77e21c32da345d Mon Sep 17 00:00:00 2001 From: Fernando Diaz Toledano Date: Sat, 10 Feb 2024 11:29:40 +0100 Subject: [PATCH 018/106] Rename project to avoid old one --- neo-devpack-dotnet.sln | 248 +++++++++--------- .../Neo.Compiler.CSharp.csproj | 2 +- src/Neo.Compiler.CSharp/Program.cs | 2 +- .../Artifacts.cs | 8 +- .../Native/ContractManagement.cs | 6 +- .../Native/CryptoLib.cs | 6 +- .../NativeArtifacts.cs | 8 +- .../Neo.SmartContract.Testing.csproj} | 0 .../SmartContract.cs | 6 +- .../TestEngine.cs} | 10 +- .../ArtifactsTests.cs | 20 +- ...eo.SmartContract.Testing.UnitTests.csproj} | 4 +- .../UtArtifacts/Contract1.cs | 6 +- 13 files changed, 162 insertions(+), 164 deletions(-) rename src/{Neo.SmartContract.TestEngine => Neo.SmartContract.Testing}/Artifacts.cs (95%) rename src/{Neo.SmartContract.TestEngine => Neo.SmartContract.Testing}/Native/ContractManagement.cs (87%) rename src/{Neo.SmartContract.TestEngine => Neo.SmartContract.Testing}/Native/CryptoLib.cs (77%) rename src/{Neo.SmartContract.TestEngine => Neo.SmartContract.Testing}/NativeArtifacts.cs (85%) rename src/{Neo.SmartContract.TestEngine/Neo.SmartContract.TestEngine.csproj => Neo.SmartContract.Testing/Neo.SmartContract.Testing.csproj} (100%) rename src/{Neo.SmartContract.TestEngine/Mocks => Neo.SmartContract.Testing}/SmartContract.cs (73%) rename src/{Neo.SmartContract.TestEngine/Engine.cs => Neo.SmartContract.Testing/TestEngine.cs} (95%) rename tests/{Neo.SmartContract.TestEngine.UnitTests => Neo.SmartContract.Testing.UnitTests}/ArtifactsTests.cs (89%) rename tests/{Neo.SmartContract.TestEngine.UnitTests/Neo.SmartContract.TestEngine.UnitTests.csproj => Neo.SmartContract.Testing.UnitTests/Neo.SmartContract.Testing.UnitTests.csproj} (62%) rename tests/{Neo.SmartContract.TestEngine.UnitTests => Neo.SmartContract.Testing.UnitTests}/UtArtifacts/Contract1.cs (83%) diff --git a/neo-devpack-dotnet.sln b/neo-devpack-dotnet.sln index 796ed203e..64d75df4c 100644 --- a/neo-devpack-dotnet.sln +++ b/neo-devpack-dotnet.sln @@ -1,124 +1,124 @@ -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 17 -VisualStudioVersion = 17.7.34003.232 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Neo.SmartContract.Framework", "src\Neo.SmartContract.Framework\Neo.SmartContract.Framework.csproj", "{C30B5859-D4B9-46E8-A797-6B0A1B49B590}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Neo.Compiler.CSharp", "src\Neo.Compiler.CSharp\Neo.Compiler.CSharp.csproj", "{A2A3B687-A1EC-4221-B792-9BBA8DED09DA}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Neo.SmartContract.Template", "src\Neo.SmartContract.Template\Neo.SmartContract.Template.csproj", "{FC0CAF5A-30A7-4857-B1A4-486FAAA39E5A}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Neo.Compiler.CSharp.UnitTests", "tests\Neo.Compiler.CSharp.UnitTests\Neo.Compiler.CSharp.UnitTests.csproj", "{4C6B120B-99B5-4888-B8D5-45031458DD07}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Neo.SmartContract.Framework.UnitTests", "tests\Neo.SmartContract.Framework.UnitTests\Neo.SmartContract.Framework.UnitTests.csproj", "{93BEC5CC-BAFF-4389-89E7-84AAFF5D495D}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{79389FC0-C621-4CEA-AD2B-6074C32E7BCA}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{D5266066-0AFD-44D5-A83E-2F73668A63C8}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Neo.Compiler.CSharp.TestContracts", "tests\Neo.Compiler.CSharp.TestContracts\Neo.Compiler.CSharp.TestContracts.csproj", "{8D67DD5A-D683-481F-915E-98683EA38791}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Neo.SmartContract.Framework.TestContracts", "tests\Neo.SmartContract.Framework.TestContracts\Neo.SmartContract.Framework.TestContracts.csproj", "{A372F1D6-51FF-472C-9508-FDAF7E6FEB13}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Neo.SmartContract.TestEngine", "tests\Neo.SmartContract.TestEngine\Neo.SmartContract.TestEngine.csproj", "{D0153204-6AEF-4D94-B0E1-8124C38C91D4}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Neo", "neo\src\Neo\Neo.csproj", "{73223FBD-C562-4FA0-9722-C7F1C382A9DE}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Neo.Cryptography.BLS12_381", "neo\src\Neo.Cryptography.BLS12_381\Neo.Cryptography.BLS12_381.csproj", "{D541BCE9-65BC-475B-94E5-19B6BFFF2B8E}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Neo.Json", "neo\src\Neo.Json\Neo.Json.csproj", "{35A34EBD-F2BF-4D83-A096-D5F007B12732}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Neo.VM", "neo\src\Neo.VM\Neo.VM.csproj", "{D6D53889-5A10-46A4-BA66-E78B56EC1881}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Dependency", "Dependency", "{49D5873D-7B38-48A5-B853-85146F032091}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Neo.SmartContract.TestEngine", "src\Neo.SmartContract.TestEngine\Neo.SmartContract.TestEngine.csproj", "{648DCE6F-A0BA-4032-951B-20CF5BBFD998}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Neo.SmartContract.TestEngine.UnitTests", "tests\Neo.SmartContract.TestEngine.UnitTests\Neo.SmartContract.TestEngine.UnitTests.csproj", "{B772B8A9-9362-4C6F-A6D3-2A4138439B2C}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Release|Any CPU = Release|Any CPU - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {C30B5859-D4B9-46E8-A797-6B0A1B49B590}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {C30B5859-D4B9-46E8-A797-6B0A1B49B590}.Debug|Any CPU.Build.0 = Debug|Any CPU - {C30B5859-D4B9-46E8-A797-6B0A1B49B590}.Release|Any CPU.ActiveCfg = Release|Any CPU - {C30B5859-D4B9-46E8-A797-6B0A1B49B590}.Release|Any CPU.Build.0 = Release|Any CPU - {A2A3B687-A1EC-4221-B792-9BBA8DED09DA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {A2A3B687-A1EC-4221-B792-9BBA8DED09DA}.Debug|Any CPU.Build.0 = Debug|Any CPU - {A2A3B687-A1EC-4221-B792-9BBA8DED09DA}.Release|Any CPU.ActiveCfg = Release|Any CPU - {A2A3B687-A1EC-4221-B792-9BBA8DED09DA}.Release|Any CPU.Build.0 = Release|Any CPU - {FC0CAF5A-30A7-4857-B1A4-486FAAA39E5A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {FC0CAF5A-30A7-4857-B1A4-486FAAA39E5A}.Debug|Any CPU.Build.0 = Debug|Any CPU - {FC0CAF5A-30A7-4857-B1A4-486FAAA39E5A}.Release|Any CPU.ActiveCfg = Release|Any CPU - {FC0CAF5A-30A7-4857-B1A4-486FAAA39E5A}.Release|Any CPU.Build.0 = Release|Any CPU - {4C6B120B-99B5-4888-B8D5-45031458DD07}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {4C6B120B-99B5-4888-B8D5-45031458DD07}.Debug|Any CPU.Build.0 = Debug|Any CPU - {4C6B120B-99B5-4888-B8D5-45031458DD07}.Release|Any CPU.ActiveCfg = Release|Any CPU - {4C6B120B-99B5-4888-B8D5-45031458DD07}.Release|Any CPU.Build.0 = Release|Any CPU - {93BEC5CC-BAFF-4389-89E7-84AAFF5D495D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {93BEC5CC-BAFF-4389-89E7-84AAFF5D495D}.Debug|Any CPU.Build.0 = Debug|Any CPU - {93BEC5CC-BAFF-4389-89E7-84AAFF5D495D}.Release|Any CPU.ActiveCfg = Release|Any CPU - {93BEC5CC-BAFF-4389-89E7-84AAFF5D495D}.Release|Any CPU.Build.0 = Release|Any CPU - {8D67DD5A-D683-481F-915E-98683EA38791}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {8D67DD5A-D683-481F-915E-98683EA38791}.Debug|Any CPU.Build.0 = Debug|Any CPU - {8D67DD5A-D683-481F-915E-98683EA38791}.Release|Any CPU.ActiveCfg = Release|Any CPU - {8D67DD5A-D683-481F-915E-98683EA38791}.Release|Any CPU.Build.0 = Release|Any CPU - {A372F1D6-51FF-472C-9508-FDAF7E6FEB13}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {A372F1D6-51FF-472C-9508-FDAF7E6FEB13}.Debug|Any CPU.Build.0 = Debug|Any CPU - {A372F1D6-51FF-472C-9508-FDAF7E6FEB13}.Release|Any CPU.ActiveCfg = Release|Any CPU - {A372F1D6-51FF-472C-9508-FDAF7E6FEB13}.Release|Any CPU.Build.0 = Release|Any CPU - {D0153204-6AEF-4D94-B0E1-8124C38C91D4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {D0153204-6AEF-4D94-B0E1-8124C38C91D4}.Debug|Any CPU.Build.0 = Debug|Any CPU - {D0153204-6AEF-4D94-B0E1-8124C38C91D4}.Release|Any CPU.ActiveCfg = Release|Any CPU - {D0153204-6AEF-4D94-B0E1-8124C38C91D4}.Release|Any CPU.Build.0 = Release|Any CPU - {73223FBD-C562-4FA0-9722-C7F1C382A9DE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {73223FBD-C562-4FA0-9722-C7F1C382A9DE}.Debug|Any CPU.Build.0 = Debug|Any CPU - {73223FBD-C562-4FA0-9722-C7F1C382A9DE}.Release|Any CPU.ActiveCfg = Release|Any CPU - {73223FBD-C562-4FA0-9722-C7F1C382A9DE}.Release|Any CPU.Build.0 = Release|Any CPU - {D541BCE9-65BC-475B-94E5-19B6BFFF2B8E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {D541BCE9-65BC-475B-94E5-19B6BFFF2B8E}.Debug|Any CPU.Build.0 = Debug|Any CPU - {D541BCE9-65BC-475B-94E5-19B6BFFF2B8E}.Release|Any CPU.ActiveCfg = Release|Any CPU - {D541BCE9-65BC-475B-94E5-19B6BFFF2B8E}.Release|Any CPU.Build.0 = Release|Any CPU - {35A34EBD-F2BF-4D83-A096-D5F007B12732}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {35A34EBD-F2BF-4D83-A096-D5F007B12732}.Debug|Any CPU.Build.0 = Debug|Any CPU - {35A34EBD-F2BF-4D83-A096-D5F007B12732}.Release|Any CPU.ActiveCfg = Release|Any CPU - {35A34EBD-F2BF-4D83-A096-D5F007B12732}.Release|Any CPU.Build.0 = Release|Any CPU - {D6D53889-5A10-46A4-BA66-E78B56EC1881}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {D6D53889-5A10-46A4-BA66-E78B56EC1881}.Debug|Any CPU.Build.0 = Debug|Any CPU - {D6D53889-5A10-46A4-BA66-E78B56EC1881}.Release|Any CPU.ActiveCfg = Release|Any CPU - {D6D53889-5A10-46A4-BA66-E78B56EC1881}.Release|Any CPU.Build.0 = Release|Any CPU - {648DCE6F-A0BA-4032-951B-20CF5BBFD998}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {648DCE6F-A0BA-4032-951B-20CF5BBFD998}.Debug|Any CPU.Build.0 = Debug|Any CPU - {648DCE6F-A0BA-4032-951B-20CF5BBFD998}.Release|Any CPU.ActiveCfg = Release|Any CPU - {648DCE6F-A0BA-4032-951B-20CF5BBFD998}.Release|Any CPU.Build.0 = Release|Any CPU - {B772B8A9-9362-4C6F-A6D3-2A4138439B2C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {B772B8A9-9362-4C6F-A6D3-2A4138439B2C}.Debug|Any CPU.Build.0 = Debug|Any CPU - {B772B8A9-9362-4C6F-A6D3-2A4138439B2C}.Release|Any CPU.ActiveCfg = Release|Any CPU - {B772B8A9-9362-4C6F-A6D3-2A4138439B2C}.Release|Any CPU.Build.0 = Release|Any CPU - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection - GlobalSection(NestedProjects) = preSolution - {C30B5859-D4B9-46E8-A797-6B0A1B49B590} = {79389FC0-C621-4CEA-AD2B-6074C32E7BCA} - {A2A3B687-A1EC-4221-B792-9BBA8DED09DA} = {79389FC0-C621-4CEA-AD2B-6074C32E7BCA} - {FC0CAF5A-30A7-4857-B1A4-486FAAA39E5A} = {79389FC0-C621-4CEA-AD2B-6074C32E7BCA} - {4C6B120B-99B5-4888-B8D5-45031458DD07} = {D5266066-0AFD-44D5-A83E-2F73668A63C8} - {93BEC5CC-BAFF-4389-89E7-84AAFF5D495D} = {D5266066-0AFD-44D5-A83E-2F73668A63C8} - {8D67DD5A-D683-481F-915E-98683EA38791} = {D5266066-0AFD-44D5-A83E-2F73668A63C8} - {A372F1D6-51FF-472C-9508-FDAF7E6FEB13} = {D5266066-0AFD-44D5-A83E-2F73668A63C8} - {D0153204-6AEF-4D94-B0E1-8124C38C91D4} = {D5266066-0AFD-44D5-A83E-2F73668A63C8} - {73223FBD-C562-4FA0-9722-C7F1C382A9DE} = {49D5873D-7B38-48A5-B853-85146F032091} - {D541BCE9-65BC-475B-94E5-19B6BFFF2B8E} = {49D5873D-7B38-48A5-B853-85146F032091} - {35A34EBD-F2BF-4D83-A096-D5F007B12732} = {49D5873D-7B38-48A5-B853-85146F032091} - {D6D53889-5A10-46A4-BA66-E78B56EC1881} = {49D5873D-7B38-48A5-B853-85146F032091} - {648DCE6F-A0BA-4032-951B-20CF5BBFD998} = {79389FC0-C621-4CEA-AD2B-6074C32E7BCA} - {B772B8A9-9362-4C6F-A6D3-2A4138439B2C} = {D5266066-0AFD-44D5-A83E-2F73668A63C8} - EndGlobalSection - GlobalSection(ExtensibilityGlobals) = postSolution - SolutionGuid = {6DA935E1-C674-4364-B087-F1B511B79215} - EndGlobalSection -EndGlobal +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.7.34003.232 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Neo.SmartContract.Framework", "src\Neo.SmartContract.Framework\Neo.SmartContract.Framework.csproj", "{C30B5859-D4B9-46E8-A797-6B0A1B49B590}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Neo.Compiler.CSharp", "src\Neo.Compiler.CSharp\Neo.Compiler.CSharp.csproj", "{A2A3B687-A1EC-4221-B792-9BBA8DED09DA}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Neo.SmartContract.Template", "src\Neo.SmartContract.Template\Neo.SmartContract.Template.csproj", "{FC0CAF5A-30A7-4857-B1A4-486FAAA39E5A}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Neo.Compiler.CSharp.UnitTests", "tests\Neo.Compiler.CSharp.UnitTests\Neo.Compiler.CSharp.UnitTests.csproj", "{4C6B120B-99B5-4888-B8D5-45031458DD07}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Neo.SmartContract.Framework.UnitTests", "tests\Neo.SmartContract.Framework.UnitTests\Neo.SmartContract.Framework.UnitTests.csproj", "{93BEC5CC-BAFF-4389-89E7-84AAFF5D495D}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{79389FC0-C621-4CEA-AD2B-6074C32E7BCA}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{D5266066-0AFD-44D5-A83E-2F73668A63C8}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Neo.Compiler.CSharp.TestContracts", "tests\Neo.Compiler.CSharp.TestContracts\Neo.Compiler.CSharp.TestContracts.csproj", "{8D67DD5A-D683-481F-915E-98683EA38791}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Neo.SmartContract.Framework.TestContracts", "tests\Neo.SmartContract.Framework.TestContracts\Neo.SmartContract.Framework.TestContracts.csproj", "{A372F1D6-51FF-472C-9508-FDAF7E6FEB13}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Neo.SmartContract.TestEngine", "tests\Neo.SmartContract.TestEngine\Neo.SmartContract.TestEngine.csproj", "{D0153204-6AEF-4D94-B0E1-8124C38C91D4}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Neo", "neo\src\Neo\Neo.csproj", "{73223FBD-C562-4FA0-9722-C7F1C382A9DE}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Neo.Cryptography.BLS12_381", "neo\src\Neo.Cryptography.BLS12_381\Neo.Cryptography.BLS12_381.csproj", "{D541BCE9-65BC-475B-94E5-19B6BFFF2B8E}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Neo.Json", "neo\src\Neo.Json\Neo.Json.csproj", "{35A34EBD-F2BF-4D83-A096-D5F007B12732}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Neo.VM", "neo\src\Neo.VM\Neo.VM.csproj", "{D6D53889-5A10-46A4-BA66-E78B56EC1881}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Dependency", "Dependency", "{49D5873D-7B38-48A5-B853-85146F032091}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Neo.SmartContract.Testing", "src\Neo.SmartContract.Testing\Neo.SmartContract.Testing.csproj", "{648DCE6F-A0BA-4032-951B-20CF5BBFD998}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Neo.SmartContract.Testing.UnitTests", "tests\Neo.SmartContract.Testing.UnitTests\Neo.SmartContract.Testing.UnitTests.csproj", "{B772B8A9-9362-4C6F-A6D3-2A4138439B2C}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {C30B5859-D4B9-46E8-A797-6B0A1B49B590}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C30B5859-D4B9-46E8-A797-6B0A1B49B590}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C30B5859-D4B9-46E8-A797-6B0A1B49B590}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C30B5859-D4B9-46E8-A797-6B0A1B49B590}.Release|Any CPU.Build.0 = Release|Any CPU + {A2A3B687-A1EC-4221-B792-9BBA8DED09DA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {A2A3B687-A1EC-4221-B792-9BBA8DED09DA}.Debug|Any CPU.Build.0 = Debug|Any CPU + {A2A3B687-A1EC-4221-B792-9BBA8DED09DA}.Release|Any CPU.ActiveCfg = Release|Any CPU + {A2A3B687-A1EC-4221-B792-9BBA8DED09DA}.Release|Any CPU.Build.0 = Release|Any CPU + {FC0CAF5A-30A7-4857-B1A4-486FAAA39E5A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {FC0CAF5A-30A7-4857-B1A4-486FAAA39E5A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {FC0CAF5A-30A7-4857-B1A4-486FAAA39E5A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {FC0CAF5A-30A7-4857-B1A4-486FAAA39E5A}.Release|Any CPU.Build.0 = Release|Any CPU + {4C6B120B-99B5-4888-B8D5-45031458DD07}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {4C6B120B-99B5-4888-B8D5-45031458DD07}.Debug|Any CPU.Build.0 = Debug|Any CPU + {4C6B120B-99B5-4888-B8D5-45031458DD07}.Release|Any CPU.ActiveCfg = Release|Any CPU + {4C6B120B-99B5-4888-B8D5-45031458DD07}.Release|Any CPU.Build.0 = Release|Any CPU + {93BEC5CC-BAFF-4389-89E7-84AAFF5D495D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {93BEC5CC-BAFF-4389-89E7-84AAFF5D495D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {93BEC5CC-BAFF-4389-89E7-84AAFF5D495D}.Release|Any CPU.ActiveCfg = Release|Any CPU + {93BEC5CC-BAFF-4389-89E7-84AAFF5D495D}.Release|Any CPU.Build.0 = Release|Any CPU + {8D67DD5A-D683-481F-915E-98683EA38791}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {8D67DD5A-D683-481F-915E-98683EA38791}.Debug|Any CPU.Build.0 = Debug|Any CPU + {8D67DD5A-D683-481F-915E-98683EA38791}.Release|Any CPU.ActiveCfg = Release|Any CPU + {8D67DD5A-D683-481F-915E-98683EA38791}.Release|Any CPU.Build.0 = Release|Any CPU + {A372F1D6-51FF-472C-9508-FDAF7E6FEB13}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {A372F1D6-51FF-472C-9508-FDAF7E6FEB13}.Debug|Any CPU.Build.0 = Debug|Any CPU + {A372F1D6-51FF-472C-9508-FDAF7E6FEB13}.Release|Any CPU.ActiveCfg = Release|Any CPU + {A372F1D6-51FF-472C-9508-FDAF7E6FEB13}.Release|Any CPU.Build.0 = Release|Any CPU + {D0153204-6AEF-4D94-B0E1-8124C38C91D4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D0153204-6AEF-4D94-B0E1-8124C38C91D4}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D0153204-6AEF-4D94-B0E1-8124C38C91D4}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D0153204-6AEF-4D94-B0E1-8124C38C91D4}.Release|Any CPU.Build.0 = Release|Any CPU + {73223FBD-C562-4FA0-9722-C7F1C382A9DE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {73223FBD-C562-4FA0-9722-C7F1C382A9DE}.Debug|Any CPU.Build.0 = Debug|Any CPU + {73223FBD-C562-4FA0-9722-C7F1C382A9DE}.Release|Any CPU.ActiveCfg = Release|Any CPU + {73223FBD-C562-4FA0-9722-C7F1C382A9DE}.Release|Any CPU.Build.0 = Release|Any CPU + {D541BCE9-65BC-475B-94E5-19B6BFFF2B8E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D541BCE9-65BC-475B-94E5-19B6BFFF2B8E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D541BCE9-65BC-475B-94E5-19B6BFFF2B8E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D541BCE9-65BC-475B-94E5-19B6BFFF2B8E}.Release|Any CPU.Build.0 = Release|Any CPU + {35A34EBD-F2BF-4D83-A096-D5F007B12732}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {35A34EBD-F2BF-4D83-A096-D5F007B12732}.Debug|Any CPU.Build.0 = Debug|Any CPU + {35A34EBD-F2BF-4D83-A096-D5F007B12732}.Release|Any CPU.ActiveCfg = Release|Any CPU + {35A34EBD-F2BF-4D83-A096-D5F007B12732}.Release|Any CPU.Build.0 = Release|Any CPU + {D6D53889-5A10-46A4-BA66-E78B56EC1881}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D6D53889-5A10-46A4-BA66-E78B56EC1881}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D6D53889-5A10-46A4-BA66-E78B56EC1881}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D6D53889-5A10-46A4-BA66-E78B56EC1881}.Release|Any CPU.Build.0 = Release|Any CPU + {648DCE6F-A0BA-4032-951B-20CF5BBFD998}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {648DCE6F-A0BA-4032-951B-20CF5BBFD998}.Debug|Any CPU.Build.0 = Debug|Any CPU + {648DCE6F-A0BA-4032-951B-20CF5BBFD998}.Release|Any CPU.ActiveCfg = Release|Any CPU + {648DCE6F-A0BA-4032-951B-20CF5BBFD998}.Release|Any CPU.Build.0 = Release|Any CPU + {B772B8A9-9362-4C6F-A6D3-2A4138439B2C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B772B8A9-9362-4C6F-A6D3-2A4138439B2C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B772B8A9-9362-4C6F-A6D3-2A4138439B2C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B772B8A9-9362-4C6F-A6D3-2A4138439B2C}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {C30B5859-D4B9-46E8-A797-6B0A1B49B590} = {79389FC0-C621-4CEA-AD2B-6074C32E7BCA} + {A2A3B687-A1EC-4221-B792-9BBA8DED09DA} = {79389FC0-C621-4CEA-AD2B-6074C32E7BCA} + {FC0CAF5A-30A7-4857-B1A4-486FAAA39E5A} = {79389FC0-C621-4CEA-AD2B-6074C32E7BCA} + {4C6B120B-99B5-4888-B8D5-45031458DD07} = {D5266066-0AFD-44D5-A83E-2F73668A63C8} + {93BEC5CC-BAFF-4389-89E7-84AAFF5D495D} = {D5266066-0AFD-44D5-A83E-2F73668A63C8} + {8D67DD5A-D683-481F-915E-98683EA38791} = {D5266066-0AFD-44D5-A83E-2F73668A63C8} + {A372F1D6-51FF-472C-9508-FDAF7E6FEB13} = {D5266066-0AFD-44D5-A83E-2F73668A63C8} + {D0153204-6AEF-4D94-B0E1-8124C38C91D4} = {D5266066-0AFD-44D5-A83E-2F73668A63C8} + {73223FBD-C562-4FA0-9722-C7F1C382A9DE} = {49D5873D-7B38-48A5-B853-85146F032091} + {D541BCE9-65BC-475B-94E5-19B6BFFF2B8E} = {49D5873D-7B38-48A5-B853-85146F032091} + {35A34EBD-F2BF-4D83-A096-D5F007B12732} = {49D5873D-7B38-48A5-B853-85146F032091} + {D6D53889-5A10-46A4-BA66-E78B56EC1881} = {49D5873D-7B38-48A5-B853-85146F032091} + {648DCE6F-A0BA-4032-951B-20CF5BBFD998} = {79389FC0-C621-4CEA-AD2B-6074C32E7BCA} + {B772B8A9-9362-4C6F-A6D3-2A4138439B2C} = {D5266066-0AFD-44D5-A83E-2F73668A63C8} + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {6DA935E1-C674-4364-B087-F1B511B79215} + EndGlobalSection +EndGlobal diff --git a/src/Neo.Compiler.CSharp/Neo.Compiler.CSharp.csproj b/src/Neo.Compiler.CSharp/Neo.Compiler.CSharp.csproj index b86759bca..7bfafc132 100644 --- a/src/Neo.Compiler.CSharp/Neo.Compiler.CSharp.csproj +++ b/src/Neo.Compiler.CSharp/Neo.Compiler.CSharp.csproj @@ -28,7 +28,7 @@ scfx - + diff --git a/src/Neo.Compiler.CSharp/Program.cs b/src/Neo.Compiler.CSharp/Program.cs index 4af6bdde1..f9a5c3599 100644 --- a/src/Neo.Compiler.CSharp/Program.cs +++ b/src/Neo.Compiler.CSharp/Program.cs @@ -14,7 +14,7 @@ using Neo.Optimizer; using Neo.SmartContract; using Neo.SmartContract.Manifest; -using Neo.SmartContract.TestEngine; +using Neo.SmartContract.Testing; using System; using System.CommandLine; using System.CommandLine.Invocation; diff --git a/src/Neo.SmartContract.TestEngine/Artifacts.cs b/src/Neo.SmartContract.Testing/Artifacts.cs similarity index 95% rename from src/Neo.SmartContract.TestEngine/Artifacts.cs rename to src/Neo.SmartContract.Testing/Artifacts.cs index 81fab39b6..5d1792810 100644 --- a/src/Neo.SmartContract.TestEngine/Artifacts.cs +++ b/src/Neo.SmartContract.Testing/Artifacts.cs @@ -2,7 +2,7 @@ using System.Linq; using System.Text; -namespace Neo.SmartContract.TestEngine +namespace Neo.SmartContract.Testing { public class Artifacts { @@ -19,9 +19,9 @@ public static string CreateSourceFromManifest(string name, ContractAbi abi) sourceCode.AppendLine("using System.Collections.Generic;"); sourceCode.AppendLine("using System.Numerics;"); sourceCode.AppendLine(""); - sourceCode.AppendLine("namespace Neo.TestEngine.Contracts;"); + sourceCode.AppendLine("namespace Neo.SmartContract.Testing;"); sourceCode.AppendLine(""); - sourceCode.AppendLine($"public abstract class {name} : Neo.SmartContract.TestEngine.Mocks.SmartContract"); + sourceCode.AppendLine($"public abstract class {name} : Neo.SmartContract.Testing.SmartContract"); sourceCode.AppendLine("{"); // Crete events @@ -74,7 +74,7 @@ public static string CreateSourceFromManifest(string name, ContractAbi abi) // Create constructor sourceCode.AppendLine("#region Constructor for internal use only"); - sourceCode.AppendLine($" protected {name}(Neo.SmartContract.TestEngine.TestEngine testEngine, Neo.UInt160 hash) : base(testEngine, hash) {{}}"); + sourceCode.AppendLine($" protected {name}(Neo.SmartContract.Testing.TestEngine testEngine, Neo.UInt160 hash) : base(testEngine, hash) {{}}"); sourceCode.AppendLine("#endregion"); sourceCode.AppendLine("}"); diff --git a/src/Neo.SmartContract.TestEngine/Native/ContractManagement.cs b/src/Neo.SmartContract.Testing/Native/ContractManagement.cs similarity index 87% rename from src/Neo.SmartContract.TestEngine/Native/ContractManagement.cs rename to src/Neo.SmartContract.Testing/Native/ContractManagement.cs index 3bbd7c910..dbd275183 100644 --- a/src/Neo.SmartContract.TestEngine/Native/ContractManagement.cs +++ b/src/Neo.SmartContract.Testing/Native/ContractManagement.cs @@ -1,9 +1,9 @@ using System.Collections.Generic; using System.Numerics; -namespace Neo.TestEngine.Contracts; +namespace Neo.SmartContract.Testing; -public abstract class ContractManagement : Neo.SmartContract.TestEngine.Mocks.SmartContract +public abstract class ContractManagement : Neo.SmartContract.Testing.SmartContract { #region Events public delegate void delDeploy(UInt160 Hash); @@ -29,6 +29,6 @@ public abstract class ContractManagement : Neo.SmartContract.TestEngine.Mocks.Sm public abstract void update(byte[] nefFile, byte[] manifest, object data); #endregion #region Constructor for internal use only - protected ContractManagement(Neo.SmartContract.TestEngine.Engine testEngine, Neo.UInt160 hash) : base(testEngine, hash) { } + protected ContractManagement(Neo.SmartContract.Testing.TestEngine testEngine, Neo.UInt160 hash) : base(testEngine, hash) { } #endregion } diff --git a/src/Neo.SmartContract.TestEngine/Native/CryptoLib.cs b/src/Neo.SmartContract.Testing/Native/CryptoLib.cs similarity index 77% rename from src/Neo.SmartContract.TestEngine/Native/CryptoLib.cs rename to src/Neo.SmartContract.Testing/Native/CryptoLib.cs index a86c68ebf..6f31cd238 100644 --- a/src/Neo.SmartContract.TestEngine/Native/CryptoLib.cs +++ b/src/Neo.SmartContract.Testing/Native/CryptoLib.cs @@ -1,9 +1,9 @@ using System.Collections.Generic; using System.Numerics; -namespace Neo.TestEngine.Contracts; +namespace Neo.SmartContract.Testing; -public abstract class CryptoLib : Neo.SmartContract.TestEngine.Mocks.SmartContract +public abstract class CryptoLib : Neo.SmartContract.Testing.SmartContract { #region Safe methods public abstract object bls12381Add(object x, object y); @@ -18,6 +18,6 @@ public abstract class CryptoLib : Neo.SmartContract.TestEngine.Mocks.SmartContra public abstract bool verifyWithECDsa(byte[] message, byte[] pubkey, byte[] signature, BigInteger curve); #endregion #region Constructor for internal use only - protected CryptoLib(Neo.SmartContract.TestEngine.Engine testEngine, Neo.UInt160 hash) : base(testEngine, hash) { } + protected CryptoLib(Neo.SmartContract.Testing.TestEngine testEngine, Neo.UInt160 hash) : base(testEngine, hash) { } #endregion } diff --git a/src/Neo.SmartContract.TestEngine/NativeArtifacts.cs b/src/Neo.SmartContract.Testing/NativeArtifacts.cs similarity index 85% rename from src/Neo.SmartContract.TestEngine/NativeArtifacts.cs rename to src/Neo.SmartContract.Testing/NativeArtifacts.cs index 8f65972cc..7b90d84f2 100644 --- a/src/Neo.SmartContract.TestEngine/NativeArtifacts.cs +++ b/src/Neo.SmartContract.Testing/NativeArtifacts.cs @@ -1,10 +1,8 @@ -using Neo.TestEngine.Contracts; - -namespace Neo.SmartContract.TestEngine +namespace Neo.SmartContract.Testing { public class NativeArtifacts { - private readonly Engine _engine; + private readonly TestEngine _engine; private ContractManagement? _contractManagement; private CryptoLib? _cryptoLib; @@ -36,7 +34,7 @@ public CryptoLib CryptoLib /// Constructor /// /// Engine - public NativeArtifacts(Engine engine) + public NativeArtifacts(TestEngine engine) { _engine = engine; } diff --git a/src/Neo.SmartContract.TestEngine/Neo.SmartContract.TestEngine.csproj b/src/Neo.SmartContract.Testing/Neo.SmartContract.Testing.csproj similarity index 100% rename from src/Neo.SmartContract.TestEngine/Neo.SmartContract.TestEngine.csproj rename to src/Neo.SmartContract.Testing/Neo.SmartContract.Testing.csproj diff --git a/src/Neo.SmartContract.TestEngine/Mocks/SmartContract.cs b/src/Neo.SmartContract.Testing/SmartContract.cs similarity index 73% rename from src/Neo.SmartContract.TestEngine/Mocks/SmartContract.cs rename to src/Neo.SmartContract.Testing/SmartContract.cs index fb1ec90f2..1821f893d 100644 --- a/src/Neo.SmartContract.TestEngine/Mocks/SmartContract.cs +++ b/src/Neo.SmartContract.Testing/SmartContract.cs @@ -1,8 +1,8 @@ -namespace Neo.SmartContract.TestEngine.Mocks +namespace Neo.SmartContract.Testing { public class SmartContract { - private readonly Engine _engine; + private readonly TestEngine _engine; /// /// Contract hash @@ -14,7 +14,7 @@ public class SmartContract /// /// TestEngine /// Contract hash - protected SmartContract(Engine testEngine, UInt160 hash) + protected SmartContract(TestEngine testEngine, UInt160 hash) { _engine = testEngine; Hash = hash; diff --git a/src/Neo.SmartContract.TestEngine/Engine.cs b/src/Neo.SmartContract.Testing/TestEngine.cs similarity index 95% rename from src/Neo.SmartContract.TestEngine/Engine.cs rename to src/Neo.SmartContract.Testing/TestEngine.cs index 4a12c0267..dd2d576d8 100644 --- a/src/Neo.SmartContract.TestEngine/Engine.cs +++ b/src/Neo.SmartContract.Testing/TestEngine.cs @@ -3,9 +3,9 @@ using Neo.Persistence; using Neo.SmartContract.Manifest; -namespace Neo.SmartContract.TestEngine +namespace Neo.SmartContract.Testing { - public class Engine + public class TestEngine { /// /// Default Protocol Settings @@ -94,7 +94,7 @@ public NativeArtifacts Native /// Contract manifest /// Construction data /// Mocked Smart Contract - public T Deploy(NefFile nef, ContractManifest manifest, object data) where T : Mocks.SmartContract + public T Deploy(NefFile nef, ContractManifest manifest, object data) where T : SmartContract { // Deploy and get the hash @@ -111,14 +111,14 @@ public T Deploy(NefFile nef, ContractManifest manifest, object data) where T /// Type /// Contract hash /// Mocked Smart Contract - public T FromHash(UInt160 hash) where T : Mocks.SmartContract + public T FromHash(UInt160 hash) where T : SmartContract { // TODO: Ensure that the contract exists return MockContract(hash); } - private T MockContract(UInt160 hash) where T : Mocks.SmartContract + private T MockContract(UInt160 hash) where T : SmartContract { // TODO: Mock sc here diff --git a/tests/Neo.SmartContract.TestEngine.UnitTests/ArtifactsTests.cs b/tests/Neo.SmartContract.Testing.UnitTests/ArtifactsTests.cs similarity index 89% rename from tests/Neo.SmartContract.TestEngine.UnitTests/ArtifactsTests.cs rename to tests/Neo.SmartContract.Testing.UnitTests/ArtifactsTests.cs index 0c2f232ab..5c2100004 100644 --- a/tests/Neo.SmartContract.TestEngine.UnitTests/ArtifactsTests.cs +++ b/tests/Neo.SmartContract.Testing.UnitTests/ArtifactsTests.cs @@ -2,7 +2,7 @@ using Neo.Json; using Neo.SmartContract.Manifest; -namespace Neo.SmartContract.TestEngine.UnitTests +namespace Neo.SmartContract.Testing.UnitTests { [TestClass] public class ArtifactsTests @@ -10,17 +10,17 @@ public class ArtifactsTests [TestMethod] public void GenerateNativeArtifacts() { - var manifest = SmartContract.Native.NativeContract.ContractManagement.Manifest; + var manifest = Native.NativeContract.ContractManagement.Manifest; var contractManagement = Artifacts.CreateSourceFromManifest(manifest.Name, manifest.Abi).Replace("\r\n", "\n").Trim(); - manifest = SmartContract.Native.NativeContract.CryptoLib.Manifest; + manifest = Native.NativeContract.CryptoLib.Manifest; var cryptoLib = Artifacts.CreateSourceFromManifest(manifest.Name, manifest.Abi).Replace("\r\n", "\n").Trim(); } public void TestNativeContracts() { - Engine engine = new(); - Assert.Equals(engine.Native.ContractManagement.Hash, SmartContract.Native.NativeContract.ContractManagement.Hash); + TestEngine engine = new(); + Assert.Equals(engine.Native.ContractManagement.Hash, Native.NativeContract.ContractManagement.Hash); } [TestMethod] @@ -37,9 +37,9 @@ public void TestCreateSourceFromManifest() using System.Collections.Generic; using System.Numerics; -namespace Neo.TestEngine.Contracts; +namespace Neo.SmartContract.Testing; -public abstract class Contract1 : Neo.SmartContract.TestEngine.Mocks.SmartContract +public abstract class Contract1 : Neo.SmartContract.Testing.SmartContract { #region Events public delegate void delSetOwner(UInt160 newOwner); @@ -66,7 +66,7 @@ public abstract class Contract1 : Neo.SmartContract.TestEngine.Mocks.SmartContra public abstract bool withdraw(UInt160 token, UInt160 to, BigInteger amount); #endregion #region Constructor for internal use only - protected Contract1(Neo.SmartContract.TestEngine.TestEngine testEngine, Neo.UInt160 hash) : base(testEngine, hash) {} + protected Contract1(Neo.SmartContract.Testing.TestEngine testEngine, Neo.UInt160 hash) : base(testEngine, hash) {} #endregion } ".Replace("\r\n", "\n").Trim()); @@ -76,11 +76,11 @@ protected Contract1(Neo.SmartContract.TestEngine.TestEngine testEngine, Neo.UInt public void FromHashTest() { UInt160 hash = UInt160.Parse("0x1230000000000000000000000000000000000000"); - Engine engine = new(); + TestEngine engine = new(); var contract = engine.FromHash(hash); - Assert.Equals(contract.Hash, hash); + Assert.AreEqual(contract.Hash, hash); } } } diff --git a/tests/Neo.SmartContract.TestEngine.UnitTests/Neo.SmartContract.TestEngine.UnitTests.csproj b/tests/Neo.SmartContract.Testing.UnitTests/Neo.SmartContract.Testing.UnitTests.csproj similarity index 62% rename from tests/Neo.SmartContract.TestEngine.UnitTests/Neo.SmartContract.TestEngine.UnitTests.csproj rename to tests/Neo.SmartContract.Testing.UnitTests/Neo.SmartContract.Testing.UnitTests.csproj index cdb30c0fd..09a33cb2e 100644 --- a/tests/Neo.SmartContract.TestEngine.UnitTests/Neo.SmartContract.TestEngine.UnitTests.csproj +++ b/tests/Neo.SmartContract.Testing.UnitTests/Neo.SmartContract.Testing.UnitTests.csproj @@ -4,8 +4,8 @@ Neo.SmartContract.TestEngine.UnitTests - - + + diff --git a/tests/Neo.SmartContract.TestEngine.UnitTests/UtArtifacts/Contract1.cs b/tests/Neo.SmartContract.Testing.UnitTests/UtArtifacts/Contract1.cs similarity index 83% rename from tests/Neo.SmartContract.TestEngine.UnitTests/UtArtifacts/Contract1.cs rename to tests/Neo.SmartContract.Testing.UnitTests/UtArtifacts/Contract1.cs index 85c926d40..70d6a0a71 100644 --- a/tests/Neo.SmartContract.TestEngine.UnitTests/UtArtifacts/Contract1.cs +++ b/tests/Neo.SmartContract.Testing.UnitTests/UtArtifacts/Contract1.cs @@ -1,8 +1,8 @@ using System.Numerics; -namespace Neo.SmartContract.TestEngine.UnitTests; +namespace Neo.SmartContract.Testing; -public abstract class Contract1 : Neo.SmartContract.TestEngine.Mocks.SmartContract +public abstract class Contract1 : Neo.SmartContract.Testing.SmartContract { #region Events public delegate void delSetOwner(UInt160 newOwner); @@ -29,6 +29,6 @@ public abstract class Contract1 : Neo.SmartContract.TestEngine.Mocks.SmartContra public abstract bool withdraw(UInt160 token, UInt160 to, BigInteger amount); #endregion #region Constructor for internal use only - protected Contract1(Neo.SmartContract.TestEngine.Engine testEngine, Neo.UInt160 hash) : base(testEngine, hash) { } + protected Contract1(Neo.SmartContract.Testing.TestEngine testEngine, Neo.UInt160 hash) : base(testEngine, hash) { } #endregion } From 3b1fc80e4747dbadde53d828798bdf9fdc56625c Mon Sep 17 00:00:00 2001 From: Fernando Diaz Toledano Date: Sat, 10 Feb 2024 11:30:21 +0100 Subject: [PATCH 019/106] LF --- neo-devpack-dotnet.sln | 248 ++++++++++++++++++++--------------------- 1 file changed, 124 insertions(+), 124 deletions(-) diff --git a/neo-devpack-dotnet.sln b/neo-devpack-dotnet.sln index 64d75df4c..2a5c1b4cd 100644 --- a/neo-devpack-dotnet.sln +++ b/neo-devpack-dotnet.sln @@ -1,124 +1,124 @@ -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 17 -VisualStudioVersion = 17.7.34003.232 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Neo.SmartContract.Framework", "src\Neo.SmartContract.Framework\Neo.SmartContract.Framework.csproj", "{C30B5859-D4B9-46E8-A797-6B0A1B49B590}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Neo.Compiler.CSharp", "src\Neo.Compiler.CSharp\Neo.Compiler.CSharp.csproj", "{A2A3B687-A1EC-4221-B792-9BBA8DED09DA}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Neo.SmartContract.Template", "src\Neo.SmartContract.Template\Neo.SmartContract.Template.csproj", "{FC0CAF5A-30A7-4857-B1A4-486FAAA39E5A}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Neo.Compiler.CSharp.UnitTests", "tests\Neo.Compiler.CSharp.UnitTests\Neo.Compiler.CSharp.UnitTests.csproj", "{4C6B120B-99B5-4888-B8D5-45031458DD07}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Neo.SmartContract.Framework.UnitTests", "tests\Neo.SmartContract.Framework.UnitTests\Neo.SmartContract.Framework.UnitTests.csproj", "{93BEC5CC-BAFF-4389-89E7-84AAFF5D495D}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{79389FC0-C621-4CEA-AD2B-6074C32E7BCA}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{D5266066-0AFD-44D5-A83E-2F73668A63C8}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Neo.Compiler.CSharp.TestContracts", "tests\Neo.Compiler.CSharp.TestContracts\Neo.Compiler.CSharp.TestContracts.csproj", "{8D67DD5A-D683-481F-915E-98683EA38791}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Neo.SmartContract.Framework.TestContracts", "tests\Neo.SmartContract.Framework.TestContracts\Neo.SmartContract.Framework.TestContracts.csproj", "{A372F1D6-51FF-472C-9508-FDAF7E6FEB13}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Neo.SmartContract.TestEngine", "tests\Neo.SmartContract.TestEngine\Neo.SmartContract.TestEngine.csproj", "{D0153204-6AEF-4D94-B0E1-8124C38C91D4}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Neo", "neo\src\Neo\Neo.csproj", "{73223FBD-C562-4FA0-9722-C7F1C382A9DE}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Neo.Cryptography.BLS12_381", "neo\src\Neo.Cryptography.BLS12_381\Neo.Cryptography.BLS12_381.csproj", "{D541BCE9-65BC-475B-94E5-19B6BFFF2B8E}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Neo.Json", "neo\src\Neo.Json\Neo.Json.csproj", "{35A34EBD-F2BF-4D83-A096-D5F007B12732}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Neo.VM", "neo\src\Neo.VM\Neo.VM.csproj", "{D6D53889-5A10-46A4-BA66-E78B56EC1881}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Dependency", "Dependency", "{49D5873D-7B38-48A5-B853-85146F032091}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Neo.SmartContract.Testing", "src\Neo.SmartContract.Testing\Neo.SmartContract.Testing.csproj", "{648DCE6F-A0BA-4032-951B-20CF5BBFD998}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Neo.SmartContract.Testing.UnitTests", "tests\Neo.SmartContract.Testing.UnitTests\Neo.SmartContract.Testing.UnitTests.csproj", "{B772B8A9-9362-4C6F-A6D3-2A4138439B2C}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Release|Any CPU = Release|Any CPU - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {C30B5859-D4B9-46E8-A797-6B0A1B49B590}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {C30B5859-D4B9-46E8-A797-6B0A1B49B590}.Debug|Any CPU.Build.0 = Debug|Any CPU - {C30B5859-D4B9-46E8-A797-6B0A1B49B590}.Release|Any CPU.ActiveCfg = Release|Any CPU - {C30B5859-D4B9-46E8-A797-6B0A1B49B590}.Release|Any CPU.Build.0 = Release|Any CPU - {A2A3B687-A1EC-4221-B792-9BBA8DED09DA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {A2A3B687-A1EC-4221-B792-9BBA8DED09DA}.Debug|Any CPU.Build.0 = Debug|Any CPU - {A2A3B687-A1EC-4221-B792-9BBA8DED09DA}.Release|Any CPU.ActiveCfg = Release|Any CPU - {A2A3B687-A1EC-4221-B792-9BBA8DED09DA}.Release|Any CPU.Build.0 = Release|Any CPU - {FC0CAF5A-30A7-4857-B1A4-486FAAA39E5A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {FC0CAF5A-30A7-4857-B1A4-486FAAA39E5A}.Debug|Any CPU.Build.0 = Debug|Any CPU - {FC0CAF5A-30A7-4857-B1A4-486FAAA39E5A}.Release|Any CPU.ActiveCfg = Release|Any CPU - {FC0CAF5A-30A7-4857-B1A4-486FAAA39E5A}.Release|Any CPU.Build.0 = Release|Any CPU - {4C6B120B-99B5-4888-B8D5-45031458DD07}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {4C6B120B-99B5-4888-B8D5-45031458DD07}.Debug|Any CPU.Build.0 = Debug|Any CPU - {4C6B120B-99B5-4888-B8D5-45031458DD07}.Release|Any CPU.ActiveCfg = Release|Any CPU - {4C6B120B-99B5-4888-B8D5-45031458DD07}.Release|Any CPU.Build.0 = Release|Any CPU - {93BEC5CC-BAFF-4389-89E7-84AAFF5D495D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {93BEC5CC-BAFF-4389-89E7-84AAFF5D495D}.Debug|Any CPU.Build.0 = Debug|Any CPU - {93BEC5CC-BAFF-4389-89E7-84AAFF5D495D}.Release|Any CPU.ActiveCfg = Release|Any CPU - {93BEC5CC-BAFF-4389-89E7-84AAFF5D495D}.Release|Any CPU.Build.0 = Release|Any CPU - {8D67DD5A-D683-481F-915E-98683EA38791}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {8D67DD5A-D683-481F-915E-98683EA38791}.Debug|Any CPU.Build.0 = Debug|Any CPU - {8D67DD5A-D683-481F-915E-98683EA38791}.Release|Any CPU.ActiveCfg = Release|Any CPU - {8D67DD5A-D683-481F-915E-98683EA38791}.Release|Any CPU.Build.0 = Release|Any CPU - {A372F1D6-51FF-472C-9508-FDAF7E6FEB13}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {A372F1D6-51FF-472C-9508-FDAF7E6FEB13}.Debug|Any CPU.Build.0 = Debug|Any CPU - {A372F1D6-51FF-472C-9508-FDAF7E6FEB13}.Release|Any CPU.ActiveCfg = Release|Any CPU - {A372F1D6-51FF-472C-9508-FDAF7E6FEB13}.Release|Any CPU.Build.0 = Release|Any CPU - {D0153204-6AEF-4D94-B0E1-8124C38C91D4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {D0153204-6AEF-4D94-B0E1-8124C38C91D4}.Debug|Any CPU.Build.0 = Debug|Any CPU - {D0153204-6AEF-4D94-B0E1-8124C38C91D4}.Release|Any CPU.ActiveCfg = Release|Any CPU - {D0153204-6AEF-4D94-B0E1-8124C38C91D4}.Release|Any CPU.Build.0 = Release|Any CPU - {73223FBD-C562-4FA0-9722-C7F1C382A9DE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {73223FBD-C562-4FA0-9722-C7F1C382A9DE}.Debug|Any CPU.Build.0 = Debug|Any CPU - {73223FBD-C562-4FA0-9722-C7F1C382A9DE}.Release|Any CPU.ActiveCfg = Release|Any CPU - {73223FBD-C562-4FA0-9722-C7F1C382A9DE}.Release|Any CPU.Build.0 = Release|Any CPU - {D541BCE9-65BC-475B-94E5-19B6BFFF2B8E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {D541BCE9-65BC-475B-94E5-19B6BFFF2B8E}.Debug|Any CPU.Build.0 = Debug|Any CPU - {D541BCE9-65BC-475B-94E5-19B6BFFF2B8E}.Release|Any CPU.ActiveCfg = Release|Any CPU - {D541BCE9-65BC-475B-94E5-19B6BFFF2B8E}.Release|Any CPU.Build.0 = Release|Any CPU - {35A34EBD-F2BF-4D83-A096-D5F007B12732}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {35A34EBD-F2BF-4D83-A096-D5F007B12732}.Debug|Any CPU.Build.0 = Debug|Any CPU - {35A34EBD-F2BF-4D83-A096-D5F007B12732}.Release|Any CPU.ActiveCfg = Release|Any CPU - {35A34EBD-F2BF-4D83-A096-D5F007B12732}.Release|Any CPU.Build.0 = Release|Any CPU - {D6D53889-5A10-46A4-BA66-E78B56EC1881}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {D6D53889-5A10-46A4-BA66-E78B56EC1881}.Debug|Any CPU.Build.0 = Debug|Any CPU - {D6D53889-5A10-46A4-BA66-E78B56EC1881}.Release|Any CPU.ActiveCfg = Release|Any CPU - {D6D53889-5A10-46A4-BA66-E78B56EC1881}.Release|Any CPU.Build.0 = Release|Any CPU - {648DCE6F-A0BA-4032-951B-20CF5BBFD998}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {648DCE6F-A0BA-4032-951B-20CF5BBFD998}.Debug|Any CPU.Build.0 = Debug|Any CPU - {648DCE6F-A0BA-4032-951B-20CF5BBFD998}.Release|Any CPU.ActiveCfg = Release|Any CPU - {648DCE6F-A0BA-4032-951B-20CF5BBFD998}.Release|Any CPU.Build.0 = Release|Any CPU - {B772B8A9-9362-4C6F-A6D3-2A4138439B2C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {B772B8A9-9362-4C6F-A6D3-2A4138439B2C}.Debug|Any CPU.Build.0 = Debug|Any CPU - {B772B8A9-9362-4C6F-A6D3-2A4138439B2C}.Release|Any CPU.ActiveCfg = Release|Any CPU - {B772B8A9-9362-4C6F-A6D3-2A4138439B2C}.Release|Any CPU.Build.0 = Release|Any CPU - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection - GlobalSection(NestedProjects) = preSolution - {C30B5859-D4B9-46E8-A797-6B0A1B49B590} = {79389FC0-C621-4CEA-AD2B-6074C32E7BCA} - {A2A3B687-A1EC-4221-B792-9BBA8DED09DA} = {79389FC0-C621-4CEA-AD2B-6074C32E7BCA} - {FC0CAF5A-30A7-4857-B1A4-486FAAA39E5A} = {79389FC0-C621-4CEA-AD2B-6074C32E7BCA} - {4C6B120B-99B5-4888-B8D5-45031458DD07} = {D5266066-0AFD-44D5-A83E-2F73668A63C8} - {93BEC5CC-BAFF-4389-89E7-84AAFF5D495D} = {D5266066-0AFD-44D5-A83E-2F73668A63C8} - {8D67DD5A-D683-481F-915E-98683EA38791} = {D5266066-0AFD-44D5-A83E-2F73668A63C8} - {A372F1D6-51FF-472C-9508-FDAF7E6FEB13} = {D5266066-0AFD-44D5-A83E-2F73668A63C8} - {D0153204-6AEF-4D94-B0E1-8124C38C91D4} = {D5266066-0AFD-44D5-A83E-2F73668A63C8} - {73223FBD-C562-4FA0-9722-C7F1C382A9DE} = {49D5873D-7B38-48A5-B853-85146F032091} - {D541BCE9-65BC-475B-94E5-19B6BFFF2B8E} = {49D5873D-7B38-48A5-B853-85146F032091} - {35A34EBD-F2BF-4D83-A096-D5F007B12732} = {49D5873D-7B38-48A5-B853-85146F032091} - {D6D53889-5A10-46A4-BA66-E78B56EC1881} = {49D5873D-7B38-48A5-B853-85146F032091} - {648DCE6F-A0BA-4032-951B-20CF5BBFD998} = {79389FC0-C621-4CEA-AD2B-6074C32E7BCA} - {B772B8A9-9362-4C6F-A6D3-2A4138439B2C} = {D5266066-0AFD-44D5-A83E-2F73668A63C8} - EndGlobalSection - GlobalSection(ExtensibilityGlobals) = postSolution - SolutionGuid = {6DA935E1-C674-4364-B087-F1B511B79215} - EndGlobalSection -EndGlobal +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.7.34003.232 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Neo.SmartContract.Framework", "src\Neo.SmartContract.Framework\Neo.SmartContract.Framework.csproj", "{C30B5859-D4B9-46E8-A797-6B0A1B49B590}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Neo.Compiler.CSharp", "src\Neo.Compiler.CSharp\Neo.Compiler.CSharp.csproj", "{A2A3B687-A1EC-4221-B792-9BBA8DED09DA}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Neo.SmartContract.Template", "src\Neo.SmartContract.Template\Neo.SmartContract.Template.csproj", "{FC0CAF5A-30A7-4857-B1A4-486FAAA39E5A}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Neo.Compiler.CSharp.UnitTests", "tests\Neo.Compiler.CSharp.UnitTests\Neo.Compiler.CSharp.UnitTests.csproj", "{4C6B120B-99B5-4888-B8D5-45031458DD07}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Neo.SmartContract.Framework.UnitTests", "tests\Neo.SmartContract.Framework.UnitTests\Neo.SmartContract.Framework.UnitTests.csproj", "{93BEC5CC-BAFF-4389-89E7-84AAFF5D495D}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{79389FC0-C621-4CEA-AD2B-6074C32E7BCA}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{D5266066-0AFD-44D5-A83E-2F73668A63C8}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Neo.Compiler.CSharp.TestContracts", "tests\Neo.Compiler.CSharp.TestContracts\Neo.Compiler.CSharp.TestContracts.csproj", "{8D67DD5A-D683-481F-915E-98683EA38791}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Neo.SmartContract.Framework.TestContracts", "tests\Neo.SmartContract.Framework.TestContracts\Neo.SmartContract.Framework.TestContracts.csproj", "{A372F1D6-51FF-472C-9508-FDAF7E6FEB13}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Neo.SmartContract.TestEngine", "tests\Neo.SmartContract.TestEngine\Neo.SmartContract.TestEngine.csproj", "{D0153204-6AEF-4D94-B0E1-8124C38C91D4}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Neo", "neo\src\Neo\Neo.csproj", "{73223FBD-C562-4FA0-9722-C7F1C382A9DE}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Neo.Cryptography.BLS12_381", "neo\src\Neo.Cryptography.BLS12_381\Neo.Cryptography.BLS12_381.csproj", "{D541BCE9-65BC-475B-94E5-19B6BFFF2B8E}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Neo.Json", "neo\src\Neo.Json\Neo.Json.csproj", "{35A34EBD-F2BF-4D83-A096-D5F007B12732}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Neo.VM", "neo\src\Neo.VM\Neo.VM.csproj", "{D6D53889-5A10-46A4-BA66-E78B56EC1881}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Dependency", "Dependency", "{49D5873D-7B38-48A5-B853-85146F032091}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Neo.SmartContract.Testing", "src\Neo.SmartContract.Testing\Neo.SmartContract.Testing.csproj", "{648DCE6F-A0BA-4032-951B-20CF5BBFD998}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Neo.SmartContract.Testing.UnitTests", "tests\Neo.SmartContract.Testing.UnitTests\Neo.SmartContract.Testing.UnitTests.csproj", "{B772B8A9-9362-4C6F-A6D3-2A4138439B2C}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {C30B5859-D4B9-46E8-A797-6B0A1B49B590}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C30B5859-D4B9-46E8-A797-6B0A1B49B590}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C30B5859-D4B9-46E8-A797-6B0A1B49B590}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C30B5859-D4B9-46E8-A797-6B0A1B49B590}.Release|Any CPU.Build.0 = Release|Any CPU + {A2A3B687-A1EC-4221-B792-9BBA8DED09DA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {A2A3B687-A1EC-4221-B792-9BBA8DED09DA}.Debug|Any CPU.Build.0 = Debug|Any CPU + {A2A3B687-A1EC-4221-B792-9BBA8DED09DA}.Release|Any CPU.ActiveCfg = Release|Any CPU + {A2A3B687-A1EC-4221-B792-9BBA8DED09DA}.Release|Any CPU.Build.0 = Release|Any CPU + {FC0CAF5A-30A7-4857-B1A4-486FAAA39E5A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {FC0CAF5A-30A7-4857-B1A4-486FAAA39E5A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {FC0CAF5A-30A7-4857-B1A4-486FAAA39E5A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {FC0CAF5A-30A7-4857-B1A4-486FAAA39E5A}.Release|Any CPU.Build.0 = Release|Any CPU + {4C6B120B-99B5-4888-B8D5-45031458DD07}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {4C6B120B-99B5-4888-B8D5-45031458DD07}.Debug|Any CPU.Build.0 = Debug|Any CPU + {4C6B120B-99B5-4888-B8D5-45031458DD07}.Release|Any CPU.ActiveCfg = Release|Any CPU + {4C6B120B-99B5-4888-B8D5-45031458DD07}.Release|Any CPU.Build.0 = Release|Any CPU + {93BEC5CC-BAFF-4389-89E7-84AAFF5D495D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {93BEC5CC-BAFF-4389-89E7-84AAFF5D495D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {93BEC5CC-BAFF-4389-89E7-84AAFF5D495D}.Release|Any CPU.ActiveCfg = Release|Any CPU + {93BEC5CC-BAFF-4389-89E7-84AAFF5D495D}.Release|Any CPU.Build.0 = Release|Any CPU + {8D67DD5A-D683-481F-915E-98683EA38791}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {8D67DD5A-D683-481F-915E-98683EA38791}.Debug|Any CPU.Build.0 = Debug|Any CPU + {8D67DD5A-D683-481F-915E-98683EA38791}.Release|Any CPU.ActiveCfg = Release|Any CPU + {8D67DD5A-D683-481F-915E-98683EA38791}.Release|Any CPU.Build.0 = Release|Any CPU + {A372F1D6-51FF-472C-9508-FDAF7E6FEB13}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {A372F1D6-51FF-472C-9508-FDAF7E6FEB13}.Debug|Any CPU.Build.0 = Debug|Any CPU + {A372F1D6-51FF-472C-9508-FDAF7E6FEB13}.Release|Any CPU.ActiveCfg = Release|Any CPU + {A372F1D6-51FF-472C-9508-FDAF7E6FEB13}.Release|Any CPU.Build.0 = Release|Any CPU + {D0153204-6AEF-4D94-B0E1-8124C38C91D4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D0153204-6AEF-4D94-B0E1-8124C38C91D4}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D0153204-6AEF-4D94-B0E1-8124C38C91D4}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D0153204-6AEF-4D94-B0E1-8124C38C91D4}.Release|Any CPU.Build.0 = Release|Any CPU + {73223FBD-C562-4FA0-9722-C7F1C382A9DE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {73223FBD-C562-4FA0-9722-C7F1C382A9DE}.Debug|Any CPU.Build.0 = Debug|Any CPU + {73223FBD-C562-4FA0-9722-C7F1C382A9DE}.Release|Any CPU.ActiveCfg = Release|Any CPU + {73223FBD-C562-4FA0-9722-C7F1C382A9DE}.Release|Any CPU.Build.0 = Release|Any CPU + {D541BCE9-65BC-475B-94E5-19B6BFFF2B8E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D541BCE9-65BC-475B-94E5-19B6BFFF2B8E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D541BCE9-65BC-475B-94E5-19B6BFFF2B8E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D541BCE9-65BC-475B-94E5-19B6BFFF2B8E}.Release|Any CPU.Build.0 = Release|Any CPU + {35A34EBD-F2BF-4D83-A096-D5F007B12732}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {35A34EBD-F2BF-4D83-A096-D5F007B12732}.Debug|Any CPU.Build.0 = Debug|Any CPU + {35A34EBD-F2BF-4D83-A096-D5F007B12732}.Release|Any CPU.ActiveCfg = Release|Any CPU + {35A34EBD-F2BF-4D83-A096-D5F007B12732}.Release|Any CPU.Build.0 = Release|Any CPU + {D6D53889-5A10-46A4-BA66-E78B56EC1881}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D6D53889-5A10-46A4-BA66-E78B56EC1881}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D6D53889-5A10-46A4-BA66-E78B56EC1881}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D6D53889-5A10-46A4-BA66-E78B56EC1881}.Release|Any CPU.Build.0 = Release|Any CPU + {648DCE6F-A0BA-4032-951B-20CF5BBFD998}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {648DCE6F-A0BA-4032-951B-20CF5BBFD998}.Debug|Any CPU.Build.0 = Debug|Any CPU + {648DCE6F-A0BA-4032-951B-20CF5BBFD998}.Release|Any CPU.ActiveCfg = Release|Any CPU + {648DCE6F-A0BA-4032-951B-20CF5BBFD998}.Release|Any CPU.Build.0 = Release|Any CPU + {B772B8A9-9362-4C6F-A6D3-2A4138439B2C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B772B8A9-9362-4C6F-A6D3-2A4138439B2C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B772B8A9-9362-4C6F-A6D3-2A4138439B2C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B772B8A9-9362-4C6F-A6D3-2A4138439B2C}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {C30B5859-D4B9-46E8-A797-6B0A1B49B590} = {79389FC0-C621-4CEA-AD2B-6074C32E7BCA} + {A2A3B687-A1EC-4221-B792-9BBA8DED09DA} = {79389FC0-C621-4CEA-AD2B-6074C32E7BCA} + {FC0CAF5A-30A7-4857-B1A4-486FAAA39E5A} = {79389FC0-C621-4CEA-AD2B-6074C32E7BCA} + {4C6B120B-99B5-4888-B8D5-45031458DD07} = {D5266066-0AFD-44D5-A83E-2F73668A63C8} + {93BEC5CC-BAFF-4389-89E7-84AAFF5D495D} = {D5266066-0AFD-44D5-A83E-2F73668A63C8} + {8D67DD5A-D683-481F-915E-98683EA38791} = {D5266066-0AFD-44D5-A83E-2F73668A63C8} + {A372F1D6-51FF-472C-9508-FDAF7E6FEB13} = {D5266066-0AFD-44D5-A83E-2F73668A63C8} + {D0153204-6AEF-4D94-B0E1-8124C38C91D4} = {D5266066-0AFD-44D5-A83E-2F73668A63C8} + {73223FBD-C562-4FA0-9722-C7F1C382A9DE} = {49D5873D-7B38-48A5-B853-85146F032091} + {D541BCE9-65BC-475B-94E5-19B6BFFF2B8E} = {49D5873D-7B38-48A5-B853-85146F032091} + {35A34EBD-F2BF-4D83-A096-D5F007B12732} = {49D5873D-7B38-48A5-B853-85146F032091} + {D6D53889-5A10-46A4-BA66-E78B56EC1881} = {49D5873D-7B38-48A5-B853-85146F032091} + {648DCE6F-A0BA-4032-951B-20CF5BBFD998} = {79389FC0-C621-4CEA-AD2B-6074C32E7BCA} + {B772B8A9-9362-4C6F-A6D3-2A4138439B2C} = {D5266066-0AFD-44D5-A83E-2F73668A63C8} + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {6DA935E1-C674-4364-B087-F1B511B79215} + EndGlobalSection +EndGlobal From 16fd895dc39dc8e5a0aa3c9cc70f5129ea862b2f Mon Sep 17 00:00:00 2001 From: Fernando Diaz Toledano Date: Sat, 10 Feb 2024 11:45:48 +0100 Subject: [PATCH 020/106] Escape name --- src/Neo.SmartContract.Testing/Artifacts.cs | 25 ++++- .../Native/ContractManagement.cs | 21 ++-- .../Native/CryptoLib.cs | 13 +-- .../Native/GasToken.cs | 25 +++++ .../Native/LedgerContract.cs | 22 +++++ .../Native/NeoToken.cs | 43 +++++++++ .../Native/OracleContract.cs | 27 ++++++ .../Native/PolicyContract.cs | 27 ++++++ .../Native/RoleManagement.cs | 22 +++++ .../Native/StdLib.cs | 35 +++++++ .../NativeArtifacts.cs | 96 +++++++++++++++++++ .../ArtifactsTests.cs | 13 ++- .../UtArtifacts/Contract1.cs | 1 + 13 files changed, 348 insertions(+), 22 deletions(-) create mode 100644 src/Neo.SmartContract.Testing/Native/GasToken.cs create mode 100644 src/Neo.SmartContract.Testing/Native/LedgerContract.cs create mode 100644 src/Neo.SmartContract.Testing/Native/NeoToken.cs create mode 100644 src/Neo.SmartContract.Testing/Native/OracleContract.cs create mode 100644 src/Neo.SmartContract.Testing/Native/PolicyContract.cs create mode 100644 src/Neo.SmartContract.Testing/Native/RoleManagement.cs create mode 100644 src/Neo.SmartContract.Testing/Native/StdLib.cs diff --git a/src/Neo.SmartContract.Testing/Artifacts.cs b/src/Neo.SmartContract.Testing/Artifacts.cs index 5d1792810..7b3420e83 100644 --- a/src/Neo.SmartContract.Testing/Artifacts.cs +++ b/src/Neo.SmartContract.Testing/Artifacts.cs @@ -1,4 +1,5 @@ using Neo.SmartContract.Manifest; +using System; using System.Linq; using System.Text; @@ -16,6 +17,7 @@ public static string CreateSourceFromManifest(string name, ContractAbi abi) { StringBuilder sourceCode = new(); + sourceCode.AppendLine("using Neo.Cryptography.ECC;"); sourceCode.AppendLine("using System.Collections.Generic;"); sourceCode.AppendLine("using System.Numerics;"); sourceCode.AppendLine(""); @@ -99,7 +101,7 @@ private static string CreateSourceEventFromManifest(ContractEventDescriptor ev) if (!isFirst) sourceCode.Append(", "); else isFirst = false; - sourceCode.Append($"{TypeToSource(arg.Type)} {arg.Name}"); + sourceCode.Append($"{TypeToSource(arg.Type)} {EscapeName(arg.Name)}"); } sourceCode.AppendLine(");"); @@ -125,7 +127,7 @@ private static string CreateSourceMethodFromManifest(ContractMethodDescriptor me if (!isFirst) sourceCode.Append(", "); else isFirst = false; - sourceCode.Append($"{TypeToSource(arg.Type)} {arg.Name}"); + sourceCode.Append($"{TypeToSource(arg.Type)} {EscapeName(arg.Name)}"); } sourceCode.AppendLine(");"); @@ -133,6 +135,25 @@ private static string CreateSourceMethodFromManifest(ContractMethodDescriptor me return sourceCode.ToString(); } + /// + /// Escape name + /// + /// Name + /// Escaped name + private static string EscapeName(string name) + { + return name switch + { + "base" => "@" + name, + "lock" => "@" + name, + "params" => "@" + name, + "struct" => "@" + name, + "class" => "@" + name, + + _ => name + }; + } + /// /// Type to source /// diff --git a/src/Neo.SmartContract.Testing/Native/ContractManagement.cs b/src/Neo.SmartContract.Testing/Native/ContractManagement.cs index dbd275183..ae1ed05e4 100644 --- a/src/Neo.SmartContract.Testing/Native/ContractManagement.cs +++ b/src/Neo.SmartContract.Testing/Native/ContractManagement.cs @@ -1,3 +1,4 @@ +using Neo.Cryptography.ECC; using System.Collections.Generic; using System.Numerics; @@ -5,30 +6,30 @@ namespace Neo.SmartContract.Testing; public abstract class ContractManagement : Neo.SmartContract.Testing.SmartContract { - #region Events +#region Events public delegate void delDeploy(UInt160 Hash); public event delDeploy? Deploy; public delegate void delDestroy(UInt160 Hash); public event delDestroy? Destroy; public delegate void delUpdate(UInt160 Hash); public event delUpdate? Update; - #endregion - #region Safe methods +#endregion +#region Safe methods public abstract List getContract(UInt160 hash); public abstract List getContractById(BigInteger id); public abstract object getContractHashes(); public abstract BigInteger getMinimumDeploymentFee(); public abstract bool hasMethod(UInt160 hash, string method, BigInteger pcount); - #endregion - #region Unsafe methods +#endregion +#region Unsafe methods public abstract List deploy(byte[] nefFile, byte[] manifest); public abstract List deploy(byte[] nefFile, byte[] manifest, object data); public abstract void destroy(); public abstract void setMinimumDeploymentFee(BigInteger value); public abstract void update(byte[] nefFile, byte[] manifest); public abstract void update(byte[] nefFile, byte[] manifest, object data); - #endregion - #region Constructor for internal use only - protected ContractManagement(Neo.SmartContract.Testing.TestEngine testEngine, Neo.UInt160 hash) : base(testEngine, hash) { } - #endregion -} +#endregion +#region Constructor for internal use only + protected ContractManagement(Neo.SmartContract.Testing.TestEngine testEngine, Neo.UInt160 hash) : base(testEngine, hash) {} +#endregion +} \ No newline at end of file diff --git a/src/Neo.SmartContract.Testing/Native/CryptoLib.cs b/src/Neo.SmartContract.Testing/Native/CryptoLib.cs index 6f31cd238..a774e6c7c 100644 --- a/src/Neo.SmartContract.Testing/Native/CryptoLib.cs +++ b/src/Neo.SmartContract.Testing/Native/CryptoLib.cs @@ -1,3 +1,4 @@ +using Neo.Cryptography.ECC; using System.Collections.Generic; using System.Numerics; @@ -5,7 +6,7 @@ namespace Neo.SmartContract.Testing; public abstract class CryptoLib : Neo.SmartContract.Testing.SmartContract { - #region Safe methods +#region Safe methods public abstract object bls12381Add(object x, object y); public abstract object bls12381Deserialize(byte[] data); public abstract bool bls12381Equal(object x, object y); @@ -16,8 +17,8 @@ public abstract class CryptoLib : Neo.SmartContract.Testing.SmartContract public abstract byte[] ripemd160(byte[] data); public abstract byte[] sha256(byte[] data); public abstract bool verifyWithECDsa(byte[] message, byte[] pubkey, byte[] signature, BigInteger curve); - #endregion - #region Constructor for internal use only - protected CryptoLib(Neo.SmartContract.Testing.TestEngine testEngine, Neo.UInt160 hash) : base(testEngine, hash) { } - #endregion -} +#endregion +#region Constructor for internal use only + protected CryptoLib(Neo.SmartContract.Testing.TestEngine testEngine, Neo.UInt160 hash) : base(testEngine, hash) {} +#endregion +} \ No newline at end of file diff --git a/src/Neo.SmartContract.Testing/Native/GasToken.cs b/src/Neo.SmartContract.Testing/Native/GasToken.cs new file mode 100644 index 000000000..d7a2806b8 --- /dev/null +++ b/src/Neo.SmartContract.Testing/Native/GasToken.cs @@ -0,0 +1,25 @@ +using Neo.Cryptography.ECC; +using System.Collections.Generic; +using System.Numerics; + +namespace Neo.SmartContract.Testing; + +public abstract class GasToken : Neo.SmartContract.Testing.SmartContract +{ +#region Events + public delegate void delTransfer(UInt160 from, UInt160 to, BigInteger amount); + public event delTransfer? Transfer; +#endregion +#region Safe methods + public abstract BigInteger balanceOf(UInt160 account); + public abstract BigInteger decimals(); + public abstract string symbol(); + public abstract BigInteger totalSupply(); +#endregion +#region Unsafe methods + public abstract bool transfer(UInt160 from, UInt160 to, BigInteger amount, object data); +#endregion +#region Constructor for internal use only + protected GasToken(Neo.SmartContract.Testing.TestEngine testEngine, Neo.UInt160 hash) : base(testEngine, hash) {} +#endregion +} \ No newline at end of file diff --git a/src/Neo.SmartContract.Testing/Native/LedgerContract.cs b/src/Neo.SmartContract.Testing/Native/LedgerContract.cs new file mode 100644 index 000000000..64df7d68a --- /dev/null +++ b/src/Neo.SmartContract.Testing/Native/LedgerContract.cs @@ -0,0 +1,22 @@ +using Neo.Cryptography.ECC; +using System.Collections.Generic; +using System.Numerics; + +namespace Neo.SmartContract.Testing; + +public abstract class LedgerContract : Neo.SmartContract.Testing.SmartContract +{ +#region Safe methods + public abstract UInt256 currentHash(); + public abstract BigInteger currentIndex(); + public abstract List getBlock(byte[] indexOrHash); + public abstract List getTransaction(UInt256 hash); + public abstract List getTransactionFromBlock(byte[] blockIndexOrHash, BigInteger txIndex); + public abstract BigInteger getTransactionHeight(UInt256 hash); + public abstract List getTransactionSigners(UInt256 hash); + public abstract BigInteger getTransactionVMState(UInt256 hash); +#endregion +#region Constructor for internal use only + protected LedgerContract(Neo.SmartContract.Testing.TestEngine testEngine, Neo.UInt160 hash) : base(testEngine, hash) {} +#endregion +} \ No newline at end of file diff --git a/src/Neo.SmartContract.Testing/Native/NeoToken.cs b/src/Neo.SmartContract.Testing/Native/NeoToken.cs new file mode 100644 index 000000000..b4a2ae798 --- /dev/null +++ b/src/Neo.SmartContract.Testing/Native/NeoToken.cs @@ -0,0 +1,43 @@ +using Neo.Cryptography.ECC; +using System.Collections.Generic; +using System.Numerics; + +namespace Neo.SmartContract.Testing; + +public abstract class NeoToken : Neo.SmartContract.Testing.SmartContract +{ +#region Events + public delegate void delCandidateStateChanged(ECPoint pubkey, bool registered, BigInteger votes); + public event delCandidateStateChanged? CandidateStateChanged; + public delegate void delTransfer(UInt160 from, UInt160 to, BigInteger amount); + public event delTransfer? Transfer; + public delegate void delVote(UInt160 account, ECPoint from, ECPoint to, BigInteger amount); + public event delVote? Vote; +#endregion +#region Safe methods + public abstract BigInteger balanceOf(UInt160 account); + public abstract BigInteger decimals(); + public abstract List getAccountState(UInt160 account); + public abstract object getAllCandidates(); + public abstract List getCandidates(); + public abstract BigInteger getCandidateVote(ECPoint pubKey); + public abstract List getCommittee(); + public abstract BigInteger getGasPerBlock(); + public abstract List getNextBlockValidators(); + public abstract BigInteger getRegisterPrice(); + public abstract string symbol(); + public abstract BigInteger totalSupply(); + public abstract BigInteger unclaimedGas(UInt160 account, BigInteger end); +#endregion +#region Unsafe methods + public abstract bool registerCandidate(ECPoint pubkey); + public abstract void setGasPerBlock(BigInteger gasPerBlock); + public abstract void setRegisterPrice(BigInteger registerPrice); + public abstract bool transfer(UInt160 from, UInt160 to, BigInteger amount, object data); + public abstract bool unregisterCandidate(ECPoint pubkey); + public abstract bool vote(UInt160 account, ECPoint voteTo); +#endregion +#region Constructor for internal use only + protected NeoToken(Neo.SmartContract.Testing.TestEngine testEngine, Neo.UInt160 hash) : base(testEngine, hash) {} +#endregion +} \ No newline at end of file diff --git a/src/Neo.SmartContract.Testing/Native/OracleContract.cs b/src/Neo.SmartContract.Testing/Native/OracleContract.cs new file mode 100644 index 000000000..c3762536e --- /dev/null +++ b/src/Neo.SmartContract.Testing/Native/OracleContract.cs @@ -0,0 +1,27 @@ +using Neo.Cryptography.ECC; +using System.Collections.Generic; +using System.Numerics; + +namespace Neo.SmartContract.Testing; + +public abstract class OracleContract : Neo.SmartContract.Testing.SmartContract +{ +#region Events + public delegate void delOracleRequest(BigInteger Id, UInt160 RequestContract, string Url, string Filter); + public event delOracleRequest? OracleRequest; + public delegate void delOracleResponse(BigInteger Id, UInt256 OriginalTx); + public event delOracleResponse? OracleResponse; +#endregion +#region Safe methods + public abstract BigInteger getPrice(); + public abstract bool verify(); +#endregion +#region Unsafe methods + public abstract void finish(); + public abstract void request(string url, string filter, string callback, object userData, BigInteger gasForResponse); + public abstract void setPrice(BigInteger price); +#endregion +#region Constructor for internal use only + protected OracleContract(Neo.SmartContract.Testing.TestEngine testEngine, Neo.UInt160 hash) : base(testEngine, hash) {} +#endregion +} \ No newline at end of file diff --git a/src/Neo.SmartContract.Testing/Native/PolicyContract.cs b/src/Neo.SmartContract.Testing/Native/PolicyContract.cs new file mode 100644 index 000000000..505628e58 --- /dev/null +++ b/src/Neo.SmartContract.Testing/Native/PolicyContract.cs @@ -0,0 +1,27 @@ +using Neo.Cryptography.ECC; +using System.Collections.Generic; +using System.Numerics; + +namespace Neo.SmartContract.Testing; + +public abstract class PolicyContract : Neo.SmartContract.Testing.SmartContract +{ +#region Safe methods + public abstract BigInteger getAttributeFee(BigInteger attributeType); + public abstract BigInteger getExecFeeFactor(); + public abstract BigInteger getFeePerByte(); + public abstract BigInteger getStoragePrice(); + public abstract bool isBlocked(UInt160 account); +#endregion +#region Unsafe methods + public abstract bool blockAccount(UInt160 account); + public abstract void setAttributeFee(BigInteger attributeType, BigInteger value); + public abstract void setExecFeeFactor(BigInteger value); + public abstract void setFeePerByte(BigInteger value); + public abstract void setStoragePrice(BigInteger value); + public abstract bool unblockAccount(UInt160 account); +#endregion +#region Constructor for internal use only + protected PolicyContract(Neo.SmartContract.Testing.TestEngine testEngine, Neo.UInt160 hash) : base(testEngine, hash) {} +#endregion +} \ No newline at end of file diff --git a/src/Neo.SmartContract.Testing/Native/RoleManagement.cs b/src/Neo.SmartContract.Testing/Native/RoleManagement.cs new file mode 100644 index 000000000..b0fedb43a --- /dev/null +++ b/src/Neo.SmartContract.Testing/Native/RoleManagement.cs @@ -0,0 +1,22 @@ +using Neo.Cryptography.ECC; +using System.Collections.Generic; +using System.Numerics; + +namespace Neo.SmartContract.Testing; + +public abstract class RoleManagement : Neo.SmartContract.Testing.SmartContract +{ +#region Events + public delegate void delDesignation(BigInteger Role, BigInteger BlockIndex); + public event delDesignation? Designation; +#endregion +#region Safe methods + public abstract List getDesignatedByRole(BigInteger role, BigInteger index); +#endregion +#region Unsafe methods + public abstract void designateAsRole(BigInteger role, List nodes); +#endregion +#region Constructor for internal use only + protected RoleManagement(Neo.SmartContract.Testing.TestEngine testEngine, Neo.UInt160 hash) : base(testEngine, hash) {} +#endregion +} \ No newline at end of file diff --git a/src/Neo.SmartContract.Testing/Native/StdLib.cs b/src/Neo.SmartContract.Testing/Native/StdLib.cs new file mode 100644 index 000000000..73db2b1f9 --- /dev/null +++ b/src/Neo.SmartContract.Testing/Native/StdLib.cs @@ -0,0 +1,35 @@ +using Neo.Cryptography.ECC; +using System.Collections.Generic; +using System.Numerics; + +namespace Neo.SmartContract.Testing; + +public abstract class StdLib : Neo.SmartContract.Testing.SmartContract +{ +#region Safe methods + public abstract BigInteger atoi(string value); + public abstract BigInteger atoi(string value, BigInteger @base); + public abstract byte[] base58CheckDecode(string s); + public abstract string base58CheckEncode(byte[] data); + public abstract byte[] base58Decode(string s); + public abstract string base58Encode(byte[] data); + public abstract byte[] base64Decode(string s); + public abstract string base64Encode(byte[] data); + public abstract object deserialize(byte[] data); + public abstract string itoa(BigInteger value); + public abstract string itoa(BigInteger value, BigInteger @base); + public abstract object jsonDeserialize(byte[] json); + public abstract byte[] jsonSerialize(object item); + public abstract BigInteger memoryCompare(byte[] str1, byte[] str2); + public abstract BigInteger memorySearch(byte[] mem, byte[] value); + public abstract BigInteger memorySearch(byte[] mem, byte[] value, BigInteger start); + public abstract BigInteger memorySearch(byte[] mem, byte[] value, BigInteger start, bool backward); + public abstract byte[] serialize(object item); + public abstract List stringSplit(string str, string separator); + public abstract List stringSplit(string str, string separator, bool removeEmptyEntries); + public abstract BigInteger strLen(string str); +#endregion +#region Constructor for internal use only + protected StdLib(Neo.SmartContract.Testing.TestEngine testEngine, Neo.UInt160 hash) : base(testEngine, hash) {} +#endregion +} \ No newline at end of file diff --git a/src/Neo.SmartContract.Testing/NativeArtifacts.cs b/src/Neo.SmartContract.Testing/NativeArtifacts.cs index 7b90d84f2..66c31c0e0 100644 --- a/src/Neo.SmartContract.Testing/NativeArtifacts.cs +++ b/src/Neo.SmartContract.Testing/NativeArtifacts.cs @@ -3,8 +3,20 @@ namespace Neo.SmartContract.Testing public class NativeArtifacts { private readonly TestEngine _engine; + + #region Native contracts + private ContractManagement? _contractManagement; private CryptoLib? _cryptoLib; + private GasToken? _gas; + private NeoToken? _neo; + private LedgerContract? _ledger; + private OracleContract? _oracle; + private PolicyContract? _policy; + private RoleManagement? _roleManagement; + private StdLib? _stdLib; + + #endregion /// /// ContractManagement @@ -30,6 +42,90 @@ public CryptoLib CryptoLib } } + /// + /// GasToken + /// + public GasToken GAS + { + get + { + _gas ??= _engine.FromHash(Native.NativeContract.GAS.Hash); + return _gas; + } + } + + /// + /// NeoToken + /// + public NeoToken NEO + { + get + { + _neo ??= _engine.FromHash(Native.NativeContract.NEO.Hash); + return _neo; + } + } + + /// + /// LedgerContract + /// + public LedgerContract Ledger + { + get + { + _ledger ??= _engine.FromHash(Native.NativeContract.Ledger.Hash); + return _ledger; + } + } + + /// + /// OracleContract + /// + public OracleContract Oracle + { + get + { + _oracle ??= _engine.FromHash(Native.NativeContract.Oracle.Hash); + return _oracle; + } + } + + /// + /// PolicyContract + /// + public PolicyContract Policy + { + get + { + _policy ??= _engine.FromHash(Native.NativeContract.Policy.Hash); + return _policy; + } + } + + /// + /// RoleManagement + /// + public RoleManagement RoleManagement + { + get + { + _roleManagement ??= _engine.FromHash(Native.NativeContract.RoleManagement.Hash); + return _roleManagement; + } + } + + /// + /// OracleContract + /// + public StdLib StdLib + { + get + { + _stdLib ??= _engine.FromHash(Native.NativeContract.StdLib.Hash); + return _stdLib; + } + } + /// /// Constructor /// diff --git a/tests/Neo.SmartContract.Testing.UnitTests/ArtifactsTests.cs b/tests/Neo.SmartContract.Testing.UnitTests/ArtifactsTests.cs index 5c2100004..8383d89dd 100644 --- a/tests/Neo.SmartContract.Testing.UnitTests/ArtifactsTests.cs +++ b/tests/Neo.SmartContract.Testing.UnitTests/ArtifactsTests.cs @@ -1,6 +1,7 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; using Neo.Json; using Neo.SmartContract.Manifest; +using System.IO; namespace Neo.SmartContract.Testing.UnitTests { @@ -10,11 +11,14 @@ public class ArtifactsTests [TestMethod] public void GenerateNativeArtifacts() { - var manifest = Native.NativeContract.ContractManagement.Manifest; - var contractManagement = Artifacts.CreateSourceFromManifest(manifest.Name, manifest.Abi).Replace("\r\n", "\n").Trim(); + foreach (var n in Native.NativeContract.Contracts) + { + var manifest = n.Manifest; + var source = Artifacts.CreateSourceFromManifest(manifest.Name, manifest.Abi).Replace("\r\n", "\n").Trim(); + var fullPath = Path.GetFullPath($"../../../../../src/Neo.SmartContract.Testing/Native/{manifest.Name}.cs"); - manifest = Native.NativeContract.CryptoLib.Manifest; - var cryptoLib = Artifacts.CreateSourceFromManifest(manifest.Name, manifest.Abi).Replace("\r\n", "\n").Trim(); + File.WriteAllText(fullPath, source); + } } public void TestNativeContracts() @@ -34,6 +38,7 @@ public void TestCreateSourceFromManifest() var source = Artifacts.CreateSourceFromManifest(manifest.Name, manifest.Abi).Replace("\r\n", "\n").Trim(); Assert.AreEqual(source, @" +using Neo.Cryptography.ECC; using System.Collections.Generic; using System.Numerics; diff --git a/tests/Neo.SmartContract.Testing.UnitTests/UtArtifacts/Contract1.cs b/tests/Neo.SmartContract.Testing.UnitTests/UtArtifacts/Contract1.cs index 70d6a0a71..0ed0458db 100644 --- a/tests/Neo.SmartContract.Testing.UnitTests/UtArtifacts/Contract1.cs +++ b/tests/Neo.SmartContract.Testing.UnitTests/UtArtifacts/Contract1.cs @@ -1,3 +1,4 @@ +using Neo.Cryptography.ECC; using System.Numerics; namespace Neo.SmartContract.Testing; From 5ab3cd49296786155235647541d0c99365fa54c1 Mon Sep 17 00:00:00 2001 From: Fernando Diaz Toledano Date: Sat, 10 Feb 2024 11:46:08 +0100 Subject: [PATCH 021/106] Avoid generation native artifacts --- tests/Neo.SmartContract.Testing.UnitTests/ArtifactsTests.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Neo.SmartContract.Testing.UnitTests/ArtifactsTests.cs b/tests/Neo.SmartContract.Testing.UnitTests/ArtifactsTests.cs index 8383d89dd..73433a12e 100644 --- a/tests/Neo.SmartContract.Testing.UnitTests/ArtifactsTests.cs +++ b/tests/Neo.SmartContract.Testing.UnitTests/ArtifactsTests.cs @@ -8,7 +8,7 @@ namespace Neo.SmartContract.Testing.UnitTests [TestClass] public class ArtifactsTests { - [TestMethod] + //[TestMethod] public void GenerateNativeArtifacts() { foreach (var n in Native.NativeContract.Contracts) From 2ecd121f92ee44c64906f217b61f9b18b11276e2 Mon Sep 17 00:00:00 2001 From: Fernando Diaz Toledano Date: Sat, 10 Feb 2024 11:52:45 +0100 Subject: [PATCH 022/106] TestNativeContracts --- .../ArtifactsTests.cs | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/tests/Neo.SmartContract.Testing.UnitTests/ArtifactsTests.cs b/tests/Neo.SmartContract.Testing.UnitTests/ArtifactsTests.cs index 73433a12e..5e5a5e650 100644 --- a/tests/Neo.SmartContract.Testing.UnitTests/ArtifactsTests.cs +++ b/tests/Neo.SmartContract.Testing.UnitTests/ArtifactsTests.cs @@ -21,10 +21,19 @@ public void GenerateNativeArtifacts() } } + [TestMethod] public void TestNativeContracts() { TestEngine engine = new(); - Assert.Equals(engine.Native.ContractManagement.Hash, Native.NativeContract.ContractManagement.Hash); + + Assert.AreEqual(engine.Native.ContractManagement.Hash, Native.NativeContract.ContractManagement.Hash); + Assert.AreEqual(engine.Native.StdLib.Hash, Native.NativeContract.StdLib.Hash); + Assert.AreEqual(engine.Native.CryptoLib.Hash, Native.NativeContract.CryptoLib.Hash); + Assert.AreEqual(engine.Native.GAS.Hash, Native.NativeContract.GAS.Hash); + Assert.AreEqual(engine.Native.NEO.Hash, Native.NativeContract.NEO.Hash); + Assert.AreEqual(engine.Native.Oracle.Hash, Native.NativeContract.Oracle.Hash); + Assert.AreEqual(engine.Native.Policy.Hash, Native.NativeContract.Policy.Hash); + Assert.AreEqual(engine.Native.RoleManagement.Hash, Native.NativeContract.RoleManagement.Hash); } [TestMethod] From 45c3e298b949d6e367a4f131469d5e857b8c0a3f Mon Sep 17 00:00:00 2001 From: Fernando Diaz Toledano Date: Sat, 10 Feb 2024 12:27:35 +0100 Subject: [PATCH 023/106] Redirect Logs and Notifications to the mocked smart contract --- .../SmartContract.cs | 52 +++++++++++++ src/Neo.SmartContract.Testing/TestEngine.cs | 58 ++++++++++++++- .../TestExtensions.cs | 40 ++++++++++ .../ArtifactsTests.cs | 40 ---------- .../TestEngineTests.cs | 73 +++++++++++++++++++ 5 files changed, 222 insertions(+), 41 deletions(-) create mode 100644 src/Neo.SmartContract.Testing/TestExtensions.cs create mode 100644 tests/Neo.SmartContract.Testing.UnitTests/TestEngineTests.cs diff --git a/src/Neo.SmartContract.Testing/SmartContract.cs b/src/Neo.SmartContract.Testing/SmartContract.cs index 1821f893d..facdf29c9 100644 --- a/src/Neo.SmartContract.Testing/SmartContract.cs +++ b/src/Neo.SmartContract.Testing/SmartContract.cs @@ -1,9 +1,15 @@ +using System; +using System.Reflection; + namespace Neo.SmartContract.Testing { public class SmartContract { private readonly TestEngine _engine; + public delegate void delOnLog(string message); + public event delOnLog? OnLog; + /// /// Contract hash /// @@ -19,5 +25,51 @@ protected SmartContract(TestEngine testEngine, UInt160 hash) _engine = testEngine; Hash = hash; } + + /// + /// OnLog + /// + /// Message + internal void InvokeOnLog(string message) + { + OnLog?.Invoke(message); + } + + /// + /// Invoke on notify + /// + /// Event name + /// State + internal void InvokeOnNotify(string eventName, VM.Types.Array state) + { + var type = GetType(); + var ev = GetType().GetEvent(eventName); + if (ev is null) return; + + var evField = type.GetField(eventName, BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public | BindingFlags.Static); + if (evField is null) return; + + var evDel = evField.GetValue(this) as Delegate; + if (evDel is null) return; + + // Invoke + + evDel.DynamicInvoke(Convert(state, evDel.Method.GetParameters())); + } + + private object?[]? Convert(VM.Types.Array state, ParameterInfo[] parameterInfos) + { + if (parameterInfos.Length > 0) + { + object?[] args = new object[parameterInfos.Length]; + + for (int x = 0; x < parameterInfos.Length; x++) + { + args[x] = state[0].ConvertTo(parameterInfos[x].ParameterType); + } + } + + return null; + } } } diff --git a/src/Neo.SmartContract.Testing/TestEngine.cs b/src/Neo.SmartContract.Testing/TestEngine.cs index dd2d576d8..beb511f2e 100644 --- a/src/Neo.SmartContract.Testing/TestEngine.cs +++ b/src/Neo.SmartContract.Testing/TestEngine.cs @@ -1,12 +1,17 @@ using Moq; using Neo.Cryptography.ECC; +using Neo.Network.P2P.Payloads; using Neo.Persistence; using Neo.SmartContract.Manifest; +using Neo.VM.Types; +using System.Collections.Generic; namespace Neo.SmartContract.Testing { public class TestEngine { + private readonly Dictionary> _contracts = new(); + /// /// Default Protocol Settings /// @@ -86,6 +91,47 @@ public NativeArtifacts Native } } + /// + /// Constructor + /// + public TestEngine() + { + ApplicationEngine.Log += ApplicationEngine_Log; + ApplicationEngine.Notify += ApplicationEngine_Notify; + } + + #region Invoke events + + private void ApplicationEngine_Notify(object? sender, NotifyEventArgs e) + { + if (_contracts.TryGetValue(e.ScriptHash, out var contracts)) + { + foreach (var contract in contracts) + { + contract.InvokeOnNotify(e.EventName, e.State); + } + } + } + + private void ApplicationEngine_Log(object? sender, LogEventArgs e) + { + if (_contracts.TryGetValue(e.ScriptHash, out var contracts)) + { + foreach (var contract in contracts) + { + contract.InvokeOnLog(e.Message); + } + } + } + + public void Log(UInt160 scriptHash, string message) => + ApplicationEngine_Log(null, new LogEventArgs(null, scriptHash, message)); + + public void Notify(UInt160 scriptHash, string eventName, Array state) => + ApplicationEngine_Notify(null, new NotifyEventArgs(null, scriptHash, eventName, state)); + + #endregion + /// /// Deploy Smart contract /// @@ -127,8 +173,18 @@ private T MockContract(UInt160 hash) where T : SmartContract CallBase = true }; - // return mocked sc + // Cache sc + if (_contracts.TryGetValue(hash, out var result)) + { + result.Add(mock.Object); + } + else + { + _contracts[hash] = new List(new SmartContract[] { mock.Object }); + } + + // return mocked sc return mock.Object; } } diff --git a/src/Neo.SmartContract.Testing/TestExtensions.cs b/src/Neo.SmartContract.Testing/TestExtensions.cs new file mode 100644 index 000000000..312b51aa8 --- /dev/null +++ b/src/Neo.SmartContract.Testing/TestExtensions.cs @@ -0,0 +1,40 @@ +using Neo.VM.Types; +using System; +using System.Numerics; + +namespace Neo.SmartContract.Testing +{ + public static class TestExtensions + { + /// + /// Convert stack item to dotnet + /// + /// Item + /// Type + /// + public static object? ConvertTo(this StackItem stackItem, Type type) + { + if (stackItem is null) return null; + + if (type == typeof(string)) return stackItem.ToString(); + if (type == typeof(byte[])) return stackItem.GetSpan().ToArray(); + + if (type == typeof(byte) || type == typeof(sbyte) || + type == typeof(short) || type == typeof(ushort) || + type == typeof(int) || type == typeof(uint) || + type == typeof(long) || type == typeof(ulong) || + type == typeof(BigInteger) + ) + { + return stackItem.GetInteger(); + } + + if (type == typeof(UInt160)) return new UInt160(stackItem.GetSpan().ToArray()); + if (type == typeof(UInt256)) return new UInt256(stackItem.GetSpan().ToArray()); + if (type == typeof(Cryptography.ECC.ECPoint)) + return Cryptography.ECC.ECPoint.FromBytes(stackItem.GetSpan().ToArray(), Cryptography.ECC.ECCurve.Secp256r1); + + return null; + } + } +} diff --git a/tests/Neo.SmartContract.Testing.UnitTests/ArtifactsTests.cs b/tests/Neo.SmartContract.Testing.UnitTests/ArtifactsTests.cs index 5e5a5e650..b2d7724fc 100644 --- a/tests/Neo.SmartContract.Testing.UnitTests/ArtifactsTests.cs +++ b/tests/Neo.SmartContract.Testing.UnitTests/ArtifactsTests.cs @@ -1,41 +1,12 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; using Neo.Json; using Neo.SmartContract.Manifest; -using System.IO; namespace Neo.SmartContract.Testing.UnitTests { [TestClass] public class ArtifactsTests { - //[TestMethod] - public void GenerateNativeArtifacts() - { - foreach (var n in Native.NativeContract.Contracts) - { - var manifest = n.Manifest; - var source = Artifacts.CreateSourceFromManifest(manifest.Name, manifest.Abi).Replace("\r\n", "\n").Trim(); - var fullPath = Path.GetFullPath($"../../../../../src/Neo.SmartContract.Testing/Native/{manifest.Name}.cs"); - - File.WriteAllText(fullPath, source); - } - } - - [TestMethod] - public void TestNativeContracts() - { - TestEngine engine = new(); - - Assert.AreEqual(engine.Native.ContractManagement.Hash, Native.NativeContract.ContractManagement.Hash); - Assert.AreEqual(engine.Native.StdLib.Hash, Native.NativeContract.StdLib.Hash); - Assert.AreEqual(engine.Native.CryptoLib.Hash, Native.NativeContract.CryptoLib.Hash); - Assert.AreEqual(engine.Native.GAS.Hash, Native.NativeContract.GAS.Hash); - Assert.AreEqual(engine.Native.NEO.Hash, Native.NativeContract.NEO.Hash); - Assert.AreEqual(engine.Native.Oracle.Hash, Native.NativeContract.Oracle.Hash); - Assert.AreEqual(engine.Native.Policy.Hash, Native.NativeContract.Policy.Hash); - Assert.AreEqual(engine.Native.RoleManagement.Hash, Native.NativeContract.RoleManagement.Hash); - } - [TestMethod] public void TestCreateSourceFromManifest() { @@ -85,16 +56,5 @@ protected Contract1(Neo.SmartContract.Testing.TestEngine testEngine, Neo.UInt160 } ".Replace("\r\n", "\n").Trim()); } - - [TestMethod] - public void FromHashTest() - { - UInt160 hash = UInt160.Parse("0x1230000000000000000000000000000000000000"); - TestEngine engine = new(); - - var contract = engine.FromHash(hash); - - Assert.AreEqual(contract.Hash, hash); - } } } diff --git a/tests/Neo.SmartContract.Testing.UnitTests/TestEngineTests.cs b/tests/Neo.SmartContract.Testing.UnitTests/TestEngineTests.cs new file mode 100644 index 000000000..1852cf90b --- /dev/null +++ b/tests/Neo.SmartContract.Testing.UnitTests/TestEngineTests.cs @@ -0,0 +1,73 @@ +using Microsoft.VisualStudio.TestTools.UnitTesting; +using System.IO; + +namespace Neo.SmartContract.Testing.UnitTests +{ + [TestClass] + public class TestEngineTests + { + //[TestMethod] + public void GenerateNativeArtifacts() + { + foreach (var n in Native.NativeContract.Contracts) + { + var manifest = n.Manifest; + var source = Artifacts.CreateSourceFromManifest(manifest.Name, manifest.Abi).Replace("\r\n", "\n").Trim(); + var fullPath = Path.GetFullPath($"../../../../../src/Neo.SmartContract.Testing/Native/{manifest.Name}.cs"); + + File.WriteAllText(fullPath, source); + } + } + + [TestMethod] + public void TestNativeContracts() + { + TestEngine engine = new(); + + Assert.AreEqual(engine.Native.ContractManagement.Hash, Native.NativeContract.ContractManagement.Hash); + Assert.AreEqual(engine.Native.StdLib.Hash, Native.NativeContract.StdLib.Hash); + Assert.AreEqual(engine.Native.CryptoLib.Hash, Native.NativeContract.CryptoLib.Hash); + Assert.AreEqual(engine.Native.GAS.Hash, Native.NativeContract.GAS.Hash); + Assert.AreEqual(engine.Native.NEO.Hash, Native.NativeContract.NEO.Hash); + Assert.AreEqual(engine.Native.Oracle.Hash, Native.NativeContract.Oracle.Hash); + Assert.AreEqual(engine.Native.Policy.Hash, Native.NativeContract.Policy.Hash); + Assert.AreEqual(engine.Native.RoleManagement.Hash, Native.NativeContract.RoleManagement.Hash); + } + + [TestMethod] + public void FromHashTest() + { + UInt160 hash = UInt160.Parse("0x1230000000000000000000000000000000000000"); + TestEngine engine = new(); + + var contract = engine.FromHash(hash); + + Assert.AreEqual(contract.Hash, hash); + } + + [TestMethod] + public void TestLog() + { + UInt160 hash = UInt160.Parse("0x1230000000000000000000000000000000000000"); + TestEngine engine = new(); + + var contractLog = false; + var contract = engine.FromHash(hash); + contract.OnLog += (msg) => + { + contractLog = true; + }; + + var neoLog = false; + engine.Native.NEO.OnLog += (msg) => + { + neoLog = true; + }; + + engine.Log(contract.Hash, "test"); + + Assert.IsTrue(contractLog); + Assert.IsFalse(neoLog); + } + } +} From e0795d76aae50707bcbba42129740f3b9f309a52 Mon Sep 17 00:00:00 2001 From: Fernando Diaz Toledano Date: Sat, 10 Feb 2024 12:50:57 +0100 Subject: [PATCH 024/106] Mock notifications --- .../SmartContract.cs | 21 ++++++++----- .../TestExtensions.cs | 1 + .../TestEngineTests.cs | 30 +++++++++++++++++++ 3 files changed, 45 insertions(+), 7 deletions(-) diff --git a/src/Neo.SmartContract.Testing/SmartContract.cs b/src/Neo.SmartContract.Testing/SmartContract.cs index facdf29c9..80739f94a 100644 --- a/src/Neo.SmartContract.Testing/SmartContract.cs +++ b/src/Neo.SmartContract.Testing/SmartContract.cs @@ -42,19 +42,24 @@ internal void InvokeOnLog(string message) /// State internal void InvokeOnNotify(string eventName, VM.Types.Array state) { - var type = GetType(); - var ev = GetType().GetEvent(eventName); + var type = GetType().BaseType ?? GetType(); // Mock + var ev = type.GetEvent(eventName); if (ev is null) return; - var evField = type.GetField(eventName, BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public | BindingFlags.Static); + var evField = type.GetField(ev.Name, BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.GetField); if (evField is null) return; - var evDel = evField.GetValue(this) as Delegate; - if (evDel is null) return; + var del = evField.GetValue(this) as Delegate; + if (del is null) return; // Invoke - evDel.DynamicInvoke(Convert(state, evDel.Method.GetParameters())); + var args = Convert(state, del.Method.GetParameters()); + + foreach (var handler in del.GetInvocationList()) + { + handler.Method.Invoke(handler.Target, args); + } } private object?[]? Convert(VM.Types.Array state, ParameterInfo[] parameterInfos) @@ -65,8 +70,10 @@ internal void InvokeOnNotify(string eventName, VM.Types.Array state) for (int x = 0; x < parameterInfos.Length; x++) { - args[x] = state[0].ConvertTo(parameterInfos[x].ParameterType); + args[x] = state[x].ConvertTo(parameterInfos[x].ParameterType); } + + return args; } return null; diff --git a/src/Neo.SmartContract.Testing/TestExtensions.cs b/src/Neo.SmartContract.Testing/TestExtensions.cs index 312b51aa8..bc2b61baf 100644 --- a/src/Neo.SmartContract.Testing/TestExtensions.cs +++ b/src/Neo.SmartContract.Testing/TestExtensions.cs @@ -16,6 +16,7 @@ public static class TestExtensions { if (stackItem is null) return null; + if (type == typeof(bool)) return stackItem.GetBoolean(); if (type == typeof(string)) return stackItem.ToString(); if (type == typeof(byte[])) return stackItem.GetSpan().ToArray(); diff --git a/tests/Neo.SmartContract.Testing.UnitTests/TestEngineTests.cs b/tests/Neo.SmartContract.Testing.UnitTests/TestEngineTests.cs index 1852cf90b..9d3922c11 100644 --- a/tests/Neo.SmartContract.Testing.UnitTests/TestEngineTests.cs +++ b/tests/Neo.SmartContract.Testing.UnitTests/TestEngineTests.cs @@ -1,5 +1,8 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; +using Neo.IO; +using Neo.VM.Types; using System.IO; +using System.Linq; namespace Neo.SmartContract.Testing.UnitTests { @@ -69,5 +72,32 @@ public void TestLog() Assert.IsTrue(contractLog); Assert.IsFalse(neoLog); } + + [TestMethod] + public void TestNotification() + { + UInt160 hash = UInt160.Parse("0x1230000000000000000000000000000000000000"); + TestEngine engine = new(); + + var neoLog = false; + engine.Native.NEO.CandidateStateChanged += (pubKey, registered, votes) => + { + neoLog = pubKey == engine.ProtocolSettings.StandbyCommittee.First() && votes == 123 && registered; + }; + + // public delegate void delCandidateStateChanged(ECPoint pubkey, bool registered, BigInteger votes); + // public event delCandidateStateChanged? CandidateStateChanged; + + engine.Notify(engine.Native.NEO.Hash, "CandidateStateChanged", + new Array(new StackItem[] + { + new ByteString(engine.ProtocolSettings.StandbyCommittee.First().ToArray()), + StackItem.True, + new Integer(123), + } + )); + + Assert.IsTrue(neoLog); + } } } From 346c41241c88cb71fac81d043f1fab97826c3486 Mon Sep 17 00:00:00 2001 From: Fernando Diaz Toledano Date: Sat, 10 Feb 2024 13:20:58 +0100 Subject: [PATCH 025/106] Converts --- .../NativeArtifacts.cs | 8 +++ .../Neo.SmartContract.Testing.csproj | 4 +- src/Neo.SmartContract.Testing/TestEngine.cs | 16 +++-- .../TestExtensions.cs | 60 ++++++++++++++++++- .../TestEngineTests.cs | 1 - 5 files changed, 80 insertions(+), 9 deletions(-) diff --git a/src/Neo.SmartContract.Testing/NativeArtifacts.cs b/src/Neo.SmartContract.Testing/NativeArtifacts.cs index 66c31c0e0..efbb5bff4 100644 --- a/src/Neo.SmartContract.Testing/NativeArtifacts.cs +++ b/src/Neo.SmartContract.Testing/NativeArtifacts.cs @@ -134,5 +134,13 @@ public NativeArtifacts(TestEngine engine) { _engine = engine; } + + /// + /// Initialize native contracts + /// + public void Initialize() + { + // TODO: Initialize them + } } } diff --git a/src/Neo.SmartContract.Testing/Neo.SmartContract.Testing.csproj b/src/Neo.SmartContract.Testing/Neo.SmartContract.Testing.csproj index 8e782e03a..33e7bcd3c 100644 --- a/src/Neo.SmartContract.Testing/Neo.SmartContract.Testing.csproj +++ b/src/Neo.SmartContract.Testing/Neo.SmartContract.Testing.csproj @@ -1,8 +1,8 @@ - Neo.SmartContract.TestEngine - Neo.SmartContract.TestEngine + Neo.SmartContract.Testing + Neo.SmartContract.Testing NEO;Blockchain;Smart Contract TestEngine for NEO smart contract testing. true diff --git a/src/Neo.SmartContract.Testing/TestEngine.cs b/src/Neo.SmartContract.Testing/TestEngine.cs index beb511f2e..2a30d2e0e 100644 --- a/src/Neo.SmartContract.Testing/TestEngine.cs +++ b/src/Neo.SmartContract.Testing/TestEngine.cs @@ -1,10 +1,12 @@ using Moq; using Neo.Cryptography.ECC; -using Neo.Network.P2P.Payloads; +using Neo.IO; using Neo.Persistence; using Neo.SmartContract.Manifest; using Neo.VM.Types; using System.Collections.Generic; +using System.Linq; +using System.Text; namespace Neo.SmartContract.Testing { @@ -142,13 +144,19 @@ public void Notify(UInt160 scriptHash, string eventName, Array state) => /// Mocked Smart Contract public T Deploy(NefFile nef, ContractManifest manifest, object data) where T : SmartContract { - // Deploy and get the hash + // Deploy - UInt160 hash = Helper.GetContractHash(Sender, nef.CheckSum, manifest.Name); + var ret = Native.ContractManagement.deploy(nef.ToArray(), Encoding.UTF8.GetBytes(manifest.ToJson().ToString(false)), data.ConvertToStackItem()); + + // Parse return + + ContractState state = new(); + ((IInteroperable)state).FromStackItem(new Array(ret.Select(u => (StackItem)u))); // Mock contract - return MockContract(hash); + //UInt160 hash = Helper.GetContractHash(Sender, nef.CheckSum, manifest.Name); + return MockContract(state.Hash); } /// diff --git a/src/Neo.SmartContract.Testing/TestExtensions.cs b/src/Neo.SmartContract.Testing/TestExtensions.cs index bc2b61baf..3683ad7d5 100644 --- a/src/Neo.SmartContract.Testing/TestExtensions.cs +++ b/src/Neo.SmartContract.Testing/TestExtensions.cs @@ -1,17 +1,73 @@ +using Neo.IO; using Neo.VM.Types; using System; +using System.Collections.Generic; using System.Numerics; namespace Neo.SmartContract.Testing { public static class TestExtensions { + /// + /// Convert dotnet type to stack item + /// + /// Data + /// StackItem + public static StackItem ConvertToStackItem(this object data) + { + if (data is null) return StackItem.Null; + if (data is bool b) return (VM.Types.Boolean)b; + if (data is string s) return (ByteString)s; + if (data is byte[] d) return (ByteString)d; + if (data is ReadOnlyMemory r) return (ByteString)r; + + if (data is byte by) return (VM.Types.Integer)by; + if (data is sbyte sby) return (VM.Types.Integer)sby; + if (data is short i16) return (VM.Types.Integer)i16; + if (data is ushort ui16) return (VM.Types.Integer)ui16; + if (data is int i32) return (VM.Types.Integer)i32; + if (data is uint ui32) return (VM.Types.Integer)ui32; + if (data is long i64) return (VM.Types.Integer)i64; + if (data is ulong ui64) return (VM.Types.Integer)ui64; + if (data is BigInteger bi) return (VM.Types.Integer)bi; + + if (data is UInt160 u160) return (ByteString)u160.ToArray(); + if (data is UInt256 u256) return (ByteString)u256.ToArray(); + if (data is Cryptography.ECC.ECPoint ec) return (ByteString)ec.ToArray(); + + if (data is object[] arr) + { + VM.Types.Array ar = new(); + + foreach (object o in arr) + { + ar.Add(ConvertToStackItem(o)); + } + + return ar; + } + + if (data is IEnumerable iarr) + { + VM.Types.Array ar = new(); + + foreach (object o in iarr) + { + ar.Add(ConvertToStackItem(o)); + } + + return ar; + } + + return StackItem.Null; + } + /// /// Convert stack item to dotnet /// /// Item /// Type - /// + /// Object public static object? ConvertTo(this StackItem stackItem, Type type) { if (stackItem is null) return null; @@ -35,7 +91,7 @@ public static class TestExtensions if (type == typeof(Cryptography.ECC.ECPoint)) return Cryptography.ECC.ECPoint.FromBytes(stackItem.GetSpan().ToArray(), Cryptography.ECC.ECCurve.Secp256r1); - return null; + return stackItem; } } } diff --git a/tests/Neo.SmartContract.Testing.UnitTests/TestEngineTests.cs b/tests/Neo.SmartContract.Testing.UnitTests/TestEngineTests.cs index 9d3922c11..acc608ba6 100644 --- a/tests/Neo.SmartContract.Testing.UnitTests/TestEngineTests.cs +++ b/tests/Neo.SmartContract.Testing.UnitTests/TestEngineTests.cs @@ -76,7 +76,6 @@ public void TestLog() [TestMethod] public void TestNotification() { - UInt160 hash = UInt160.Parse("0x1230000000000000000000000000000000000000"); TestEngine engine = new(); var neoLog = false; From 4ad592ad84324d57c254a5610fdad6445129bce4 Mon Sep 17 00:00:00 2001 From: Fernando Diaz Toledano Date: Sat, 10 Feb 2024 13:35:10 +0100 Subject: [PATCH 026/106] format --- src/Neo.SmartContract.Testing/Artifacts.cs | 16 +++++++-------- .../Native/ContractManagement.cs | 20 +++++++++---------- .../Native/CryptoLib.cs | 12 +++++------ .../Native/GasToken.cs | 20 +++++++++---------- .../Native/LedgerContract.cs | 12 +++++------ .../Native/NeoToken.cs | 20 +++++++++---------- .../Native/OracleContract.cs | 20 +++++++++---------- .../Native/PolicyContract.cs | 16 +++++++-------- .../Native/RoleManagement.cs | 20 +++++++++---------- .../Native/StdLib.cs | 12 +++++------ src/Neo.SmartContract.Testing/TestEngine.cs | 19 ++++++++++++------ .../TestExtensions.cs | 2 +- .../ArtifactsTests.cs | 18 ++++++++--------- .../TestEngineTests.cs | 2 +- 14 files changed, 108 insertions(+), 101 deletions(-) diff --git a/src/Neo.SmartContract.Testing/Artifacts.cs b/src/Neo.SmartContract.Testing/Artifacts.cs index 7b3420e83..f7928005e 100644 --- a/src/Neo.SmartContract.Testing/Artifacts.cs +++ b/src/Neo.SmartContract.Testing/Artifacts.cs @@ -30,21 +30,21 @@ public static string CreateSourceFromManifest(string name, ContractAbi abi) if (abi.Events.Any()) { - sourceCode.AppendLine("#region Events"); + sourceCode.AppendLine(" #region Events"); foreach (var ev in abi.Events.OrderBy(u => u.Name)) { sourceCode.Append(CreateSourceEventFromManifest(ev)); } - sourceCode.AppendLine("#endregion"); + sourceCode.AppendLine(" #endregion"); } // Crete methods if (abi.Methods.Any(u => u.Safe)) { - sourceCode.AppendLine("#region Safe methods"); + sourceCode.AppendLine(" #region Safe methods"); foreach (var method in abi.Methods.Where(u => u.Safe).OrderBy(u => u.Name)) { @@ -55,12 +55,12 @@ public static string CreateSourceFromManifest(string name, ContractAbi abi) sourceCode.Append(CreateSourceMethodFromManifest(method)); } - sourceCode.AppendLine("#endregion"); + sourceCode.AppendLine(" #endregion"); } if (abi.Methods.Any(u => !u.Safe)) { - sourceCode.AppendLine("#region Unsafe methods"); + sourceCode.AppendLine(" #region Unsafe methods"); foreach (var method in abi.Methods.Where(u => !u.Safe).OrderBy(u => u.Name)) { @@ -70,14 +70,14 @@ public static string CreateSourceFromManifest(string name, ContractAbi abi) sourceCode.Append(CreateSourceMethodFromManifest(method)); } - sourceCode.AppendLine("#endregion"); + sourceCode.AppendLine(" #endregion"); } // Create constructor - sourceCode.AppendLine("#region Constructor for internal use only"); + sourceCode.AppendLine(" #region Constructor for internal use only"); sourceCode.AppendLine($" protected {name}(Neo.SmartContract.Testing.TestEngine testEngine, Neo.UInt160 hash) : base(testEngine, hash) {{}}"); - sourceCode.AppendLine("#endregion"); + sourceCode.AppendLine(" #endregion"); sourceCode.AppendLine("}"); diff --git a/src/Neo.SmartContract.Testing/Native/ContractManagement.cs b/src/Neo.SmartContract.Testing/Native/ContractManagement.cs index ae1ed05e4..dd691450b 100644 --- a/src/Neo.SmartContract.Testing/Native/ContractManagement.cs +++ b/src/Neo.SmartContract.Testing/Native/ContractManagement.cs @@ -6,30 +6,30 @@ namespace Neo.SmartContract.Testing; public abstract class ContractManagement : Neo.SmartContract.Testing.SmartContract { -#region Events + #region Events public delegate void delDeploy(UInt160 Hash); public event delDeploy? Deploy; public delegate void delDestroy(UInt160 Hash); public event delDestroy? Destroy; public delegate void delUpdate(UInt160 Hash); public event delUpdate? Update; -#endregion -#region Safe methods + #endregion + #region Safe methods public abstract List getContract(UInt160 hash); public abstract List getContractById(BigInteger id); public abstract object getContractHashes(); public abstract BigInteger getMinimumDeploymentFee(); public abstract bool hasMethod(UInt160 hash, string method, BigInteger pcount); -#endregion -#region Unsafe methods + #endregion + #region Unsafe methods public abstract List deploy(byte[] nefFile, byte[] manifest); public abstract List deploy(byte[] nefFile, byte[] manifest, object data); public abstract void destroy(); public abstract void setMinimumDeploymentFee(BigInteger value); public abstract void update(byte[] nefFile, byte[] manifest); public abstract void update(byte[] nefFile, byte[] manifest, object data); -#endregion -#region Constructor for internal use only - protected ContractManagement(Neo.SmartContract.Testing.TestEngine testEngine, Neo.UInt160 hash) : base(testEngine, hash) {} -#endregion -} \ No newline at end of file + #endregion + #region Constructor for internal use only + protected ContractManagement(Neo.SmartContract.Testing.TestEngine testEngine, Neo.UInt160 hash) : base(testEngine, hash) { } + #endregion +} diff --git a/src/Neo.SmartContract.Testing/Native/CryptoLib.cs b/src/Neo.SmartContract.Testing/Native/CryptoLib.cs index a774e6c7c..b1d7b6676 100644 --- a/src/Neo.SmartContract.Testing/Native/CryptoLib.cs +++ b/src/Neo.SmartContract.Testing/Native/CryptoLib.cs @@ -6,7 +6,7 @@ namespace Neo.SmartContract.Testing; public abstract class CryptoLib : Neo.SmartContract.Testing.SmartContract { -#region Safe methods + #region Safe methods public abstract object bls12381Add(object x, object y); public abstract object bls12381Deserialize(byte[] data); public abstract bool bls12381Equal(object x, object y); @@ -17,8 +17,8 @@ public abstract class CryptoLib : Neo.SmartContract.Testing.SmartContract public abstract byte[] ripemd160(byte[] data); public abstract byte[] sha256(byte[] data); public abstract bool verifyWithECDsa(byte[] message, byte[] pubkey, byte[] signature, BigInteger curve); -#endregion -#region Constructor for internal use only - protected CryptoLib(Neo.SmartContract.Testing.TestEngine testEngine, Neo.UInt160 hash) : base(testEngine, hash) {} -#endregion -} \ No newline at end of file + #endregion + #region Constructor for internal use only + protected CryptoLib(Neo.SmartContract.Testing.TestEngine testEngine, Neo.UInt160 hash) : base(testEngine, hash) { } + #endregion +} diff --git a/src/Neo.SmartContract.Testing/Native/GasToken.cs b/src/Neo.SmartContract.Testing/Native/GasToken.cs index d7a2806b8..6bc9ca9c3 100644 --- a/src/Neo.SmartContract.Testing/Native/GasToken.cs +++ b/src/Neo.SmartContract.Testing/Native/GasToken.cs @@ -6,20 +6,20 @@ namespace Neo.SmartContract.Testing; public abstract class GasToken : Neo.SmartContract.Testing.SmartContract { -#region Events + #region Events public delegate void delTransfer(UInt160 from, UInt160 to, BigInteger amount); public event delTransfer? Transfer; -#endregion -#region Safe methods + #endregion + #region Safe methods public abstract BigInteger balanceOf(UInt160 account); public abstract BigInteger decimals(); public abstract string symbol(); public abstract BigInteger totalSupply(); -#endregion -#region Unsafe methods + #endregion + #region Unsafe methods public abstract bool transfer(UInt160 from, UInt160 to, BigInteger amount, object data); -#endregion -#region Constructor for internal use only - protected GasToken(Neo.SmartContract.Testing.TestEngine testEngine, Neo.UInt160 hash) : base(testEngine, hash) {} -#endregion -} \ No newline at end of file + #endregion + #region Constructor for internal use only + protected GasToken(Neo.SmartContract.Testing.TestEngine testEngine, Neo.UInt160 hash) : base(testEngine, hash) { } + #endregion +} diff --git a/src/Neo.SmartContract.Testing/Native/LedgerContract.cs b/src/Neo.SmartContract.Testing/Native/LedgerContract.cs index 64df7d68a..a1be82c92 100644 --- a/src/Neo.SmartContract.Testing/Native/LedgerContract.cs +++ b/src/Neo.SmartContract.Testing/Native/LedgerContract.cs @@ -6,7 +6,7 @@ namespace Neo.SmartContract.Testing; public abstract class LedgerContract : Neo.SmartContract.Testing.SmartContract { -#region Safe methods + #region Safe methods public abstract UInt256 currentHash(); public abstract BigInteger currentIndex(); public abstract List getBlock(byte[] indexOrHash); @@ -15,8 +15,8 @@ public abstract class LedgerContract : Neo.SmartContract.Testing.SmartContract public abstract BigInteger getTransactionHeight(UInt256 hash); public abstract List getTransactionSigners(UInt256 hash); public abstract BigInteger getTransactionVMState(UInt256 hash); -#endregion -#region Constructor for internal use only - protected LedgerContract(Neo.SmartContract.Testing.TestEngine testEngine, Neo.UInt160 hash) : base(testEngine, hash) {} -#endregion -} \ No newline at end of file + #endregion + #region Constructor for internal use only + protected LedgerContract(Neo.SmartContract.Testing.TestEngine testEngine, Neo.UInt160 hash) : base(testEngine, hash) { } + #endregion +} diff --git a/src/Neo.SmartContract.Testing/Native/NeoToken.cs b/src/Neo.SmartContract.Testing/Native/NeoToken.cs index b4a2ae798..af7369bf3 100644 --- a/src/Neo.SmartContract.Testing/Native/NeoToken.cs +++ b/src/Neo.SmartContract.Testing/Native/NeoToken.cs @@ -6,15 +6,15 @@ namespace Neo.SmartContract.Testing; public abstract class NeoToken : Neo.SmartContract.Testing.SmartContract { -#region Events + #region Events public delegate void delCandidateStateChanged(ECPoint pubkey, bool registered, BigInteger votes); public event delCandidateStateChanged? CandidateStateChanged; public delegate void delTransfer(UInt160 from, UInt160 to, BigInteger amount); public event delTransfer? Transfer; public delegate void delVote(UInt160 account, ECPoint from, ECPoint to, BigInteger amount); public event delVote? Vote; -#endregion -#region Safe methods + #endregion + #region Safe methods public abstract BigInteger balanceOf(UInt160 account); public abstract BigInteger decimals(); public abstract List getAccountState(UInt160 account); @@ -28,16 +28,16 @@ public abstract class NeoToken : Neo.SmartContract.Testing.SmartContract public abstract string symbol(); public abstract BigInteger totalSupply(); public abstract BigInteger unclaimedGas(UInt160 account, BigInteger end); -#endregion -#region Unsafe methods + #endregion + #region Unsafe methods public abstract bool registerCandidate(ECPoint pubkey); public abstract void setGasPerBlock(BigInteger gasPerBlock); public abstract void setRegisterPrice(BigInteger registerPrice); public abstract bool transfer(UInt160 from, UInt160 to, BigInteger amount, object data); public abstract bool unregisterCandidate(ECPoint pubkey); public abstract bool vote(UInt160 account, ECPoint voteTo); -#endregion -#region Constructor for internal use only - protected NeoToken(Neo.SmartContract.Testing.TestEngine testEngine, Neo.UInt160 hash) : base(testEngine, hash) {} -#endregion -} \ No newline at end of file + #endregion + #region Constructor for internal use only + protected NeoToken(Neo.SmartContract.Testing.TestEngine testEngine, Neo.UInt160 hash) : base(testEngine, hash) { } + #endregion +} diff --git a/src/Neo.SmartContract.Testing/Native/OracleContract.cs b/src/Neo.SmartContract.Testing/Native/OracleContract.cs index c3762536e..f9d3beb3a 100644 --- a/src/Neo.SmartContract.Testing/Native/OracleContract.cs +++ b/src/Neo.SmartContract.Testing/Native/OracleContract.cs @@ -6,22 +6,22 @@ namespace Neo.SmartContract.Testing; public abstract class OracleContract : Neo.SmartContract.Testing.SmartContract { -#region Events + #region Events public delegate void delOracleRequest(BigInteger Id, UInt160 RequestContract, string Url, string Filter); public event delOracleRequest? OracleRequest; public delegate void delOracleResponse(BigInteger Id, UInt256 OriginalTx); public event delOracleResponse? OracleResponse; -#endregion -#region Safe methods + #endregion + #region Safe methods public abstract BigInteger getPrice(); public abstract bool verify(); -#endregion -#region Unsafe methods + #endregion + #region Unsafe methods public abstract void finish(); public abstract void request(string url, string filter, string callback, object userData, BigInteger gasForResponse); public abstract void setPrice(BigInteger price); -#endregion -#region Constructor for internal use only - protected OracleContract(Neo.SmartContract.Testing.TestEngine testEngine, Neo.UInt160 hash) : base(testEngine, hash) {} -#endregion -} \ No newline at end of file + #endregion + #region Constructor for internal use only + protected OracleContract(Neo.SmartContract.Testing.TestEngine testEngine, Neo.UInt160 hash) : base(testEngine, hash) { } + #endregion +} diff --git a/src/Neo.SmartContract.Testing/Native/PolicyContract.cs b/src/Neo.SmartContract.Testing/Native/PolicyContract.cs index 505628e58..a71512bf8 100644 --- a/src/Neo.SmartContract.Testing/Native/PolicyContract.cs +++ b/src/Neo.SmartContract.Testing/Native/PolicyContract.cs @@ -6,22 +6,22 @@ namespace Neo.SmartContract.Testing; public abstract class PolicyContract : Neo.SmartContract.Testing.SmartContract { -#region Safe methods + #region Safe methods public abstract BigInteger getAttributeFee(BigInteger attributeType); public abstract BigInteger getExecFeeFactor(); public abstract BigInteger getFeePerByte(); public abstract BigInteger getStoragePrice(); public abstract bool isBlocked(UInt160 account); -#endregion -#region Unsafe methods + #endregion + #region Unsafe methods public abstract bool blockAccount(UInt160 account); public abstract void setAttributeFee(BigInteger attributeType, BigInteger value); public abstract void setExecFeeFactor(BigInteger value); public abstract void setFeePerByte(BigInteger value); public abstract void setStoragePrice(BigInteger value); public abstract bool unblockAccount(UInt160 account); -#endregion -#region Constructor for internal use only - protected PolicyContract(Neo.SmartContract.Testing.TestEngine testEngine, Neo.UInt160 hash) : base(testEngine, hash) {} -#endregion -} \ No newline at end of file + #endregion + #region Constructor for internal use only + protected PolicyContract(Neo.SmartContract.Testing.TestEngine testEngine, Neo.UInt160 hash) : base(testEngine, hash) { } + #endregion +} diff --git a/src/Neo.SmartContract.Testing/Native/RoleManagement.cs b/src/Neo.SmartContract.Testing/Native/RoleManagement.cs index b0fedb43a..e40229bd2 100644 --- a/src/Neo.SmartContract.Testing/Native/RoleManagement.cs +++ b/src/Neo.SmartContract.Testing/Native/RoleManagement.cs @@ -6,17 +6,17 @@ namespace Neo.SmartContract.Testing; public abstract class RoleManagement : Neo.SmartContract.Testing.SmartContract { -#region Events + #region Events public delegate void delDesignation(BigInteger Role, BigInteger BlockIndex); public event delDesignation? Designation; -#endregion -#region Safe methods + #endregion + #region Safe methods public abstract List getDesignatedByRole(BigInteger role, BigInteger index); -#endregion -#region Unsafe methods + #endregion + #region Unsafe methods public abstract void designateAsRole(BigInteger role, List nodes); -#endregion -#region Constructor for internal use only - protected RoleManagement(Neo.SmartContract.Testing.TestEngine testEngine, Neo.UInt160 hash) : base(testEngine, hash) {} -#endregion -} \ No newline at end of file + #endregion + #region Constructor for internal use only + protected RoleManagement(Neo.SmartContract.Testing.TestEngine testEngine, Neo.UInt160 hash) : base(testEngine, hash) { } + #endregion +} diff --git a/src/Neo.SmartContract.Testing/Native/StdLib.cs b/src/Neo.SmartContract.Testing/Native/StdLib.cs index 73db2b1f9..f587ccefe 100644 --- a/src/Neo.SmartContract.Testing/Native/StdLib.cs +++ b/src/Neo.SmartContract.Testing/Native/StdLib.cs @@ -6,7 +6,7 @@ namespace Neo.SmartContract.Testing; public abstract class StdLib : Neo.SmartContract.Testing.SmartContract { -#region Safe methods + #region Safe methods public abstract BigInteger atoi(string value); public abstract BigInteger atoi(string value, BigInteger @base); public abstract byte[] base58CheckDecode(string s); @@ -28,8 +28,8 @@ public abstract class StdLib : Neo.SmartContract.Testing.SmartContract public abstract List stringSplit(string str, string separator); public abstract List stringSplit(string str, string separator, bool removeEmptyEntries); public abstract BigInteger strLen(string str); -#endregion -#region Constructor for internal use only - protected StdLib(Neo.SmartContract.Testing.TestEngine testEngine, Neo.UInt160 hash) : base(testEngine, hash) {} -#endregion -} \ No newline at end of file + #endregion + #region Constructor for internal use only + protected StdLib(Neo.SmartContract.Testing.TestEngine testEngine, Neo.UInt160 hash) : base(testEngine, hash) { } + #endregion +} diff --git a/src/Neo.SmartContract.Testing/TestEngine.cs b/src/Neo.SmartContract.Testing/TestEngine.cs index 2a30d2e0e..ec81ee049 100644 --- a/src/Neo.SmartContract.Testing/TestEngine.cs +++ b/src/Neo.SmartContract.Testing/TestEngine.cs @@ -1,4 +1,4 @@ -using Moq; +using Moq; using Neo.Cryptography.ECC; using Neo.IO; using Neo.Persistence; @@ -150,7 +150,7 @@ public T Deploy(NefFile nef, ContractManifest manifest, object data) where T // Parse return - ContractState state = new(); + ContractState state = new(); // Move to TestExtensions.ConvertTo? ((IInteroperable)state).FromStackItem(new Array(ret.Select(u => (StackItem)u))); // Mock contract @@ -167,20 +167,27 @@ public T Deploy(NefFile nef, ContractManifest manifest, object data) where T /// Mocked Smart Contract public T FromHash(UInt160 hash) where T : SmartContract { - // TODO: Ensure that the contract exists - return MockContract(hash); + + //var ret = Native.ContractManagement.getContract(hash); + + //// Parse return + + //ContractState state = new(); // Move to TestExtensions.ConvertTo? + //((IInteroperable)state).FromStackItem(new Array(ret.Select(u => (StackItem)u))); + + //return MockContract(state.Hash); } private T MockContract(UInt160 hash) where T : SmartContract { - // TODO: Mock sc here - var mock = new Mock(this, hash) { CallBase = true }; + // TODO: Mock sc here + // Cache sc if (_contracts.TryGetValue(hash, out var result)) diff --git a/src/Neo.SmartContract.Testing/TestExtensions.cs b/src/Neo.SmartContract.Testing/TestExtensions.cs index 3683ad7d5..94176668d 100644 --- a/src/Neo.SmartContract.Testing/TestExtensions.cs +++ b/src/Neo.SmartContract.Testing/TestExtensions.cs @@ -1,4 +1,4 @@ -using Neo.IO; +using Neo.IO; using Neo.VM.Types; using System; using System.Collections.Generic; diff --git a/tests/Neo.SmartContract.Testing.UnitTests/ArtifactsTests.cs b/tests/Neo.SmartContract.Testing.UnitTests/ArtifactsTests.cs index b2d7724fc..4a525ed0d 100644 --- a/tests/Neo.SmartContract.Testing.UnitTests/ArtifactsTests.cs +++ b/tests/Neo.SmartContract.Testing.UnitTests/ArtifactsTests.cs @@ -1,4 +1,4 @@ -using Microsoft.VisualStudio.TestTools.UnitTesting; +using Microsoft.VisualStudio.TestTools.UnitTesting; using Neo.Json; using Neo.SmartContract.Manifest; @@ -26,21 +26,21 @@ namespace Neo.SmartContract.Testing; public abstract class Contract1 : Neo.SmartContract.Testing.SmartContract { -#region Events + #region Events public delegate void delSetOwner(UInt160 newOwner); public event delSetOwner? SetOwner; public delegate void delTransfer(UInt160 from, UInt160 to, BigInteger amount); public event delTransfer? Transfer; -#endregion -#region Safe methods + #endregion + #region Safe methods public abstract BigInteger balanceOf(UInt160 owner); public abstract BigInteger decimals(); public abstract UInt160 getOwner(); public abstract string symbol(); public abstract BigInteger totalSupply(); public abstract bool verify(); -#endregion -#region Unsafe methods + #endregion + #region Unsafe methods public abstract void burn(UInt160 account, BigInteger amount); public abstract void mint(UInt160 to, BigInteger amount); public abstract string myMethod(); @@ -49,10 +49,10 @@ public abstract class Contract1 : Neo.SmartContract.Testing.SmartContract public abstract bool transfer(UInt160 from, UInt160 to, BigInteger amount, object data); public abstract void update(byte[] nefFile, string manifest); public abstract bool withdraw(UInt160 token, UInt160 to, BigInteger amount); -#endregion -#region Constructor for internal use only + #endregion + #region Constructor for internal use only protected Contract1(Neo.SmartContract.Testing.TestEngine testEngine, Neo.UInt160 hash) : base(testEngine, hash) {} -#endregion + #endregion } ".Replace("\r\n", "\n").Trim()); } diff --git a/tests/Neo.SmartContract.Testing.UnitTests/TestEngineTests.cs b/tests/Neo.SmartContract.Testing.UnitTests/TestEngineTests.cs index acc608ba6..0d9072fd0 100644 --- a/tests/Neo.SmartContract.Testing.UnitTests/TestEngineTests.cs +++ b/tests/Neo.SmartContract.Testing.UnitTests/TestEngineTests.cs @@ -1,4 +1,4 @@ -using Microsoft.VisualStudio.TestTools.UnitTesting; +using Microsoft.VisualStudio.TestTools.UnitTesting; using Neo.IO; using Neo.VM.Types; using System.IO; From b380e7a1ac633924fa32847ebb531da5cc9077a6 Mon Sep 17 00:00:00 2001 From: Fernando Diaz Toledano Date: Sat, 10 Feb 2024 15:21:59 +0100 Subject: [PATCH 027/106] LoadFromJson --- src/Neo.SmartContract.Testing/TestEngine.cs | 4 +- src/Neo.SmartContract.Testing/TestStorage.cs | 84 +++++++++++++++++++ .../TestStorageTests.cs | 53 ++++++++++++ 3 files changed, 139 insertions(+), 2 deletions(-) create mode 100644 src/Neo.SmartContract.Testing/TestStorage.cs create mode 100644 tests/Neo.SmartContract.Testing.UnitTests/TestStorageTests.cs diff --git a/src/Neo.SmartContract.Testing/TestEngine.cs b/src/Neo.SmartContract.Testing/TestEngine.cs index ec81ee049..9fc51aba1 100644 --- a/src/Neo.SmartContract.Testing/TestEngine.cs +++ b/src/Neo.SmartContract.Testing/TestEngine.cs @@ -65,9 +65,9 @@ public class TestEngine }; /// - /// Store + /// Storage /// - public IStore Store { get; init; } = new MemoryStore(); + public TestStorage Store { get; init; } = new TestStorage(new MemoryStore()); /// /// Protocol Settings diff --git a/src/Neo.SmartContract.Testing/TestStorage.cs b/src/Neo.SmartContract.Testing/TestStorage.cs new file mode 100644 index 000000000..4d3cb0a51 --- /dev/null +++ b/src/Neo.SmartContract.Testing/TestStorage.cs @@ -0,0 +1,84 @@ +using Neo.Json; +using Neo.Persistence; +using System; +using System.Linq; + +namespace Neo.SmartContract.Testing +{ + public class TestStorage + { + /// + /// Store + /// + public IStore Store { get; init; } = new MemoryStore(); + + /// + /// Snapshot + /// + public ISnapshot Snapshot { get; private set; } + + /// + /// Constructor + /// + /// Store + public TestStorage(IStore store) + { + Store = store; + Snapshot = Store.GetSnapshot(); + } + + /// + /// Commit + /// + public void Commit() + { + Snapshot.Commit(); + Snapshot = Store.GetSnapshot(); + } + + /// + /// Rollback + /// + public void Rollback() + { + Snapshot.Dispose(); + Snapshot = Store.GetSnapshot(); + } + + /// + /// Load data from json + /// + /// Expected data (in base64): + /// + /// - "key":"value" + /// - "prefix": { "key":"value" } + /// + /// Snapshot to be used + /// Json Object + public void LoadFromJson(JObject json) + { + foreach (var entry in json.Properties) + { + if (entry.Value is JString str) + { + // "key":"value" in base64 + + Snapshot.Put(Convert.FromBase64String(entry.Key), Convert.FromBase64String(str.Value)); + } + else if (entry.Value is JObject obj) + { + // "prefix": { "key":"value" } in base64 + + foreach (var subEntry in obj.Properties) + { + if (subEntry.Value is JString subStr) + { + Snapshot.Put(Convert.FromBase64String(entry.Key).Concat(Convert.FromBase64String(subEntry.Key)).ToArray(), + Convert.FromBase64String(subStr.Value)); + } + } + } + } + } + } +} diff --git a/tests/Neo.SmartContract.Testing.UnitTests/TestStorageTests.cs b/tests/Neo.SmartContract.Testing.UnitTests/TestStorageTests.cs new file mode 100644 index 000000000..177d7ebe8 --- /dev/null +++ b/tests/Neo.SmartContract.Testing.UnitTests/TestStorageTests.cs @@ -0,0 +1,53 @@ +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Neo.Json; +using Neo.Persistence; +using System; +using System.Linq; +using System.Text; + +namespace Neo.SmartContract.Testing.UnitTests +{ + [TestClass] + public class TestStorageTests + { + [TestMethod] + public void LoadFromJsonTest() + { + TestStorage store = new(new MemoryStore()); + + // empty + + var entries = store.Store.Seek(Array.Empty(), SeekDirection.Forward).ToArray(); + Assert.AreEqual(entries.Length, 0); + + // simple object + + var json = @"{""a2V5"":""dmFsdWU=""}"; + + store.LoadFromJson((JObject)JToken.Parse(json)); + store.Commit(); + + entries = store.Store.Seek(Array.Empty(), SeekDirection.Forward).ToArray(); + Assert.AreEqual(entries.Length, 1); + + Assert.AreEqual("key", Encoding.ASCII.GetString(entries[0].Key)); + Assert.AreEqual("value", Encoding.ASCII.GetString(entries[0].Value)); + + // prefix object + + json = @"{""bXkt"":{""a2V5"":""bXktdmFsdWU=""}}"; + + store.LoadFromJson((JObject)JToken.Parse(json)); + store.Commit(); + + entries = store.Store.Seek(Array.Empty(), SeekDirection.Forward).ToArray(); + Assert.AreEqual(entries.Length, 2); + + Assert.AreEqual("key", Encoding.ASCII.GetString(entries[0].Key)); + Assert.AreEqual("value", Encoding.ASCII.GetString(entries[0].Value)); + + Assert.AreEqual("my-key", Encoding.ASCII.GetString(entries[1].Key)); + Assert.AreEqual("my-value", Encoding.ASCII.GetString(entries[1].Value)); + } + } +} From 15f35666de3dad7ed015808c7c963b0288ef9639 Mon Sep 17 00:00:00 2001 From: Fernando Diaz Toledano Date: Sat, 10 Feb 2024 15:49:52 +0100 Subject: [PATCH 028/106] Initialize native contracts --- .../NativeArtifacts.cs | 28 +++++++++++++++++-- src/Neo.SmartContract.Testing/TestEngine.cs | 2 +- .../NativeArtifactsTests.cs | 21 ++++++++++++++ 3 files changed, 48 insertions(+), 3 deletions(-) create mode 100644 tests/Neo.SmartContract.Testing.UnitTests/NativeArtifactsTests.cs diff --git a/src/Neo.SmartContract.Testing/NativeArtifacts.cs b/src/Neo.SmartContract.Testing/NativeArtifacts.cs index efbb5bff4..d593f3297 100644 --- a/src/Neo.SmartContract.Testing/NativeArtifacts.cs +++ b/src/Neo.SmartContract.Testing/NativeArtifacts.cs @@ -1,3 +1,6 @@ +using Neo.Persistence; +using System; + namespace Neo.SmartContract.Testing { public class NativeArtifacts @@ -138,9 +141,30 @@ public NativeArtifacts(TestEngine engine) /// /// Initialize native contracts /// - public void Initialize() + /// Initialize native contracts + public void Initialize(bool commit = false) { - // TODO: Initialize them + var persistingBlock = NeoSystem.CreateGenesisBlock(_engine.ProtocolSettings); + using SnapshotCache snapshot = new(_engine.Storage.Snapshot); + + foreach (var native in Native.NativeContract.Contracts) + { + var method = native.GetType().GetMethod("OnPersist", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance); + + using var engine = ApplicationEngine.Create(TriggerType.OnPersist, persistingBlock, + snapshot, persistingBlock, _engine.ProtocolSettings); + + engine.LoadScript(Array.Empty()); + method!.Invoke(native, new object[] { engine }); + + engine.Snapshot.Commit(); + } + + if (commit) + { + snapshot.Commit(); + _engine.Storage.Commit(); + } } } } diff --git a/src/Neo.SmartContract.Testing/TestEngine.cs b/src/Neo.SmartContract.Testing/TestEngine.cs index 9fc51aba1..4b00daea8 100644 --- a/src/Neo.SmartContract.Testing/TestEngine.cs +++ b/src/Neo.SmartContract.Testing/TestEngine.cs @@ -67,7 +67,7 @@ public class TestEngine /// /// Storage /// - public TestStorage Store { get; init; } = new TestStorage(new MemoryStore()); + public TestStorage Storage { get; init; } = new TestStorage(new MemoryStore()); /// /// Protocol Settings diff --git a/tests/Neo.SmartContract.Testing.UnitTests/NativeArtifactsTests.cs b/tests/Neo.SmartContract.Testing.UnitTests/NativeArtifactsTests.cs new file mode 100644 index 000000000..dcc9450a6 --- /dev/null +++ b/tests/Neo.SmartContract.Testing.UnitTests/NativeArtifactsTests.cs @@ -0,0 +1,21 @@ +using Microsoft.VisualStudio.TestTools.UnitTesting; +using System.Linq; + +namespace Neo.SmartContract.Testing.UnitTests +{ + [TestClass] + public class NativeArtifactsTests + { + [TestMethod] + public void TestInitialize() + { + var engine = new TestEngine(); + + Assert.AreEqual(0, engine.Storage.Store.Seek(System.Array.Empty(), Persistence.SeekDirection.Forward).Count()); + + engine.Native.Initialize(true); + + Assert.AreEqual(35, engine.Storage.Store.Seek(System.Array.Empty(), Persistence.SeekDirection.Forward).Count()); + } + } +} From b852249111d714045ddb0a26734e8484a790e7f6 Mon Sep 17 00:00:00 2001 From: Fernando Diaz Toledano Date: Sat, 10 Feb 2024 18:20:03 +0100 Subject: [PATCH 029/106] Partially mocked --- .../NativeArtifacts.cs | 49 ++++-- .../SmartContract.cs | 39 +++++ src/Neo.SmartContract.Testing/TestEngine.cs | 158 ++++++++++++++++-- .../TestExtensions.cs | 18 +- .../NativeArtifactsTests.cs | 7 +- .../TestEngineTests.cs | 6 +- 6 files changed, 236 insertions(+), 41 deletions(-) diff --git a/src/Neo.SmartContract.Testing/NativeArtifacts.cs b/src/Neo.SmartContract.Testing/NativeArtifacts.cs index d593f3297..d9bac02ef 100644 --- a/src/Neo.SmartContract.Testing/NativeArtifacts.cs +++ b/src/Neo.SmartContract.Testing/NativeArtifacts.cs @@ -1,5 +1,6 @@ using Neo.Persistence; using System; +using System.Reflection; namespace Neo.SmartContract.Testing { @@ -28,7 +29,7 @@ public ContractManagement ContractManagement { get { - _contractManagement ??= _engine.FromHash(Native.NativeContract.ContractManagement.Hash); + _contractManagement ??= _engine.FromHash(Native.NativeContract.ContractManagement.Hash, false); return _contractManagement; } } @@ -40,7 +41,7 @@ public CryptoLib CryptoLib { get { - _cryptoLib ??= _engine.FromHash(Native.NativeContract.CryptoLib.Hash); + _cryptoLib ??= _engine.FromHash(Native.NativeContract.CryptoLib.Hash, false); return _cryptoLib; } } @@ -52,7 +53,7 @@ public GasToken GAS { get { - _gas ??= _engine.FromHash(Native.NativeContract.GAS.Hash); + _gas ??= _engine.FromHash(Native.NativeContract.GAS.Hash, false); return _gas; } } @@ -64,7 +65,7 @@ public NeoToken NEO { get { - _neo ??= _engine.FromHash(Native.NativeContract.NEO.Hash); + _neo ??= _engine.FromHash(Native.NativeContract.NEO.Hash, false); return _neo; } } @@ -76,7 +77,7 @@ public LedgerContract Ledger { get { - _ledger ??= _engine.FromHash(Native.NativeContract.Ledger.Hash); + _ledger ??= _engine.FromHash(Native.NativeContract.Ledger.Hash, false); return _ledger; } } @@ -88,7 +89,7 @@ public OracleContract Oracle { get { - _oracle ??= _engine.FromHash(Native.NativeContract.Oracle.Hash); + _oracle ??= _engine.FromHash(Native.NativeContract.Oracle.Hash, false); return _oracle; } } @@ -100,7 +101,7 @@ public PolicyContract Policy { get { - _policy ??= _engine.FromHash(Native.NativeContract.Policy.Hash); + _policy ??= _engine.FromHash(Native.NativeContract.Policy.Hash, false); return _policy; } } @@ -112,7 +113,7 @@ public RoleManagement RoleManagement { get { - _roleManagement ??= _engine.FromHash(Native.NativeContract.RoleManagement.Hash); + _roleManagement ??= _engine.FromHash(Native.NativeContract.RoleManagement.Hash, false); return _roleManagement; } } @@ -124,7 +125,7 @@ public StdLib StdLib { get { - _stdLib ??= _engine.FromHash(Native.NativeContract.StdLib.Hash); + _stdLib ??= _engine.FromHash(Native.NativeContract.StdLib.Hash, false); return _stdLib; } } @@ -144,20 +145,36 @@ public NativeArtifacts(TestEngine engine) /// Initialize native contracts public void Initialize(bool commit = false) { - var persistingBlock = NeoSystem.CreateGenesisBlock(_engine.ProtocolSettings); + var genesis = NeoSystem.CreateGenesisBlock(_engine.ProtocolSettings); using SnapshotCache snapshot = new(_engine.Storage.Snapshot); foreach (var native in Native.NativeContract.Contracts) { - var method = native.GetType().GetMethod("OnPersist", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance); + // Mock Native.OnPersist - using var engine = ApplicationEngine.Create(TriggerType.OnPersist, persistingBlock, - snapshot, persistingBlock, _engine.ProtocolSettings); + var method = native.GetType().GetMethod("OnPersist", BindingFlags.NonPublic | BindingFlags.Instance); - engine.LoadScript(Array.Empty()); - method!.Invoke(native, new object[] { engine }); + using (var engine = ApplicationEngine.Create(TriggerType.OnPersist, genesis, snapshot, genesis, _engine.ProtocolSettings)) + { - engine.Snapshot.Commit(); + engine.LoadScript(Array.Empty()); + method!.Invoke(native, new object[] { engine }); + + engine.Snapshot.Commit(); + } + + // Mock Native.PostPersist + + method = native.GetType().GetMethod("PostPersist", BindingFlags.NonPublic | BindingFlags.Instance); + + using (var engine = ApplicationEngine.Create(TriggerType.OnPersist, genesis, snapshot, genesis, _engine.ProtocolSettings)) + { + + engine.LoadScript(Array.Empty()); + method!.Invoke(native, new object[] { engine }); + + engine.Snapshot.Commit(); + } } if (commit) diff --git a/src/Neo.SmartContract.Testing/SmartContract.cs b/src/Neo.SmartContract.Testing/SmartContract.cs index 80739f94a..b787d9c14 100644 --- a/src/Neo.SmartContract.Testing/SmartContract.cs +++ b/src/Neo.SmartContract.Testing/SmartContract.cs @@ -1,3 +1,6 @@ +using Neo.Persistence; +using Neo.VM; +using Neo.VM.Types; using System; using System.Reflection; @@ -26,6 +29,42 @@ protected SmartContract(TestEngine testEngine, UInt160 hash) Hash = hash; } + /// + /// Invoke to NeoVM + /// + /// Method name + /// Arguments + /// Object + internal StackItem Invoke(string methodName, params object[] args) + { + using SnapshotCache snapshot = new(_engine.Storage.Snapshot); + var block = NeoSystem.CreateGenesisBlock(_engine.ProtocolSettings); + + // Compose script + + using ScriptBuilder script = new(); + script.EmitDynamicCall(Hash, methodName, args); + + // Execute in neo VM + + using var engine = ApplicationEngine.Create(TriggerType.OnPersist, + _engine.Transaction, snapshot, block, _engine.ProtocolSettings); + + engine.LoadScript(script.ToArray()); + + if (engine.Execute() != VMState.HALT) + { + throw engine.FaultException ?? new Exception($"Error while executing {methodName}"); + } + + engine.Snapshot.Commit(); + + // Return + + if (engine.ResultStack.Count == 0) return StackItem.Null; + return engine.ResultStack.Pop(); + } + /// /// OnLog /// diff --git a/src/Neo.SmartContract.Testing/TestEngine.cs b/src/Neo.SmartContract.Testing/TestEngine.cs index 4b00daea8..9d2554bee 100644 --- a/src/Neo.SmartContract.Testing/TestEngine.cs +++ b/src/Neo.SmartContract.Testing/TestEngine.cs @@ -1,11 +1,18 @@ using Moq; +using Moq.Protected; using Neo.Cryptography.ECC; using Neo.IO; +using Neo.Network.P2P.Payloads; using Neo.Persistence; using Neo.SmartContract.Manifest; using Neo.VM.Types; +using System; using System.Collections.Generic; using System.Linq; +using System.Linq.Expressions; +using System.Numerics; +using System.Reflection; +using System.Reflection.Metadata.Ecma335; using System.Text; namespace Neo.SmartContract.Testing @@ -74,10 +81,32 @@ public class TestEngine /// public ProtocolSettings ProtocolSettings { get; init; } = Default; + /// + /// Transaction + /// + public Transaction Transaction { get; set; } = new Transaction() + { + Attributes = System.Array.Empty(), + Script = System.Array.Empty(), + Signers = new Signer[] + { + new Signer() { Account=Contract.GetBFTAddress(Default.StandbyValidators) } + }, + Witnesses = new Witness[] + { + new Witness() + { + InvocationScript = Contract.CreateMultiSigRedeemScript( + Default.StandbyValidators.Count - (Default.StandbyValidators.Count - 1) / 3, Default.StandbyValidators), + VerificationScript = System.Array.Empty() + } + } + }; + /// /// Sender /// - public UInt160 Sender { get; } = UInt160.Zero; + public UInt160 Sender => Transaction.Sender; private NativeArtifacts? _native; @@ -127,10 +156,10 @@ private void ApplicationEngine_Log(object? sender, LogEventArgs e) } public void Log(UInt160 scriptHash, string message) => - ApplicationEngine_Log(null, new LogEventArgs(null, scriptHash, message)); + ApplicationEngine_Log(null, new LogEventArgs(Transaction, scriptHash, message)); - public void Notify(UInt160 scriptHash, string eventName, Array state) => - ApplicationEngine_Notify(null, new NotifyEventArgs(null, scriptHash, eventName, state)); + public void Notify(UInt160 scriptHash, string eventName, VM.Types.Array state) => + ApplicationEngine_Notify(null, new NotifyEventArgs(Transaction, scriptHash, eventName, state)); #endregion @@ -151,7 +180,7 @@ public T Deploy(NefFile nef, ContractManifest manifest, object data) where T // Parse return ContractState state = new(); // Move to TestExtensions.ConvertTo? - ((IInteroperable)state).FromStackItem(new Array(ret.Select(u => (StackItem)u))); + ((IInteroperable)state).FromStackItem(new VM.Types.Array(ret.Select(u => (StackItem)u))); // Mock contract @@ -164,19 +193,23 @@ public T Deploy(NefFile nef, ContractManifest manifest, object data) where T /// /// Type /// Contract hash + /// Check existence (default: true) /// Mocked Smart Contract - public T FromHash(UInt160 hash) where T : SmartContract + public T FromHash(UInt160 hash, bool checkExistence = true) where T : SmartContract { - return MockContract(hash); + if (!checkExistence) + { + return MockContract(hash); + } - //var ret = Native.ContractManagement.getContract(hash); + var ret = Native.ContractManagement.getContract(hash); - //// Parse return + // Parse return - //ContractState state = new(); // Move to TestExtensions.ConvertTo? - //((IInteroperable)state).FromStackItem(new Array(ret.Select(u => (StackItem)u))); + ContractState state = new(); // Move to TestExtensions.ConvertTo? + ((IInteroperable)state).FromStackItem(new VM.Types.Array(ret.Select(u => (StackItem)u))); - //return MockContract(state.Hash); + return MockContract(state.Hash); } private T MockContract(UInt160 hash) where T : SmartContract @@ -186,7 +219,35 @@ private T MockContract(UInt160 hash) where T : SmartContract CallBase = true }; - // TODO: Mock sc here + // Mock sc here + + foreach (var method in typeof(T).GetMethods()) + { + if (!method.IsAbstract) continue; + + // Get methods + + Type[] args = new Type[method.GetParameters().Length]; + for (int x = 0; x < args.Length; x++) + { + args[x] = method.GetParameters()[x].ParameterType; + } + + // Mock by return type + + if (method.GetParameters().Length != 0) continue; + + if (method.ReturnType != typeof(void)) + { + MockMethod(mock, method.Name, args, method.ReturnType); + } + else + { + MockMethod(mock, method.Name, args); + } + } + + mock.Verify(); // Cache sc @@ -202,5 +263,76 @@ private T MockContract(UInt160 hash) where T : SmartContract // return mocked sc return mock.Object; } + + private static readonly MethodInfo isAnyMethod = typeof(It).GetMethod(nameof(It.IsAny), BindingFlags.Public | BindingFlags.Static)!; + + private static MethodCallExpression BuildIsAnyExpressions(Type type) + { + return Expression.Call(isAnyMethod.MakeGenericMethod(type)); + } + + private Expression BuildIsAnyExpressions(Mock mock, string name, Type[] args) + where T : SmartContract + { + var mockType = mock.Object.GetType().BaseType!; + var expArgs = args.Select(BuildIsAnyExpressions).ToArray(); + + var instanceParam = Expression.Parameter(mockType, "x"); + + var metodoInfo = mockType.GetMethod(name, args)!; + var callExpression = Expression.Call(instanceParam, metodoInfo, expArgs); + var parameterExpression = Expression.Parameter(mockType, "x"); + + return Expression.Lambda(callExpression, parameterExpression); + } + + private void MockMethod(Mock mock, string name, Type[] args, Type returnType) + where T : SmartContract + { + Expression exp = BuildIsAnyExpressions(mock, name, args); + + var setupMethod = mock.GetType() + .GetMethods(BindingFlags.Instance | BindingFlags.Public) + .First(u => u.Name == nameof(IProtectedMock.Setup) && + u.GetParameters().Length == 1 && + u.GetParameters()[0].ParameterType.ToString().Contains("[System.Func`") + ) + .MakeGenericMethod(returnType); + + var setup = setupMethod.Invoke(mock, new object[] { exp })!; + + var retMethod = setup.GetType() + .GetMethod("Returns", new Type[] { typeof(InvocationFunc) })!; + + _ = retMethod.Invoke(setup, new object[] { new InvocationFunc(invocation => + { + return mock.Object.Invoke(invocation.Method.Name, invocation.Arguments.ToArray()).ConvertTo(returnType)!; + }) + }); + } + + private void MockMethod(Mock mock, string name, Type[] args) + where T : SmartContract + { + Expression exp = BuildIsAnyExpressions(mock, name, args); + + var setupMethod = mock.GetType() + .GetMethods(BindingFlags.Instance | BindingFlags.Public) + .First(u => u.Name == nameof(IProtectedMock.Setup) && + u.GetParameters().Length == 1 && + u.GetParameters()[0].ParameterType.ToString().Contains("[System.Action`") + ); + + var setup = setupMethod.Invoke(mock, new object[] { exp }); + + var retMethod = mock.GetType() + .GetMethod("Callback", BindingFlags.Static | BindingFlags.Public)!; + + _ = retMethod.Invoke(setup, new object[] { new InvocationAction(invocation => + { + _=mock.Object.Invoke(invocation.Method.Name, invocation.Arguments.ToArray()); + }) + }); + } } } diff --git a/src/Neo.SmartContract.Testing/TestExtensions.cs b/src/Neo.SmartContract.Testing/TestExtensions.cs index 94176668d..a036d4932 100644 --- a/src/Neo.SmartContract.Testing/TestExtensions.cs +++ b/src/Neo.SmartContract.Testing/TestExtensions.cs @@ -76,15 +76,15 @@ public static StackItem ConvertToStackItem(this object data) if (type == typeof(string)) return stackItem.ToString(); if (type == typeof(byte[])) return stackItem.GetSpan().ToArray(); - if (type == typeof(byte) || type == typeof(sbyte) || - type == typeof(short) || type == typeof(ushort) || - type == typeof(int) || type == typeof(uint) || - type == typeof(long) || type == typeof(ulong) || - type == typeof(BigInteger) - ) - { - return stackItem.GetInteger(); - } + if (type == typeof(byte)) return (byte)stackItem.GetInteger(); + if (type == typeof(sbyte)) return (sbyte)stackItem.GetInteger(); + if (type == typeof(short)) return (short)stackItem.GetInteger(); + if (type == typeof(ushort)) return (ushort)stackItem.GetInteger(); + if (type == typeof(int)) return (int)stackItem.GetInteger(); + if (type == typeof(uint)) return (uint)stackItem.GetInteger(); + if (type == typeof(long)) return (long)stackItem.GetInteger(); + if (type == typeof(ulong)) return (ulong)stackItem.GetInteger(); + if (type == typeof(BigInteger)) return stackItem.GetInteger(); if (type == typeof(UInt160)) return new UInt160(stackItem.GetSpan().ToArray()); if (type == typeof(UInt256)) return new UInt256(stackItem.GetSpan().ToArray()); diff --git a/tests/Neo.SmartContract.Testing.UnitTests/NativeArtifactsTests.cs b/tests/Neo.SmartContract.Testing.UnitTests/NativeArtifactsTests.cs index dcc9450a6..18b1d9a73 100644 --- a/tests/Neo.SmartContract.Testing.UnitTests/NativeArtifactsTests.cs +++ b/tests/Neo.SmartContract.Testing.UnitTests/NativeArtifactsTests.cs @@ -15,7 +15,12 @@ public void TestInitialize() engine.Native.Initialize(true); - Assert.AreEqual(35, engine.Storage.Store.Seek(System.Array.Empty(), Persistence.SeekDirection.Forward).Count()); + // Ensure that the main address contains the totalSupply + + var addr = Contract.GetBFTAddress(engine.ProtocolSettings.StandbyValidators); + + Assert.AreEqual(100_000_000, engine.Native.NEO.totalSupply()); + Assert.AreEqual(engine.Native.NEO.totalSupply(), engine.Native.NEO.balanceOf(addr)); } } } diff --git a/tests/Neo.SmartContract.Testing.UnitTests/TestEngineTests.cs b/tests/Neo.SmartContract.Testing.UnitTests/TestEngineTests.cs index 0d9072fd0..fd561dc01 100644 --- a/tests/Neo.SmartContract.Testing.UnitTests/TestEngineTests.cs +++ b/tests/Neo.SmartContract.Testing.UnitTests/TestEngineTests.cs @@ -43,7 +43,7 @@ public void FromHashTest() UInt160 hash = UInt160.Parse("0x1230000000000000000000000000000000000000"); TestEngine engine = new(); - var contract = engine.FromHash(hash); + var contract = engine.FromHash(hash, false); Assert.AreEqual(contract.Hash, hash); } @@ -55,13 +55,14 @@ public void TestLog() TestEngine engine = new(); var contractLog = false; - var contract = engine.FromHash(hash); + var contract = engine.FromHash(hash, false); contract.OnLog += (msg) => { contractLog = true; }; var neoLog = false; + engine.Native.Initialize(); engine.Native.NEO.OnLog += (msg) => { neoLog = true; @@ -79,6 +80,7 @@ public void TestNotification() TestEngine engine = new(); var neoLog = false; + engine.Native.Initialize(); engine.Native.NEO.CandidateStateChanged += (pubKey, registered, votes) => { neoLog = pubKey == engine.ProtocolSettings.StandbyCommittee.First() && votes == 123 && registered; From 6938ccc353e7134fc31e41a15a77bfc83df0e8f8 Mon Sep 17 00:00:00 2001 From: Fernando Diaz Toledano Date: Sat, 10 Feb 2024 18:23:00 +0100 Subject: [PATCH 030/106] Mocked with args --- src/Neo.SmartContract.Testing/TestEngine.cs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/Neo.SmartContract.Testing/TestEngine.cs b/src/Neo.SmartContract.Testing/TestEngine.cs index 9d2554bee..356b7e8c4 100644 --- a/src/Neo.SmartContract.Testing/TestEngine.cs +++ b/src/Neo.SmartContract.Testing/TestEngine.cs @@ -235,15 +235,13 @@ private T MockContract(UInt160 hash) where T : SmartContract // Mock by return type - if (method.GetParameters().Length != 0) continue; - if (method.ReturnType != typeof(void)) { MockMethod(mock, method.Name, args, method.ReturnType); } else { - MockMethod(mock, method.Name, args); + //MockMethod(mock, method.Name, args); } } @@ -326,7 +324,7 @@ private void MockMethod(Mock mock, string name, Type[] args) var setup = setupMethod.Invoke(mock, new object[] { exp }); var retMethod = mock.GetType() - .GetMethod("Callback", BindingFlags.Static | BindingFlags.Public)!; + .GetMethod("Callback", new Type[] { typeof(InvocationAction) })!; _ = retMethod.Invoke(setup, new object[] { new InvocationAction(invocation => { From d6a22029251a294a79264654058b9c5db5192301 Mon Sep 17 00:00:00 2001 From: Fernando Diaz Toledano Date: Sat, 10 Feb 2024 18:54:29 +0100 Subject: [PATCH 031/106] Fix Scope --- .../NativeArtifacts.cs | 10 ++++++++ .../SmartContract.cs | 2 +- src/Neo.SmartContract.Testing/TestEngine.cs | 16 ++++++------ .../NativeArtifactsTests.cs | 25 +++++++++++++++++++ 4 files changed, 45 insertions(+), 8 deletions(-) diff --git a/src/Neo.SmartContract.Testing/NativeArtifacts.cs b/src/Neo.SmartContract.Testing/NativeArtifacts.cs index d9bac02ef..5529daabd 100644 --- a/src/Neo.SmartContract.Testing/NativeArtifacts.cs +++ b/src/Neo.SmartContract.Testing/NativeArtifacts.cs @@ -139,6 +139,16 @@ public NativeArtifacts(TestEngine engine) _engine = engine; } + /// + /// GetCommitteeAddress + /// + public UInt160 GetCommitteeAddress() + { + using SnapshotCache snapshot = new(_engine.Storage.Snapshot); + + return Native.NativeContract.NEO.GetCommitteeAddress(snapshot); + } + /// /// Initialize native contracts /// diff --git a/src/Neo.SmartContract.Testing/SmartContract.cs b/src/Neo.SmartContract.Testing/SmartContract.cs index b787d9c14..2d2d2a8d7 100644 --- a/src/Neo.SmartContract.Testing/SmartContract.cs +++ b/src/Neo.SmartContract.Testing/SmartContract.cs @@ -101,7 +101,7 @@ internal void InvokeOnNotify(string eventName, VM.Types.Array state) } } - private object?[]? Convert(VM.Types.Array state, ParameterInfo[] parameterInfos) + private static object?[]? Convert(VM.Types.Array state, ParameterInfo[] parameterInfos) { if (parameterInfos.Length > 0) { diff --git a/src/Neo.SmartContract.Testing/TestEngine.cs b/src/Neo.SmartContract.Testing/TestEngine.cs index 356b7e8c4..e81cbbac2 100644 --- a/src/Neo.SmartContract.Testing/TestEngine.cs +++ b/src/Neo.SmartContract.Testing/TestEngine.cs @@ -10,9 +10,7 @@ using System.Collections.Generic; using System.Linq; using System.Linq.Expressions; -using System.Numerics; using System.Reflection; -using System.Reflection.Metadata.Ecma335; using System.Text; namespace Neo.SmartContract.Testing @@ -90,7 +88,11 @@ public class TestEngine Script = System.Array.Empty(), Signers = new Signer[] { - new Signer() { Account=Contract.GetBFTAddress(Default.StandbyValidators) } + new Signer() + { + Account = Contract.GetBFTAddress(Default.StandbyValidators), + Scopes = WitnessScope.Global + } }, Witnesses = new Witness[] { @@ -241,7 +243,7 @@ private T MockContract(UInt160 hash) where T : SmartContract } else { - //MockMethod(mock, method.Name, args); + MockMethod(mock, method.Name, args); } } @@ -321,14 +323,14 @@ private void MockMethod(Mock mock, string name, Type[] args) u.GetParameters()[0].ParameterType.ToString().Contains("[System.Action`") ); - var setup = setupMethod.Invoke(mock, new object[] { exp }); + var setup = setupMethod.Invoke(mock, new object[] { exp })!; - var retMethod = mock.GetType() + var retMethod = setup.GetType() .GetMethod("Callback", new Type[] { typeof(InvocationAction) })!; _ = retMethod.Invoke(setup, new object[] { new InvocationAction(invocation => { - _=mock.Object.Invoke(invocation.Method.Name, invocation.Arguments.ToArray()); + mock.Object.Invoke(invocation.Method.Name, invocation.Arguments.ToArray()); }) }); } diff --git a/tests/Neo.SmartContract.Testing.UnitTests/NativeArtifactsTests.cs b/tests/Neo.SmartContract.Testing.UnitTests/NativeArtifactsTests.cs index 18b1d9a73..8f1939c30 100644 --- a/tests/Neo.SmartContract.Testing.UnitTests/NativeArtifactsTests.cs +++ b/tests/Neo.SmartContract.Testing.UnitTests/NativeArtifactsTests.cs @@ -1,5 +1,6 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; using System.Linq; +using System.Reflection; namespace Neo.SmartContract.Testing.UnitTests { @@ -21,6 +22,30 @@ public void TestInitialize() Assert.AreEqual(100_000_000, engine.Native.NEO.totalSupply()); Assert.AreEqual(engine.Native.NEO.totalSupply(), engine.Native.NEO.balanceOf(addr)); + + // Test set + + Assert.AreEqual(500000000, engine.Native.NEO.getGasPerBlock()); + + // Fake signature + + engine.Transaction.Signers = new Network.P2P.Payloads.Signer[] + { + new Network.P2P.Payloads.Signer() + { + Account = engine.Native.GetCommitteeAddress(), + Scopes = Network.P2P.Payloads.WitnessScope.Global + } + }; + engine.Native.NEO.setGasPerBlock(123); + + Assert.AreEqual(123, engine.Native.NEO.getGasPerBlock()); + + // Invalid signature + + engine.Transaction.Signers[0].Scopes = Network.P2P.Payloads.WitnessScope.None; + + Assert.ThrowsException(() => engine.Native.NEO.setGasPerBlock(123)); } } } From 26397a302fef74e4cc66d3f648db367524735f4a Mon Sep 17 00:00:00 2001 From: Fernando Diaz Toledano Date: Sat, 10 Feb 2024 19:04:18 +0100 Subject: [PATCH 032/106] Found bug in MemoryStore --- src/Neo.SmartContract.Testing/NativeArtifacts.cs | 9 ++++++--- src/Neo.SmartContract.Testing/TestEngine.cs | 12 +++++++++++- .../NativeArtifactsTests.cs | 6 +++--- 3 files changed, 20 insertions(+), 7 deletions(-) diff --git a/src/Neo.SmartContract.Testing/NativeArtifacts.cs b/src/Neo.SmartContract.Testing/NativeArtifacts.cs index 5529daabd..550238c04 100644 --- a/src/Neo.SmartContract.Testing/NativeArtifacts.cs +++ b/src/Neo.SmartContract.Testing/NativeArtifacts.cs @@ -170,7 +170,8 @@ public void Initialize(bool commit = false) engine.LoadScript(Array.Empty()); method!.Invoke(native, new object[] { engine }); - engine.Snapshot.Commit(); + snapshot.Commit(); + engine.Snapshot.Commit(); // Bug in MemoryStore } // Mock Native.PostPersist @@ -183,13 +184,15 @@ public void Initialize(bool commit = false) engine.LoadScript(Array.Empty()); method!.Invoke(native, new object[] { engine }); - engine.Snapshot.Commit(); + snapshot.Commit(); + engine.Snapshot.Commit(); // Bug in MemoryStore } } + snapshot.Commit(); + if (commit) { - snapshot.Commit(); _engine.Storage.Commit(); } } diff --git a/src/Neo.SmartContract.Testing/TestEngine.cs b/src/Neo.SmartContract.Testing/TestEngine.cs index e81cbbac2..ef3b194d0 100644 --- a/src/Neo.SmartContract.Testing/TestEngine.cs +++ b/src/Neo.SmartContract.Testing/TestEngine.cs @@ -79,6 +79,11 @@ public class TestEngine /// public ProtocolSettings ProtocolSettings { get; init; } = Default; + /// + /// BFTAddress + /// + public UInt160 BFTAddress => Contract.GetBFTAddress(ProtocolSettings.StandbyValidators); + /// /// Transaction /// @@ -127,10 +132,15 @@ public NativeArtifacts Native /// /// Constructor /// - public TestEngine() + public TestEngine(bool initializeNativeContracts = false) { ApplicationEngine.Log += ApplicationEngine_Log; ApplicationEngine.Notify += ApplicationEngine_Notify; + + if (initializeNativeContracts) + { + Native.Initialize(false); + } } #region Invoke events diff --git a/tests/Neo.SmartContract.Testing.UnitTests/NativeArtifactsTests.cs b/tests/Neo.SmartContract.Testing.UnitTests/NativeArtifactsTests.cs index 8f1939c30..9220de216 100644 --- a/tests/Neo.SmartContract.Testing.UnitTests/NativeArtifactsTests.cs +++ b/tests/Neo.SmartContract.Testing.UnitTests/NativeArtifactsTests.cs @@ -18,10 +18,8 @@ public void TestInitialize() // Ensure that the main address contains the totalSupply - var addr = Contract.GetBFTAddress(engine.ProtocolSettings.StandbyValidators); - Assert.AreEqual(100_000_000, engine.Native.NEO.totalSupply()); - Assert.AreEqual(engine.Native.NEO.totalSupply(), engine.Native.NEO.balanceOf(addr)); + Assert.AreEqual(engine.Native.NEO.totalSupply(), engine.Native.NEO.balanceOf(engine.BFTAddress)); // Test set @@ -39,6 +37,8 @@ public void TestInitialize() }; engine.Native.NEO.setGasPerBlock(123); + engine.Storage.Commit(); // Bug in MemoryStore + Assert.AreEqual(123, engine.Native.NEO.getGasPerBlock()); // Invalid signature From 70632d6582619b8e16d74c07428873f7a094f84f Mon Sep 17 00:00:00 2001 From: Fernando Diaz Toledano Date: Sat, 10 Feb 2024 19:19:05 +0100 Subject: [PATCH 033/106] TriggerType.Application --- src/Neo.SmartContract.Testing/SmartContract.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Neo.SmartContract.Testing/SmartContract.cs b/src/Neo.SmartContract.Testing/SmartContract.cs index 2d2d2a8d7..ce2bcccaa 100644 --- a/src/Neo.SmartContract.Testing/SmartContract.cs +++ b/src/Neo.SmartContract.Testing/SmartContract.cs @@ -47,7 +47,7 @@ internal StackItem Invoke(string methodName, params object[] args) // Execute in neo VM - using var engine = ApplicationEngine.Create(TriggerType.OnPersist, + using var engine = ApplicationEngine.Create(TriggerType.Application, _engine.Transaction, snapshot, block, _engine.ProtocolSettings); engine.LoadScript(script.ToArray()); From f00d32a7eae7b739cf512f9c8d735ad84af38f19 Mon Sep 17 00:00:00 2001 From: Fernando Diaz Toledano Date: Sat, 10 Feb 2024 19:38:23 +0100 Subject: [PATCH 034/106] clean and fixes --- .../SmartContract.cs | 3 +- src/Neo.SmartContract.Testing/TestEngine.cs | 70 ++++++++++++------- .../NativeArtifactsTests.cs | 53 +++++++++++++- 3 files changed, 96 insertions(+), 30 deletions(-) diff --git a/src/Neo.SmartContract.Testing/SmartContract.cs b/src/Neo.SmartContract.Testing/SmartContract.cs index ce2bcccaa..03d8c86c0 100644 --- a/src/Neo.SmartContract.Testing/SmartContract.cs +++ b/src/Neo.SmartContract.Testing/SmartContract.cs @@ -38,7 +38,6 @@ protected SmartContract(TestEngine testEngine, UInt160 hash) internal StackItem Invoke(string methodName, params object[] args) { using SnapshotCache snapshot = new(_engine.Storage.Snapshot); - var block = NeoSystem.CreateGenesisBlock(_engine.ProtocolSettings); // Compose script @@ -48,7 +47,7 @@ internal StackItem Invoke(string methodName, params object[] args) // Execute in neo VM using var engine = ApplicationEngine.Create(TriggerType.Application, - _engine.Transaction, snapshot, block, _engine.ProtocolSettings); + _engine.Transaction, snapshot, _engine.CurrentBlock, _engine.ProtocolSettings); engine.LoadScript(script.ToArray()); diff --git a/src/Neo.SmartContract.Testing/TestEngine.cs b/src/Neo.SmartContract.Testing/TestEngine.cs index ef3b194d0..d0001f679 100644 --- a/src/Neo.SmartContract.Testing/TestEngine.cs +++ b/src/Neo.SmartContract.Testing/TestEngine.cs @@ -77,38 +77,22 @@ public class TestEngine /// /// Protocol Settings /// - public ProtocolSettings ProtocolSettings { get; init; } = Default; + public ProtocolSettings ProtocolSettings { get; } /// /// BFTAddress /// - public UInt160 BFTAddress => Contract.GetBFTAddress(ProtocolSettings.StandbyValidators); + public UInt160 BFTAddress { get; } + + /// + /// BFTAddress + /// + public Block CurrentBlock { get; } /// /// Transaction /// - public Transaction Transaction { get; set; } = new Transaction() - { - Attributes = System.Array.Empty(), - Script = System.Array.Empty(), - Signers = new Signer[] - { - new Signer() - { - Account = Contract.GetBFTAddress(Default.StandbyValidators), - Scopes = WitnessScope.Global - } - }, - Witnesses = new Witness[] - { - new Witness() - { - InvocationScript = Contract.CreateMultiSigRedeemScript( - Default.StandbyValidators.Count - (Default.StandbyValidators.Count - 1) / 3, Default.StandbyValidators), - VerificationScript = System.Array.Empty() - } - } - }; + public Transaction Transaction { get; set; } /// /// Sender @@ -132,8 +116,44 @@ public NativeArtifacts Native /// /// Constructor /// - public TestEngine(bool initializeNativeContracts = false) + /// Initialize native contracts + public TestEngine(bool initializeNativeContracts = false) : this(Default, initializeNativeContracts) { } + + /// + /// Constructor + /// + /// Settings + /// Initialize native contracts + public TestEngine(ProtocolSettings settings, bool initializeNativeContracts = false) { + ProtocolSettings = settings; + CurrentBlock = NeoSystem.CreateGenesisBlock(ProtocolSettings); + CurrentBlock.Header.Index++; + + BFTAddress = Contract.GetBFTAddress(ProtocolSettings.StandbyValidators); + Transaction = new Transaction() + { + Attributes = System.Array.Empty(), + Script = System.Array.Empty(), + Signers = new Signer[] + { + new Signer() + { + Account = BFTAddress, + Scopes = WitnessScope.Global + } + }, + Witnesses = new Witness[] + { + new Witness() + { + InvocationScript = Contract.CreateMultiSigRedeemScript( + settings.StandbyValidators.Count - (settings.StandbyValidators.Count - 1) / 3, settings.StandbyValidators), + VerificationScript = System.Array.Empty() + } + } + }; + ApplicationEngine.Log += ApplicationEngine_Log; ApplicationEngine.Notify += ApplicationEngine_Notify; diff --git a/tests/Neo.SmartContract.Testing.UnitTests/NativeArtifactsTests.cs b/tests/Neo.SmartContract.Testing.UnitTests/NativeArtifactsTests.cs index 9220de216..4a761e0ba 100644 --- a/tests/Neo.SmartContract.Testing.UnitTests/NativeArtifactsTests.cs +++ b/tests/Neo.SmartContract.Testing.UnitTests/NativeArtifactsTests.cs @@ -1,5 +1,6 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; using System.Linq; +using System.Numerics; using System.Reflection; namespace Neo.SmartContract.Testing.UnitTests @@ -20,6 +21,13 @@ public void TestInitialize() Assert.AreEqual(100_000_000, engine.Native.NEO.totalSupply()); Assert.AreEqual(engine.Native.NEO.totalSupply(), engine.Native.NEO.balanceOf(engine.BFTAddress)); + } + + [TestMethod] + public void TestTransfer() + { + var engine = new TestEngine(true); + engine.Storage.Commit(); // Bug in MemoryStore // Test set @@ -27,6 +35,44 @@ public void TestInitialize() // Fake signature + engine.Transaction.Signers = new Network.P2P.Payloads.Signer[] + { + new Network.P2P.Payloads.Signer() + { + Account = engine.BFTAddress, + Scopes = Network.P2P.Payloads.WitnessScope.Global + } + }; + + bool raisedEvent = false; + + engine.Native.NEO.Transfer += (UInt160 from, UInt160 to, BigInteger amount) => + { + raisedEvent = true; + }; + + UInt160 wallet = UInt160.Parse("0x1230000000000000000000000000000000000000"); + + Assert.AreEqual(0, engine.Native.NEO.balanceOf(wallet)); + Assert.IsTrue(engine.Native.NEO.transfer(engine.Transaction.Sender, wallet, 123, null)); + + Assert.IsTrue(raisedEvent); + engine.Storage.Commit(); // Bug in MemoryStore + Assert.AreEqual(123, engine.Native.NEO.balanceOf(wallet)); + } + + [TestMethod] + public void TestSignature() + { + var engine = new TestEngine(true); + engine.Storage.Commit(); // Bug in MemoryStore + + // Test set + + Assert.AreEqual(100000000000, engine.Native.NEO.getRegisterPrice()); + + // Fake signature + engine.Transaction.Signers = new Network.P2P.Payloads.Signer[] { new Network.P2P.Payloads.Signer() @@ -35,17 +81,18 @@ public void TestInitialize() Scopes = Network.P2P.Payloads.WitnessScope.Global } }; - engine.Native.NEO.setGasPerBlock(123); + + engine.Native.NEO.setRegisterPrice(123); engine.Storage.Commit(); // Bug in MemoryStore - Assert.AreEqual(123, engine.Native.NEO.getGasPerBlock()); + Assert.AreEqual(123, engine.Native.NEO.getRegisterPrice()); // Invalid signature engine.Transaction.Signers[0].Scopes = Network.P2P.Payloads.WitnessScope.None; - Assert.ThrowsException(() => engine.Native.NEO.setGasPerBlock(123)); + Assert.ThrowsException(() => engine.Native.NEO.setRegisterPrice(123)); } } } From 20b9ae231595e34e417da53b8220a8fe8dd66779 Mon Sep 17 00:00:00 2001 From: Fernando Diaz Toledano Date: Sat, 10 Feb 2024 19:41:24 +0100 Subject: [PATCH 035/106] format --- src/Neo.SmartContract.Testing/SmartContract.cs | 6 +++--- src/Neo.SmartContract.Testing/TestStorage.cs | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Neo.SmartContract.Testing/SmartContract.cs b/src/Neo.SmartContract.Testing/SmartContract.cs index 03d8c86c0..dc046580d 100644 --- a/src/Neo.SmartContract.Testing/SmartContract.cs +++ b/src/Neo.SmartContract.Testing/SmartContract.cs @@ -1,7 +1,7 @@ -using Neo.Persistence; +using Neo.Persistence; using Neo.VM; -using Neo.VM.Types; -using System; +using Neo.VM.Types; +using System; using System.Reflection; namespace Neo.SmartContract.Testing diff --git a/src/Neo.SmartContract.Testing/TestStorage.cs b/src/Neo.SmartContract.Testing/TestStorage.cs index 4d3cb0a51..9d139d5c0 100644 --- a/src/Neo.SmartContract.Testing/TestStorage.cs +++ b/src/Neo.SmartContract.Testing/TestStorage.cs @@ -1,4 +1,4 @@ -using Neo.Json; +using Neo.Json; using Neo.Persistence; using System; using System.Linq; From b62efb48735410c476dba89888798c078ce663d4 Mon Sep 17 00:00:00 2001 From: Fernando Diaz Toledano Date: Sat, 10 Feb 2024 19:45:20 +0100 Subject: [PATCH 036/106] Remove utartifact --- .../TestEngineTests.cs | 4 +-- .../UtArtifacts/Contract1.cs | 35 ------------------- 2 files changed, 2 insertions(+), 37 deletions(-) delete mode 100644 tests/Neo.SmartContract.Testing.UnitTests/UtArtifacts/Contract1.cs diff --git a/tests/Neo.SmartContract.Testing.UnitTests/TestEngineTests.cs b/tests/Neo.SmartContract.Testing.UnitTests/TestEngineTests.cs index fd561dc01..3b8e61327 100644 --- a/tests/Neo.SmartContract.Testing.UnitTests/TestEngineTests.cs +++ b/tests/Neo.SmartContract.Testing.UnitTests/TestEngineTests.cs @@ -43,7 +43,7 @@ public void FromHashTest() UInt160 hash = UInt160.Parse("0x1230000000000000000000000000000000000000"); TestEngine engine = new(); - var contract = engine.FromHash(hash, false); + var contract = engine.FromHash(hash, false); Assert.AreEqual(contract.Hash, hash); } @@ -55,7 +55,7 @@ public void TestLog() TestEngine engine = new(); var contractLog = false; - var contract = engine.FromHash(hash, false); + var contract = engine.FromHash(hash, false); contract.OnLog += (msg) => { contractLog = true; diff --git a/tests/Neo.SmartContract.Testing.UnitTests/UtArtifacts/Contract1.cs b/tests/Neo.SmartContract.Testing.UnitTests/UtArtifacts/Contract1.cs deleted file mode 100644 index 0ed0458db..000000000 --- a/tests/Neo.SmartContract.Testing.UnitTests/UtArtifacts/Contract1.cs +++ /dev/null @@ -1,35 +0,0 @@ -using Neo.Cryptography.ECC; -using System.Numerics; - -namespace Neo.SmartContract.Testing; - -public abstract class Contract1 : Neo.SmartContract.Testing.SmartContract -{ - #region Events - public delegate void delSetOwner(UInt160 newOwner); - public event delSetOwner? SetOwner; - public delegate void delTransfer(UInt160 from, UInt160 to, BigInteger amount); - public event delTransfer? Transfer; - #endregion - #region Safe methods - public abstract BigInteger balanceOf(UInt160 owner); - public abstract BigInteger decimals(); - public abstract UInt160 getOwner(); - public abstract string symbol(); - public abstract BigInteger totalSupply(); - public abstract bool verify(); - #endregion - #region Unsafe methods - public abstract void burn(UInt160 account, BigInteger amount); - public abstract void mint(UInt160 to, BigInteger amount); - public abstract string myMethod(); - public abstract void onNEP17Payment(UInt160 from, BigInteger amount, object data); - public abstract void setOwner(UInt160 newOwner); - public abstract bool transfer(UInt160 from, UInt160 to, BigInteger amount, object data); - public abstract void update(byte[] nefFile, string manifest); - public abstract bool withdraw(UInt160 token, UInt160 to, BigInteger amount); - #endregion - #region Constructor for internal use only - protected Contract1(Neo.SmartContract.Testing.TestEngine testEngine, Neo.UInt160 hash) : base(testEngine, hash) { } - #endregion -} From c552403351f91fd8ba44e149dd63313909f1aac7 Mon Sep 17 00:00:00 2001 From: Fernando Diaz Toledano Date: Sat, 10 Feb 2024 20:01:38 +0100 Subject: [PATCH 037/106] Fix FromHash --- .../MockExtensions.cs | 82 +++++++++++++++++++ src/Neo.SmartContract.Testing/TestEngine.cs | 82 +------------------ .../TestExtensions.cs | 10 +++ .../TestEngineTests.cs | 18 +++- 4 files changed, 112 insertions(+), 80 deletions(-) create mode 100644 src/Neo.SmartContract.Testing/MockExtensions.cs diff --git a/src/Neo.SmartContract.Testing/MockExtensions.cs b/src/Neo.SmartContract.Testing/MockExtensions.cs new file mode 100644 index 000000000..39e94c8b8 --- /dev/null +++ b/src/Neo.SmartContract.Testing/MockExtensions.cs @@ -0,0 +1,82 @@ +using Moq; +using System; +using System.Linq; +using System.Linq.Expressions; +using System.Reflection; + +namespace Neo.SmartContract.Testing +{ + internal static class MockExtensions + { + private static readonly MethodInfo isAnyMethod = typeof(It).GetMethod(nameof(It.IsAny), BindingFlags.Public | BindingFlags.Static)!; + + private static MethodCallExpression BuildIsAnyExpressions(Type type) + { + return Expression.Call(isAnyMethod.MakeGenericMethod(type)); + } + + private static Expression BuildIsAnyExpressions(Mock mock, string name, Type[] args) + where T : SmartContract + { + var mockType = mock.Object.GetType().BaseType!; + var expArgs = args.Select(BuildIsAnyExpressions).ToArray(); + + var instanceParam = Expression.Parameter(mockType, "x"); + + var metodoInfo = mockType.GetMethod(name, args)!; + var callExpression = Expression.Call(instanceParam, metodoInfo, expArgs); + var parameterExpression = Expression.Parameter(mockType, "x"); + + return Expression.Lambda(callExpression, parameterExpression); + } + + public static void MockMethodWithReturn(this Mock mock, string name, Type[] args, Type returnType) + where T : SmartContract + { + Expression exp = BuildIsAnyExpressions(mock, name, args); + + var setupMethod = mock.GetType() + .GetMethods(BindingFlags.Instance | BindingFlags.Public) + .First(u => u.Name == nameof(Mock.Setup) && + u.GetParameters().Length == 1 && + u.GetParameters()[0].ParameterType.ToString().Contains("[System.Func`") + ) + .MakeGenericMethod(returnType); + + var setup = setupMethod.Invoke(mock, new object[] { exp })!; + + var retMethod = setup.GetType() + .GetMethod("Returns", new Type[] { typeof(InvocationFunc) })!; + + _ = retMethod.Invoke(setup, new object[] { new InvocationFunc(invocation => + { + return mock.Object.Invoke(invocation.Method.Name, invocation.Arguments.ToArray()).ConvertTo(returnType)!; + }) + }); + } + + public static void MockMethod(this Mock mock, string name, Type[] args) + where T : SmartContract + { + Expression exp = BuildIsAnyExpressions(mock, name, args); + + var setupMethod = mock.GetType() + .GetMethods(BindingFlags.Instance | BindingFlags.Public) + .First(u => u.Name == nameof(Mock.Setup) && + u.GetParameters().Length == 1 && + u.GetParameters()[0].ParameterType.ToString().Contains("[System.Action`") + ); + + var setup = setupMethod.Invoke(mock, new object[] { exp })!; + + var retMethod = setup.GetType() + .GetMethod("Callback", new Type[] { typeof(InvocationAction) })!; + + _ = retMethod.Invoke(setup, new object[] { new InvocationAction(invocation => + { + mock.Object.Invoke(invocation.Method.Name, invocation.Arguments.ToArray()); + }) + }); + } + } +} diff --git a/src/Neo.SmartContract.Testing/TestEngine.cs b/src/Neo.SmartContract.Testing/TestEngine.cs index d0001f679..b08896746 100644 --- a/src/Neo.SmartContract.Testing/TestEngine.cs +++ b/src/Neo.SmartContract.Testing/TestEngine.cs @@ -1,5 +1,4 @@ using Moq; -using Moq.Protected; using Neo.Cryptography.ECC; using Neo.IO; using Neo.Network.P2P.Payloads; @@ -9,8 +8,6 @@ using System; using System.Collections.Generic; using System.Linq; -using System.Linq.Expressions; -using System.Reflection; using System.Text; namespace Neo.SmartContract.Testing @@ -211,7 +208,7 @@ public T Deploy(NefFile nef, ContractManifest manifest, object data) where T // Parse return - ContractState state = new(); // Move to TestExtensions.ConvertTo? + ContractState state = new(); ((IInteroperable)state).FromStackItem(new VM.Types.Array(ret.Select(u => (StackItem)u))); // Mock contract @@ -238,7 +235,7 @@ public T FromHash(UInt160 hash, bool checkExistence = true) where T : SmartCo // Parse return - ContractState state = new(); // Move to TestExtensions.ConvertTo? + ContractState state = new(); ((IInteroperable)state).FromStackItem(new VM.Types.Array(ret.Select(u => (StackItem)u))); return MockContract(state.Hash); @@ -269,11 +266,11 @@ private T MockContract(UInt160 hash) where T : SmartContract if (method.ReturnType != typeof(void)) { - MockMethod(mock, method.Name, args, method.ReturnType); + mock.MockMethodWithReturn(method.Name, args, method.ReturnType); } else { - MockMethod(mock, method.Name, args); + mock.MockMethod(method.Name, args); } } @@ -293,76 +290,5 @@ private T MockContract(UInt160 hash) where T : SmartContract // return mocked sc return mock.Object; } - - private static readonly MethodInfo isAnyMethod = typeof(It).GetMethod(nameof(It.IsAny), BindingFlags.Public | BindingFlags.Static)!; - - private static MethodCallExpression BuildIsAnyExpressions(Type type) - { - return Expression.Call(isAnyMethod.MakeGenericMethod(type)); - } - - private Expression BuildIsAnyExpressions(Mock mock, string name, Type[] args) - where T : SmartContract - { - var mockType = mock.Object.GetType().BaseType!; - var expArgs = args.Select(BuildIsAnyExpressions).ToArray(); - - var instanceParam = Expression.Parameter(mockType, "x"); - - var metodoInfo = mockType.GetMethod(name, args)!; - var callExpression = Expression.Call(instanceParam, metodoInfo, expArgs); - var parameterExpression = Expression.Parameter(mockType, "x"); - - return Expression.Lambda(callExpression, parameterExpression); - } - - private void MockMethod(Mock mock, string name, Type[] args, Type returnType) - where T : SmartContract - { - Expression exp = BuildIsAnyExpressions(mock, name, args); - - var setupMethod = mock.GetType() - .GetMethods(BindingFlags.Instance | BindingFlags.Public) - .First(u => u.Name == nameof(IProtectedMock.Setup) && - u.GetParameters().Length == 1 && - u.GetParameters()[0].ParameterType.ToString().Contains("[System.Func`") - ) - .MakeGenericMethod(returnType); - - var setup = setupMethod.Invoke(mock, new object[] { exp })!; - - var retMethod = setup.GetType() - .GetMethod("Returns", new Type[] { typeof(InvocationFunc) })!; - - _ = retMethod.Invoke(setup, new object[] { new InvocationFunc(invocation => - { - return mock.Object.Invoke(invocation.Method.Name, invocation.Arguments.ToArray()).ConvertTo(returnType)!; - }) - }); - } - - private void MockMethod(Mock mock, string name, Type[] args) - where T : SmartContract - { - Expression exp = BuildIsAnyExpressions(mock, name, args); - - var setupMethod = mock.GetType() - .GetMethods(BindingFlags.Instance | BindingFlags.Public) - .First(u => u.Name == nameof(IProtectedMock.Setup) && - u.GetParameters().Length == 1 && - u.GetParameters()[0].ParameterType.ToString().Contains("[System.Action`") - ); - - var setup = setupMethod.Invoke(mock, new object[] { exp })!; - - var retMethod = setup.GetType() - .GetMethod("Callback", new Type[] { typeof(InvocationAction) })!; - - _ = retMethod.Invoke(setup, new object[] { new InvocationAction(invocation => - { - mock.Object.Invoke(invocation.Method.Name, invocation.Arguments.ToArray()); - }) - }); - } } } diff --git a/src/Neo.SmartContract.Testing/TestExtensions.cs b/src/Neo.SmartContract.Testing/TestExtensions.cs index a036d4932..8c47a88a8 100644 --- a/src/Neo.SmartContract.Testing/TestExtensions.cs +++ b/src/Neo.SmartContract.Testing/TestExtensions.cs @@ -91,6 +91,16 @@ public static StackItem ConvertToStackItem(this object data) if (type == typeof(Cryptography.ECC.ECPoint)) return Cryptography.ECC.ECPoint.FromBytes(stackItem.GetSpan().ToArray(), Cryptography.ECC.ECCurve.Secp256r1); + if (type == typeof(List)) + { + if (stackItem is not CompoundType cp) + { + return stackItem; + } + + return new List(cp.SubItems); + } + return stackItem; } } diff --git a/tests/Neo.SmartContract.Testing.UnitTests/TestEngineTests.cs b/tests/Neo.SmartContract.Testing.UnitTests/TestEngineTests.cs index 3b8e61327..bb2156e43 100644 --- a/tests/Neo.SmartContract.Testing.UnitTests/TestEngineTests.cs +++ b/tests/Neo.SmartContract.Testing.UnitTests/TestEngineTests.cs @@ -1,6 +1,8 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; using Neo.IO; using Neo.VM.Types; +using System; +using System.Collections.Generic; using System.IO; using System.Linq; @@ -22,10 +24,22 @@ public void GenerateNativeArtifacts() } } + [TestMethod] + public void TestHashExists() + { + TestEngine engine = new(false); + + Assert.ThrowsException(() => engine.FromHash(engine.Native.NEO.Hash, true)); + + engine.Native.Initialize(true); + + Assert.IsInstanceOfType(engine.FromHash(engine.Native.NEO.Hash, true)); + } + [TestMethod] public void TestNativeContracts() { - TestEngine engine = new(); + TestEngine engine = new(true); Assert.AreEqual(engine.Native.ContractManagement.Hash, Native.NativeContract.ContractManagement.Hash); Assert.AreEqual(engine.Native.StdLib.Hash, Native.NativeContract.StdLib.Hash); @@ -90,7 +104,7 @@ public void TestNotification() // public event delCandidateStateChanged? CandidateStateChanged; engine.Notify(engine.Native.NEO.Hash, "CandidateStateChanged", - new Array(new StackItem[] + new VM.Types.Array(new StackItem[] { new ByteString(engine.ProtocolSettings.StandbyCommittee.First().ToArray()), StackItem.True, From 9189bd252ba201d6f71e1a38aa94ad1abdc54d7d Mon Sep 17 00:00:00 2001 From: Fernando Diaz Toledano Date: Sat, 10 Feb 2024 20:04:36 +0100 Subject: [PATCH 038/106] Clean code --- src/Neo.SmartContract.Testing/TestExtensions.cs | 8 +++----- .../TestEngineTests.cs | 2 +- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/src/Neo.SmartContract.Testing/TestExtensions.cs b/src/Neo.SmartContract.Testing/TestExtensions.cs index 8c47a88a8..792b80b0c 100644 --- a/src/Neo.SmartContract.Testing/TestExtensions.cs +++ b/src/Neo.SmartContract.Testing/TestExtensions.cs @@ -93,15 +93,13 @@ public static StackItem ConvertToStackItem(this object data) if (type == typeof(List)) { - if (stackItem is not CompoundType cp) + if (stackItem is CompoundType cp) { - return stackItem; + return new List(cp.SubItems); } - - return new List(cp.SubItems); } - return stackItem; + throw new FormatException($"Impossible to convert {stackItem} to {type}"); } } } diff --git a/tests/Neo.SmartContract.Testing.UnitTests/TestEngineTests.cs b/tests/Neo.SmartContract.Testing.UnitTests/TestEngineTests.cs index bb2156e43..d6162a294 100644 --- a/tests/Neo.SmartContract.Testing.UnitTests/TestEngineTests.cs +++ b/tests/Neo.SmartContract.Testing.UnitTests/TestEngineTests.cs @@ -39,7 +39,7 @@ public void TestHashExists() [TestMethod] public void TestNativeContracts() { - TestEngine engine = new(true); + TestEngine engine = new(false); Assert.AreEqual(engine.Native.ContractManagement.Hash, Native.NativeContract.ContractManagement.Hash); Assert.AreEqual(engine.Native.StdLib.Hash, Native.NativeContract.StdLib.Hash); From f0bca7fcb614748ac78ab67f40bbc9791c391639 Mon Sep 17 00:00:00 2001 From: Fernando Diaz Toledano Date: Sat, 10 Feb 2024 20:12:02 +0100 Subject: [PATCH 039/106] Store current script in transaction --- src/Neo.SmartContract.Testing/NativeArtifacts.cs | 3 ++- src/Neo.SmartContract.Testing/SmartContract.cs | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Neo.SmartContract.Testing/NativeArtifacts.cs b/src/Neo.SmartContract.Testing/NativeArtifacts.cs index 550238c04..8f608ff69 100644 --- a/src/Neo.SmartContract.Testing/NativeArtifacts.cs +++ b/src/Neo.SmartContract.Testing/NativeArtifacts.cs @@ -155,6 +155,8 @@ public UInt160 GetCommitteeAddress() /// Initialize native contracts public void Initialize(bool commit = false) { + _engine.Transaction.Script = Array.Empty(); // Store the script in the current transaction + var genesis = NeoSystem.CreateGenesisBlock(_engine.ProtocolSettings); using SnapshotCache snapshot = new(_engine.Storage.Snapshot); @@ -166,7 +168,6 @@ public void Initialize(bool commit = false) using (var engine = ApplicationEngine.Create(TriggerType.OnPersist, genesis, snapshot, genesis, _engine.ProtocolSettings)) { - engine.LoadScript(Array.Empty()); method!.Invoke(native, new object[] { engine }); diff --git a/src/Neo.SmartContract.Testing/SmartContract.cs b/src/Neo.SmartContract.Testing/SmartContract.cs index dc046580d..a6e8c2a8f 100644 --- a/src/Neo.SmartContract.Testing/SmartContract.cs +++ b/src/Neo.SmartContract.Testing/SmartContract.cs @@ -43,6 +43,7 @@ internal StackItem Invoke(string methodName, params object[] args) using ScriptBuilder script = new(); script.EmitDynamicCall(Hash, methodName, args); + _engine.Transaction.Script = script.ToArray(); // Store the script in the current transaction // Execute in neo VM From 3d8a9a698f4c1fc00501da8e0c32ef5157db32de Mon Sep 17 00:00:00 2001 From: Fernando Diaz Toledano Date: Sat, 10 Feb 2024 20:16:28 +0100 Subject: [PATCH 040/106] Allow to set the Gas --- src/Neo.SmartContract.Testing/NativeArtifacts.cs | 4 ++-- src/Neo.SmartContract.Testing/SmartContract.cs | 2 +- src/Neo.SmartContract.Testing/TestEngine.cs | 5 +++++ 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/src/Neo.SmartContract.Testing/NativeArtifacts.cs b/src/Neo.SmartContract.Testing/NativeArtifacts.cs index 8f608ff69..a1c921792 100644 --- a/src/Neo.SmartContract.Testing/NativeArtifacts.cs +++ b/src/Neo.SmartContract.Testing/NativeArtifacts.cs @@ -166,7 +166,7 @@ public void Initialize(bool commit = false) var method = native.GetType().GetMethod("OnPersist", BindingFlags.NonPublic | BindingFlags.Instance); - using (var engine = ApplicationEngine.Create(TriggerType.OnPersist, genesis, snapshot, genesis, _engine.ProtocolSettings)) + using (var engine = ApplicationEngine.Create(TriggerType.OnPersist, genesis, snapshot, genesis, _engine.ProtocolSettings, _engine.Gas)) { engine.LoadScript(Array.Empty()); method!.Invoke(native, new object[] { engine }); @@ -179,7 +179,7 @@ public void Initialize(bool commit = false) method = native.GetType().GetMethod("PostPersist", BindingFlags.NonPublic | BindingFlags.Instance); - using (var engine = ApplicationEngine.Create(TriggerType.OnPersist, genesis, snapshot, genesis, _engine.ProtocolSettings)) + using (var engine = ApplicationEngine.Create(TriggerType.OnPersist, genesis, snapshot, genesis, _engine.ProtocolSettings, _engine.Gas)) { engine.LoadScript(Array.Empty()); diff --git a/src/Neo.SmartContract.Testing/SmartContract.cs b/src/Neo.SmartContract.Testing/SmartContract.cs index a6e8c2a8f..127091e9a 100644 --- a/src/Neo.SmartContract.Testing/SmartContract.cs +++ b/src/Neo.SmartContract.Testing/SmartContract.cs @@ -48,7 +48,7 @@ internal StackItem Invoke(string methodName, params object[] args) // Execute in neo VM using var engine = ApplicationEngine.Create(TriggerType.Application, - _engine.Transaction, snapshot, _engine.CurrentBlock, _engine.ProtocolSettings); + _engine.Transaction, snapshot, _engine.CurrentBlock, _engine.ProtocolSettings, _engine.Gas); engine.LoadScript(script.ToArray()); diff --git a/src/Neo.SmartContract.Testing/TestEngine.cs b/src/Neo.SmartContract.Testing/TestEngine.cs index b08896746..27c7cde55 100644 --- a/src/Neo.SmartContract.Testing/TestEngine.cs +++ b/src/Neo.SmartContract.Testing/TestEngine.cs @@ -91,6 +91,11 @@ public class TestEngine /// public Transaction Transaction { get; set; } + /// + /// Gas + /// + public long Gas = ApplicationEngine.TestModeGas; + /// /// Sender /// From c3d3c611239feed62c7c3b93df4be94235ac79b0 Mon Sep 17 00:00:00 2001 From: Fernando Diaz Toledano Date: Sat, 10 Feb 2024 20:27:10 +0100 Subject: [PATCH 041/106] Clean code --- src/Neo.SmartContract.Testing/TestEngine.cs | 33 +++-------- .../TestExtensions.cs | 7 +-- .../TestEngineTests.cs | 57 ------------------- 3 files changed, 10 insertions(+), 87 deletions(-) diff --git a/src/Neo.SmartContract.Testing/TestEngine.cs b/src/Neo.SmartContract.Testing/TestEngine.cs index 27c7cde55..8e0ffc182 100644 --- a/src/Neo.SmartContract.Testing/TestEngine.cs +++ b/src/Neo.SmartContract.Testing/TestEngine.cs @@ -15,6 +15,7 @@ namespace Neo.SmartContract.Testing public class TestEngine { private readonly Dictionary> _contracts = new(); + private NativeArtifacts? _native; /// /// Default Protocol Settings @@ -50,14 +51,7 @@ public class TestEngine ECPoint.Parse("02cd5a5547119e24feaa7c2a0f37b8c9366216bab7054de0065c9be42084003c8a", ECCurve.Secp256r1) }, ValidatorsCount = 7, - SeedList = new[] - { - "seed1.neo.org:10333", - "seed2.neo.org:10333", - "seed3.neo.org:10333", - "seed4.neo.org:10333", - "seed5.neo.org:10333" - }, + SeedList = System.Array.Empty(), MillisecondsPerBlock = ProtocolSettings.Default.MillisecondsPerBlock, MaxTransactionsPerBlock = ProtocolSettings.Default.MaxTransactionsPerBlock, MemoryPoolMaxTransactions = ProtocolSettings.Default.MemoryPoolMaxTransactions, @@ -101,8 +95,6 @@ public class TestEngine /// public UInt160 Sender => Transaction.Sender; - private NativeArtifacts? _native; - /// /// Native artifacts /// @@ -189,12 +181,6 @@ private void ApplicationEngine_Log(object? sender, LogEventArgs e) } } - public void Log(UInt160 scriptHash, string message) => - ApplicationEngine_Log(null, new LogEventArgs(Transaction, scriptHash, message)); - - public void Notify(UInt160 scriptHash, string eventName, VM.Types.Array state) => - ApplicationEngine_Notify(null, new NotifyEventArgs(Transaction, scriptHash, eventName, state)); - #endregion /// @@ -253,21 +239,17 @@ private T MockContract(UInt160 hash) where T : SmartContract CallBase = true }; - // Mock sc here + // Mock SmartContract foreach (var method in typeof(T).GetMethods()) { if (!method.IsAbstract) continue; - // Get methods + // Get args - Type[] args = new Type[method.GetParameters().Length]; - for (int x = 0; x < args.Length; x++) - { - args[x] = method.GetParameters()[x].ParameterType; - } + Type[] args = method.GetParameters().Select(u => u.ParameterType).ToArray(); - // Mock by return type + // Mock by ReturnType if (method.ReturnType != typeof(void)) { @@ -292,7 +274,8 @@ private T MockContract(UInt160 hash) where T : SmartContract _contracts[hash] = new List(new SmartContract[] { mock.Object }); } - // return mocked sc + // return mocked SmartContract + return mock.Object; } } diff --git a/src/Neo.SmartContract.Testing/TestExtensions.cs b/src/Neo.SmartContract.Testing/TestExtensions.cs index 792b80b0c..10c8e9644 100644 --- a/src/Neo.SmartContract.Testing/TestExtensions.cs +++ b/src/Neo.SmartContract.Testing/TestExtensions.cs @@ -91,12 +91,9 @@ public static StackItem ConvertToStackItem(this object data) if (type == typeof(Cryptography.ECC.ECPoint)) return Cryptography.ECC.ECPoint.FromBytes(stackItem.GetSpan().ToArray(), Cryptography.ECC.ECCurve.Secp256r1); - if (type == typeof(List)) + if (type == typeof(List) && stackItem is CompoundType cp) { - if (stackItem is CompoundType cp) - { - return new List(cp.SubItems); - } + return new List(cp.SubItems); } throw new FormatException($"Impossible to convert {stackItem} to {type}"); diff --git a/tests/Neo.SmartContract.Testing.UnitTests/TestEngineTests.cs b/tests/Neo.SmartContract.Testing.UnitTests/TestEngineTests.cs index d6162a294..6fc8c654b 100644 --- a/tests/Neo.SmartContract.Testing.UnitTests/TestEngineTests.cs +++ b/tests/Neo.SmartContract.Testing.UnitTests/TestEngineTests.cs @@ -1,10 +1,6 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; -using Neo.IO; -using Neo.VM.Types; -using System; using System.Collections.Generic; using System.IO; -using System.Linq; namespace Neo.SmartContract.Testing.UnitTests { @@ -61,58 +57,5 @@ public void FromHashTest() Assert.AreEqual(contract.Hash, hash); } - - [TestMethod] - public void TestLog() - { - UInt160 hash = UInt160.Parse("0x1230000000000000000000000000000000000000"); - TestEngine engine = new(); - - var contractLog = false; - var contract = engine.FromHash(hash, false); - contract.OnLog += (msg) => - { - contractLog = true; - }; - - var neoLog = false; - engine.Native.Initialize(); - engine.Native.NEO.OnLog += (msg) => - { - neoLog = true; - }; - - engine.Log(contract.Hash, "test"); - - Assert.IsTrue(contractLog); - Assert.IsFalse(neoLog); - } - - [TestMethod] - public void TestNotification() - { - TestEngine engine = new(); - - var neoLog = false; - engine.Native.Initialize(); - engine.Native.NEO.CandidateStateChanged += (pubKey, registered, votes) => - { - neoLog = pubKey == engine.ProtocolSettings.StandbyCommittee.First() && votes == 123 && registered; - }; - - // public delegate void delCandidateStateChanged(ECPoint pubkey, bool registered, BigInteger votes); - // public event delCandidateStateChanged? CandidateStateChanged; - - engine.Notify(engine.Native.NEO.Hash, "CandidateStateChanged", - new VM.Types.Array(new StackItem[] - { - new ByteString(engine.ProtocolSettings.StandbyCommittee.First().ToArray()), - StackItem.True, - new Integer(123), - } - )); - - Assert.IsTrue(neoLog); - } } } From 1d5b0ed92b8e337d4810a2d7eb7c944149ffb6e2 Mon Sep 17 00:00:00 2001 From: Fernando Diaz Toledano Date: Sat, 10 Feb 2024 20:29:33 +0100 Subject: [PATCH 042/106] Reduce changes --- .../templates/neocontractnep17/Contract1.cs | 42 ++++++++++--------- 1 file changed, 22 insertions(+), 20 deletions(-) diff --git a/src/Neo.SmartContract.Template/templates/neocontractnep17/Contract1.cs b/src/Neo.SmartContract.Template/templates/neocontractnep17/Contract1.cs index 09c77719e..c05084d54 100644 --- a/src/Neo.SmartContract.Template/templates/neocontractnep17/Contract1.cs +++ b/src/Neo.SmartContract.Template/templates/neocontractnep17/Contract1.cs @@ -1,4 +1,5 @@ using Neo; +using Neo.SmartContract; using Neo.SmartContract.Framework; using Neo.SmartContract.Framework.Attributes; using Neo.SmartContract.Framework.Native; @@ -24,10 +25,19 @@ public class Contract1 : Nep17Token private const byte Prefix_Owner = 0xff; + // TODO: Replace it with your own address. + [InitialValue("", Neo.SmartContract.ContractParameterType.Hash160)] + private static readonly UInt160 InitialOwner = default; + [Safe] public static UInt160 GetOwner() { - return (UInt160)Storage.Get(new[] { Prefix_Owner }); + var currentOwner = Storage.Get(new[] { Prefix_Owner }); + + if (currentOwner == null) + return InitialOwner; + + return (UInt160)currentOwner; } private static bool IsOwner() => @@ -42,22 +52,24 @@ public static void SetOwner(UInt160 newOwner) { if (IsOwner() == false) throw new InvalidOperationException("No Authorization!"); - - ExecutionEngine.Assert(newOwner.IsValid && !newOwner.IsZero, "owner must be valid"); - - Storage.Put(new[] { Prefix_Owner }, newOwner); - OnSetOwner(newOwner); + if (newOwner != null && newOwner.IsValid) + { + Storage.Put(new[] { Prefix_Owner }, newOwner); + OnSetOwner(newOwner); + } } #endregion #region NEP17 - // TODO: Replace "EXAMPLE" with a short name all UPPERCASE 3-8 characters - public override string Symbol { [Safe] get => "EXAMPLE"; } - // NOTE: Valid Range 0-31 - public override byte Decimals { [Safe] get => 8; } + [Safe] + public override byte Decimals() => 8; + + // TODO: Replace "EXAMPLE" with a short name all UPPERCASE 3-8 characters + [Safe] + public override string Symbol() => "EXAMPLE"; public static new void Burn(UInt160 account, BigInteger amount) { @@ -129,16 +141,6 @@ public static void _deploy(object data, bool update) return; } - // Init method, you must deploy the contract with the owner as an argument, or it will take the sender - if (data is null) data = Runtime.Transaction.Sender; - - UInt160 initialOwner = (UInt160)data; - - ExecutionEngine.Assert(initialOwner.IsValid && !initialOwner.IsZero, "owner must exists"); - - Storage.Put(new[] { Prefix_Owner }, initialOwner); - OnSetOwner(initialOwner); - // This will be executed during deploy Storage.Put(Storage.CurrentContext, "Hello", "World"); } From 4a45434cdc39a9f2ca03e6b6f8ab5a67a91344e1 Mon Sep 17 00:00:00 2001 From: Fernando Diaz Toledano Date: Sun, 11 Feb 2024 12:40:22 +0100 Subject: [PATCH 043/106] Change Snapshot --- .../NativeArtifacts.cs | 27 ++++++++----------- .../SmartContract.cs | 7 +++-- src/Neo.SmartContract.Testing/TestStorage.cs | 15 ++++++----- .../NativeArtifactsTests.cs | 5 ---- .../TestStorageTests.cs | 12 ++++----- 5 files changed, 28 insertions(+), 38 deletions(-) diff --git a/src/Neo.SmartContract.Testing/NativeArtifacts.cs b/src/Neo.SmartContract.Testing/NativeArtifacts.cs index a1c921792..e18c446b9 100644 --- a/src/Neo.SmartContract.Testing/NativeArtifacts.cs +++ b/src/Neo.SmartContract.Testing/NativeArtifacts.cs @@ -1,4 +1,4 @@ -using Neo.Persistence; +using Neo.Persistence; using System; using System.Reflection; @@ -144,9 +144,7 @@ public NativeArtifacts(TestEngine engine) /// public UInt160 GetCommitteeAddress() { - using SnapshotCache snapshot = new(_engine.Storage.Snapshot); - - return Native.NativeContract.NEO.GetCommitteeAddress(snapshot); + return Native.NativeContract.NEO.GetCommitteeAddress(_engine.Storage.Snapshot); } /// @@ -158,7 +156,6 @@ public void Initialize(bool commit = false) _engine.Transaction.Script = Array.Empty(); // Store the script in the current transaction var genesis = NeoSystem.CreateGenesisBlock(_engine.ProtocolSettings); - using SnapshotCache snapshot = new(_engine.Storage.Snapshot); foreach (var native in Native.NativeContract.Contracts) { @@ -166,31 +163,29 @@ public void Initialize(bool commit = false) var method = native.GetType().GetMethod("OnPersist", BindingFlags.NonPublic | BindingFlags.Instance); - using (var engine = ApplicationEngine.Create(TriggerType.OnPersist, genesis, snapshot, genesis, _engine.ProtocolSettings, _engine.Gas)) + DataCache clonedSnapshot = _engine.Storage.Snapshot.CreateSnapshot(); + using (var engine = ApplicationEngine.Create(TriggerType.OnPersist, genesis, clonedSnapshot, genesis, _engine.ProtocolSettings, _engine.Gas)) { engine.LoadScript(Array.Empty()); method!.Invoke(native, new object[] { engine }); - - snapshot.Commit(); - engine.Snapshot.Commit(); // Bug in MemoryStore + if (engine.Execute() != VM.VMState.HALT) + throw new Exception($"Error executing {native.Name}.OnPersist"); } // Mock Native.PostPersist method = native.GetType().GetMethod("PostPersist", BindingFlags.NonPublic | BindingFlags.Instance); - using (var engine = ApplicationEngine.Create(TriggerType.OnPersist, genesis, snapshot, genesis, _engine.ProtocolSettings, _engine.Gas)) + using (var engine = ApplicationEngine.Create(TriggerType.OnPersist, genesis, clonedSnapshot, genesis, _engine.ProtocolSettings, _engine.Gas)) { - engine.LoadScript(Array.Empty()); method!.Invoke(native, new object[] { engine }); - - snapshot.Commit(); - engine.Snapshot.Commit(); // Bug in MemoryStore + if (engine.Execute() != VM.VMState.HALT) + throw new Exception($"Error executing {native.Name}.OnPersist"); } - } - snapshot.Commit(); + clonedSnapshot.Commit(); + } if (commit) { diff --git a/src/Neo.SmartContract.Testing/SmartContract.cs b/src/Neo.SmartContract.Testing/SmartContract.cs index 127091e9a..228de8497 100644 --- a/src/Neo.SmartContract.Testing/SmartContract.cs +++ b/src/Neo.SmartContract.Testing/SmartContract.cs @@ -1,4 +1,3 @@ -using Neo.Persistence; using Neo.VM; using Neo.VM.Types; using System; @@ -37,8 +36,6 @@ protected SmartContract(TestEngine testEngine, UInt160 hash) /// Object internal StackItem Invoke(string methodName, params object[] args) { - using SnapshotCache snapshot = new(_engine.Storage.Snapshot); - // Compose script using ScriptBuilder script = new(); @@ -47,6 +44,8 @@ internal StackItem Invoke(string methodName, params object[] args) // Execute in neo VM + var snapshot = _engine.Storage.Snapshot.CreateSnapshot(); + using var engine = ApplicationEngine.Create(TriggerType.Application, _engine.Transaction, snapshot, _engine.CurrentBlock, _engine.ProtocolSettings, _engine.Gas); @@ -57,7 +56,7 @@ internal StackItem Invoke(string methodName, params object[] args) throw engine.FaultException ?? new Exception($"Error while executing {methodName}"); } - engine.Snapshot.Commit(); + snapshot.Commit(); // Return diff --git a/src/Neo.SmartContract.Testing/TestStorage.cs b/src/Neo.SmartContract.Testing/TestStorage.cs index 9d139d5c0..5f1c4fdaa 100644 --- a/src/Neo.SmartContract.Testing/TestStorage.cs +++ b/src/Neo.SmartContract.Testing/TestStorage.cs @@ -15,7 +15,7 @@ public class TestStorage /// /// Snapshot /// - public ISnapshot Snapshot { get; private set; } + public SnapshotCache Snapshot { get; private set; } /// /// Constructor @@ -24,7 +24,7 @@ public class TestStorage public TestStorage(IStore store) { Store = store; - Snapshot = Store.GetSnapshot(); + Snapshot = new SnapshotCache(Store.GetSnapshot()); } /// @@ -33,7 +33,6 @@ public TestStorage(IStore store) public void Commit() { Snapshot.Commit(); - Snapshot = Store.GetSnapshot(); } /// @@ -42,7 +41,7 @@ public void Commit() public void Rollback() { Snapshot.Dispose(); - Snapshot = Store.GetSnapshot(); + Snapshot = new SnapshotCache(Store.GetSnapshot()); } /// @@ -63,7 +62,7 @@ public void LoadFromJson(JObject json) { // "key":"value" in base64 - Snapshot.Put(Convert.FromBase64String(entry.Key), Convert.FromBase64String(str.Value)); + Snapshot.Add(new StorageKey(Convert.FromBase64String(entry.Key)), new StorageItem(Convert.FromBase64String(str.Value))); } else if (entry.Value is JObject obj) { @@ -73,8 +72,10 @@ public void LoadFromJson(JObject json) { if (subEntry.Value is JString subStr) { - Snapshot.Put(Convert.FromBase64String(entry.Key).Concat(Convert.FromBase64String(subEntry.Key)).ToArray(), - Convert.FromBase64String(subStr.Value)); + Snapshot.Add( + new StorageKey(Convert.FromBase64String(entry.Key).Concat(Convert.FromBase64String(subEntry.Key)).ToArray()), + new StorageItem(Convert.FromBase64String(subStr.Value)) + ); } } } diff --git a/tests/Neo.SmartContract.Testing.UnitTests/NativeArtifactsTests.cs b/tests/Neo.SmartContract.Testing.UnitTests/NativeArtifactsTests.cs index 4a761e0ba..8a5026e65 100644 --- a/tests/Neo.SmartContract.Testing.UnitTests/NativeArtifactsTests.cs +++ b/tests/Neo.SmartContract.Testing.UnitTests/NativeArtifactsTests.cs @@ -27,7 +27,6 @@ public void TestInitialize() public void TestTransfer() { var engine = new TestEngine(true); - engine.Storage.Commit(); // Bug in MemoryStore // Test set @@ -57,7 +56,6 @@ public void TestTransfer() Assert.IsTrue(engine.Native.NEO.transfer(engine.Transaction.Sender, wallet, 123, null)); Assert.IsTrue(raisedEvent); - engine.Storage.Commit(); // Bug in MemoryStore Assert.AreEqual(123, engine.Native.NEO.balanceOf(wallet)); } @@ -65,7 +63,6 @@ public void TestTransfer() public void TestSignature() { var engine = new TestEngine(true); - engine.Storage.Commit(); // Bug in MemoryStore // Test set @@ -84,8 +81,6 @@ public void TestSignature() engine.Native.NEO.setRegisterPrice(123); - engine.Storage.Commit(); // Bug in MemoryStore - Assert.AreEqual(123, engine.Native.NEO.getRegisterPrice()); // Invalid signature diff --git a/tests/Neo.SmartContract.Testing.UnitTests/TestStorageTests.cs b/tests/Neo.SmartContract.Testing.UnitTests/TestStorageTests.cs index 177d7ebe8..369496e5a 100644 --- a/tests/Neo.SmartContract.Testing.UnitTests/TestStorageTests.cs +++ b/tests/Neo.SmartContract.Testing.UnitTests/TestStorageTests.cs @@ -22,7 +22,7 @@ public void LoadFromJsonTest() // simple object - var json = @"{""a2V5"":""dmFsdWU=""}"; + var json = @"{""bXlSYXdLZXk="":""dmFsdWU=""}"; store.LoadFromJson((JObject)JToken.Parse(json)); store.Commit(); @@ -30,12 +30,12 @@ public void LoadFromJsonTest() entries = store.Store.Seek(Array.Empty(), SeekDirection.Forward).ToArray(); Assert.AreEqual(entries.Length, 1); - Assert.AreEqual("key", Encoding.ASCII.GetString(entries[0].Key)); + Assert.AreEqual("myRawKey", Encoding.ASCII.GetString(entries[0].Key)); Assert.AreEqual("value", Encoding.ASCII.GetString(entries[0].Value)); // prefix object - json = @"{""bXkt"":{""a2V5"":""bXktdmFsdWU=""}}"; + json = @"{""bXk="":{""UmF3S2V5LTI="":""dmFsdWUtMg==""}}"; store.LoadFromJson((JObject)JToken.Parse(json)); store.Commit(); @@ -43,11 +43,11 @@ public void LoadFromJsonTest() entries = store.Store.Seek(Array.Empty(), SeekDirection.Forward).ToArray(); Assert.AreEqual(entries.Length, 2); - Assert.AreEqual("key", Encoding.ASCII.GetString(entries[0].Key)); + Assert.AreEqual("myRawKey", Encoding.ASCII.GetString(entries[0].Key)); Assert.AreEqual("value", Encoding.ASCII.GetString(entries[0].Value)); - Assert.AreEqual("my-key", Encoding.ASCII.GetString(entries[1].Key)); - Assert.AreEqual("my-value", Encoding.ASCII.GetString(entries[1].Value)); + Assert.AreEqual("myRawKey-2", Encoding.ASCII.GetString(entries[1].Key)); + Assert.AreEqual("value-2", Encoding.ASCII.GetString(entries[1].Value)); } } } From dea0149d9ae65689fbf519cbe0a65cf696d74b78 Mon Sep 17 00:00:00 2001 From: Fernando Diaz Toledano Date: Sun, 11 Feb 2024 12:47:13 +0100 Subject: [PATCH 044/106] Change to Artifact to ArtifactExtensions --- src/Neo.Compiler.CSharp/Program.cs | 2 +- .../{Artifacts.cs => ArtifactExtensions.cs} | 15 ++++++++++----- .../ArtifactsTests.cs | 4 ++-- .../TestEngineTests.cs | 2 +- 4 files changed, 14 insertions(+), 9 deletions(-) rename src/Neo.SmartContract.Testing/{Artifacts.cs => ArtifactExtensions.cs} (94%) diff --git a/src/Neo.Compiler.CSharp/Program.cs b/src/Neo.Compiler.CSharp/Program.cs index f9a5c3599..cc46a4b27 100644 --- a/src/Neo.Compiler.CSharp/Program.cs +++ b/src/Neo.Compiler.CSharp/Program.cs @@ -180,7 +180,7 @@ private static int ProcessOutputs(Options options, string folder, CompilationCon // Create artifacts { path = Path.Combine(outputFolder, $"{baseName}.artifacts.cs"); - File.WriteAllText(path, Artifacts.CreateSourceFromManifest(baseName, manifest.Abi)); + File.WriteAllText(path, manifest.Abi.GetArtifactsSource(baseName)); Console.WriteLine($"Created {path}"); } if (options.Debug) diff --git a/src/Neo.SmartContract.Testing/Artifacts.cs b/src/Neo.SmartContract.Testing/ArtifactExtensions.cs similarity index 94% rename from src/Neo.SmartContract.Testing/Artifacts.cs rename to src/Neo.SmartContract.Testing/ArtifactExtensions.cs index f7928005e..70b597e43 100644 --- a/src/Neo.SmartContract.Testing/Artifacts.cs +++ b/src/Neo.SmartContract.Testing/ArtifactExtensions.cs @@ -5,15 +5,15 @@ namespace Neo.SmartContract.Testing { - public class Artifacts + public static class ArtifactExtensions { /// - /// Create source code from contract Abi + /// Get source code from contract Abi /// - /// Contract name /// Abi + /// Contract name /// Source - public static string CreateSourceFromManifest(string name, ContractAbi abi) + public static string GetArtifactsSource(this ContractAbi abi, string name) { StringBuilder sourceCode = new(); @@ -81,7 +81,12 @@ public static string CreateSourceFromManifest(string name, ContractAbi abi) sourceCode.AppendLine("}"); - return sourceCode.ToString(); + if (Environment.NewLine.Length == 2) + { + return sourceCode.ToString().Replace("\r\n", "\n").Trim(); + } + + return sourceCode.ToString().TrimEnd(); } /// diff --git a/tests/Neo.SmartContract.Testing.UnitTests/ArtifactsTests.cs b/tests/Neo.SmartContract.Testing.UnitTests/ArtifactsTests.cs index 4a525ed0d..a60e875d9 100644 --- a/tests/Neo.SmartContract.Testing.UnitTests/ArtifactsTests.cs +++ b/tests/Neo.SmartContract.Testing.UnitTests/ArtifactsTests.cs @@ -8,14 +8,14 @@ namespace Neo.SmartContract.Testing.UnitTests public class ArtifactsTests { [TestMethod] - public void TestCreateSourceFromManifest() + public void TestGetArtifactsSource() { var manifest = ContractManifest.FromJson(JToken.Parse( @"{""name"":""Contract1"",""groups"":[],""features"":{},""supportedstandards"":[""NEP-17""],""abi"":{""methods"":[{""name"":""symbol"",""parameters"":[],""returntype"":""String"",""offset"":1406,""safe"":true},{""name"":""decimals"",""parameters"":[],""returntype"":""Integer"",""offset"":1421,""safe"":true},{""name"":""totalSupply"",""parameters"":[],""returntype"":""Integer"",""offset"":43,""safe"":true},{""name"":""balanceOf"",""parameters"":[{""name"":""owner"",""type"":""Hash160""}],""returntype"":""Integer"",""offset"":85,""safe"":true},{""name"":""transfer"",""parameters"":[{""name"":""from"",""type"":""Hash160""},{""name"":""to"",""type"":""Hash160""},{""name"":""amount"",""type"":""Integer""},{""name"":""data"",""type"":""Any""}],""returntype"":""Boolean"",""offset"":281,""safe"":false},{""name"":""getOwner"",""parameters"":[],""returntype"":""Hash160"",""offset"":711,""safe"":true},{""name"":""setOwner"",""parameters"":[{""name"":""newOwner"",""type"":""Hash160""}],""returntype"":""Void"",""offset"":755,""safe"":false},{""name"":""burn"",""parameters"":[{""name"":""account"",""type"":""Hash160""},{""name"":""amount"",""type"":""Integer""}],""returntype"":""Void"",""offset"":873,""safe"":false},{""name"":""mint"",""parameters"":[{""name"":""to"",""type"":""Hash160""},{""name"":""amount"",""type"":""Integer""}],""returntype"":""Void"",""offset"":915,""safe"":false},{""name"":""withdraw"",""parameters"":[{""name"":""token"",""type"":""Hash160""},{""name"":""to"",""type"":""Hash160""},{""name"":""amount"",""type"":""Integer""}],""returntype"":""Boolean"",""offset"":957,""safe"":false},{""name"":""onNEP17Payment"",""parameters"":[{""name"":""from"",""type"":""Hash160""},{""name"":""amount"",""type"":""Integer""},{""name"":""data"",""type"":""Any""}],""returntype"":""Void"",""offset"":1139,""safe"":false},{""name"":""verify"",""parameters"":[],""returntype"":""Boolean"",""offset"":1203,""safe"":true},{""name"":""myMethod"",""parameters"":[],""returntype"":""String"",""offset"":1209,""safe"":false},{""name"":""_deploy"",""parameters"":[{""name"":""data"",""type"":""Any""},{""name"":""update"",""type"":""Boolean""}],""returntype"":""Void"",""offset"":1229,""safe"":false},{""name"":""update"",""parameters"":[{""name"":""nefFile"",""type"":""ByteArray""},{""name"":""manifest"",""type"":""String""}],""returntype"":""Void"",""offset"":1352,""safe"":false},{""name"":""_initialize"",""parameters"":[],""returntype"":""Void"",""offset"":1390,""safe"":false}],""events"":[{""name"":""Transfer"",""parameters"":[{""name"":""from"",""type"":""Hash160""},{""name"":""to"",""type"":""Hash160""},{""name"":""amount"",""type"":""Integer""}]},{""name"":""SetOwner"",""parameters"":[{""name"":""newOwner"",""type"":""Hash160""}]}]},""permissions"":[{""contract"":""*"",""methods"":""*""}],""trusts"":[],""extra"":{""Author"":""\u003CYour Name Or Company Here\u003E"",""Description"":""\u003CDescription Here\u003E"",""Email"":""\u003CYour Public Email Here\u003E"",""Version"":""\u003CVersion String Here\u003E""}}") as JObject); // Create artifacts - var source = Artifacts.CreateSourceFromManifest(manifest.Name, manifest.Abi).Replace("\r\n", "\n").Trim(); + var source = manifest.Abi.GetArtifactsSource(manifest.Name); Assert.AreEqual(source, @" using Neo.Cryptography.ECC; diff --git a/tests/Neo.SmartContract.Testing.UnitTests/TestEngineTests.cs b/tests/Neo.SmartContract.Testing.UnitTests/TestEngineTests.cs index 6fc8c654b..9784a1825 100644 --- a/tests/Neo.SmartContract.Testing.UnitTests/TestEngineTests.cs +++ b/tests/Neo.SmartContract.Testing.UnitTests/TestEngineTests.cs @@ -13,7 +13,7 @@ public void GenerateNativeArtifacts() foreach (var n in Native.NativeContract.Contracts) { var manifest = n.Manifest; - var source = Artifacts.CreateSourceFromManifest(manifest.Name, manifest.Abi).Replace("\r\n", "\n").Trim(); + var source = manifest.Abi.GetArtifactsSource(manifest.Name); var fullPath = Path.GetFullPath($"../../../../../src/Neo.SmartContract.Testing/Native/{manifest.Name}.cs"); File.WriteAllText(fullPath, source); From 7bc66de4bd06b609bcf5cee2c6f99aa45aa7247f Mon Sep 17 00:00:00 2001 From: Fernando Diaz Toledano Date: Sun, 11 Feb 2024 12:49:53 +0100 Subject: [PATCH 045/106] Clean code --- .../SmartContract.cs | 19 +-------------- .../TestExtensions.cs | 24 +++++++++++++++++++ 2 files changed, 25 insertions(+), 18 deletions(-) diff --git a/src/Neo.SmartContract.Testing/SmartContract.cs b/src/Neo.SmartContract.Testing/SmartContract.cs index 228de8497..0ce7c10f5 100644 --- a/src/Neo.SmartContract.Testing/SmartContract.cs +++ b/src/Neo.SmartContract.Testing/SmartContract.cs @@ -92,29 +92,12 @@ internal void InvokeOnNotify(string eventName, VM.Types.Array state) // Invoke - var args = Convert(state, del.Method.GetParameters()); + var args = state.ConvertTo(del.Method.GetParameters()); foreach (var handler in del.GetInvocationList()) { handler.Method.Invoke(handler.Target, args); } } - - private static object?[]? Convert(VM.Types.Array state, ParameterInfo[] parameterInfos) - { - if (parameterInfos.Length > 0) - { - object?[] args = new object[parameterInfos.Length]; - - for (int x = 0; x < parameterInfos.Length; x++) - { - args[x] = state[x].ConvertTo(parameterInfos[x].ParameterType); - } - - return args; - } - - return null; - } } } diff --git a/src/Neo.SmartContract.Testing/TestExtensions.cs b/src/Neo.SmartContract.Testing/TestExtensions.cs index 10c8e9644..e0c0a8a94 100644 --- a/src/Neo.SmartContract.Testing/TestExtensions.cs +++ b/src/Neo.SmartContract.Testing/TestExtensions.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; using System.Numerics; +using System.Reflection; namespace Neo.SmartContract.Testing { @@ -62,6 +63,29 @@ public static StackItem ConvertToStackItem(this object data) return StackItem.Null; } + /// + /// Convert Array stack item to dotnet array + /// + /// Item + /// Parameters + /// Object + public static object?[]? ConvertTo(this VM.Types.Array state, ParameterInfo[] parameters) + { + if (parameters.Length > 0) + { + object?[] args = new object[parameters.Length]; + + for (int x = 0; x < parameters.Length; x++) + { + args[x] = state[x].ConvertTo(parameters[x].ParameterType); + } + + return args; + } + + return null; + } + /// /// Convert stack item to dotnet /// From 3c57448d75c14ac1e530e755258cf687abd2c9bb Mon Sep 17 00:00:00 2001 From: Fernando Diaz Toledano Date: Sun, 11 Feb 2024 13:02:35 +0100 Subject: [PATCH 046/106] Move to Extensions folder --- src/Neo.Compiler.CSharp/Program.cs | 2 +- .../{ => Extensions}/ArtifactExtensions.cs | 2 +- .../{ => Extensions}/MockExtensions.cs | 2 +- .../{ => Extensions}/TestExtensions.cs | 24 +++++++++---------- .../SmartContract.cs | 1 + src/Neo.SmartContract.Testing/TestEngine.cs | 1 + .../ArtifactExtensionsTests.cs} | 5 ++-- .../TestEngineTests.cs | 1 + 8 files changed, 21 insertions(+), 17 deletions(-) rename src/Neo.SmartContract.Testing/{ => Extensions}/ArtifactExtensions.cs (99%) rename src/Neo.SmartContract.Testing/{ => Extensions}/MockExtensions.cs (98%) rename src/Neo.SmartContract.Testing/{ => Extensions}/TestExtensions.cs (84%) rename tests/Neo.SmartContract.Testing.UnitTests/{ArtifactsTests.cs => Extensions/ArtifactExtensionsTests.cs} (97%) diff --git a/src/Neo.Compiler.CSharp/Program.cs b/src/Neo.Compiler.CSharp/Program.cs index cc46a4b27..08360d60a 100644 --- a/src/Neo.Compiler.CSharp/Program.cs +++ b/src/Neo.Compiler.CSharp/Program.cs @@ -14,7 +14,7 @@ using Neo.Optimizer; using Neo.SmartContract; using Neo.SmartContract.Manifest; -using Neo.SmartContract.Testing; +using Neo.SmartContract.Testing.Extensions; using System; using System.CommandLine; using System.CommandLine.Invocation; diff --git a/src/Neo.SmartContract.Testing/ArtifactExtensions.cs b/src/Neo.SmartContract.Testing/Extensions/ArtifactExtensions.cs similarity index 99% rename from src/Neo.SmartContract.Testing/ArtifactExtensions.cs rename to src/Neo.SmartContract.Testing/Extensions/ArtifactExtensions.cs index 70b597e43..8325bfe0b 100644 --- a/src/Neo.SmartContract.Testing/ArtifactExtensions.cs +++ b/src/Neo.SmartContract.Testing/Extensions/ArtifactExtensions.cs @@ -3,7 +3,7 @@ using System.Linq; using System.Text; -namespace Neo.SmartContract.Testing +namespace Neo.SmartContract.Testing.Extensions { public static class ArtifactExtensions { diff --git a/src/Neo.SmartContract.Testing/MockExtensions.cs b/src/Neo.SmartContract.Testing/Extensions/MockExtensions.cs similarity index 98% rename from src/Neo.SmartContract.Testing/MockExtensions.cs rename to src/Neo.SmartContract.Testing/Extensions/MockExtensions.cs index 39e94c8b8..7b280bb5f 100644 --- a/src/Neo.SmartContract.Testing/MockExtensions.cs +++ b/src/Neo.SmartContract.Testing/Extensions/MockExtensions.cs @@ -4,7 +4,7 @@ using System.Linq.Expressions; using System.Reflection; -namespace Neo.SmartContract.Testing +namespace Neo.SmartContract.Testing.Extensions { internal static class MockExtensions { diff --git a/src/Neo.SmartContract.Testing/TestExtensions.cs b/src/Neo.SmartContract.Testing/Extensions/TestExtensions.cs similarity index 84% rename from src/Neo.SmartContract.Testing/TestExtensions.cs rename to src/Neo.SmartContract.Testing/Extensions/TestExtensions.cs index e0c0a8a94..69c530e98 100644 --- a/src/Neo.SmartContract.Testing/TestExtensions.cs +++ b/src/Neo.SmartContract.Testing/Extensions/TestExtensions.cs @@ -5,7 +5,7 @@ using System.Numerics; using System.Reflection; -namespace Neo.SmartContract.Testing +namespace Neo.SmartContract.Testing.Extensions { public static class TestExtensions { @@ -22,15 +22,15 @@ public static StackItem ConvertToStackItem(this object data) if (data is byte[] d) return (ByteString)d; if (data is ReadOnlyMemory r) return (ByteString)r; - if (data is byte by) return (VM.Types.Integer)by; - if (data is sbyte sby) return (VM.Types.Integer)sby; - if (data is short i16) return (VM.Types.Integer)i16; - if (data is ushort ui16) return (VM.Types.Integer)ui16; - if (data is int i32) return (VM.Types.Integer)i32; - if (data is uint ui32) return (VM.Types.Integer)ui32; - if (data is long i64) return (VM.Types.Integer)i64; - if (data is ulong ui64) return (VM.Types.Integer)ui64; - if (data is BigInteger bi) return (VM.Types.Integer)bi; + if (data is byte by) return (Integer)by; + if (data is sbyte sby) return (Integer)sby; + if (data is short i16) return (Integer)i16; + if (data is ushort ui16) return (Integer)ui16; + if (data is int i32) return (Integer)i32; + if (data is uint ui32) return (Integer)ui32; + if (data is long i64) return (Integer)i64; + if (data is ulong ui64) return (Integer)ui64; + if (data is BigInteger bi) return (Integer)bi; if (data is UInt160 u160) return (ByteString)u160.ToArray(); if (data is UInt256 u256) return (ByteString)u256.ToArray(); @@ -42,7 +42,7 @@ public static StackItem ConvertToStackItem(this object data) foreach (object o in arr) { - ar.Add(ConvertToStackItem(o)); + ar.Add(o.ConvertToStackItem()); } return ar; @@ -54,7 +54,7 @@ public static StackItem ConvertToStackItem(this object data) foreach (object o in iarr) { - ar.Add(ConvertToStackItem(o)); + ar.Add(o.ConvertToStackItem()); } return ar; diff --git a/src/Neo.SmartContract.Testing/SmartContract.cs b/src/Neo.SmartContract.Testing/SmartContract.cs index 0ce7c10f5..9a1fc2552 100644 --- a/src/Neo.SmartContract.Testing/SmartContract.cs +++ b/src/Neo.SmartContract.Testing/SmartContract.cs @@ -1,3 +1,4 @@ +using Neo.SmartContract.Testing.Extensions; using Neo.VM; using Neo.VM.Types; using System; diff --git a/src/Neo.SmartContract.Testing/TestEngine.cs b/src/Neo.SmartContract.Testing/TestEngine.cs index 8e0ffc182..e5845c181 100644 --- a/src/Neo.SmartContract.Testing/TestEngine.cs +++ b/src/Neo.SmartContract.Testing/TestEngine.cs @@ -4,6 +4,7 @@ using Neo.Network.P2P.Payloads; using Neo.Persistence; using Neo.SmartContract.Manifest; +using Neo.SmartContract.Testing.Extensions; using Neo.VM.Types; using System; using System.Collections.Generic; diff --git a/tests/Neo.SmartContract.Testing.UnitTests/ArtifactsTests.cs b/tests/Neo.SmartContract.Testing.UnitTests/Extensions/ArtifactExtensionsTests.cs similarity index 97% rename from tests/Neo.SmartContract.Testing.UnitTests/ArtifactsTests.cs rename to tests/Neo.SmartContract.Testing.UnitTests/Extensions/ArtifactExtensionsTests.cs index a60e875d9..a45ea26c7 100644 --- a/tests/Neo.SmartContract.Testing.UnitTests/ArtifactsTests.cs +++ b/tests/Neo.SmartContract.Testing.UnitTests/Extensions/ArtifactExtensionsTests.cs @@ -1,11 +1,12 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; using Neo.Json; using Neo.SmartContract.Manifest; +using Neo.SmartContract.Testing.Extensions; -namespace Neo.SmartContract.Testing.UnitTests +namespace Neo.SmartContract.TestEngine.UnitTests.Extensions { [TestClass] - public class ArtifactsTests + public class ArtifactExtensionsTests { [TestMethod] public void TestGetArtifactsSource() diff --git a/tests/Neo.SmartContract.Testing.UnitTests/TestEngineTests.cs b/tests/Neo.SmartContract.Testing.UnitTests/TestEngineTests.cs index 9784a1825..2c0c6dda3 100644 --- a/tests/Neo.SmartContract.Testing.UnitTests/TestEngineTests.cs +++ b/tests/Neo.SmartContract.Testing.UnitTests/TestEngineTests.cs @@ -1,4 +1,5 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; +using Neo.SmartContract.Testing.Extensions; using System.Collections.Generic; using System.IO; From 4b1e448a05237d0a4d9224c740b684fb813a3839 Mon Sep 17 00:00:00 2001 From: Fernando Diaz Toledano Date: Sun, 11 Feb 2024 13:31:17 +0100 Subject: [PATCH 047/106] Fix Native initialization --- .../Extensions/TestExtensions.cs | 2 +- .../NativeArtifacts.cs | 19 ++++++++++++++++--- .../SmartContract.cs | 7 ++++++- 3 files changed, 23 insertions(+), 5 deletions(-) diff --git a/src/Neo.SmartContract.Testing/Extensions/TestExtensions.cs b/src/Neo.SmartContract.Testing/Extensions/TestExtensions.cs index 69c530e98..2a479c74c 100644 --- a/src/Neo.SmartContract.Testing/Extensions/TestExtensions.cs +++ b/src/Neo.SmartContract.Testing/Extensions/TestExtensions.cs @@ -94,7 +94,7 @@ public static StackItem ConvertToStackItem(this object data) /// Object public static object? ConvertTo(this StackItem stackItem, Type type) { - if (stackItem is null) return null; + if (stackItem is null || stackItem.IsNull) return null; if (type == typeof(bool)) return stackItem.GetBoolean(); if (type == typeof(string)) return stackItem.ToString(); diff --git a/src/Neo.SmartContract.Testing/NativeArtifacts.cs b/src/Neo.SmartContract.Testing/NativeArtifacts.cs index e18c446b9..ac722b266 100644 --- a/src/Neo.SmartContract.Testing/NativeArtifacts.cs +++ b/src/Neo.SmartContract.Testing/NativeArtifacts.cs @@ -157,7 +157,14 @@ public void Initialize(bool commit = false) var genesis = NeoSystem.CreateGenesisBlock(_engine.ProtocolSettings); - foreach (var native in Native.NativeContract.Contracts) + foreach (var native in new Native.NativeContract[] + { + Native.NativeContract.ContractManagement, + Native.NativeContract.Ledger, + Native.NativeContract.NEO, + Native.NativeContract.GAS + } + ) { // Mock Native.OnPersist @@ -167,7 +174,10 @@ public void Initialize(bool commit = false) using (var engine = ApplicationEngine.Create(TriggerType.OnPersist, genesis, clonedSnapshot, genesis, _engine.ProtocolSettings, _engine.Gas)) { engine.LoadScript(Array.Empty()); - method!.Invoke(native, new object[] { engine }); + if (method!.Invoke(native, new object[] { engine }) is not ContractTask task) + throw new Exception($"Error casting {native.Name}.OnPersist to ContractTask"); + + task.GetAwaiter().GetResult(); if (engine.Execute() != VM.VMState.HALT) throw new Exception($"Error executing {native.Name}.OnPersist"); } @@ -179,7 +189,10 @@ public void Initialize(bool commit = false) using (var engine = ApplicationEngine.Create(TriggerType.OnPersist, genesis, clonedSnapshot, genesis, _engine.ProtocolSettings, _engine.Gas)) { engine.LoadScript(Array.Empty()); - method!.Invoke(native, new object[] { engine }); + if (method!.Invoke(native, new object[] { engine }) is not ContractTask task) + throw new Exception($"Error casting {native.Name}.PostPersist to ContractTask"); + + task.GetAwaiter().GetResult(); if (engine.Execute() != VM.VMState.HALT) throw new Exception($"Error executing {native.Name}.OnPersist"); } diff --git a/src/Neo.SmartContract.Testing/SmartContract.cs b/src/Neo.SmartContract.Testing/SmartContract.cs index 9a1fc2552..de0257dc5 100644 --- a/src/Neo.SmartContract.Testing/SmartContract.cs +++ b/src/Neo.SmartContract.Testing/SmartContract.cs @@ -91,11 +91,16 @@ internal void InvokeOnNotify(string eventName, VM.Types.Array state) var del = evField.GetValue(this) as Delegate; if (del is null) return; + // Avoid parse if is not needed + + var invocations = del.GetInvocationList(); + if (invocations.Length == 0) return; + // Invoke var args = state.ConvertTo(del.Method.GetParameters()); - foreach (var handler in del.GetInvocationList()) + foreach (var handler in invocations) { handler.Method.Invoke(handler.Target, args); } From 670c24d3bf2b9a26ad954e62daef9b3a19df05ac Mon Sep 17 00:00:00 2001 From: Fernando Diaz Toledano Date: Sun, 11 Feb 2024 14:50:36 +0100 Subject: [PATCH 048/106] Allow Custom mocks --- src/Neo.SmartContract.Testing/CustomMock.cs | 17 ++++ .../Extensions/MockExtensions.cs | 19 ++++ .../NativeArtifacts.cs | 4 +- .../SmartContract.cs | 21 +---- src/Neo.SmartContract.Testing/TestEngine.cs | 93 ++++++++++++++++++- .../TestingApplicationEngine.cs | 92 ++++++++++++++++++ .../TestEngineTests.cs | 23 +++++ 7 files changed, 244 insertions(+), 25 deletions(-) create mode 100644 src/Neo.SmartContract.Testing/CustomMock.cs create mode 100644 src/Neo.SmartContract.Testing/TestingApplicationEngine.cs diff --git a/src/Neo.SmartContract.Testing/CustomMock.cs b/src/Neo.SmartContract.Testing/CustomMock.cs new file mode 100644 index 000000000..ce39327bc --- /dev/null +++ b/src/Neo.SmartContract.Testing/CustomMock.cs @@ -0,0 +1,17 @@ +using System.Reflection; + +namespace Neo.SmartContract.Testing +{ + internal class CustomMock + { + /// + /// Contract + /// + public required SmartContract Contract { get; init; } + + /// + /// Method + /// + public required MethodInfo Method { get; init; } + } +} diff --git a/src/Neo.SmartContract.Testing/Extensions/MockExtensions.cs b/src/Neo.SmartContract.Testing/Extensions/MockExtensions.cs index 7b280bb5f..0578e4931 100644 --- a/src/Neo.SmartContract.Testing/Extensions/MockExtensions.cs +++ b/src/Neo.SmartContract.Testing/Extensions/MockExtensions.cs @@ -8,8 +8,27 @@ namespace Neo.SmartContract.Testing.Extensions { internal static class MockExtensions { + private static readonly Type methodCallType = typeof(Mock).Assembly.GetType("Moq.MethodCall")!; private static readonly MethodInfo isAnyMethod = typeof(It).GetMethod(nameof(It.IsAny), BindingFlags.Public | BindingFlags.Static)!; + public static bool IsMocked(this Mock mock, MethodInfo method) + where T : SmartContract + { + var property = methodCallType.GetProperty("Method")!; + + foreach (var setup in mock.Setups) + { + if (setup.GetType() != methodCallType) continue; + + if (method.Equals(property.GetValue(setup))) + { + return true; + } + } + + return false; + } + private static MethodCallExpression BuildIsAnyExpressions(Type type) { return Expression.Call(isAnyMethod.MakeGenericMethod(type)); diff --git a/src/Neo.SmartContract.Testing/NativeArtifacts.cs b/src/Neo.SmartContract.Testing/NativeArtifacts.cs index ac722b266..d3f428750 100644 --- a/src/Neo.SmartContract.Testing/NativeArtifacts.cs +++ b/src/Neo.SmartContract.Testing/NativeArtifacts.cs @@ -171,7 +171,7 @@ public void Initialize(bool commit = false) var method = native.GetType().GetMethod("OnPersist", BindingFlags.NonPublic | BindingFlags.Instance); DataCache clonedSnapshot = _engine.Storage.Snapshot.CreateSnapshot(); - using (var engine = ApplicationEngine.Create(TriggerType.OnPersist, genesis, clonedSnapshot, genesis, _engine.ProtocolSettings, _engine.Gas)) + using (var engine = new TestingApplicationEngine(_engine, TriggerType.OnPersist, genesis, clonedSnapshot, genesis, _engine.ProtocolSettings, _engine.Gas)) { engine.LoadScript(Array.Empty()); if (method!.Invoke(native, new object[] { engine }) is not ContractTask task) @@ -186,7 +186,7 @@ public void Initialize(bool commit = false) method = native.GetType().GetMethod("PostPersist", BindingFlags.NonPublic | BindingFlags.Instance); - using (var engine = ApplicationEngine.Create(TriggerType.OnPersist, genesis, clonedSnapshot, genesis, _engine.ProtocolSettings, _engine.Gas)) + using (var engine = new TestingApplicationEngine(_engine, TriggerType.OnPersist, genesis, clonedSnapshot, genesis, _engine.ProtocolSettings, _engine.Gas)) { engine.LoadScript(Array.Empty()); if (method!.Invoke(native, new object[] { engine }) is not ContractTask task) diff --git a/src/Neo.SmartContract.Testing/SmartContract.cs b/src/Neo.SmartContract.Testing/SmartContract.cs index de0257dc5..2f26e8b45 100644 --- a/src/Neo.SmartContract.Testing/SmartContract.cs +++ b/src/Neo.SmartContract.Testing/SmartContract.cs @@ -43,26 +43,7 @@ internal StackItem Invoke(string methodName, params object[] args) script.EmitDynamicCall(Hash, methodName, args); _engine.Transaction.Script = script.ToArray(); // Store the script in the current transaction - // Execute in neo VM - - var snapshot = _engine.Storage.Snapshot.CreateSnapshot(); - - using var engine = ApplicationEngine.Create(TriggerType.Application, - _engine.Transaction, snapshot, _engine.CurrentBlock, _engine.ProtocolSettings, _engine.Gas); - - engine.LoadScript(script.ToArray()); - - if (engine.Execute() != VMState.HALT) - { - throw engine.FaultException ?? new Exception($"Error while executing {methodName}"); - } - - snapshot.Commit(); - - // Return - - if (engine.ResultStack.Count == 0) return StackItem.Null; - return engine.ResultStack.Pop(); + return _engine.Execute(script.ToArray()); } /// diff --git a/src/Neo.SmartContract.Testing/TestEngine.cs b/src/Neo.SmartContract.Testing/TestEngine.cs index e5845c181..010e98843 100644 --- a/src/Neo.SmartContract.Testing/TestEngine.cs +++ b/src/Neo.SmartContract.Testing/TestEngine.cs @@ -5,9 +5,11 @@ using Neo.Persistence; using Neo.SmartContract.Manifest; using Neo.SmartContract.Testing.Extensions; +using Neo.VM; using Neo.VM.Types; using System; using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Text; @@ -16,6 +18,7 @@ namespace Neo.SmartContract.Testing public class TestEngine { private readonly Dictionary> _contracts = new(); + private readonly Dictionary> _customMocks = new(); private NativeArtifacts? _native; /// @@ -217,10 +220,23 @@ public T Deploy(NefFile nef, ContractManifest manifest, object data) where T /// Check existence (default: true) /// Mocked Smart Contract public T FromHash(UInt160 hash, bool checkExistence = true) where T : SmartContract + { + return FromHash(hash, null, checkExistence); + } + + /// + /// Deploy Smart contract + /// + /// Type + /// Contract hash + /// Custom Mock + /// Check existence (default: true) + /// Mocked Smart Contract + public T FromHash(UInt160 hash, Action>? customMock = null, bool checkExistence = true) where T : SmartContract { if (!checkExistence) { - return MockContract(hash); + return MockContract(hash, customMock); } var ret = Native.ContractManagement.getContract(hash); @@ -230,22 +246,48 @@ public T FromHash(UInt160 hash, bool checkExistence = true) where T : SmartCo ContractState state = new(); ((IInteroperable)state).FromStackItem(new VM.Types.Array(ret.Select(u => (StackItem)u))); - return MockContract(state.Hash); + return MockContract(state.Hash, customMock); } - private T MockContract(UInt160 hash) where T : SmartContract + private T MockContract(UInt160 hash, Action>? customMock = null) where T : SmartContract { var mock = new Mock(this, hash) { CallBase = true }; + // User can mock specific calls + + customMock?.Invoke(mock); + // Mock SmartContract foreach (var method in typeof(T).GetMethods()) { if (!method.IsAbstract) continue; + // Avoid to mock already mocked by custom mocks + + if (mock.IsMocked(method)) + { + var mockName = method.Name + ";" + method.GetParameters().Length; + var cm = new CustomMock() { Contract = mock.Object, Method = method }; + + if (_customMocks.TryGetValue(hash, out var mocks)) + { + if (!mocks.TryAdd(mockName, cm)) + { + throw new Exception("The same method can't be mocked twice"); + } + } + else + { + _customMocks.Add(hash, new Dictionary() { { mockName, cm } }); + } + + continue; + } + // Get args Type[] args = method.GetParameters().Select(u => u.ParameterType).ToArray(); @@ -279,5 +321,50 @@ private T MockContract(UInt160 hash) where T : SmartContract return mock.Object; } + + internal bool TryGetCustomMock(UInt160 hash, string method, int rc, [NotNullWhen(true)] out CustomMock? mi) + { + if (_customMocks.TryGetValue(hash, out var mocks)) + { + var mockName = method + ";" + rc; + + if (mocks.TryGetValue(mockName, out mi)) + { + return true; + } + } + + mi = null; + return false; + } + + /// + /// Execute raw script + /// + /// Script + /// StackItem + public StackItem Execute(Script script) + { + // Execute in neo VM + + var snapshot = Storage.Snapshot.CreateSnapshot(); + + using var engine = new TestingApplicationEngine(this, TriggerType.Application, + Transaction, snapshot, CurrentBlock, ProtocolSettings, Gas); + + engine.LoadScript(script); + + if (engine.Execute() != VMState.HALT) + { + throw engine.FaultException ?? new Exception($"Error while executing the script"); + } + + snapshot.Commit(); + + // Return + + if (engine.ResultStack.Count == 0) return StackItem.Null; + return engine.ResultStack.Pop(); + } } } diff --git a/src/Neo.SmartContract.Testing/TestingApplicationEngine.cs b/src/Neo.SmartContract.Testing/TestingApplicationEngine.cs new file mode 100644 index 000000000..47e4ae592 --- /dev/null +++ b/src/Neo.SmartContract.Testing/TestingApplicationEngine.cs @@ -0,0 +1,92 @@ +using Neo.Network.P2P.Payloads; +using Neo.Persistence; +using Neo.SmartContract.Manifest; +using Neo.SmartContract.Native; +using Neo.SmartContract.Testing.Extensions; +using Neo.VM.Types; +using System; + +namespace Neo.SmartContract.Testing +{ + internal class TestingApplicationEngine : ApplicationEngine + { + /// + /// Testing engine + /// + public TestEngine Engine { get; } + + public TestingApplicationEngine(TestEngine engine, TriggerType trigger, IVerifiable container, DataCache snapshot, Block persistingBlock, ProtocolSettings settings, long gas) + : base(trigger, container, snapshot, persistingBlock, settings, gas, null) + { + Engine = engine; + } + + protected override void OnSysCall(InteropDescriptor descriptor) + { + if (descriptor.Hash == 1381727586 && descriptor.Name == "System.Contract.Call") + { + // Extract args + + StackItem[] originalArgs = new StackItem[descriptor.Parameters.Count]; + object[] parameters = new object[descriptor.Parameters.Count]; + for (int i = 0; i < parameters.Length; i++) + { + originalArgs[i] = Pop(); + parameters[i] = Convert(originalArgs[i], descriptor.Parameters[i]); + } + + if (parameters[0] is UInt160 contractHash && + parameters[1] is string method && + parameters[2] is CallFlags callFlags && + parameters[3] is VM.Types.Array args && + Engine.TryGetCustomMock(contractHash, method, args.Count, out var customMock)) + { + // Apply cost + + ValidateCallFlags(descriptor.RequiredCallFlags); + AddGas(descriptor.FixedPrice * ExecFeeFactor); + + // Redirect VM execution if the method is mocked + + if (method.StartsWith('_')) throw new ArgumentException($"Invalid Method Name: {method}"); + if ((callFlags & ~CallFlags.All) != 0) + throw new ArgumentOutOfRangeException(nameof(callFlags)); + + ContractState contract = NativeContract.ContractManagement.GetContract(Snapshot, contractHash); + if (contract is null) throw new InvalidOperationException($"Called Contract Does Not Exist: {contractHash}"); + ContractMethodDescriptor md = contract.Manifest.Abi.GetMethod(method, args.Count); + if (md is null) throw new InvalidOperationException($"Method \"{method}\" with {args.Count} parameter(s) doesn't exist in the contract {contractHash}."); + bool hasReturnValue = md.ReturnType != ContractParameterType.Void; + + // Convert args + + var methodParameters = customMock.Method.GetParameters(); + parameters = new object[args.Count]; + for (int i = 0; i < args.Count; i++) + { + parameters[i] = args[i].ConvertTo(methodParameters[i].ParameterType)!; + } + + // Invoke + + object returnValue = customMock.Method.Invoke(customMock.Contract, parameters); + if (hasReturnValue) + Push(Convert(returnValue)); + + return; + } + else + { + // Revert Pops and do default + + for (int i = parameters.Length - 1; i >= 0; i--) + { + Push(originalArgs[i]); + } + } + } + + base.OnSysCall(descriptor); + } + } +} diff --git a/tests/Neo.SmartContract.Testing.UnitTests/TestEngineTests.cs b/tests/Neo.SmartContract.Testing.UnitTests/TestEngineTests.cs index 2c0c6dda3..fff1704e9 100644 --- a/tests/Neo.SmartContract.Testing.UnitTests/TestEngineTests.cs +++ b/tests/Neo.SmartContract.Testing.UnitTests/TestEngineTests.cs @@ -1,5 +1,7 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; +using Moq; using Neo.SmartContract.Testing.Extensions; +using Neo.VM; using System.Collections.Generic; using System.IO; @@ -33,6 +35,27 @@ public void TestHashExists() Assert.IsInstanceOfType(engine.FromHash(engine.Native.NEO.Hash, true)); } + [TestMethod] + public void TestCustomMock() + { + TestEngine engine = new(true); + + var neo = engine.FromHash(engine.Native.NEO.Hash, + mock => mock.Setup(o => o.balanceOf(It.IsAny())).Returns(123), + false); + + // Test direct call + + Assert.AreEqual(123, neo.balanceOf(engine.BFTAddress)); + + // Test vm call + + using ScriptBuilder script = new(); + script.EmitDynamicCall(neo.Hash, nameof(neo.balanceOf), engine.BFTAddress); + + Assert.AreEqual(123, engine.Execute(script.ToArray()).GetInteger()); + } + [TestMethod] public void TestNativeContracts() { From dc3d33c2c66c485e5f265ef07ba775ea4a9de09c Mon Sep 17 00:00:00 2001 From: Fernando Diaz Toledano Date: Sun, 11 Feb 2024 14:57:16 +0100 Subject: [PATCH 049/106] Format --- src/Neo.SmartContract.Testing/NativeArtifacts.cs | 2 +- src/Neo.SmartContract.Testing/SmartContract.cs | 2 +- src/Neo.SmartContract.Testing/TestingApplicationEngine.cs | 8 +++----- 3 files changed, 5 insertions(+), 7 deletions(-) diff --git a/src/Neo.SmartContract.Testing/NativeArtifacts.cs b/src/Neo.SmartContract.Testing/NativeArtifacts.cs index d3f428750..6c43f013f 100644 --- a/src/Neo.SmartContract.Testing/NativeArtifacts.cs +++ b/src/Neo.SmartContract.Testing/NativeArtifacts.cs @@ -1,4 +1,4 @@ -using Neo.Persistence; +using Neo.Persistence; using System; using System.Reflection; diff --git a/src/Neo.SmartContract.Testing/SmartContract.cs b/src/Neo.SmartContract.Testing/SmartContract.cs index 2f26e8b45..db2489acb 100644 --- a/src/Neo.SmartContract.Testing/SmartContract.cs +++ b/src/Neo.SmartContract.Testing/SmartContract.cs @@ -1,4 +1,4 @@ -using Neo.SmartContract.Testing.Extensions; +using Neo.SmartContract.Testing.Extensions; using Neo.VM; using Neo.VM.Types; using System; diff --git a/src/Neo.SmartContract.Testing/TestingApplicationEngine.cs b/src/Neo.SmartContract.Testing/TestingApplicationEngine.cs index 47e4ae592..7e435b99c 100644 --- a/src/Neo.SmartContract.Testing/TestingApplicationEngine.cs +++ b/src/Neo.SmartContract.Testing/TestingApplicationEngine.cs @@ -41,13 +41,11 @@ parameters[2] is CallFlags callFlags && parameters[3] is VM.Types.Array args && Engine.TryGetCustomMock(contractHash, method, args.Count, out var customMock)) { - // Apply cost + // Do the same logic as ApplicationEngine ValidateCallFlags(descriptor.RequiredCallFlags); AddGas(descriptor.FixedPrice * ExecFeeFactor); - // Redirect VM execution if the method is mocked - if (method.StartsWith('_')) throw new ArgumentException($"Invalid Method Name: {method}"); if ((callFlags & ~CallFlags.All) != 0) throw new ArgumentOutOfRangeException(nameof(callFlags)); @@ -58,7 +56,7 @@ parameters[3] is VM.Types.Array args && if (md is null) throw new InvalidOperationException($"Method \"{method}\" with {args.Count} parameter(s) doesn't exist in the contract {contractHash}."); bool hasReturnValue = md.ReturnType != ContractParameterType.Void; - // Convert args + // Convert args to mocked method var methodParameters = customMock.Method.GetParameters(); parameters = new object[args.Count]; @@ -69,7 +67,7 @@ parameters[3] is VM.Types.Array args && // Invoke - object returnValue = customMock.Method.Invoke(customMock.Contract, parameters); + var returnValue = customMock.Method.Invoke(customMock.Contract, parameters); if (hasReturnValue) Push(Convert(returnValue)); From 6b7e35e4f414d88941d100b22bdf7b5cb1798e89 Mon Sep 17 00:00:00 2001 From: Fernando Diaz Toledano Date: Sun, 11 Feb 2024 15:03:00 +0100 Subject: [PATCH 050/106] some vars --- .../TestingApplicationEngine.cs | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/src/Neo.SmartContract.Testing/TestingApplicationEngine.cs b/src/Neo.SmartContract.Testing/TestingApplicationEngine.cs index 7e435b99c..49889b819 100644 --- a/src/Neo.SmartContract.Testing/TestingApplicationEngine.cs +++ b/src/Neo.SmartContract.Testing/TestingApplicationEngine.cs @@ -1,6 +1,5 @@ using Neo.Network.P2P.Payloads; using Neo.Persistence; -using Neo.SmartContract.Manifest; using Neo.SmartContract.Native; using Neo.SmartContract.Testing.Extensions; using Neo.VM.Types; @@ -23,12 +22,14 @@ public TestingApplicationEngine(TestEngine engine, TriggerType trigger, IVerifia protected override void OnSysCall(InteropDescriptor descriptor) { - if (descriptor.Hash == 1381727586 && descriptor.Name == "System.Contract.Call") + // Check if the syscall is a contract call and we need to mock it because it was defined by the user + + if (descriptor.Hash == 1381727586 && descriptor.Name == "System.Contract.Call" && descriptor.Parameters.Count == 4) { // Extract args - StackItem[] originalArgs = new StackItem[descriptor.Parameters.Count]; - object[] parameters = new object[descriptor.Parameters.Count]; + var originalArgs = new StackItem[descriptor.Parameters.Count]; + var parameters = new object[originalArgs.Length]; for (int i = 0; i < parameters.Length; i++) { originalArgs[i] = Pop(); @@ -50,11 +51,11 @@ parameters[3] is VM.Types.Array args && if ((callFlags & ~CallFlags.All) != 0) throw new ArgumentOutOfRangeException(nameof(callFlags)); - ContractState contract = NativeContract.ContractManagement.GetContract(Snapshot, contractHash); + var contract = NativeContract.ContractManagement.GetContract(Snapshot, contractHash); if (contract is null) throw new InvalidOperationException($"Called Contract Does Not Exist: {contractHash}"); - ContractMethodDescriptor md = contract.Manifest.Abi.GetMethod(method, args.Count); + var md = contract.Manifest.Abi.GetMethod(method, args.Count); if (md is null) throw new InvalidOperationException($"Method \"{method}\" with {args.Count} parameter(s) doesn't exist in the contract {contractHash}."); - bool hasReturnValue = md.ReturnType != ContractParameterType.Void; + var hasReturnValue = md.ReturnType != ContractParameterType.Void; // Convert args to mocked method From 37d9b2c971d1e36f5be05456caa0c40c5cfc3c2b Mon Sep 17 00:00:00 2001 From: Fernando Diaz Toledano Date: Sun, 11 Feb 2024 15:10:50 +0100 Subject: [PATCH 051/106] Add some summaries --- src/Neo.SmartContract.Testing/CustomMock.cs | 4 ++-- src/Neo.SmartContract.Testing/NativeArtifacts.cs | 3 +++ src/Neo.SmartContract.Testing/TestStorage.cs | 3 +++ src/Neo.SmartContract.Testing/TestingApplicationEngine.cs | 3 +++ 4 files changed, 11 insertions(+), 2 deletions(-) diff --git a/src/Neo.SmartContract.Testing/CustomMock.cs b/src/Neo.SmartContract.Testing/CustomMock.cs index ce39327bc..903f702c1 100644 --- a/src/Neo.SmartContract.Testing/CustomMock.cs +++ b/src/Neo.SmartContract.Testing/CustomMock.cs @@ -5,12 +5,12 @@ namespace Neo.SmartContract.Testing internal class CustomMock { /// - /// Contract + /// Mocked contract /// public required SmartContract Contract { get; init; } /// - /// Method + /// Mocked method /// public required MethodInfo Method { get; init; } } diff --git a/src/Neo.SmartContract.Testing/NativeArtifacts.cs b/src/Neo.SmartContract.Testing/NativeArtifacts.cs index 6c43f013f..f6b2477b9 100644 --- a/src/Neo.SmartContract.Testing/NativeArtifacts.cs +++ b/src/Neo.SmartContract.Testing/NativeArtifacts.cs @@ -4,6 +4,9 @@ namespace Neo.SmartContract.Testing { + /// + /// NativeArtifacts makes it easier to access native contracts + /// public class NativeArtifacts { private readonly TestEngine _engine; diff --git a/src/Neo.SmartContract.Testing/TestStorage.cs b/src/Neo.SmartContract.Testing/TestStorage.cs index 5f1c4fdaa..2c2b55361 100644 --- a/src/Neo.SmartContract.Testing/TestStorage.cs +++ b/src/Neo.SmartContract.Testing/TestStorage.cs @@ -5,6 +5,9 @@ namespace Neo.SmartContract.Testing { + /// + /// TestStorage centralizes the storage management of our TestEngine + /// public class TestStorage { /// diff --git a/src/Neo.SmartContract.Testing/TestingApplicationEngine.cs b/src/Neo.SmartContract.Testing/TestingApplicationEngine.cs index 49889b819..f01537d18 100644 --- a/src/Neo.SmartContract.Testing/TestingApplicationEngine.cs +++ b/src/Neo.SmartContract.Testing/TestingApplicationEngine.cs @@ -7,6 +7,9 @@ namespace Neo.SmartContract.Testing { + /// + /// TestingApplicationEngine is responsible for redirecting System.Contract.Call syscalls to their corresponding mock if necessary + /// internal class TestingApplicationEngine : ApplicationEngine { /// From aff569c1d11c8d490d2fbdde4d3d313e4e82e042 Mon Sep 17 00:00:00 2001 From: Fernando Diaz Toledano Date: Sun, 11 Feb 2024 15:16:09 +0100 Subject: [PATCH 052/106] Allow to mock undeployed contracts --- src/Neo.SmartContract.Testing/TestingApplicationEngine.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/Neo.SmartContract.Testing/TestingApplicationEngine.cs b/src/Neo.SmartContract.Testing/TestingApplicationEngine.cs index f01537d18..a540b11cc 100644 --- a/src/Neo.SmartContract.Testing/TestingApplicationEngine.cs +++ b/src/Neo.SmartContract.Testing/TestingApplicationEngine.cs @@ -54,11 +54,13 @@ parameters[3] is VM.Types.Array args && if ((callFlags & ~CallFlags.All) != 0) throw new ArgumentOutOfRangeException(nameof(callFlags)); + /* Note: we allow to mock undeployed contracts var contract = NativeContract.ContractManagement.GetContract(Snapshot, contractHash); if (contract is null) throw new InvalidOperationException($"Called Contract Does Not Exist: {contractHash}"); var md = contract.Manifest.Abi.GetMethod(method, args.Count); if (md is null) throw new InvalidOperationException($"Method \"{method}\" with {args.Count} parameter(s) doesn't exist in the contract {contractHash}."); var hasReturnValue = md.ReturnType != ContractParameterType.Void; + */ // Convert args to mocked method @@ -71,6 +73,7 @@ parameters[3] is VM.Types.Array args && // Invoke + var hasReturnValue = customMock.Method.ReturnType != typeof(void); var returnValue = customMock.Method.Invoke(customMock.Contract, parameters); if (hasReturnValue) Push(Convert(returnValue)); From 8324b1ac8ad00354756ec5d98193d5af423a6621 Mon Sep 17 00:00:00 2001 From: Fernando Diaz Toledano Date: Sun, 11 Feb 2024 15:20:18 +0100 Subject: [PATCH 053/106] Test undeployed mocked contracts --- .../TestEngineTests.cs | 27 ++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/tests/Neo.SmartContract.Testing.UnitTests/TestEngineTests.cs b/tests/Neo.SmartContract.Testing.UnitTests/TestEngineTests.cs index fff1704e9..214cab8d1 100644 --- a/tests/Neo.SmartContract.Testing.UnitTests/TestEngineTests.cs +++ b/tests/Neo.SmartContract.Testing.UnitTests/TestEngineTests.cs @@ -10,6 +10,12 @@ namespace Neo.SmartContract.Testing.UnitTests [TestClass] public class TestEngineTests { + public abstract class MyUndeployedContract : SmartContract + { + public abstract int myReturnMethod(); + protected MyUndeployedContract(TestEngine testEngine, UInt160 hash) : base(testEngine, hash) { } + } + //[TestMethod] public void GenerateNativeArtifacts() { @@ -50,10 +56,25 @@ public void TestCustomMock() // Test vm call - using ScriptBuilder script = new(); - script.EmitDynamicCall(neo.Hash, nameof(neo.balanceOf), engine.BFTAddress); + using (ScriptBuilder script = new()) + { + script.EmitDynamicCall(neo.Hash, nameof(neo.balanceOf), engine.BFTAddress); + + Assert.AreEqual(123, engine.Execute(script.ToArray()).GetInteger()); + } + + // Test mock on undeployed contract + + var undeployed = engine.FromHash(UInt160.Zero, + mock => mock.Setup(o => o.myReturnMethod()).Returns(1234), + false); + + using (ScriptBuilder script = new()) + { + script.EmitDynamicCall(UInt160.Zero, nameof(undeployed.myReturnMethod)); - Assert.AreEqual(123, engine.Execute(script.ToArray()).GetInteger()); + Assert.AreEqual(1234, engine.Execute(script.ToArray()).GetInteger()); + } } [TestMethod] From ca460ef23bb78bc013d0badef65034f949946c67 Mon Sep 17 00:00:00 2001 From: Fernando Diaz Toledano Date: Sun, 11 Feb 2024 15:26:47 +0100 Subject: [PATCH 054/106] Change init native to true by default --- src/Neo.SmartContract.Testing/TestEngine.cs | 4 ++-- .../NativeArtifactsTests.cs | 4 ++-- tests/Neo.SmartContract.Testing.UnitTests/TestEngineTests.cs | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/Neo.SmartContract.Testing/TestEngine.cs b/src/Neo.SmartContract.Testing/TestEngine.cs index 010e98843..99b775b4b 100644 --- a/src/Neo.SmartContract.Testing/TestEngine.cs +++ b/src/Neo.SmartContract.Testing/TestEngine.cs @@ -115,14 +115,14 @@ public NativeArtifacts Native /// Constructor /// /// Initialize native contracts - public TestEngine(bool initializeNativeContracts = false) : this(Default, initializeNativeContracts) { } + public TestEngine(bool initializeNativeContracts = true) : this(Default, initializeNativeContracts) { } /// /// Constructor /// /// Settings /// Initialize native contracts - public TestEngine(ProtocolSettings settings, bool initializeNativeContracts = false) + public TestEngine(ProtocolSettings settings, bool initializeNativeContracts = true) { ProtocolSettings = settings; CurrentBlock = NeoSystem.CreateGenesisBlock(ProtocolSettings); diff --git a/tests/Neo.SmartContract.Testing.UnitTests/NativeArtifactsTests.cs b/tests/Neo.SmartContract.Testing.UnitTests/NativeArtifactsTests.cs index 8a5026e65..54996e7dc 100644 --- a/tests/Neo.SmartContract.Testing.UnitTests/NativeArtifactsTests.cs +++ b/tests/Neo.SmartContract.Testing.UnitTests/NativeArtifactsTests.cs @@ -11,11 +11,11 @@ public class NativeArtifactsTests [TestMethod] public void TestInitialize() { - var engine = new TestEngine(); + var engine = new TestEngine(false); Assert.AreEqual(0, engine.Storage.Store.Seek(System.Array.Empty(), Persistence.SeekDirection.Forward).Count()); - engine.Native.Initialize(true); + engine.Native.Initialize(false); // Ensure that the main address contains the totalSupply diff --git a/tests/Neo.SmartContract.Testing.UnitTests/TestEngineTests.cs b/tests/Neo.SmartContract.Testing.UnitTests/TestEngineTests.cs index 214cab8d1..44e211b4a 100644 --- a/tests/Neo.SmartContract.Testing.UnitTests/TestEngineTests.cs +++ b/tests/Neo.SmartContract.Testing.UnitTests/TestEngineTests.cs @@ -36,7 +36,7 @@ public void TestHashExists() Assert.ThrowsException(() => engine.FromHash(engine.Native.NEO.Hash, true)); - engine.Native.Initialize(true); + engine.Native.Initialize(false); Assert.IsInstanceOfType(engine.FromHash(engine.Native.NEO.Hash, true)); } @@ -96,7 +96,7 @@ public void TestNativeContracts() public void FromHashTest() { UInt160 hash = UInt160.Parse("0x1230000000000000000000000000000000000000"); - TestEngine engine = new(); + TestEngine engine = new(false); var contract = engine.FromHash(hash, false); From 9af21d23c188c9ac63ef076c6ac52ccf21a622b9 Mon Sep 17 00:00:00 2001 From: Fernando Diaz Toledano Date: Sun, 11 Feb 2024 15:28:23 +0100 Subject: [PATCH 055/106] Clean using --- src/Neo.SmartContract.Testing/TestingApplicationEngine.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Neo.SmartContract.Testing/TestingApplicationEngine.cs b/src/Neo.SmartContract.Testing/TestingApplicationEngine.cs index a540b11cc..2b5f547f1 100644 --- a/src/Neo.SmartContract.Testing/TestingApplicationEngine.cs +++ b/src/Neo.SmartContract.Testing/TestingApplicationEngine.cs @@ -1,6 +1,5 @@ using Neo.Network.P2P.Payloads; using Neo.Persistence; -using Neo.SmartContract.Native; using Neo.SmartContract.Testing.Extensions; using Neo.VM.Types; using System; From fea0222dffa1bf2e64a3cbb9011e4b949a763401 Mon Sep 17 00:00:00 2001 From: Fernando Diaz Toledano Date: Sun, 11 Feb 2024 15:35:18 +0100 Subject: [PATCH 056/106] Allow null in deploy --- src/Neo.SmartContract.Testing/Extensions/TestExtensions.cs | 2 +- src/Neo.SmartContract.Testing/TestEngine.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Neo.SmartContract.Testing/Extensions/TestExtensions.cs b/src/Neo.SmartContract.Testing/Extensions/TestExtensions.cs index 2a479c74c..d6d3f9516 100644 --- a/src/Neo.SmartContract.Testing/Extensions/TestExtensions.cs +++ b/src/Neo.SmartContract.Testing/Extensions/TestExtensions.cs @@ -14,7 +14,7 @@ public static class TestExtensions /// /// Data /// StackItem - public static StackItem ConvertToStackItem(this object data) + public static StackItem ConvertToStackItem(this object? data) { if (data is null) return StackItem.Null; if (data is bool b) return (VM.Types.Boolean)b; diff --git a/src/Neo.SmartContract.Testing/TestEngine.cs b/src/Neo.SmartContract.Testing/TestEngine.cs index 99b775b4b..e88d9055d 100644 --- a/src/Neo.SmartContract.Testing/TestEngine.cs +++ b/src/Neo.SmartContract.Testing/TestEngine.cs @@ -195,7 +195,7 @@ private void ApplicationEngine_Log(object? sender, LogEventArgs e) /// Contract manifest /// Construction data /// Mocked Smart Contract - public T Deploy(NefFile nef, ContractManifest manifest, object data) where T : SmartContract + public T Deploy(NefFile nef, ContractManifest manifest, object? data = null) where T : SmartContract { // Deploy From c2314751c0311df9bca6059f94c99922e0729020 Mon Sep 17 00:00:00 2001 From: Fernando Diaz Toledano Date: Sun, 11 Feb 2024 15:43:05 +0100 Subject: [PATCH 057/106] Modify ContractManagement artifact --- .../Extensions/TestExtensions.cs | 7 +++++++ .../Native/ContractManagement.cs | 8 ++++---- src/Neo.SmartContract.Testing/TestEngine.cs | 14 ++------------ 3 files changed, 13 insertions(+), 16 deletions(-) diff --git a/src/Neo.SmartContract.Testing/Extensions/TestExtensions.cs b/src/Neo.SmartContract.Testing/Extensions/TestExtensions.cs index d6d3f9516..2dcbdfdaf 100644 --- a/src/Neo.SmartContract.Testing/Extensions/TestExtensions.cs +++ b/src/Neo.SmartContract.Testing/Extensions/TestExtensions.cs @@ -120,6 +120,13 @@ public static StackItem ConvertToStackItem(this object? data) return new List(cp.SubItems); } + if (typeof(IInteroperable).IsAssignableFrom(type)) + { + var interoperable = (IInteroperable)Activator.CreateInstance(type)!; + interoperable.FromStackItem(stackItem); + return interoperable; + } + throw new FormatException($"Impossible to convert {stackItem} to {type}"); } } diff --git a/src/Neo.SmartContract.Testing/Native/ContractManagement.cs b/src/Neo.SmartContract.Testing/Native/ContractManagement.cs index dd691450b..b0cc08ba6 100644 --- a/src/Neo.SmartContract.Testing/Native/ContractManagement.cs +++ b/src/Neo.SmartContract.Testing/Native/ContractManagement.cs @@ -15,15 +15,15 @@ public abstract class ContractManagement : Neo.SmartContract.Testing.SmartContra public event delUpdate? Update; #endregion #region Safe methods - public abstract List getContract(UInt160 hash); - public abstract List getContractById(BigInteger id); + public abstract ContractState getContract(UInt160 hash); + public abstract ContractState getContractById(BigInteger id); public abstract object getContractHashes(); public abstract BigInteger getMinimumDeploymentFee(); public abstract bool hasMethod(UInt160 hash, string method, BigInteger pcount); #endregion #region Unsafe methods - public abstract List deploy(byte[] nefFile, byte[] manifest); - public abstract List deploy(byte[] nefFile, byte[] manifest, object data); + public abstract ContractState deploy(byte[] nefFile, byte[] manifest); + public abstract ContractState deploy(byte[] nefFile, byte[] manifest, object data); public abstract void destroy(); public abstract void setMinimumDeploymentFee(BigInteger value); public abstract void update(byte[] nefFile, byte[] manifest); diff --git a/src/Neo.SmartContract.Testing/TestEngine.cs b/src/Neo.SmartContract.Testing/TestEngine.cs index e88d9055d..c5669409b 100644 --- a/src/Neo.SmartContract.Testing/TestEngine.cs +++ b/src/Neo.SmartContract.Testing/TestEngine.cs @@ -199,12 +199,7 @@ public T Deploy(NefFile nef, ContractManifest manifest, object? data = null) { // Deploy - var ret = Native.ContractManagement.deploy(nef.ToArray(), Encoding.UTF8.GetBytes(manifest.ToJson().ToString(false)), data.ConvertToStackItem()); - - // Parse return - - ContractState state = new(); - ((IInteroperable)state).FromStackItem(new VM.Types.Array(ret.Select(u => (StackItem)u))); + var state = Native.ContractManagement.deploy(nef.ToArray(), Encoding.UTF8.GetBytes(manifest.ToJson().ToString(false)), data.ConvertToStackItem()); // Mock contract @@ -239,12 +234,7 @@ public T FromHash(UInt160 hash, Action>? customMock = null, bool chec return MockContract(hash, customMock); } - var ret = Native.ContractManagement.getContract(hash); - - // Parse return - - ContractState state = new(); - ((IInteroperable)state).FromStackItem(new VM.Types.Array(ret.Select(u => (StackItem)u))); + var state = Native.ContractManagement.getContract(hash); return MockContract(state.Hash, customMock); } From 67544d9f7e1de2ca1ede3c2d69a97980f7039703 Mon Sep 17 00:00:00 2001 From: Fernando Diaz Toledano Date: Sun, 11 Feb 2024 19:06:26 +0100 Subject: [PATCH 058/106] Readme --- src/Neo.SmartContract.Testing/README.md | 231 ++++++++++++++++++ .../SmartContract.cs | 14 +- .../SmartContractStorage.cs | 66 +++++ src/Neo.SmartContract.Testing/TestEngine.cs | 7 +- src/Neo.SmartContract.Testing/TestStorage.cs | 17 +- .../NativeArtifactsTests.cs | 14 +- .../SmartContractStorageTests.cs | 35 +++ .../TestEngineTests.cs | 23 +- 8 files changed, 395 insertions(+), 12 deletions(-) create mode 100644 src/Neo.SmartContract.Testing/README.md create mode 100644 src/Neo.SmartContract.Testing/SmartContractStorage.cs create mode 100644 tests/Neo.SmartContract.Testing.UnitTests/SmartContractStorageTests.cs diff --git a/src/Neo.SmartContract.Testing/README.md b/src/Neo.SmartContract.Testing/README.md new file mode 100644 index 000000000..cb76a2639 --- /dev/null +++ b/src/Neo.SmartContract.Testing/README.md @@ -0,0 +1,231 @@ +# Neo.SmartContract.Testing + +The **Neo.SmartContract.Testing** project is designed to facilitate the development of unit tests for smart contract developers in neo, it does not require the project to be done in C#, as it is possible to export artifacts from a `NefFile`. + +## Table of Contents + +- [Installation and configuration](#installation-and-configuration) + - [Generating Artifacts](#generating-artifacts) + - [Example of use](#example-of-use) + - [TestEngine](#testengine) + - [Properties](#properties) + - [Methods](#methods) + - [Example of use](#example-of-use) + - [NativeArtifacts](#nativeartifacts) + - [Methods](#methods) + - [Example of use](#example-of-use) + - [SmartContractStorage](#smartcontractstorage) + - [Methods](#methods) + - [Example of use](#example-of-use) + - [Custom mocks](#custom-mocks) + - [Example of use](#example-of-use) + - [Forging signatures](#forging-signatures) + - [Example of use](#example-of-use) + +## Installation and configuration + +### Generating Artifacts + +The process of generating the artifacts, or the source code necessary to interact with the contract, is extremely simple. There are two main ways to do it: + +1. Using the `ABI` of a contract, the necessary source code to interact with the contract can be generated by calling the `GetArtifactsSource` method available in the `Neo.SmartContract.Testing.Extensions` namespace, we will only have to specify the name of our resulting class, which will usually be the same as the one existing in the `Name` field of the manifest. + +2. Through the Neo C# compiler, automatically when compiling a contract in C#, the necessary source code to interact with the contract is generated. This is available in the same path as the generated .nef file, and its + +#### Example of use + +```csharp +[TestClass] +public class MyUnitTestClass +{ + [TestMethod] + public void GenerateNativeArtifacts() + { + foreach (var n in Native.NativeContract.Contracts) + { + var manifest = n.Manifest; + var source = manifest.Abi.GetArtifactsSource(manifest.Name); + + File.WriteAllText($"{manifest.Name}.cs", source); + } + } +} +``` + +### TestEngine + +The `TestEngine` class is the main class of the library, providing a simple and intuitive interface for testing smart contracts. + +#### Properties + +The publicly exposed read-only properties are as follows: + +- **ProtocolSettings**: Assigned during the construction of the `TestEngine` and defines the configuration values of the test environment. It defaults to the current blockchain protocol. +- **Sender**: Returns the script hash of the transaction sender, which corresponds to the first `Signer` defined in the `Transaction` object. +- **Native**: Allows access to the native contracts, and their state. It facilitates access to the chain's native contracts through some precompiled artifacts. This point is further detailed in [NativeArtifacts](#nativeartifacts). +- **BFTAddress**: Defines the address for the validators of the defined *ProtocolSettings*. + +For read and write, we have: + +- **Gas**: Sets the gas execution limit for contract calls. +- **CurrentBlock**: Defaults to `Genesis` for the defined `ProtocolSettings`, but the height has been incremented by 1 to avoid issues related to the generation of gas from native contracts. +- **Transaction**: Defines the transaction that will be used as `ScriptContainer` for the neo virtual machine, by default it updates the script of the same as calls are composed and executed, and the `Signers` will be used as validators for the `CheckWitness`, regardless of whether the signature is correct or not, so if you want to test with different wallets or scopes, you do not need to sign the transaction correctly, just set the desired signers. +- **Storage**: Abstracts access to storage, allowing for easy `Snapshots` as well as reverting them. It can only be set during the initialization of the class, and allows access to the storage of contracts, as well as manually altering their state. + +#### Methods + +It has two main methods: + +- **Execute(script)**: Executes a script on the neo virtual machine and returns the execution result. +- **Deploy(nef, manifest, data, customMock)**: Deploys the smart contract by calling the native method `ContractManagement.deploy`. It allows setting [custom mocks](#custom-mocks), which will be detailed later. And returns the instance of the contract that has been deployed. +- **FromHash(hash, customMocks, checkExistence)**: Creates an instance without needing a `NefFile` or `Manifest`, only requiring the contract's hash. It does not consider whether the contract exists on the chain unless `checkExistence` is set to `true`. + +#### Example of use + +```csharp +// Create the engine initializing the native contracts + +var engine = new TestEngine(true); + +// Instantiate neo contract from native hash, (not necessary if we use engine.Native.NEO) + +var neo = engine.FromHash(engine.Native.NEO.Hash, false); + +// Ensure that the main address contains the totalSupply + +Assert.AreEqual(100_000_000, neo.totalSupply()); +Assert.AreEqual(neo.totalSupply(), neo.balanceOf(engine.BFTAddress)); +``` + +### NativeArtifacts + +This class provides precompiled artifacts for neo's native contracts, thereby simplifying and facilitating calls to native contracts. + +#### Methods + +It has two main methods: + +- **GetCommitteeAddress()**: Returns the address of the current chain's committee. +- **Initialize(bool commit = false)**: Initializes the native contract with the necessary parameters for its operation. It's important to note that this step must usually be performed, or deploying contracts won't be possible. However, if using a `Storage` that already contains chain data and these contracts have been initialized, + +#### Example of use + +```csharp +// Create the engine initializing the native contracts + +var engine = new TestEngine(true); + +// Ensure that the main address contains the totalSupply + +Assert.AreEqual(100_000_000, engine.Native.NEO.totalSupply()); +Assert.AreEqual(engine.Native.NEO.totalSupply(), engine.Native.NEO.balanceOf(engine.BFTAddress)); +``` + +### SmartContractStorage + +Avoids dealing with prefixes foreign to the internal behavior of the storage, focusing the developer solely on accessing the storage of the contract in question, just as it is managed by the smart contract itself, allowing reading, injecting, and deleting entries of the contract in question. + +#### Methods + +Mainly exposes the methods `Read`, `Put`, and `Remove`, all of them responsible for reading and manipulating the contract's information. + +#### Example of use + +```csharp +// Defines the prefix used to store the registration price in neo + +const byte Prefix_RegisterPrice = 13; + +// Engine an contract creation + +TestEngine engine = new(true); + +var neo = engine.FromHash(engine.Native.NEO.Hash, false); + +// Check previous data + +Assert.AreEqual(100000000000, neo.getRegisterPrice()); + +// Alter data + +neo.Storage.Put(new byte[] { Prefix_RegisterPrice }, BigInteger.MinusOne.ToByteArray()); + +// Check altered data + +Assert.AreEqual(BigInteger.MinusOne, neo.getRegisterPrice()); +``` + +### Custom mocks + +Custom mocks allow redirecting certain calls to smart contracts so that instead of calling the underlying contract, the logic is redirected to a method in .NET, allowing the developer to test in complex environments without significant issues. + +Imagine that our project checks that our account has a balance of 123 NEO. It would be enough to redirect the calls to the NEO `balanceOf` method in the following way, so that it always returns 123. + +It's important to note that all syscalls going to the contract in question will also be redirected, not only the calls to the method in .NET. + + +#### Example of use + +```csharp +// Initialize TestEngine and native smart contracts + +TestEngine engine = new(true); + +// Get neo token smart contract and mock balanceOf to always return 123 + +var neo = engine.FromHash(engine.Native.NEO.Hash, + mock => mock.Setup(o => o.balanceOf(It.IsAny())).Returns(123), + false); + +// Test direct call + +Assert.AreEqual(123, neo.balanceOf(engine.BFTAddress)); + +// Test vm call + +using (ScriptBuilder script = new()) +{ + script.EmitDynamicCall(neo.Hash, nameof(neo.balanceOf), engine.BFTAddress); + + Assert.AreEqual(123, engine.Execute(script.ToArray()).GetInteger()); +} +``` + +### Forging signatures + +To fake signatures and allow testing our contracts in authorized and unauthorized environments, it's enough to replace the signers of the `Transaction` object in our `TestEngine`. This way, we can simulate the signatures of other users. It's worth noting that it's not necessary to modify the `Witnesses` since it's not checked whether the transaction is well-formed. + +#### Example of use + +```csharp +// Initialize out TestEngine + +var engine = new TestEngine(true); + +// Check initial value of getRegisterPrice + +Assert.AreEqual(100000000000, engine.Native.NEO.getRegisterPrice()); + +// Fake Committee Signature + +engine.Transaction.Signers = new Network.P2P.Payloads.Signer[] +{ + new Network.P2P.Payloads.Signer() + { + Account = engine.Native.GetCommitteeAddress(), + Scopes = Network.P2P.Payloads.WitnessScope.Global + } +}; + +// Change RegisterPrice to 123 + +engine.Native.NEO.setRegisterPrice(123); + +Assert.AreEqual(123, engine.Native.NEO.getRegisterPrice()); + +// Now test it without this signature + +engine.Transaction.Signers[0].Scopes = Network.P2P.Payloads.WitnessScope.None; + +Assert.ThrowsException(() => engine.Native.NEO.setRegisterPrice(123)); +``` diff --git a/src/Neo.SmartContract.Testing/SmartContract.cs b/src/Neo.SmartContract.Testing/SmartContract.cs index db2489acb..b3dcf9762 100644 --- a/src/Neo.SmartContract.Testing/SmartContract.cs +++ b/src/Neo.SmartContract.Testing/SmartContract.cs @@ -8,7 +8,7 @@ namespace Neo.SmartContract.Testing { public class SmartContract { - private readonly TestEngine _engine; + internal readonly TestEngine Engine; public delegate void delOnLog(string message); public event delOnLog? OnLog; @@ -18,6 +18,11 @@ public class SmartContract /// public UInt160 Hash { get; } + /// + /// Storage for this contract + /// + public SmartContractStorage Storage { get; } + /// /// Constructor /// @@ -25,8 +30,9 @@ public class SmartContract /// Contract hash protected SmartContract(TestEngine testEngine, UInt160 hash) { - _engine = testEngine; + Engine = testEngine; Hash = hash; + Storage = new SmartContractStorage(this); } /// @@ -41,9 +47,9 @@ internal StackItem Invoke(string methodName, params object[] args) using ScriptBuilder script = new(); script.EmitDynamicCall(Hash, methodName, args); - _engine.Transaction.Script = script.ToArray(); // Store the script in the current transaction + Engine.Transaction.Script = script.ToArray(); // Store the script in the current transaction - return _engine.Execute(script.ToArray()); + return Engine.Execute(script.ToArray()); } /// diff --git a/src/Neo.SmartContract.Testing/SmartContractStorage.cs b/src/Neo.SmartContract.Testing/SmartContractStorage.cs new file mode 100644 index 000000000..3ef1af397 --- /dev/null +++ b/src/Neo.SmartContract.Testing/SmartContractStorage.cs @@ -0,0 +1,66 @@ +using System; + +namespace Neo.SmartContract.Testing +{ + public class SmartContractStorage + { + private readonly SmartContract _smartContract; + private int? _smartContractId; + + /// + /// Constructor + /// + /// Smart Contract + internal SmartContractStorage(SmartContract smartContract) + { + _smartContract = smartContract; + } + + private int GetContractId() + { + _smartContractId ??= _smartContract.Engine.Native.ContractManagement.getContract(_smartContract.Hash).Id; + return _smartContractId.Value; + } + + /// + /// Remove an entry from the smart contract storage + /// + /// Key + public ReadOnlyMemory Read(ReadOnlyMemory key) + { + var skey = new StorageKey() { Id = GetContractId(), Key = key }; + var entry = _smartContract.Engine.Storage.Snapshot.TryGet(skey); + + if (entry != null) + { + return entry.Value; + } + + return null; + } + + /// + /// Put an entry in the smart contract storage + /// + /// Key + /// Value + public void Put(ReadOnlyMemory key, ReadOnlyMemory value) + { + var skey = new StorageKey() { Id = GetContractId(), Key = key }; + + var entry = _smartContract.Engine.Storage.Snapshot.GetAndChange(skey, () => new StorageItem() { Value = value }); + entry.Value = value; + } + + /// + /// Remove an entry from the smart contract storage + /// + /// Key + public void Remove(ReadOnlyMemory key) + { + var skey = new StorageKey() { Id = GetContractId(), Key = key }; + + _smartContract.Engine.Storage.Snapshot.Delete(skey); + } + } +} diff --git a/src/Neo.SmartContract.Testing/TestEngine.cs b/src/Neo.SmartContract.Testing/TestEngine.cs index c5669409b..c9d6aace3 100644 --- a/src/Neo.SmartContract.Testing/TestEngine.cs +++ b/src/Neo.SmartContract.Testing/TestEngine.cs @@ -92,7 +92,7 @@ public class TestEngine /// /// Gas /// - public long Gas = ApplicationEngine.TestModeGas; + public long Gas { get; set; } = ApplicationEngine.TestModeGas; /// /// Sender @@ -194,8 +194,9 @@ private void ApplicationEngine_Log(object? sender, LogEventArgs e) /// Nef file /// Contract manifest /// Construction data + /// Custom Mock /// Mocked Smart Contract - public T Deploy(NefFile nef, ContractManifest manifest, object? data = null) where T : SmartContract + public T Deploy(NefFile nef, ContractManifest manifest, object? data = null, Action>? customMock = null) where T : SmartContract { // Deploy @@ -204,7 +205,7 @@ public T Deploy(NefFile nef, ContractManifest manifest, object? data = null) // Mock contract //UInt160 hash = Helper.GetContractHash(Sender, nef.CheckSum, manifest.Name); - return MockContract(state.Hash); + return MockContract(state.Hash, customMock); } /// diff --git a/src/Neo.SmartContract.Testing/TestStorage.cs b/src/Neo.SmartContract.Testing/TestStorage.cs index 2c2b55361..2c053640b 100644 --- a/src/Neo.SmartContract.Testing/TestStorage.cs +++ b/src/Neo.SmartContract.Testing/TestStorage.cs @@ -1,6 +1,7 @@ using Neo.Json; using Neo.Persistence; using System; +using System.Buffers.Binary; using System.Linq; namespace Neo.SmartContract.Testing @@ -71,12 +72,26 @@ public void LoadFromJson(JObject json) { // "prefix": { "key":"value" } in base64 + byte[] prefix; + + try + { + prefix = Convert.FromBase64String(entry.Key); + } + catch + { + // It's a number? + + prefix = new byte[sizeof(int)]; + BinaryPrimitives.WriteInt32LittleEndian(prefix, int.Parse(entry.Key)); + } + foreach (var subEntry in obj.Properties) { if (subEntry.Value is JString subStr) { Snapshot.Add( - new StorageKey(Convert.FromBase64String(entry.Key).Concat(Convert.FromBase64String(subEntry.Key)).ToArray()), + new StorageKey(prefix.Concat(Convert.FromBase64String(subEntry.Key)).ToArray()), new StorageItem(Convert.FromBase64String(subStr.Value)) ); } diff --git a/tests/Neo.SmartContract.Testing.UnitTests/NativeArtifactsTests.cs b/tests/Neo.SmartContract.Testing.UnitTests/NativeArtifactsTests.cs index 54996e7dc..a91a11f48 100644 --- a/tests/Neo.SmartContract.Testing.UnitTests/NativeArtifactsTests.cs +++ b/tests/Neo.SmartContract.Testing.UnitTests/NativeArtifactsTests.cs @@ -11,10 +11,14 @@ public class NativeArtifactsTests [TestMethod] public void TestInitialize() { + // Create the engine without initialize the native contracts + var engine = new TestEngine(false); Assert.AreEqual(0, engine.Storage.Store.Seek(System.Array.Empty(), Persistence.SeekDirection.Forward).Count()); + // Initialize native contracts + engine.Native.Initialize(false); // Ensure that the main address contains the totalSupply @@ -62,13 +66,15 @@ public void TestTransfer() [TestMethod] public void TestSignature() { + // Initialize out TestEngine + var engine = new TestEngine(true); - // Test set + // Check initial value of getRegisterPrice Assert.AreEqual(100000000000, engine.Native.NEO.getRegisterPrice()); - // Fake signature + // Fake Committee Signature engine.Transaction.Signers = new Network.P2P.Payloads.Signer[] { @@ -79,11 +85,13 @@ public void TestSignature() } }; + // Change RegisterPrice to 123 + engine.Native.NEO.setRegisterPrice(123); Assert.AreEqual(123, engine.Native.NEO.getRegisterPrice()); - // Invalid signature + // Now test it without this signature engine.Transaction.Signers[0].Scopes = Network.P2P.Payloads.WitnessScope.None; diff --git a/tests/Neo.SmartContract.Testing.UnitTests/SmartContractStorageTests.cs b/tests/Neo.SmartContract.Testing.UnitTests/SmartContractStorageTests.cs new file mode 100644 index 000000000..0fe0b4dad --- /dev/null +++ b/tests/Neo.SmartContract.Testing.UnitTests/SmartContractStorageTests.cs @@ -0,0 +1,35 @@ +using Microsoft.VisualStudio.TestTools.UnitTesting; +using System.Numerics; + +namespace Neo.SmartContract.Testing.UnitTests +{ + [TestClass] + public class SmartContractStorageTests + { + [TestMethod] + public void TestAlterStorage() + { + // Defines the prefix used to store the registration price in neo + + const byte Prefix_RegisterPrice = 13; + + // Engine an contract creation + + TestEngine engine = new(true); + + var neo = engine.FromHash(engine.Native.NEO.Hash, false); + + // Check previous data + + Assert.AreEqual(100000000000, neo.getRegisterPrice()); + + // Alter data + + neo.Storage.Put(new byte[] { Prefix_RegisterPrice }, BigInteger.MinusOne.ToByteArray()); + + // Check altered data + + Assert.AreEqual(BigInteger.MinusOne, neo.getRegisterPrice()); + } + } +} diff --git a/tests/Neo.SmartContract.Testing.UnitTests/TestEngineTests.cs b/tests/Neo.SmartContract.Testing.UnitTests/TestEngineTests.cs index 44e211b4a..1ebf59b14 100644 --- a/tests/Neo.SmartContract.Testing.UnitTests/TestEngineTests.cs +++ b/tests/Neo.SmartContract.Testing.UnitTests/TestEngineTests.cs @@ -44,8 +44,12 @@ public void TestHashExists() [TestMethod] public void TestCustomMock() { + // Initialize TestEngine and native smart contracts + TestEngine engine = new(true); + // Get neo token smart contract and mock balanceOf to always return 123 + var neo = engine.FromHash(engine.Native.NEO.Hash, mock => mock.Setup(o => o.balanceOf(It.IsAny())).Returns(123), false); @@ -93,7 +97,7 @@ public void TestNativeContracts() } [TestMethod] - public void FromHashTest() + public void FromHashWithoutCheckTest() { UInt160 hash = UInt160.Parse("0x1230000000000000000000000000000000000000"); TestEngine engine = new(false); @@ -102,5 +106,22 @@ public void FromHashTest() Assert.AreEqual(contract.Hash, hash); } + + [TestMethod] + public void FromHashTest() + { + // Create the engine initializing the native contracts + + var engine = new TestEngine(true); + + // Instantiate neo contract from native hash, (not necessary if we use engine.Native.NEO) + + var neo = engine.FromHash(engine.Native.NEO.Hash, true); + + // Ensure that the main address contains the totalSupply + + Assert.AreEqual(100_000_000, neo.totalSupply()); + Assert.AreEqual(neo.totalSupply(), neo.balanceOf(engine.BFTAddress)); + } } } From 29133bc5e4508535df5020d22b056fec83cdf277 Mon Sep 17 00:00:00 2001 From: Fernando Diaz Toledano Date: Sun, 11 Feb 2024 19:13:16 +0100 Subject: [PATCH 059/106] Fix menu --- src/Neo.SmartContract.Testing/README.md | 38 ++++++++++++------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/src/Neo.SmartContract.Testing/README.md b/src/Neo.SmartContract.Testing/README.md index cb76a2639..27ddb6295 100644 --- a/src/Neo.SmartContract.Testing/README.md +++ b/src/Neo.SmartContract.Testing/README.md @@ -7,24 +7,24 @@ The **Neo.SmartContract.Testing** project is designed to facilitate the developm - [Installation and configuration](#installation-and-configuration) - [Generating Artifacts](#generating-artifacts) - [Example of use](#example-of-use) - - [TestEngine](#testengine) - - [Properties](#properties) - - [Methods](#methods) - - [Example of use](#example-of-use) - - [NativeArtifacts](#nativeartifacts) - - [Methods](#methods) - - [Example of use](#example-of-use) - - [SmartContractStorage](#smartcontractstorage) - - [Methods](#methods) - - [Example of use](#example-of-use) - - [Custom mocks](#custom-mocks) - - [Example of use](#example-of-use) - - [Forging signatures](#forging-signatures) - - [Example of use](#example-of-use) - -## Installation and configuration - -### Generating Artifacts +- [TestEngine](#testengine) + - [Properties](#properties) + - [Methods](#methods) + - [Example of use](#example-of-use) +- [NativeArtifacts](#nativeartifacts) + - [Methods](#methods) + - [Example of use](#example-of-use) +- [SmartContractStorage](#smartcontractstorage) + - [Methods](#methods) + - [Example of use](#example-of-use) +- [Custom mocks](#custom-mocks) + - [Example of use](#example-of-use) +- [Forging signatures](#forging-signatures) + - [Example of use](#example-of-use) + +### Installation and configuration + +#### Generating Artifacts The process of generating the artifacts, or the source code necessary to interact with the contract, is extremely simple. There are two main ways to do it: @@ -32,7 +32,7 @@ The process of generating the artifacts, or the source code necessary to interac 2. Through the Neo C# compiler, automatically when compiling a contract in C#, the necessary source code to interact with the contract is generated. This is available in the same path as the generated .nef file, and its -#### Example of use +##### Example of use ```csharp [TestClass] From f545e6b8244c54fd5d2a15291de43380bf7537ac Mon Sep 17 00:00:00 2001 From: Fernando Diaz Toledano Date: Sun, 11 Feb 2024 19:15:26 +0100 Subject: [PATCH 060/106] Resume example using native access --- src/Neo.SmartContract.Testing/README.md | 8 +++----- .../SmartContractStorageTests.cs | 8 +++----- 2 files changed, 6 insertions(+), 10 deletions(-) diff --git a/src/Neo.SmartContract.Testing/README.md b/src/Neo.SmartContract.Testing/README.md index 27ddb6295..c9bfdc9a8 100644 --- a/src/Neo.SmartContract.Testing/README.md +++ b/src/Neo.SmartContract.Testing/README.md @@ -140,19 +140,17 @@ const byte Prefix_RegisterPrice = 13; TestEngine engine = new(true); -var neo = engine.FromHash(engine.Native.NEO.Hash, false); - // Check previous data -Assert.AreEqual(100000000000, neo.getRegisterPrice()); +Assert.AreEqual(100000000000, engine.Native.NEO.getRegisterPrice()); // Alter data -neo.Storage.Put(new byte[] { Prefix_RegisterPrice }, BigInteger.MinusOne.ToByteArray()); +engine.Native.NEO.Storage.Put(new byte[] { Prefix_RegisterPrice }, BigInteger.MinusOne.ToByteArray()); // Check altered data -Assert.AreEqual(BigInteger.MinusOne, neo.getRegisterPrice()); +Assert.AreEqual(BigInteger.MinusOne, engine.Native.NEO.getRegisterPrice()); ``` ### Custom mocks diff --git a/tests/Neo.SmartContract.Testing.UnitTests/SmartContractStorageTests.cs b/tests/Neo.SmartContract.Testing.UnitTests/SmartContractStorageTests.cs index 0fe0b4dad..8384a702b 100644 --- a/tests/Neo.SmartContract.Testing.UnitTests/SmartContractStorageTests.cs +++ b/tests/Neo.SmartContract.Testing.UnitTests/SmartContractStorageTests.cs @@ -17,19 +17,17 @@ public void TestAlterStorage() TestEngine engine = new(true); - var neo = engine.FromHash(engine.Native.NEO.Hash, false); - // Check previous data - Assert.AreEqual(100000000000, neo.getRegisterPrice()); + Assert.AreEqual(100000000000, engine.Native.NEO.getRegisterPrice()); // Alter data - neo.Storage.Put(new byte[] { Prefix_RegisterPrice }, BigInteger.MinusOne.ToByteArray()); + engine.Native.NEO.Storage.Put(new byte[] { Prefix_RegisterPrice }, BigInteger.MinusOne.ToByteArray()); // Check altered data - Assert.AreEqual(BigInteger.MinusOne, neo.getRegisterPrice()); + Assert.AreEqual(BigInteger.MinusOne, engine.Native.NEO.getRegisterPrice()); } } } From b02b1ee55bece6d6bab374e640214ed74eec2d54 Mon Sep 17 00:00:00 2001 From: Fernando Diaz Toledano Date: Sun, 11 Feb 2024 19:17:33 +0100 Subject: [PATCH 061/106] Clean storage example --- src/Neo.SmartContract.Testing/README.md | 4 ++-- .../SmartContractStorage.cs | 14 ++++++++++++++ .../SmartContractStorageTests.cs | 4 ++-- 3 files changed, 18 insertions(+), 4 deletions(-) diff --git a/src/Neo.SmartContract.Testing/README.md b/src/Neo.SmartContract.Testing/README.md index c9bfdc9a8..44e49907b 100644 --- a/src/Neo.SmartContract.Testing/README.md +++ b/src/Neo.SmartContract.Testing/README.md @@ -134,7 +134,7 @@ Mainly exposes the methods `Read`, `Put`, and `Remove`, all of them responsible ```csharp // Defines the prefix used to store the registration price in neo -const byte Prefix_RegisterPrice = 13; +byte[] registerPricePrefix = new byte[] { 13 }; // Engine an contract creation @@ -146,7 +146,7 @@ Assert.AreEqual(100000000000, engine.Native.NEO.getRegisterPrice()); // Alter data -engine.Native.NEO.Storage.Put(new byte[] { Prefix_RegisterPrice }, BigInteger.MinusOne.ToByteArray()); +engine.Native.NEO.Storage.Put(registerPricePrefix, BigInteger.MinusOne); // Check altered data diff --git a/src/Neo.SmartContract.Testing/SmartContractStorage.cs b/src/Neo.SmartContract.Testing/SmartContractStorage.cs index 3ef1af397..1fbf2bfeb 100644 --- a/src/Neo.SmartContract.Testing/SmartContractStorage.cs +++ b/src/Neo.SmartContract.Testing/SmartContractStorage.cs @@ -1,4 +1,5 @@ using System; +using System.Numerics; namespace Neo.SmartContract.Testing { @@ -52,6 +53,19 @@ public void Put(ReadOnlyMemory key, ReadOnlyMemory value) entry.Value = value; } + /// + /// Put an entry in the smart contract storage + /// + /// Key + /// Value + public void Put(ReadOnlyMemory key, BigInteger value) + { + var skey = new StorageKey() { Id = GetContractId(), Key = key }; + + var entry = _smartContract.Engine.Storage.Snapshot.GetAndChange(skey, () => new StorageItem(value)); + entry.Set(value); + } + /// /// Remove an entry from the smart contract storage /// diff --git a/tests/Neo.SmartContract.Testing.UnitTests/SmartContractStorageTests.cs b/tests/Neo.SmartContract.Testing.UnitTests/SmartContractStorageTests.cs index 8384a702b..150982fe8 100644 --- a/tests/Neo.SmartContract.Testing.UnitTests/SmartContractStorageTests.cs +++ b/tests/Neo.SmartContract.Testing.UnitTests/SmartContractStorageTests.cs @@ -11,7 +11,7 @@ public void TestAlterStorage() { // Defines the prefix used to store the registration price in neo - const byte Prefix_RegisterPrice = 13; + byte[] registerPricePrefix = new byte[] { 13 }; // Engine an contract creation @@ -23,7 +23,7 @@ public void TestAlterStorage() // Alter data - engine.Native.NEO.Storage.Put(new byte[] { Prefix_RegisterPrice }, BigInteger.MinusOne.ToByteArray()); + engine.Native.NEO.Storage.Put(registerPricePrefix, BigInteger.MinusOne); // Check altered data From 04ca62911f2d949df672ab2ec1fb466990e11733 Mon Sep 17 00:00:00 2001 From: Fernando Diaz Toledano Date: Sun, 11 Feb 2024 19:22:50 +0100 Subject: [PATCH 062/106] fix readme --- src/Neo.SmartContract.Testing/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Neo.SmartContract.Testing/README.md b/src/Neo.SmartContract.Testing/README.md index 44e49907b..e30e6d04b 100644 --- a/src/Neo.SmartContract.Testing/README.md +++ b/src/Neo.SmartContract.Testing/README.md @@ -1,6 +1,6 @@ # Neo.SmartContract.Testing -The **Neo.SmartContract.Testing** project is designed to facilitate the development of unit tests for smart contract developers in neo, it does not require the project to be done in C#, as it is possible to export artifacts from a `NefFile`. +The **Neo.SmartContract.Testing** project is designed to facilitate the development of unit tests for smart contract developers in neo, it does not require the project to be done in C#, as it is possible to export artifacts from an `Abi`. ## Table of Contents From 7e0a5c9ff7aea91f7555982b2dd6ff1599972048 Mon Sep 17 00:00:00 2001 From: Fernando Diaz Toledano Date: Sun, 11 Feb 2024 19:24:43 +0100 Subject: [PATCH 063/106] Fix readme --- src/Neo.SmartContract.Testing/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Neo.SmartContract.Testing/README.md b/src/Neo.SmartContract.Testing/README.md index e30e6d04b..96f75c4a6 100644 --- a/src/Neo.SmartContract.Testing/README.md +++ b/src/Neo.SmartContract.Testing/README.md @@ -30,7 +30,7 @@ The process of generating the artifacts, or the source code necessary to interac 1. Using the `ABI` of a contract, the necessary source code to interact with the contract can be generated by calling the `GetArtifactsSource` method available in the `Neo.SmartContract.Testing.Extensions` namespace, we will only have to specify the name of our resulting class, which will usually be the same as the one existing in the `Name` field of the manifest. -2. Through the Neo C# compiler, automatically when compiling a contract in C#, the necessary source code to interact with the contract is generated. This is available in the same path as the generated .nef file, and its +2. Through the Neo C# compiler, automatically when compiling a contract in C#, the necessary source code to interact with the contract is generated. This is available in the same path as the generated .nef file, and its extension is `.artifacts.cs`. ##### Example of use From e9348200d07e536045f060f415e64ea85e1621a5 Mon Sep 17 00:00:00 2001 From: Fernando Diaz Toledano Date: Sun, 11 Feb 2024 20:14:17 +0100 Subject: [PATCH 064/106] Fix readme and move CommitteeAddress --- src/Neo.SmartContract.Testing/NativeArtifacts.cs | 8 -------- src/Neo.SmartContract.Testing/README.md | 12 ++++++------ src/Neo.SmartContract.Testing/TestEngine.cs | 8 +++++++- .../NativeArtifactsTests.cs | 2 +- 4 files changed, 14 insertions(+), 16 deletions(-) diff --git a/src/Neo.SmartContract.Testing/NativeArtifacts.cs b/src/Neo.SmartContract.Testing/NativeArtifacts.cs index f6b2477b9..e3a2b674d 100644 --- a/src/Neo.SmartContract.Testing/NativeArtifacts.cs +++ b/src/Neo.SmartContract.Testing/NativeArtifacts.cs @@ -142,14 +142,6 @@ public NativeArtifacts(TestEngine engine) _engine = engine; } - /// - /// GetCommitteeAddress - /// - public UInt160 GetCommitteeAddress() - { - return Native.NativeContract.NEO.GetCommitteeAddress(_engine.Storage.Snapshot); - } - /// /// Initialize native contracts /// diff --git a/src/Neo.SmartContract.Testing/README.md b/src/Neo.SmartContract.Testing/README.md index 96f75c4a6..974997cbd 100644 --- a/src/Neo.SmartContract.Testing/README.md +++ b/src/Neo.SmartContract.Testing/README.md @@ -64,6 +64,7 @@ The publicly exposed read-only properties are as follows: - **Sender**: Returns the script hash of the transaction sender, which corresponds to the first `Signer` defined in the `Transaction` object. - **Native**: Allows access to the native contracts, and their state. It facilitates access to the chain's native contracts through some precompiled artifacts. This point is further detailed in [NativeArtifacts](#nativeartifacts). - **BFTAddress**: Defines the address for the validators of the defined *ProtocolSettings*. +- **CommitteeAddress**: Returns the address of the current chain's committee. For read and write, we have: @@ -103,10 +104,9 @@ This class provides precompiled artifacts for neo's native contracts, thereby si #### Methods -It has two main methods: +It has only one method: -- **GetCommitteeAddress()**: Returns the address of the current chain's committee. -- **Initialize(bool commit = false)**: Initializes the native contract with the necessary parameters for its operation. It's important to note that this step must usually be performed, or deploying contracts won't be possible. However, if using a `Storage` that already contains chain data and these contracts have been initialized, +- **Initialize(bool commit = false)**: Initializes the native contract with the necessary parameters for its operation. It's important to note that this step must usually be performed, or deploying contracts won't be possible. However, if using a `Storage` that already contains chain data and these contracts have been initialized, calling this method should be avoided. The `commit` argument determines whether to commit to the active `Snapshot` of the `TestStorage` (default is `false`). #### Example of use @@ -123,7 +123,7 @@ Assert.AreEqual(engine.Native.NEO.totalSupply(), engine.Native.NEO.balanceOf(eng ### SmartContractStorage -Avoids dealing with prefixes foreign to the internal behavior of the storage, focusing the developer solely on accessing the storage of the contract in question, just as it is managed by the smart contract itself, allowing reading, injecting, and deleting entries of the contract in question. +Avoids dealing with prefixes foreign to the internal behavior of the storage, focusing the developer solely on accessing the storage of the contract, just as it is managed by the smart contract itself, allowing reading, injecting, and deleting entries of the contract in question. #### Methods @@ -159,7 +159,7 @@ Custom mocks allow redirecting certain calls to smart contracts so that instead Imagine that our project checks that our account has a balance of 123 NEO. It would be enough to redirect the calls to the NEO `balanceOf` method in the following way, so that it always returns 123. -It's important to note that all syscalls going to the contract in question will also be redirected, not only the calls to the method in .NET. +It's important to note that all syscalls going to this contract will also be redirected, not only the calls to the method in .NET. #### Example of use @@ -210,7 +210,7 @@ engine.Transaction.Signers = new Network.P2P.Payloads.Signer[] { new Network.P2P.Payloads.Signer() { - Account = engine.Native.GetCommitteeAddress(), + Account = engine.CommitteeAddress, Scopes = Network.P2P.Payloads.WitnessScope.Global } }; diff --git a/src/Neo.SmartContract.Testing/TestEngine.cs b/src/Neo.SmartContract.Testing/TestEngine.cs index c9d6aace3..fa6a393d4 100644 --- a/src/Neo.SmartContract.Testing/TestEngine.cs +++ b/src/Neo.SmartContract.Testing/TestEngine.cs @@ -75,10 +75,16 @@ public class TestEngine public ProtocolSettings ProtocolSettings { get; } /// - /// BFTAddress + /// BFT Address /// public UInt160 BFTAddress { get; } + /// + /// Committee Address + /// + public UInt160 CommitteeAddress => + Neo.SmartContract.Native.NativeContract.NEO.GetCommitteeAddress(Storage.Snapshot); + /// /// BFTAddress /// diff --git a/tests/Neo.SmartContract.Testing.UnitTests/NativeArtifactsTests.cs b/tests/Neo.SmartContract.Testing.UnitTests/NativeArtifactsTests.cs index a91a11f48..0bc9c051f 100644 --- a/tests/Neo.SmartContract.Testing.UnitTests/NativeArtifactsTests.cs +++ b/tests/Neo.SmartContract.Testing.UnitTests/NativeArtifactsTests.cs @@ -80,7 +80,7 @@ public void TestSignature() { new Network.P2P.Payloads.Signer() { - Account = engine.Native.GetCommitteeAddress(), + Account = engine.CommitteeAddress, Scopes = Network.P2P.Payloads.WitnessScope.Global } }; From f0cd97d8d591aa56e19a7b840264b313548689de Mon Sep 17 00:00:00 2001 From: Fernando Diaz Toledano Date: Sun, 11 Feb 2024 20:21:42 +0100 Subject: [PATCH 065/106] Add event testing to readme --- src/Neo.SmartContract.Testing/README.md | 50 +++++++++++++++++++ .../NativeArtifactsTests.cs | 28 +++++++---- 2 files changed, 68 insertions(+), 10 deletions(-) diff --git a/src/Neo.SmartContract.Testing/README.md b/src/Neo.SmartContract.Testing/README.md index 974997cbd..b013d06a9 100644 --- a/src/Neo.SmartContract.Testing/README.md +++ b/src/Neo.SmartContract.Testing/README.md @@ -21,6 +21,8 @@ The **Neo.SmartContract.Testing** project is designed to facilitate the developm - [Example of use](#example-of-use) - [Forging signatures](#forging-signatures) - [Example of use](#example-of-use) +- [Event testing](#event-testing) + - [Example of use](#example-of-use) ### Installation and configuration @@ -227,3 +229,51 @@ engine.Transaction.Signers[0].Scopes = Network.P2P.Payloads.WitnessScope.None; Assert.ThrowsException(() => engine.Native.NEO.setRegisterPrice(123)); ``` + +### Event testing + +Testing that our events have been triggered has never been so easy. Simply when a contract notification is launched, the corresponding event will be invoked, making it easier to capture and detect. + +#### Example of use + +```csharp + // Create and initialize TestEngine + + var engine = new TestEngine(true); + + // Fake signature of BFTAddress + + engine.Transaction.Signers = new Network.P2P.Payloads.Signer[] + { + new Network.P2P.Payloads.Signer() + { + Account = engine.BFTAddress, + Scopes = Network.P2P.Payloads.WitnessScope.Global + } + }; + + // Attach to Transfer event + + var raisedEvent = false; + + engine.Native.NEO.Transfer += (UInt160 from, UInt160 to, BigInteger amount) => + { + // If the event is raised, the variable will be changed + raisedEvent = true; + }; + + // Define address to transfer funds + + UInt160 addressTo = UInt160.Parse("0x1230000000000000000000000000000000000000"); + + Assert.AreEqual(0, engine.Native.NEO.balanceOf(addressTo)); + + // Transfer funds + + Assert.IsTrue(engine.Native.NEO.transfer(engine.Transaction.Sender, addressTo, 123, null)); + + // Ensure that we have balance and the event was raised + + Assert.IsTrue(raisedEvent); + Assert.AreEqual(123, engine.Native.NEO.balanceOf(addressTo)); +``` diff --git a/tests/Neo.SmartContract.Testing.UnitTests/NativeArtifactsTests.cs b/tests/Neo.SmartContract.Testing.UnitTests/NativeArtifactsTests.cs index 0bc9c051f..8f6d7435b 100644 --- a/tests/Neo.SmartContract.Testing.UnitTests/NativeArtifactsTests.cs +++ b/tests/Neo.SmartContract.Testing.UnitTests/NativeArtifactsTests.cs @@ -30,13 +30,11 @@ public void TestInitialize() [TestMethod] public void TestTransfer() { - var engine = new TestEngine(true); - - // Test set + // Create and initialize TestEngine - Assert.AreEqual(500000000, engine.Native.NEO.getGasPerBlock()); + var engine = new TestEngine(true); - // Fake signature + // Fake signature of BFTAddress engine.Transaction.Signers = new Network.P2P.Payloads.Signer[] { @@ -47,20 +45,30 @@ public void TestTransfer() } }; - bool raisedEvent = false; + // Attach to Transfer event + + var raisedEvent = false; engine.Native.NEO.Transfer += (UInt160 from, UInt160 to, BigInteger amount) => { + // If the event is raised, the variable will be changed raisedEvent = true; }; - UInt160 wallet = UInt160.Parse("0x1230000000000000000000000000000000000000"); + // Define address to transfer funds + + UInt160 addressTo = UInt160.Parse("0x1230000000000000000000000000000000000000"); + + Assert.AreEqual(0, engine.Native.NEO.balanceOf(addressTo)); + + // Transfer funds + + Assert.IsTrue(engine.Native.NEO.transfer(engine.Transaction.Sender, addressTo, 123, null)); - Assert.AreEqual(0, engine.Native.NEO.balanceOf(wallet)); - Assert.IsTrue(engine.Native.NEO.transfer(engine.Transaction.Sender, wallet, 123, null)); + // Ensure that we have balance and the event was raised Assert.IsTrue(raisedEvent); - Assert.AreEqual(123, engine.Native.NEO.balanceOf(wallet)); + Assert.AreEqual(123, engine.Native.NEO.balanceOf(addressTo)); } [TestMethod] From 98c0b44377708570f5775ae889e0fb67bdaced12 Mon Sep 17 00:00:00 2001 From: Fernando Diaz Toledano Date: Sun, 11 Feb 2024 21:07:58 +0100 Subject: [PATCH 066/106] Allow properties! --- .../Extensions/ArtifactExtensions.cs | 88 +++++++++++++++++-- .../Extensions/MockExtensions.cs | 26 +++++- .../Native/ContractManagement.cs | 33 ++++++- .../Native/CryptoLib.cs | 34 ++++++- .../Native/GasToken.cs | 19 +++- .../Native/LedgerContract.cs | 28 +++++- .../Native/NeoToken.cs | 53 ++++++++--- .../Native/OracleContract.cs | 18 +++- .../Native/PolicyContract.cs | 30 +++++-- .../Native/RoleManagement.cs | 10 ++- .../Native/StdLib.cs | 67 +++++++++++++- src/Neo.SmartContract.Testing/TestEngine.cs | 3 +- .../Extensions/ArtifactExtensionsTests.cs | 44 +++++++++- .../NativeArtifactsTests.cs | 8 +- .../SmartContractStorageTests.cs | 4 +- .../TestEngineTests.cs | 2 +- 16 files changed, 411 insertions(+), 56 deletions(-) diff --git a/src/Neo.SmartContract.Testing/Extensions/ArtifactExtensions.cs b/src/Neo.SmartContract.Testing/Extensions/ArtifactExtensions.cs index 8325bfe0b..56efb2013 100644 --- a/src/Neo.SmartContract.Testing/Extensions/ArtifactExtensions.cs +++ b/src/Neo.SmartContract.Testing/Extensions/ArtifactExtensions.cs @@ -1,5 +1,6 @@ using Neo.SmartContract.Manifest; using System; +using System.Collections.Generic; using System.Linq; using System.Text; @@ -12,8 +13,9 @@ public static class ArtifactExtensions /// /// Abi /// Contract name + /// Generate properties /// Source - public static string GetArtifactsSource(this ContractAbi abi, string name) + public static string GetArtifactsSource(this ContractAbi abi, string name, bool generateProperties = true) { StringBuilder sourceCode = new(); @@ -40,13 +42,32 @@ public static string GetArtifactsSource(this ContractAbi abi, string name) sourceCode.AppendLine(" #endregion"); } - // Crete methods + // Create methods - if (abi.Methods.Any(u => u.Safe)) + var methods = abi.Methods; + + if (generateProperties) + { + (methods, var properties) = ProcessAbiMethods(abi.Methods); + + if (properties.Any()) + { + sourceCode.AppendLine(" #region Properties"); + + foreach (var property in properties.OrderBy(u => u.getter.Name)) + { + sourceCode.Append(CreateSourcePropertyFromManifest(property.getter.Name[3..], property.getter.ReturnType, property.setter is not null)); + } + + sourceCode.AppendLine(" #endregion"); + } + } + + if (methods.Any(u => u.Safe)) { sourceCode.AppendLine(" #region Safe methods"); - foreach (var method in abi.Methods.Where(u => u.Safe).OrderBy(u => u.Name)) + foreach (var method in methods.Where(u => u.Safe).OrderBy(u => u.Name)) { // This method can't be called, so avoid them @@ -58,11 +79,11 @@ public static string GetArtifactsSource(this ContractAbi abi, string name) sourceCode.AppendLine(" #endregion"); } - if (abi.Methods.Any(u => !u.Safe)) + if (methods.Any(u => !u.Safe)) { sourceCode.AppendLine(" #region Unsafe methods"); - foreach (var method in abi.Methods.Where(u => !u.Safe).OrderBy(u => u.Name)) + foreach (var method in methods.Where(u => !u.Safe).OrderBy(u => u.Name)) { // This method can't be called, so avoid them @@ -89,6 +110,39 @@ public static string GetArtifactsSource(this ContractAbi abi, string name) return sourceCode.ToString().TrimEnd(); } + private static (ContractMethodDescriptor[] methods, (ContractMethodDescriptor getter, ContractMethodDescriptor? setter)[] properties) + ProcessAbiMethods(ContractMethodDescriptor[] methods) + { + List methodList = new(methods); + List<(ContractMethodDescriptor, ContractMethodDescriptor?)> properties = new(); + + // Detect and extract properties, first find getXXXX && Safe && 0 args && return != void + + foreach (ContractMethodDescriptor getter in methods.Where(u => u.Name.StartsWith("get") && u.Safe && u.Parameters.Length == 0 && u.ReturnType != ContractParameterType.Void).ToArray()) + { + // Find setter: setXXX && one arg && not safe && parameter = getter.return && return == void + + var setter = methodList.FirstOrDefault( + u => + u.Name == "set" + getter.Name[3..] && + !u.Safe && + u.Parameters.Length == 1 && + u.Parameters[0].Type == getter.ReturnType && + u.ReturnType == ContractParameterType.Void + ); + + properties.Add((getter, setter)); + methodList.Remove(getter); + + if (setter != null) + { + methodList.Remove(setter); + } + } + + return (methodList.ToArray(), properties.ToArray()); + } + /// /// Create source code from event /// @@ -115,6 +169,23 @@ private static string CreateSourceEventFromManifest(ContractEventDescriptor ev) return sourceCode.ToString(); } + /// + /// Create source code from manifest property + /// + /// Property name + /// Property type + /// True if has set + /// Source + private static string CreateSourcePropertyFromManifest(string propertyName, ContractParameterType propertyType, bool hasSet) + { + var getset = hasSet ? "{ get; set; }" : "{ get; }"; + + StringBuilder sourceCode = new(); + sourceCode.AppendLine($" public abstract {TypeToSource(propertyType)} {EscapeName(propertyName)} {getset}"); + + return sourceCode.ToString(); + } + /// /// Create source code from manifest method /// @@ -124,7 +195,10 @@ private static string CreateSourceMethodFromManifest(ContractMethodDescriptor me { StringBuilder sourceCode = new(); - sourceCode.Append($" public abstract {TypeToSource(method.ReturnType)} {method.Name}("); + sourceCode.AppendLine($" /// "); + sourceCode.AppendLine($" /// {(method.Safe ? "Safe method" : "Unsafe method")}"); + sourceCode.AppendLine($" /// "); + sourceCode.Append($" public abstract {TypeToSource(method.ReturnType)} {EscapeName(method.Name)}("); bool isFirst = true; foreach (var arg in method.Parameters) diff --git a/src/Neo.SmartContract.Testing/Extensions/MockExtensions.cs b/src/Neo.SmartContract.Testing/Extensions/MockExtensions.cs index 0578e4931..c106685ba 100644 --- a/src/Neo.SmartContract.Testing/Extensions/MockExtensions.cs +++ b/src/Neo.SmartContract.Testing/Extensions/MockExtensions.cs @@ -69,7 +69,18 @@ public static void MockMethodWithReturn(this Mock mock, string name, Type[ _ = retMethod.Invoke(setup, new object[] { new InvocationFunc(invocation => { - return mock.Object.Invoke(invocation.Method.Name, invocation.Arguments.ToArray()).ConvertTo(returnType)!; + var isAccessor = invocation.Method.DeclaringType?.GetProperties() + .Any(prop => prop.GetSetMethod() == invocation.Method || prop.GetGetMethod() == invocation.Method); + + if (isAccessor == true) + { + // remove _ from get_ or set_ + return mock.Object.Invoke(invocation.Method.Name.Remove(3, 1), invocation.Arguments.ToArray()).ConvertTo(returnType)!; + } + else + { + return mock.Object.Invoke(invocation.Method.Name, invocation.Arguments.ToArray()).ConvertTo(returnType)!; + } }) }); } @@ -93,7 +104,18 @@ public static void MockMethod(this Mock mock, string name, Type[] args) _ = retMethod.Invoke(setup, new object[] { new InvocationAction(invocation => { - mock.Object.Invoke(invocation.Method.Name, invocation.Arguments.ToArray()); + var isAccessor = invocation.Method.DeclaringType?.GetProperties() + .Any(prop => prop.GetSetMethod() == invocation.Method || prop.GetGetMethod() == invocation.Method); + + if (isAccessor == true) + { + // remove _ from get_ or set_ + mock.Object.Invoke(invocation.Method.Name.Remove(3, 1), invocation.Arguments.ToArray()); + } + else + { + mock.Object.Invoke(invocation.Method.Name, invocation.Arguments.ToArray()); + } }) }); } diff --git a/src/Neo.SmartContract.Testing/Native/ContractManagement.cs b/src/Neo.SmartContract.Testing/Native/ContractManagement.cs index b0cc08ba6..28a63e2b0 100644 --- a/src/Neo.SmartContract.Testing/Native/ContractManagement.cs +++ b/src/Neo.SmartContract.Testing/Native/ContractManagement.cs @@ -14,22 +14,47 @@ public abstract class ContractManagement : Neo.SmartContract.Testing.SmartContra public delegate void delUpdate(UInt160 Hash); public event delUpdate? Update; #endregion + #region Properties + public abstract object ContractHashes { get; } + public abstract BigInteger MinimumDeploymentFee { get; set; } + #endregion #region Safe methods + /// + /// Safe method + /// public abstract ContractState getContract(UInt160 hash); + /// + /// Safe method + /// public abstract ContractState getContractById(BigInteger id); - public abstract object getContractHashes(); - public abstract BigInteger getMinimumDeploymentFee(); + /// + /// Safe method + /// public abstract bool hasMethod(UInt160 hash, string method, BigInteger pcount); #endregion #region Unsafe methods + /// + /// Unsafe method + /// public abstract ContractState deploy(byte[] nefFile, byte[] manifest); + /// + /// Unsafe method + /// public abstract ContractState deploy(byte[] nefFile, byte[] manifest, object data); + /// + /// Unsafe method + /// public abstract void destroy(); - public abstract void setMinimumDeploymentFee(BigInteger value); + /// + /// Unsafe method + /// public abstract void update(byte[] nefFile, byte[] manifest); + /// + /// Unsafe method + /// public abstract void update(byte[] nefFile, byte[] manifest, object data); #endregion #region Constructor for internal use only - protected ContractManagement(Neo.SmartContract.Testing.TestEngine testEngine, Neo.UInt160 hash) : base(testEngine, hash) { } + protected ContractManagement(Neo.SmartContract.Testing.TestEngine testEngine, Neo.UInt160 hash) : base(testEngine, hash) {} #endregion } diff --git a/src/Neo.SmartContract.Testing/Native/CryptoLib.cs b/src/Neo.SmartContract.Testing/Native/CryptoLib.cs index b1d7b6676..31c05d49f 100644 --- a/src/Neo.SmartContract.Testing/Native/CryptoLib.cs +++ b/src/Neo.SmartContract.Testing/Native/CryptoLib.cs @@ -7,18 +7,48 @@ namespace Neo.SmartContract.Testing; public abstract class CryptoLib : Neo.SmartContract.Testing.SmartContract { #region Safe methods + /// + /// Safe method + /// public abstract object bls12381Add(object x, object y); + /// + /// Safe method + /// public abstract object bls12381Deserialize(byte[] data); + /// + /// Safe method + /// public abstract bool bls12381Equal(object x, object y); + /// + /// Safe method + /// public abstract object bls12381Mul(object x, byte[] mul, bool neg); + /// + /// Safe method + /// public abstract object bls12381Pairing(object g1, object g2); + /// + /// Safe method + /// public abstract byte[] bls12381Serialize(object g); + /// + /// Safe method + /// public abstract byte[] murmur32(byte[] data, BigInteger seed); + /// + /// Safe method + /// public abstract byte[] ripemd160(byte[] data); + /// + /// Safe method + /// public abstract byte[] sha256(byte[] data); + /// + /// Safe method + /// public abstract bool verifyWithECDsa(byte[] message, byte[] pubkey, byte[] signature, BigInteger curve); #endregion #region Constructor for internal use only - protected CryptoLib(Neo.SmartContract.Testing.TestEngine testEngine, Neo.UInt160 hash) : base(testEngine, hash) { } + protected CryptoLib(Neo.SmartContract.Testing.TestEngine testEngine, Neo.UInt160 hash) : base(testEngine, hash) {} #endregion -} +} \ No newline at end of file diff --git a/src/Neo.SmartContract.Testing/Native/GasToken.cs b/src/Neo.SmartContract.Testing/Native/GasToken.cs index 6bc9ca9c3..14655e333 100644 --- a/src/Neo.SmartContract.Testing/Native/GasToken.cs +++ b/src/Neo.SmartContract.Testing/Native/GasToken.cs @@ -11,15 +11,30 @@ public abstract class GasToken : Neo.SmartContract.Testing.SmartContract public event delTransfer? Transfer; #endregion #region Safe methods + /// + /// Safe method + /// public abstract BigInteger balanceOf(UInt160 account); + /// + /// Safe method + /// public abstract BigInteger decimals(); + /// + /// Safe method + /// public abstract string symbol(); + /// + /// Safe method + /// public abstract BigInteger totalSupply(); #endregion #region Unsafe methods + /// + /// Unsafe method + /// public abstract bool transfer(UInt160 from, UInt160 to, BigInteger amount, object data); #endregion #region Constructor for internal use only - protected GasToken(Neo.SmartContract.Testing.TestEngine testEngine, Neo.UInt160 hash) : base(testEngine, hash) { } + protected GasToken(Neo.SmartContract.Testing.TestEngine testEngine, Neo.UInt160 hash) : base(testEngine, hash) {} #endregion -} +} \ No newline at end of file diff --git a/src/Neo.SmartContract.Testing/Native/LedgerContract.cs b/src/Neo.SmartContract.Testing/Native/LedgerContract.cs index a1be82c92..817e213a8 100644 --- a/src/Neo.SmartContract.Testing/Native/LedgerContract.cs +++ b/src/Neo.SmartContract.Testing/Native/LedgerContract.cs @@ -7,16 +7,40 @@ namespace Neo.SmartContract.Testing; public abstract class LedgerContract : Neo.SmartContract.Testing.SmartContract { #region Safe methods + /// + /// Safe method + /// public abstract UInt256 currentHash(); + /// + /// Safe method + /// public abstract BigInteger currentIndex(); + /// + /// Safe method + /// public abstract List getBlock(byte[] indexOrHash); + /// + /// Safe method + /// public abstract List getTransaction(UInt256 hash); + /// + /// Safe method + /// public abstract List getTransactionFromBlock(byte[] blockIndexOrHash, BigInteger txIndex); + /// + /// Safe method + /// public abstract BigInteger getTransactionHeight(UInt256 hash); + /// + /// Safe method + /// public abstract List getTransactionSigners(UInt256 hash); + /// + /// Safe method + /// public abstract BigInteger getTransactionVMState(UInt256 hash); #endregion #region Constructor for internal use only - protected LedgerContract(Neo.SmartContract.Testing.TestEngine testEngine, Neo.UInt160 hash) : base(testEngine, hash) { } + protected LedgerContract(Neo.SmartContract.Testing.TestEngine testEngine, Neo.UInt160 hash) : base(testEngine, hash) {} #endregion -} +} \ No newline at end of file diff --git a/src/Neo.SmartContract.Testing/Native/NeoToken.cs b/src/Neo.SmartContract.Testing/Native/NeoToken.cs index af7369bf3..6a4e88e48 100644 --- a/src/Neo.SmartContract.Testing/Native/NeoToken.cs +++ b/src/Neo.SmartContract.Testing/Native/NeoToken.cs @@ -14,30 +14,63 @@ public abstract class NeoToken : Neo.SmartContract.Testing.SmartContract public delegate void delVote(UInt160 account, ECPoint from, ECPoint to, BigInteger amount); public event delVote? Vote; #endregion + #region Properties + public abstract object AllCandidates { get; } + public abstract List Candidates { get; } + public abstract List Committee { get; } + public abstract BigInteger GasPerBlock { get; set; } + public abstract List NextBlockValidators { get; } + public abstract BigInteger RegisterPrice { get; set; } + #endregion #region Safe methods + /// + /// Safe method + /// public abstract BigInteger balanceOf(UInt160 account); + /// + /// Safe method + /// public abstract BigInteger decimals(); + /// + /// Safe method + /// public abstract List getAccountState(UInt160 account); - public abstract object getAllCandidates(); - public abstract List getCandidates(); + /// + /// Safe method + /// public abstract BigInteger getCandidateVote(ECPoint pubKey); - public abstract List getCommittee(); - public abstract BigInteger getGasPerBlock(); - public abstract List getNextBlockValidators(); - public abstract BigInteger getRegisterPrice(); + /// + /// Safe method + /// public abstract string symbol(); + /// + /// Safe method + /// public abstract BigInteger totalSupply(); + /// + /// Safe method + /// public abstract BigInteger unclaimedGas(UInt160 account, BigInteger end); #endregion #region Unsafe methods + /// + /// Unsafe method + /// public abstract bool registerCandidate(ECPoint pubkey); - public abstract void setGasPerBlock(BigInteger gasPerBlock); - public abstract void setRegisterPrice(BigInteger registerPrice); + /// + /// Unsafe method + /// public abstract bool transfer(UInt160 from, UInt160 to, BigInteger amount, object data); + /// + /// Unsafe method + /// public abstract bool unregisterCandidate(ECPoint pubkey); + /// + /// Unsafe method + /// public abstract bool vote(UInt160 account, ECPoint voteTo); #endregion #region Constructor for internal use only - protected NeoToken(Neo.SmartContract.Testing.TestEngine testEngine, Neo.UInt160 hash) : base(testEngine, hash) { } + protected NeoToken(Neo.SmartContract.Testing.TestEngine testEngine, Neo.UInt160 hash) : base(testEngine, hash) {} #endregion -} +} \ No newline at end of file diff --git a/src/Neo.SmartContract.Testing/Native/OracleContract.cs b/src/Neo.SmartContract.Testing/Native/OracleContract.cs index f9d3beb3a..48f03e6ab 100644 --- a/src/Neo.SmartContract.Testing/Native/OracleContract.cs +++ b/src/Neo.SmartContract.Testing/Native/OracleContract.cs @@ -12,16 +12,26 @@ public abstract class OracleContract : Neo.SmartContract.Testing.SmartContract public delegate void delOracleResponse(BigInteger Id, UInt256 OriginalTx); public event delOracleResponse? OracleResponse; #endregion + #region Properties + public abstract BigInteger Price { get; set; } + #endregion #region Safe methods - public abstract BigInteger getPrice(); + /// + /// Safe method + /// public abstract bool verify(); #endregion #region Unsafe methods + /// + /// Unsafe method + /// public abstract void finish(); + /// + /// Unsafe method + /// public abstract void request(string url, string filter, string callback, object userData, BigInteger gasForResponse); - public abstract void setPrice(BigInteger price); #endregion #region Constructor for internal use only - protected OracleContract(Neo.SmartContract.Testing.TestEngine testEngine, Neo.UInt160 hash) : base(testEngine, hash) { } + protected OracleContract(Neo.SmartContract.Testing.TestEngine testEngine, Neo.UInt160 hash) : base(testEngine, hash) {} #endregion -} +} \ No newline at end of file diff --git a/src/Neo.SmartContract.Testing/Native/PolicyContract.cs b/src/Neo.SmartContract.Testing/Native/PolicyContract.cs index a71512bf8..165c804a7 100644 --- a/src/Neo.SmartContract.Testing/Native/PolicyContract.cs +++ b/src/Neo.SmartContract.Testing/Native/PolicyContract.cs @@ -6,22 +6,36 @@ namespace Neo.SmartContract.Testing; public abstract class PolicyContract : Neo.SmartContract.Testing.SmartContract { + #region Properties + public abstract BigInteger ExecFeeFactor { get; set; } + public abstract BigInteger FeePerByte { get; set; } + public abstract BigInteger StoragePrice { get; set; } + #endregion #region Safe methods + /// + /// Safe method + /// public abstract BigInteger getAttributeFee(BigInteger attributeType); - public abstract BigInteger getExecFeeFactor(); - public abstract BigInteger getFeePerByte(); - public abstract BigInteger getStoragePrice(); + /// + /// Safe method + /// public abstract bool isBlocked(UInt160 account); #endregion #region Unsafe methods + /// + /// Unsafe method + /// public abstract bool blockAccount(UInt160 account); + /// + /// Unsafe method + /// public abstract void setAttributeFee(BigInteger attributeType, BigInteger value); - public abstract void setExecFeeFactor(BigInteger value); - public abstract void setFeePerByte(BigInteger value); - public abstract void setStoragePrice(BigInteger value); + /// + /// Unsafe method + /// public abstract bool unblockAccount(UInt160 account); #endregion #region Constructor for internal use only - protected PolicyContract(Neo.SmartContract.Testing.TestEngine testEngine, Neo.UInt160 hash) : base(testEngine, hash) { } + protected PolicyContract(Neo.SmartContract.Testing.TestEngine testEngine, Neo.UInt160 hash) : base(testEngine, hash) {} #endregion -} +} \ No newline at end of file diff --git a/src/Neo.SmartContract.Testing/Native/RoleManagement.cs b/src/Neo.SmartContract.Testing/Native/RoleManagement.cs index e40229bd2..0e88855f8 100644 --- a/src/Neo.SmartContract.Testing/Native/RoleManagement.cs +++ b/src/Neo.SmartContract.Testing/Native/RoleManagement.cs @@ -11,12 +11,18 @@ public abstract class RoleManagement : Neo.SmartContract.Testing.SmartContract public event delDesignation? Designation; #endregion #region Safe methods + /// + /// Safe method + /// public abstract List getDesignatedByRole(BigInteger role, BigInteger index); #endregion #region Unsafe methods + /// + /// Unsafe method + /// public abstract void designateAsRole(BigInteger role, List nodes); #endregion #region Constructor for internal use only - protected RoleManagement(Neo.SmartContract.Testing.TestEngine testEngine, Neo.UInt160 hash) : base(testEngine, hash) { } + protected RoleManagement(Neo.SmartContract.Testing.TestEngine testEngine, Neo.UInt160 hash) : base(testEngine, hash) {} #endregion -} +} \ No newline at end of file diff --git a/src/Neo.SmartContract.Testing/Native/StdLib.cs b/src/Neo.SmartContract.Testing/Native/StdLib.cs index f587ccefe..941ba5c0d 100644 --- a/src/Neo.SmartContract.Testing/Native/StdLib.cs +++ b/src/Neo.SmartContract.Testing/Native/StdLib.cs @@ -7,29 +7,92 @@ namespace Neo.SmartContract.Testing; public abstract class StdLib : Neo.SmartContract.Testing.SmartContract { #region Safe methods + /// + /// Safe method + /// public abstract BigInteger atoi(string value); + /// + /// Safe method + /// public abstract BigInteger atoi(string value, BigInteger @base); + /// + /// Safe method + /// public abstract byte[] base58CheckDecode(string s); + /// + /// Safe method + /// public abstract string base58CheckEncode(byte[] data); + /// + /// Safe method + /// public abstract byte[] base58Decode(string s); + /// + /// Safe method + /// public abstract string base58Encode(byte[] data); + /// + /// Safe method + /// public abstract byte[] base64Decode(string s); + /// + /// Safe method + /// public abstract string base64Encode(byte[] data); + /// + /// Safe method + /// public abstract object deserialize(byte[] data); + /// + /// Safe method + /// public abstract string itoa(BigInteger value); + /// + /// Safe method + /// public abstract string itoa(BigInteger value, BigInteger @base); + /// + /// Safe method + /// public abstract object jsonDeserialize(byte[] json); + /// + /// Safe method + /// public abstract byte[] jsonSerialize(object item); + /// + /// Safe method + /// public abstract BigInteger memoryCompare(byte[] str1, byte[] str2); + /// + /// Safe method + /// public abstract BigInteger memorySearch(byte[] mem, byte[] value); + /// + /// Safe method + /// public abstract BigInteger memorySearch(byte[] mem, byte[] value, BigInteger start); + /// + /// Safe method + /// public abstract BigInteger memorySearch(byte[] mem, byte[] value, BigInteger start, bool backward); + /// + /// Safe method + /// public abstract byte[] serialize(object item); + /// + /// Safe method + /// public abstract List stringSplit(string str, string separator); + /// + /// Safe method + /// public abstract List stringSplit(string str, string separator, bool removeEmptyEntries); + /// + /// Safe method + /// public abstract BigInteger strLen(string str); #endregion #region Constructor for internal use only - protected StdLib(Neo.SmartContract.Testing.TestEngine testEngine, Neo.UInt160 hash) : base(testEngine, hash) { } + protected StdLib(Neo.SmartContract.Testing.TestEngine testEngine, Neo.UInt160 hash) : base(testEngine, hash) {} #endregion -} +} \ No newline at end of file diff --git a/src/Neo.SmartContract.Testing/TestEngine.cs b/src/Neo.SmartContract.Testing/TestEngine.cs index fa6a393d4..9671d8607 100644 --- a/src/Neo.SmartContract.Testing/TestEngine.cs +++ b/src/Neo.SmartContract.Testing/TestEngine.cs @@ -11,6 +11,7 @@ using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using System.Linq; +using System.Reflection; using System.Text; namespace Neo.SmartContract.Testing @@ -259,7 +260,7 @@ private T MockContract(UInt160 hash, Action>? customMock = null) wher // Mock SmartContract - foreach (var method in typeof(T).GetMethods()) + foreach (var method in typeof(T).GetMethods(BindingFlags.Instance | BindingFlags.Public)) { if (!method.IsAbstract) continue; diff --git a/tests/Neo.SmartContract.Testing.UnitTests/Extensions/ArtifactExtensionsTests.cs b/tests/Neo.SmartContract.Testing.UnitTests/Extensions/ArtifactExtensionsTests.cs index a45ea26c7..82c360ab2 100644 --- a/tests/Neo.SmartContract.Testing.UnitTests/Extensions/ArtifactExtensionsTests.cs +++ b/tests/Neo.SmartContract.Testing.UnitTests/Extensions/ArtifactExtensionsTests.cs @@ -16,7 +16,7 @@ public void TestGetArtifactsSource() // Create artifacts - var source = manifest.Abi.GetArtifactsSource(manifest.Name); + var source = manifest.Abi.GetArtifactsSource(manifest.Name, generateProperties: true); Assert.AreEqual(source, @" using Neo.Cryptography.ECC; @@ -33,28 +33,66 @@ public abstract class Contract1 : Neo.SmartContract.Testing.SmartContract public delegate void delTransfer(UInt160 from, UInt160 to, BigInteger amount); public event delTransfer? Transfer; #endregion + #region Properties + public abstract UInt160 Owner { get; set; } + #endregion #region Safe methods + /// + /// Safe method + /// public abstract BigInteger balanceOf(UInt160 owner); + /// + /// Safe method + /// public abstract BigInteger decimals(); - public abstract UInt160 getOwner(); + /// + /// Safe method + /// public abstract string symbol(); + /// + /// Safe method + /// public abstract BigInteger totalSupply(); + /// + /// Safe method + /// public abstract bool verify(); #endregion #region Unsafe methods + /// + /// Unsafe method + /// public abstract void burn(UInt160 account, BigInteger amount); + /// + /// Unsafe method + /// public abstract void mint(UInt160 to, BigInteger amount); + /// + /// Unsafe method + /// public abstract string myMethod(); + /// + /// Unsafe method + /// public abstract void onNEP17Payment(UInt160 from, BigInteger amount, object data); - public abstract void setOwner(UInt160 newOwner); + /// + /// Unsafe method + /// public abstract bool transfer(UInt160 from, UInt160 to, BigInteger amount, object data); + /// + /// Unsafe method + /// public abstract void update(byte[] nefFile, string manifest); + /// + /// Unsafe method + /// public abstract bool withdraw(UInt160 token, UInt160 to, BigInteger amount); #endregion #region Constructor for internal use only protected Contract1(Neo.SmartContract.Testing.TestEngine testEngine, Neo.UInt160 hash) : base(testEngine, hash) {} #endregion } + ".Replace("\r\n", "\n").Trim()); } } diff --git a/tests/Neo.SmartContract.Testing.UnitTests/NativeArtifactsTests.cs b/tests/Neo.SmartContract.Testing.UnitTests/NativeArtifactsTests.cs index 8f6d7435b..11f891555 100644 --- a/tests/Neo.SmartContract.Testing.UnitTests/NativeArtifactsTests.cs +++ b/tests/Neo.SmartContract.Testing.UnitTests/NativeArtifactsTests.cs @@ -80,7 +80,7 @@ public void TestSignature() // Check initial value of getRegisterPrice - Assert.AreEqual(100000000000, engine.Native.NEO.getRegisterPrice()); + Assert.AreEqual(100000000000, engine.Native.NEO.RegisterPrice); // Fake Committee Signature @@ -95,15 +95,15 @@ public void TestSignature() // Change RegisterPrice to 123 - engine.Native.NEO.setRegisterPrice(123); + engine.Native.NEO.RegisterPrice = 123; - Assert.AreEqual(123, engine.Native.NEO.getRegisterPrice()); + Assert.AreEqual(123, engine.Native.NEO.RegisterPrice); // Now test it without this signature engine.Transaction.Signers[0].Scopes = Network.P2P.Payloads.WitnessScope.None; - Assert.ThrowsException(() => engine.Native.NEO.setRegisterPrice(123)); + Assert.ThrowsException(() => engine.Native.NEO.RegisterPrice = 123); } } } diff --git a/tests/Neo.SmartContract.Testing.UnitTests/SmartContractStorageTests.cs b/tests/Neo.SmartContract.Testing.UnitTests/SmartContractStorageTests.cs index 150982fe8..11b9b784c 100644 --- a/tests/Neo.SmartContract.Testing.UnitTests/SmartContractStorageTests.cs +++ b/tests/Neo.SmartContract.Testing.UnitTests/SmartContractStorageTests.cs @@ -19,7 +19,7 @@ public void TestAlterStorage() // Check previous data - Assert.AreEqual(100000000000, engine.Native.NEO.getRegisterPrice()); + Assert.AreEqual(100000000000, engine.Native.NEO.RegisterPrice); // Alter data @@ -27,7 +27,7 @@ public void TestAlterStorage() // Check altered data - Assert.AreEqual(BigInteger.MinusOne, engine.Native.NEO.getRegisterPrice()); + Assert.AreEqual(BigInteger.MinusOne, engine.Native.NEO.RegisterPrice); } } } diff --git a/tests/Neo.SmartContract.Testing.UnitTests/TestEngineTests.cs b/tests/Neo.SmartContract.Testing.UnitTests/TestEngineTests.cs index 1ebf59b14..921981f1b 100644 --- a/tests/Neo.SmartContract.Testing.UnitTests/TestEngineTests.cs +++ b/tests/Neo.SmartContract.Testing.UnitTests/TestEngineTests.cs @@ -22,7 +22,7 @@ public void GenerateNativeArtifacts() foreach (var n in Native.NativeContract.Contracts) { var manifest = n.Manifest; - var source = manifest.Abi.GetArtifactsSource(manifest.Name); + var source = manifest.Abi.GetArtifactsSource(manifest.Name, generateProperties: true); var fullPath = Path.GetFullPath($"../../../../../src/Neo.SmartContract.Testing/Native/{manifest.Name}.cs"); File.WriteAllText(fullPath, source); From 8bd03ba86201f7739f7b0ae28b8eb34c654e5152 Mon Sep 17 00:00:00 2001 From: Fernando Diaz Toledano Date: Sun, 11 Feb 2024 21:33:54 +0100 Subject: [PATCH 067/106] Allow properties if the method is without args and safe --- .../Extensions/ArtifactExtensions.cs | 24 +++++++------- .../Extensions/MockExtensions.cs | 33 +++++-------------- .../Native/ContractManagement.cs | 7 ++-- .../Native/CryptoLib.cs | 1 + .../Native/GasToken.cs | 18 ++++------ .../Native/LedgerContract.cs | 13 +++----- .../Native/NeoToken.cs | 28 ++++++---------- .../Native/OracleContract.cs | 10 ++---- .../Native/PolicyContract.cs | 7 ++-- .../Native/RoleManagement.cs | 1 + .../Native/StdLib.cs | 1 + .../Extensions/ArtifactExtensionsTests.cs | 24 ++++---------- .../NativeArtifactsTests.cs | 4 +-- .../TestEngineTests.cs | 4 +-- 14 files changed, 67 insertions(+), 108 deletions(-) diff --git a/src/Neo.SmartContract.Testing/Extensions/ArtifactExtensions.cs b/src/Neo.SmartContract.Testing/Extensions/ArtifactExtensions.cs index 56efb2013..bc4c23162 100644 --- a/src/Neo.SmartContract.Testing/Extensions/ArtifactExtensions.cs +++ b/src/Neo.SmartContract.Testing/Extensions/ArtifactExtensions.cs @@ -21,6 +21,7 @@ public static string GetArtifactsSource(this ContractAbi abi, string name, bool sourceCode.AppendLine("using Neo.Cryptography.ECC;"); sourceCode.AppendLine("using System.Collections.Generic;"); + sourceCode.AppendLine("using System.ComponentModel;"); sourceCode.AppendLine("using System.Numerics;"); sourceCode.AppendLine(""); sourceCode.AppendLine("namespace Neo.SmartContract.Testing;"); @@ -56,7 +57,7 @@ public static string GetArtifactsSource(this ContractAbi abi, string name, bool foreach (var property in properties.OrderBy(u => u.getter.Name)) { - sourceCode.Append(CreateSourcePropertyFromManifest(property.getter.Name[3..], property.getter.ReturnType, property.setter is not null)); + sourceCode.Append(CreateSourcePropertyFromManifest(property.getter, property.setter)); } sourceCode.AppendLine(" #endregion"); @@ -116,20 +117,21 @@ private static (ContractMethodDescriptor[] methods, (ContractMethodDescriptor ge List methodList = new(methods); List<(ContractMethodDescriptor, ContractMethodDescriptor?)> properties = new(); - // Detect and extract properties, first find getXXXX && Safe && 0 args && return != void + // Detect and extract properties, first find Safe && 0 args && return != void - foreach (ContractMethodDescriptor getter in methods.Where(u => u.Name.StartsWith("get") && u.Safe && u.Parameters.Length == 0 && u.ReturnType != ContractParameterType.Void).ToArray()) + foreach (ContractMethodDescriptor getter in methods.Where(u => u.Safe && u.Parameters.Length == 0 && u.ReturnType != ContractParameterType.Void).ToArray()) { // Find setter: setXXX && one arg && not safe && parameter = getter.return && return == void - var setter = methodList.FirstOrDefault( + var setter = getter.Name.StartsWith("get") ? // Only find setter if start with get + methodList.FirstOrDefault( u => u.Name == "set" + getter.Name[3..] && !u.Safe && u.Parameters.Length == 1 && u.Parameters[0].Type == getter.ReturnType && u.ReturnType == ContractParameterType.Void - ); + ) : null; properties.Add((getter, setter)); methodList.Remove(getter); @@ -172,16 +174,16 @@ private static string CreateSourceEventFromManifest(ContractEventDescriptor ev) /// /// Create source code from manifest property /// - /// Property name - /// Property type - /// True if has set + /// Getter + /// Setter /// Source - private static string CreateSourcePropertyFromManifest(string propertyName, ContractParameterType propertyType, bool hasSet) + private static string CreateSourcePropertyFromManifest(ContractMethodDescriptor getter, ContractMethodDescriptor? setter) { - var getset = hasSet ? "{ get; set; }" : "{ get; }"; + var propertyName = getter.Name.StartsWith("get") ? getter.Name[3..] : getter.Name; + var getset = setter is not null ? $"{{ [DisplayName(\"{getter.Name}\")] get; [DisplayName(\"{setter.Name}\")] set; }}" : $"{{ [DisplayName(\"{getter.Name}\")] get; }}"; StringBuilder sourceCode = new(); - sourceCode.AppendLine($" public abstract {TypeToSource(propertyType)} {EscapeName(propertyName)} {getset}"); + sourceCode.AppendLine($" public abstract {TypeToSource(getter.ReturnType)} {EscapeName(propertyName)} {getset}"); return sourceCode.ToString(); } diff --git a/src/Neo.SmartContract.Testing/Extensions/MockExtensions.cs b/src/Neo.SmartContract.Testing/Extensions/MockExtensions.cs index c106685ba..8666937cf 100644 --- a/src/Neo.SmartContract.Testing/Extensions/MockExtensions.cs +++ b/src/Neo.SmartContract.Testing/Extensions/MockExtensions.cs @@ -1,5 +1,6 @@ using Moq; using System; +using System.ComponentModel; using System.Linq; using System.Linq.Expressions; using System.Reflection; @@ -69,18 +70,10 @@ public static void MockMethodWithReturn(this Mock mock, string name, Type[ _ = retMethod.Invoke(setup, new object[] { new InvocationFunc(invocation => { - var isAccessor = invocation.Method.DeclaringType?.GetProperties() - .Any(prop => prop.GetSetMethod() == invocation.Method || prop.GetGetMethod() == invocation.Method); - - if (isAccessor == true) - { - // remove _ from get_ or set_ - return mock.Object.Invoke(invocation.Method.Name.Remove(3, 1), invocation.Arguments.ToArray()).ConvertTo(returnType)!; - } - else - { - return mock.Object.Invoke(invocation.Method.Name, invocation.Arguments.ToArray()).ConvertTo(returnType)!; - } + var display = invocation.Method.GetCustomAttribute(); + var name = display is not null ? display.DisplayName : invocation.Method.Name; + + return mock.Object.Invoke(name, invocation.Arguments.ToArray()).ConvertTo(returnType)!; }) }); } @@ -104,18 +97,10 @@ public static void MockMethod(this Mock mock, string name, Type[] args) _ = retMethod.Invoke(setup, new object[] { new InvocationAction(invocation => { - var isAccessor = invocation.Method.DeclaringType?.GetProperties() - .Any(prop => prop.GetSetMethod() == invocation.Method || prop.GetGetMethod() == invocation.Method); - - if (isAccessor == true) - { - // remove _ from get_ or set_ - mock.Object.Invoke(invocation.Method.Name.Remove(3, 1), invocation.Arguments.ToArray()); - } - else - { - mock.Object.Invoke(invocation.Method.Name, invocation.Arguments.ToArray()); - } + var display = invocation.Method.GetCustomAttribute(); + var name = display is not null ? display.DisplayName : invocation.Method.Name; + + mock.Object.Invoke(name, invocation.Arguments.ToArray()); }) }); } diff --git a/src/Neo.SmartContract.Testing/Native/ContractManagement.cs b/src/Neo.SmartContract.Testing/Native/ContractManagement.cs index 28a63e2b0..15bd27061 100644 --- a/src/Neo.SmartContract.Testing/Native/ContractManagement.cs +++ b/src/Neo.SmartContract.Testing/Native/ContractManagement.cs @@ -1,5 +1,6 @@ using Neo.Cryptography.ECC; using System.Collections.Generic; +using System.ComponentModel; using System.Numerics; namespace Neo.SmartContract.Testing; @@ -15,8 +16,8 @@ public abstract class ContractManagement : Neo.SmartContract.Testing.SmartContra public event delUpdate? Update; #endregion #region Properties - public abstract object ContractHashes { get; } - public abstract BigInteger MinimumDeploymentFee { get; set; } + public abstract object ContractHashes { [DisplayName("getContractHashes")] get; } + public abstract BigInteger MinimumDeploymentFee { [DisplayName("getMinimumDeploymentFee")] get; [DisplayName("setMinimumDeploymentFee")] set; } #endregion #region Safe methods /// @@ -55,6 +56,6 @@ public abstract class ContractManagement : Neo.SmartContract.Testing.SmartContra public abstract void update(byte[] nefFile, byte[] manifest, object data); #endregion #region Constructor for internal use only - protected ContractManagement(Neo.SmartContract.Testing.TestEngine testEngine, Neo.UInt160 hash) : base(testEngine, hash) {} + protected ContractManagement(Neo.SmartContract.Testing.TestEngine testEngine, Neo.UInt160 hash) : base(testEngine, hash) { } #endregion } diff --git a/src/Neo.SmartContract.Testing/Native/CryptoLib.cs b/src/Neo.SmartContract.Testing/Native/CryptoLib.cs index 31c05d49f..f3383406c 100644 --- a/src/Neo.SmartContract.Testing/Native/CryptoLib.cs +++ b/src/Neo.SmartContract.Testing/Native/CryptoLib.cs @@ -1,5 +1,6 @@ using Neo.Cryptography.ECC; using System.Collections.Generic; +using System.ComponentModel; using System.Numerics; namespace Neo.SmartContract.Testing; diff --git a/src/Neo.SmartContract.Testing/Native/GasToken.cs b/src/Neo.SmartContract.Testing/Native/GasToken.cs index 14655e333..2472b23d0 100644 --- a/src/Neo.SmartContract.Testing/Native/GasToken.cs +++ b/src/Neo.SmartContract.Testing/Native/GasToken.cs @@ -1,5 +1,6 @@ using Neo.Cryptography.ECC; using System.Collections.Generic; +using System.ComponentModel; using System.Numerics; namespace Neo.SmartContract.Testing; @@ -10,23 +11,16 @@ public abstract class GasToken : Neo.SmartContract.Testing.SmartContract public delegate void delTransfer(UInt160 from, UInt160 to, BigInteger amount); public event delTransfer? Transfer; #endregion + #region Properties + public abstract BigInteger decimals { [DisplayName("decimals")] get; } + public abstract string symbol { [DisplayName("symbol")] get; } + public abstract BigInteger totalSupply { [DisplayName("totalSupply")] get; } + #endregion #region Safe methods /// /// Safe method /// public abstract BigInteger balanceOf(UInt160 account); - /// - /// Safe method - /// - public abstract BigInteger decimals(); - /// - /// Safe method - /// - public abstract string symbol(); - /// - /// Safe method - /// - public abstract BigInteger totalSupply(); #endregion #region Unsafe methods /// diff --git a/src/Neo.SmartContract.Testing/Native/LedgerContract.cs b/src/Neo.SmartContract.Testing/Native/LedgerContract.cs index 817e213a8..96ed10d1f 100644 --- a/src/Neo.SmartContract.Testing/Native/LedgerContract.cs +++ b/src/Neo.SmartContract.Testing/Native/LedgerContract.cs @@ -1,23 +1,20 @@ using Neo.Cryptography.ECC; using System.Collections.Generic; +using System.ComponentModel; using System.Numerics; namespace Neo.SmartContract.Testing; public abstract class LedgerContract : Neo.SmartContract.Testing.SmartContract { + #region Properties + public abstract UInt256 currentHash { [DisplayName("currentHash")] get; } + public abstract BigInteger currentIndex { [DisplayName("currentIndex")] get; } + #endregion #region Safe methods /// /// Safe method /// - public abstract UInt256 currentHash(); - /// - /// Safe method - /// - public abstract BigInteger currentIndex(); - /// - /// Safe method - /// public abstract List getBlock(byte[] indexOrHash); /// /// Safe method diff --git a/src/Neo.SmartContract.Testing/Native/NeoToken.cs b/src/Neo.SmartContract.Testing/Native/NeoToken.cs index 6a4e88e48..67434a667 100644 --- a/src/Neo.SmartContract.Testing/Native/NeoToken.cs +++ b/src/Neo.SmartContract.Testing/Native/NeoToken.cs @@ -1,5 +1,6 @@ using Neo.Cryptography.ECC; using System.Collections.Generic; +using System.ComponentModel; using System.Numerics; namespace Neo.SmartContract.Testing; @@ -15,12 +16,15 @@ public abstract class NeoToken : Neo.SmartContract.Testing.SmartContract public event delVote? Vote; #endregion #region Properties - public abstract object AllCandidates { get; } - public abstract List Candidates { get; } - public abstract List Committee { get; } - public abstract BigInteger GasPerBlock { get; set; } - public abstract List NextBlockValidators { get; } - public abstract BigInteger RegisterPrice { get; set; } + public abstract BigInteger decimals { [DisplayName("decimals")] get; } + public abstract object AllCandidates { [DisplayName("getAllCandidates")] get; } + public abstract List Candidates { [DisplayName("getCandidates")] get; } + public abstract List Committee { [DisplayName("getCommittee")] get; } + public abstract BigInteger GasPerBlock { [DisplayName("getGasPerBlock")] get; [DisplayName("setGasPerBlock")] set; } + public abstract List NextBlockValidators { [DisplayName("getNextBlockValidators")] get; } + public abstract BigInteger RegisterPrice { [DisplayName("getRegisterPrice")] get; [DisplayName("setRegisterPrice")] set; } + public abstract string symbol { [DisplayName("symbol")] get; } + public abstract BigInteger totalSupply { [DisplayName("totalSupply")] get; } #endregion #region Safe methods /// @@ -30,10 +34,6 @@ public abstract class NeoToken : Neo.SmartContract.Testing.SmartContract /// /// Safe method /// - public abstract BigInteger decimals(); - /// - /// Safe method - /// public abstract List getAccountState(UInt160 account); /// /// Safe method @@ -42,14 +42,6 @@ public abstract class NeoToken : Neo.SmartContract.Testing.SmartContract /// /// Safe method /// - public abstract string symbol(); - /// - /// Safe method - /// - public abstract BigInteger totalSupply(); - /// - /// Safe method - /// public abstract BigInteger unclaimedGas(UInt160 account, BigInteger end); #endregion #region Unsafe methods diff --git a/src/Neo.SmartContract.Testing/Native/OracleContract.cs b/src/Neo.SmartContract.Testing/Native/OracleContract.cs index 48f03e6ab..51572ae2a 100644 --- a/src/Neo.SmartContract.Testing/Native/OracleContract.cs +++ b/src/Neo.SmartContract.Testing/Native/OracleContract.cs @@ -1,5 +1,6 @@ using Neo.Cryptography.ECC; using System.Collections.Generic; +using System.ComponentModel; using System.Numerics; namespace Neo.SmartContract.Testing; @@ -13,13 +14,8 @@ public abstract class OracleContract : Neo.SmartContract.Testing.SmartContract public event delOracleResponse? OracleResponse; #endregion #region Properties - public abstract BigInteger Price { get; set; } - #endregion - #region Safe methods - /// - /// Safe method - /// - public abstract bool verify(); + public abstract BigInteger Price { [DisplayName("getPrice")] get; [DisplayName("setPrice")] set; } + public abstract bool verify { [DisplayName("verify")] get; } #endregion #region Unsafe methods /// diff --git a/src/Neo.SmartContract.Testing/Native/PolicyContract.cs b/src/Neo.SmartContract.Testing/Native/PolicyContract.cs index 165c804a7..55dfb615f 100644 --- a/src/Neo.SmartContract.Testing/Native/PolicyContract.cs +++ b/src/Neo.SmartContract.Testing/Native/PolicyContract.cs @@ -1,5 +1,6 @@ using Neo.Cryptography.ECC; using System.Collections.Generic; +using System.ComponentModel; using System.Numerics; namespace Neo.SmartContract.Testing; @@ -7,9 +8,9 @@ namespace Neo.SmartContract.Testing; public abstract class PolicyContract : Neo.SmartContract.Testing.SmartContract { #region Properties - public abstract BigInteger ExecFeeFactor { get; set; } - public abstract BigInteger FeePerByte { get; set; } - public abstract BigInteger StoragePrice { get; set; } + public abstract BigInteger ExecFeeFactor { [DisplayName("getExecFeeFactor")] get; [DisplayName("setExecFeeFactor")] set; } + public abstract BigInteger FeePerByte { [DisplayName("getFeePerByte")] get; [DisplayName("setFeePerByte")] set; } + public abstract BigInteger StoragePrice { [DisplayName("getStoragePrice")] get; [DisplayName("setStoragePrice")] set; } #endregion #region Safe methods /// diff --git a/src/Neo.SmartContract.Testing/Native/RoleManagement.cs b/src/Neo.SmartContract.Testing/Native/RoleManagement.cs index 0e88855f8..7563af22c 100644 --- a/src/Neo.SmartContract.Testing/Native/RoleManagement.cs +++ b/src/Neo.SmartContract.Testing/Native/RoleManagement.cs @@ -1,5 +1,6 @@ using Neo.Cryptography.ECC; using System.Collections.Generic; +using System.ComponentModel; using System.Numerics; namespace Neo.SmartContract.Testing; diff --git a/src/Neo.SmartContract.Testing/Native/StdLib.cs b/src/Neo.SmartContract.Testing/Native/StdLib.cs index 941ba5c0d..4f7dd9791 100644 --- a/src/Neo.SmartContract.Testing/Native/StdLib.cs +++ b/src/Neo.SmartContract.Testing/Native/StdLib.cs @@ -1,5 +1,6 @@ using Neo.Cryptography.ECC; using System.Collections.Generic; +using System.ComponentModel; using System.Numerics; namespace Neo.SmartContract.Testing; diff --git a/tests/Neo.SmartContract.Testing.UnitTests/Extensions/ArtifactExtensionsTests.cs b/tests/Neo.SmartContract.Testing.UnitTests/Extensions/ArtifactExtensionsTests.cs index 82c360ab2..cebac9e27 100644 --- a/tests/Neo.SmartContract.Testing.UnitTests/Extensions/ArtifactExtensionsTests.cs +++ b/tests/Neo.SmartContract.Testing.UnitTests/Extensions/ArtifactExtensionsTests.cs @@ -21,6 +21,7 @@ public void TestGetArtifactsSource() Assert.AreEqual(source, @" using Neo.Cryptography.ECC; using System.Collections.Generic; +using System.ComponentModel; using System.Numerics; namespace Neo.SmartContract.Testing; @@ -34,29 +35,17 @@ public abstract class Contract1 : Neo.SmartContract.Testing.SmartContract public event delTransfer? Transfer; #endregion #region Properties - public abstract UInt160 Owner { get; set; } + public abstract BigInteger decimals { [DisplayName(""decimals"")] get; } + public abstract UInt160 Owner { [DisplayName(""getOwner"")] get; [DisplayName(""setOwner"")] set; } + public abstract string symbol { [DisplayName(""symbol"")] get; } + public abstract BigInteger totalSupply { [DisplayName(""totalSupply"")] get; } + public abstract bool verify { [DisplayName(""verify"")] get; } #endregion #region Safe methods /// /// Safe method /// public abstract BigInteger balanceOf(UInt160 owner); - /// - /// Safe method - /// - public abstract BigInteger decimals(); - /// - /// Safe method - /// - public abstract string symbol(); - /// - /// Safe method - /// - public abstract BigInteger totalSupply(); - /// - /// Safe method - /// - public abstract bool verify(); #endregion #region Unsafe methods /// @@ -92,7 +81,6 @@ public abstract class Contract1 : Neo.SmartContract.Testing.SmartContract protected Contract1(Neo.SmartContract.Testing.TestEngine testEngine, Neo.UInt160 hash) : base(testEngine, hash) {} #endregion } - ".Replace("\r\n", "\n").Trim()); } } diff --git a/tests/Neo.SmartContract.Testing.UnitTests/NativeArtifactsTests.cs b/tests/Neo.SmartContract.Testing.UnitTests/NativeArtifactsTests.cs index 11f891555..109f0c701 100644 --- a/tests/Neo.SmartContract.Testing.UnitTests/NativeArtifactsTests.cs +++ b/tests/Neo.SmartContract.Testing.UnitTests/NativeArtifactsTests.cs @@ -23,8 +23,8 @@ public void TestInitialize() // Ensure that the main address contains the totalSupply - Assert.AreEqual(100_000_000, engine.Native.NEO.totalSupply()); - Assert.AreEqual(engine.Native.NEO.totalSupply(), engine.Native.NEO.balanceOf(engine.BFTAddress)); + Assert.AreEqual(100_000_000, engine.Native.NEO.totalSupply); + Assert.AreEqual(engine.Native.NEO.totalSupply, engine.Native.NEO.balanceOf(engine.BFTAddress)); } [TestMethod] diff --git a/tests/Neo.SmartContract.Testing.UnitTests/TestEngineTests.cs b/tests/Neo.SmartContract.Testing.UnitTests/TestEngineTests.cs index 921981f1b..5073d89d6 100644 --- a/tests/Neo.SmartContract.Testing.UnitTests/TestEngineTests.cs +++ b/tests/Neo.SmartContract.Testing.UnitTests/TestEngineTests.cs @@ -120,8 +120,8 @@ public void FromHashTest() // Ensure that the main address contains the totalSupply - Assert.AreEqual(100_000_000, neo.totalSupply()); - Assert.AreEqual(neo.totalSupply(), neo.balanceOf(engine.BFTAddress)); + Assert.AreEqual(100_000_000, neo.totalSupply); + Assert.AreEqual(neo.totalSupply, neo.balanceOf(engine.BFTAddress)); } } } From a662f37747ce8cb0707ad43891cdcf2cb1849b6d Mon Sep 17 00:00:00 2001 From: Fernando Diaz Toledano Date: Sun, 11 Feb 2024 21:57:08 +0100 Subject: [PATCH 068/106] User uppercase for first letter (conflicts with events and methods in native contracts) --- .../Extensions/ArtifactExtensions.cs | 26 +++++++- .../Native/ContractManagement.cs | 33 ++++++---- .../Native/CryptoLib.cs | 30 ++++++--- .../Native/GasToken.cs | 17 ++--- .../Native/LedgerContract.cs | 22 ++++--- .../Native/NeoToken.cs | 38 ++++++----- .../Native/OracleContract.cs | 8 ++- .../Native/PolicyContract.cs | 15 +++-- .../Native/RoleManagement.cs | 6 +- .../Native/StdLib.cs | 63 ++++++++++++------- .../SmartContract.cs | 9 ++- .../SmartContractStorage.cs | 2 +- src/Neo.SmartContract.Testing/TestEngine.cs | 4 +- .../Extensions/ArtifactExtensionsTests.cs | 32 ++++++---- .../NativeArtifactsTests.cs | 12 ++-- .../TestEngineTests.cs | 10 +-- 16 files changed, 216 insertions(+), 111 deletions(-) diff --git a/src/Neo.SmartContract.Testing/Extensions/ArtifactExtensions.cs b/src/Neo.SmartContract.Testing/Extensions/ArtifactExtensions.cs index bc4c23162..353854a4f 100644 --- a/src/Neo.SmartContract.Testing/Extensions/ArtifactExtensions.cs +++ b/src/Neo.SmartContract.Testing/Extensions/ArtifactExtensions.cs @@ -179,11 +179,11 @@ private static string CreateSourceEventFromManifest(ContractEventDescriptor ev) /// Source private static string CreateSourcePropertyFromManifest(ContractMethodDescriptor getter, ContractMethodDescriptor? setter) { - var propertyName = getter.Name.StartsWith("get") ? getter.Name[3..] : getter.Name; + var propertyName = TongleLowercase(EscapeName(getter.Name.StartsWith("get") ? getter.Name[3..] : getter.Name), out _); var getset = setter is not null ? $"{{ [DisplayName(\"{getter.Name}\")] get; [DisplayName(\"{setter.Name}\")] set; }}" : $"{{ [DisplayName(\"{getter.Name}\")] get; }}"; StringBuilder sourceCode = new(); - sourceCode.AppendLine($" public abstract {TypeToSource(getter.ReturnType)} {EscapeName(propertyName)} {getset}"); + sourceCode.AppendLine($" public abstract {TypeToSource(getter.ReturnType)} {propertyName} {getset}"); return sourceCode.ToString(); } @@ -195,12 +195,18 @@ private static string CreateSourcePropertyFromManifest(ContractMethodDescriptor /// Source private static string CreateSourceMethodFromManifest(ContractMethodDescriptor method) { + var methodName = TongleLowercase(EscapeName(method.Name), out var lcChanged); + StringBuilder sourceCode = new(); sourceCode.AppendLine($" /// "); sourceCode.AppendLine($" /// {(method.Safe ? "Safe method" : "Unsafe method")}"); sourceCode.AppendLine($" /// "); - sourceCode.Append($" public abstract {TypeToSource(method.ReturnType)} {EscapeName(method.Name)}("); + if (lcChanged) + { + sourceCode.AppendLine($" [DisplayName(\"{method.Name}\")]"); + } + sourceCode.Append($" public abstract {TypeToSource(method.ReturnType)} {methodName}("); bool isFirst = true; foreach (var arg in method.Parameters) @@ -216,6 +222,20 @@ private static string CreateSourceMethodFromManifest(ContractMethodDescriptor me return sourceCode.ToString(); } + private static string TongleLowercase(string value, out bool lcChanged) + { + if (value.Length == 0) + { + lcChanged = false; + return value; + } + + lcChanged = char.IsLower(value[0]); + if (lcChanged) return value[0].ToString().ToUpperInvariant() + value[1..]; + + return value; + } + /// /// Escape name /// diff --git a/src/Neo.SmartContract.Testing/Native/ContractManagement.cs b/src/Neo.SmartContract.Testing/Native/ContractManagement.cs index 15bd27061..66781ca65 100644 --- a/src/Neo.SmartContract.Testing/Native/ContractManagement.cs +++ b/src/Neo.SmartContract.Testing/Native/ContractManagement.cs @@ -9,11 +9,14 @@ public abstract class ContractManagement : Neo.SmartContract.Testing.SmartContra { #region Events public delegate void delDeploy(UInt160 Hash); - public event delDeploy? Deploy; + [DisplayName("Deploy")] + public event delDeploy? OnDeploy; public delegate void delDestroy(UInt160 Hash); - public event delDestroy? Destroy; + [DisplayName("Destroy")] + public event delDestroy? OnDestroy; public delegate void delUpdate(UInt160 Hash); - public event delUpdate? Update; + [DisplayName("Update")] + public event delUpdate? OnUpdate; #endregion #region Properties public abstract object ContractHashes { [DisplayName("getContractHashes")] get; } @@ -23,37 +26,45 @@ public abstract class ContractManagement : Neo.SmartContract.Testing.SmartContra /// /// Safe method /// - public abstract ContractState getContract(UInt160 hash); + [DisplayName("getContract")] + public abstract ContractState GetContract(UInt160 hash); /// /// Safe method /// - public abstract ContractState getContractById(BigInteger id); + [DisplayName("getContractById")] + public abstract ContractState GetContractById(BigInteger id); /// /// Safe method /// - public abstract bool hasMethod(UInt160 hash, string method, BigInteger pcount); + [DisplayName("hasMethod")] + public abstract bool HasMethod(UInt160 hash, string method, BigInteger pcount); #endregion #region Unsafe methods /// /// Unsafe method /// - public abstract ContractState deploy(byte[] nefFile, byte[] manifest); + [DisplayName("deploy")] + public abstract ContractState Deploy(byte[] nefFile, byte[] manifest); /// /// Unsafe method /// - public abstract ContractState deploy(byte[] nefFile, byte[] manifest, object data); + [DisplayName("deploy")] + public abstract ContractState Deploy(byte[] nefFile, byte[] manifest, object data); /// /// Unsafe method /// - public abstract void destroy(); + [DisplayName("destroy")] + public abstract void Destroy(); /// /// Unsafe method /// - public abstract void update(byte[] nefFile, byte[] manifest); + [DisplayName("update")] + public abstract void Update(byte[] nefFile, byte[] manifest); /// /// Unsafe method /// - public abstract void update(byte[] nefFile, byte[] manifest, object data); + [DisplayName("update")] + public abstract void Update(byte[] nefFile, byte[] manifest, object data); #endregion #region Constructor for internal use only protected ContractManagement(Neo.SmartContract.Testing.TestEngine testEngine, Neo.UInt160 hash) : base(testEngine, hash) { } diff --git a/src/Neo.SmartContract.Testing/Native/CryptoLib.cs b/src/Neo.SmartContract.Testing/Native/CryptoLib.cs index f3383406c..24afd8f3d 100644 --- a/src/Neo.SmartContract.Testing/Native/CryptoLib.cs +++ b/src/Neo.SmartContract.Testing/Native/CryptoLib.cs @@ -11,43 +11,53 @@ public abstract class CryptoLib : Neo.SmartContract.Testing.SmartContract /// /// Safe method /// - public abstract object bls12381Add(object x, object y); + [DisplayName("bls12381Add")] + public abstract object Bls12381Add(object x, object y); /// /// Safe method /// - public abstract object bls12381Deserialize(byte[] data); + [DisplayName("bls12381Deserialize")] + public abstract object Bls12381Deserialize(byte[] data); /// /// Safe method /// - public abstract bool bls12381Equal(object x, object y); + [DisplayName("bls12381Equal")] + public abstract bool Bls12381Equal(object x, object y); /// /// Safe method /// - public abstract object bls12381Mul(object x, byte[] mul, bool neg); + [DisplayName("bls12381Mul")] + public abstract object Bls12381Mul(object x, byte[] mul, bool neg); /// /// Safe method /// - public abstract object bls12381Pairing(object g1, object g2); + [DisplayName("bls12381Pairing")] + public abstract object Bls12381Pairing(object g1, object g2); /// /// Safe method /// - public abstract byte[] bls12381Serialize(object g); + [DisplayName("bls12381Serialize")] + public abstract byte[] Bls12381Serialize(object g); /// /// Safe method /// - public abstract byte[] murmur32(byte[] data, BigInteger seed); + [DisplayName("murmur32")] + public abstract byte[] Murmur32(byte[] data, BigInteger seed); /// /// Safe method /// - public abstract byte[] ripemd160(byte[] data); + [DisplayName("ripemd160")] + public abstract byte[] Ripemd160(byte[] data); /// /// Safe method /// - public abstract byte[] sha256(byte[] data); + [DisplayName("sha256")] + public abstract byte[] Sha256(byte[] data); /// /// Safe method /// - public abstract bool verifyWithECDsa(byte[] message, byte[] pubkey, byte[] signature, BigInteger curve); + [DisplayName("verifyWithECDsa")] + public abstract bool VerifyWithECDsa(byte[] message, byte[] pubkey, byte[] signature, BigInteger curve); #endregion #region Constructor for internal use only protected CryptoLib(Neo.SmartContract.Testing.TestEngine testEngine, Neo.UInt160 hash) : base(testEngine, hash) {} diff --git a/src/Neo.SmartContract.Testing/Native/GasToken.cs b/src/Neo.SmartContract.Testing/Native/GasToken.cs index 2472b23d0..8998424cb 100644 --- a/src/Neo.SmartContract.Testing/Native/GasToken.cs +++ b/src/Neo.SmartContract.Testing/Native/GasToken.cs @@ -9,26 +9,29 @@ public abstract class GasToken : Neo.SmartContract.Testing.SmartContract { #region Events public delegate void delTransfer(UInt160 from, UInt160 to, BigInteger amount); - public event delTransfer? Transfer; + [DisplayName("Transfer")] + public event delTransfer? OnTransfer; #endregion #region Properties - public abstract BigInteger decimals { [DisplayName("decimals")] get; } - public abstract string symbol { [DisplayName("symbol")] get; } - public abstract BigInteger totalSupply { [DisplayName("totalSupply")] get; } + public abstract BigInteger Decimals { [DisplayName("decimals")] get; } + public abstract string Symbol { [DisplayName("symbol")] get; } + public abstract BigInteger TotalSupply { [DisplayName("totalSupply")] get; } #endregion #region Safe methods /// /// Safe method /// - public abstract BigInteger balanceOf(UInt160 account); + [DisplayName("balanceOf")] + public abstract BigInteger BalanceOf(UInt160 account); #endregion #region Unsafe methods /// /// Unsafe method /// - public abstract bool transfer(UInt160 from, UInt160 to, BigInteger amount, object data); + [DisplayName("transfer")] + public abstract bool Transfer(UInt160 from, UInt160 to, BigInteger amount, object data); #endregion #region Constructor for internal use only protected GasToken(Neo.SmartContract.Testing.TestEngine testEngine, Neo.UInt160 hash) : base(testEngine, hash) {} #endregion -} \ No newline at end of file +} diff --git a/src/Neo.SmartContract.Testing/Native/LedgerContract.cs b/src/Neo.SmartContract.Testing/Native/LedgerContract.cs index 96ed10d1f..a479c34c6 100644 --- a/src/Neo.SmartContract.Testing/Native/LedgerContract.cs +++ b/src/Neo.SmartContract.Testing/Native/LedgerContract.cs @@ -8,34 +8,40 @@ namespace Neo.SmartContract.Testing; public abstract class LedgerContract : Neo.SmartContract.Testing.SmartContract { #region Properties - public abstract UInt256 currentHash { [DisplayName("currentHash")] get; } - public abstract BigInteger currentIndex { [DisplayName("currentIndex")] get; } + public abstract UInt256 CurrentHash { [DisplayName("currentHash")] get; } + public abstract BigInteger CurrentIndex { [DisplayName("currentIndex")] get; } #endregion #region Safe methods /// /// Safe method /// - public abstract List getBlock(byte[] indexOrHash); + [DisplayName("getBlock")] + public abstract List GetBlock(byte[] indexOrHash); /// /// Safe method /// - public abstract List getTransaction(UInt256 hash); + [DisplayName("getTransaction")] + public abstract List GetTransaction(UInt256 hash); /// /// Safe method /// - public abstract List getTransactionFromBlock(byte[] blockIndexOrHash, BigInteger txIndex); + [DisplayName("getTransactionFromBlock")] + public abstract List GetTransactionFromBlock(byte[] blockIndexOrHash, BigInteger txIndex); /// /// Safe method /// - public abstract BigInteger getTransactionHeight(UInt256 hash); + [DisplayName("getTransactionHeight")] + public abstract BigInteger GetTransactionHeight(UInt256 hash); /// /// Safe method /// - public abstract List getTransactionSigners(UInt256 hash); + [DisplayName("getTransactionSigners")] + public abstract List GetTransactionSigners(UInt256 hash); /// /// Safe method /// - public abstract BigInteger getTransactionVMState(UInt256 hash); + [DisplayName("getTransactionVMState")] + public abstract BigInteger GetTransactionVMState(UInt256 hash); #endregion #region Constructor for internal use only protected LedgerContract(Neo.SmartContract.Testing.TestEngine testEngine, Neo.UInt160 hash) : base(testEngine, hash) {} diff --git a/src/Neo.SmartContract.Testing/Native/NeoToken.cs b/src/Neo.SmartContract.Testing/Native/NeoToken.cs index 67434a667..3c6c1ddbd 100644 --- a/src/Neo.SmartContract.Testing/Native/NeoToken.cs +++ b/src/Neo.SmartContract.Testing/Native/NeoToken.cs @@ -11,58 +11,68 @@ public abstract class NeoToken : Neo.SmartContract.Testing.SmartContract public delegate void delCandidateStateChanged(ECPoint pubkey, bool registered, BigInteger votes); public event delCandidateStateChanged? CandidateStateChanged; public delegate void delTransfer(UInt160 from, UInt160 to, BigInteger amount); - public event delTransfer? Transfer; + [DisplayName("Transfer")] + public event delTransfer? OnTransfer; public delegate void delVote(UInt160 account, ECPoint from, ECPoint to, BigInteger amount); - public event delVote? Vote; + [DisplayName("Vote")] + public event delVote? OnVote; #endregion #region Properties - public abstract BigInteger decimals { [DisplayName("decimals")] get; } + public abstract BigInteger Decimals { [DisplayName("decimals")] get; } public abstract object AllCandidates { [DisplayName("getAllCandidates")] get; } public abstract List Candidates { [DisplayName("getCandidates")] get; } public abstract List Committee { [DisplayName("getCommittee")] get; } public abstract BigInteger GasPerBlock { [DisplayName("getGasPerBlock")] get; [DisplayName("setGasPerBlock")] set; } public abstract List NextBlockValidators { [DisplayName("getNextBlockValidators")] get; } public abstract BigInteger RegisterPrice { [DisplayName("getRegisterPrice")] get; [DisplayName("setRegisterPrice")] set; } - public abstract string symbol { [DisplayName("symbol")] get; } - public abstract BigInteger totalSupply { [DisplayName("totalSupply")] get; } + public abstract string Symbol { [DisplayName("symbol")] get; } + public abstract BigInteger TotalSupply { [DisplayName("totalSupply")] get; } #endregion #region Safe methods /// /// Safe method /// - public abstract BigInteger balanceOf(UInt160 account); + [DisplayName("balanceOf")] + public abstract BigInteger BalanceOf(UInt160 account); /// /// Safe method /// - public abstract List getAccountState(UInt160 account); + [DisplayName("getAccountState")] + public abstract List GetAccountState(UInt160 account); /// /// Safe method /// - public abstract BigInteger getCandidateVote(ECPoint pubKey); + [DisplayName("getCandidateVote")] + public abstract BigInteger GetCandidateVote(ECPoint pubKey); /// /// Safe method /// - public abstract BigInteger unclaimedGas(UInt160 account, BigInteger end); + [DisplayName("unclaimedGas")] + public abstract BigInteger UnclaimedGas(UInt160 account, BigInteger end); #endregion #region Unsafe methods /// /// Unsafe method /// - public abstract bool registerCandidate(ECPoint pubkey); + [DisplayName("registerCandidate")] + public abstract bool RegisterCandidate(ECPoint pubkey); /// /// Unsafe method /// - public abstract bool transfer(UInt160 from, UInt160 to, BigInteger amount, object data); + [DisplayName("transfer")] + public abstract bool Transfer(UInt160 from, UInt160 to, BigInteger amount, object data); /// /// Unsafe method /// - public abstract bool unregisterCandidate(ECPoint pubkey); + [DisplayName("unregisterCandidate")] + public abstract bool UnregisterCandidate(ECPoint pubkey); /// /// Unsafe method /// - public abstract bool vote(UInt160 account, ECPoint voteTo); + [DisplayName("vote")] + public abstract bool Vote(UInt160 account, ECPoint voteTo); #endregion #region Constructor for internal use only protected NeoToken(Neo.SmartContract.Testing.TestEngine testEngine, Neo.UInt160 hash) : base(testEngine, hash) {} #endregion -} \ No newline at end of file +} diff --git a/src/Neo.SmartContract.Testing/Native/OracleContract.cs b/src/Neo.SmartContract.Testing/Native/OracleContract.cs index 51572ae2a..fdafdb459 100644 --- a/src/Neo.SmartContract.Testing/Native/OracleContract.cs +++ b/src/Neo.SmartContract.Testing/Native/OracleContract.cs @@ -15,17 +15,19 @@ public abstract class OracleContract : Neo.SmartContract.Testing.SmartContract #endregion #region Properties public abstract BigInteger Price { [DisplayName("getPrice")] get; [DisplayName("setPrice")] set; } - public abstract bool verify { [DisplayName("verify")] get; } + public abstract bool Verify { [DisplayName("verify")] get; } #endregion #region Unsafe methods /// /// Unsafe method /// - public abstract void finish(); + [DisplayName("finish")] + public abstract void Finish(); /// /// Unsafe method /// - public abstract void request(string url, string filter, string callback, object userData, BigInteger gasForResponse); + [DisplayName("request")] + public abstract void Request(string url, string filter, string callback, object userData, BigInteger gasForResponse); #endregion #region Constructor for internal use only protected OracleContract(Neo.SmartContract.Testing.TestEngine testEngine, Neo.UInt160 hash) : base(testEngine, hash) {} diff --git a/src/Neo.SmartContract.Testing/Native/PolicyContract.cs b/src/Neo.SmartContract.Testing/Native/PolicyContract.cs index 55dfb615f..27abaf7cd 100644 --- a/src/Neo.SmartContract.Testing/Native/PolicyContract.cs +++ b/src/Neo.SmartContract.Testing/Native/PolicyContract.cs @@ -16,25 +16,30 @@ public abstract class PolicyContract : Neo.SmartContract.Testing.SmartContract /// /// Safe method /// - public abstract BigInteger getAttributeFee(BigInteger attributeType); + [DisplayName("getAttributeFee")] + public abstract BigInteger GetAttributeFee(BigInteger attributeType); /// /// Safe method /// - public abstract bool isBlocked(UInt160 account); + [DisplayName("isBlocked")] + public abstract bool IsBlocked(UInt160 account); #endregion #region Unsafe methods /// /// Unsafe method /// - public abstract bool blockAccount(UInt160 account); + [DisplayName("blockAccount")] + public abstract bool BlockAccount(UInt160 account); /// /// Unsafe method /// - public abstract void setAttributeFee(BigInteger attributeType, BigInteger value); + [DisplayName("setAttributeFee")] + public abstract void SetAttributeFee(BigInteger attributeType, BigInteger value); /// /// Unsafe method /// - public abstract bool unblockAccount(UInt160 account); + [DisplayName("unblockAccount")] + public abstract bool UnblockAccount(UInt160 account); #endregion #region Constructor for internal use only protected PolicyContract(Neo.SmartContract.Testing.TestEngine testEngine, Neo.UInt160 hash) : base(testEngine, hash) {} diff --git a/src/Neo.SmartContract.Testing/Native/RoleManagement.cs b/src/Neo.SmartContract.Testing/Native/RoleManagement.cs index 7563af22c..99c530505 100644 --- a/src/Neo.SmartContract.Testing/Native/RoleManagement.cs +++ b/src/Neo.SmartContract.Testing/Native/RoleManagement.cs @@ -15,13 +15,15 @@ public abstract class RoleManagement : Neo.SmartContract.Testing.SmartContract /// /// Safe method /// - public abstract List getDesignatedByRole(BigInteger role, BigInteger index); + [DisplayName("getDesignatedByRole")] + public abstract List GetDesignatedByRole(BigInteger role, BigInteger index); #endregion #region Unsafe methods /// /// Unsafe method /// - public abstract void designateAsRole(BigInteger role, List nodes); + [DisplayName("designateAsRole")] + public abstract void DesignateAsRole(BigInteger role, List nodes); #endregion #region Constructor for internal use only protected RoleManagement(Neo.SmartContract.Testing.TestEngine testEngine, Neo.UInt160 hash) : base(testEngine, hash) {} diff --git a/src/Neo.SmartContract.Testing/Native/StdLib.cs b/src/Neo.SmartContract.Testing/Native/StdLib.cs index 4f7dd9791..ff8d27d5b 100644 --- a/src/Neo.SmartContract.Testing/Native/StdLib.cs +++ b/src/Neo.SmartContract.Testing/Native/StdLib.cs @@ -11,87 +11,108 @@ public abstract class StdLib : Neo.SmartContract.Testing.SmartContract /// /// Safe method /// - public abstract BigInteger atoi(string value); + [DisplayName("atoi")] + public abstract BigInteger Atoi(string value); /// /// Safe method /// - public abstract BigInteger atoi(string value, BigInteger @base); + [DisplayName("atoi")] + public abstract BigInteger Atoi(string value, BigInteger @base); /// /// Safe method /// - public abstract byte[] base58CheckDecode(string s); + [DisplayName("base58CheckDecode")] + public abstract byte[] Base58CheckDecode(string s); /// /// Safe method /// - public abstract string base58CheckEncode(byte[] data); + [DisplayName("base58CheckEncode")] + public abstract string Base58CheckEncode(byte[] data); /// /// Safe method /// - public abstract byte[] base58Decode(string s); + [DisplayName("base58Decode")] + public abstract byte[] Base58Decode(string s); /// /// Safe method /// - public abstract string base58Encode(byte[] data); + [DisplayName("base58Encode")] + public abstract string Base58Encode(byte[] data); /// /// Safe method /// - public abstract byte[] base64Decode(string s); + [DisplayName("base64Decode")] + public abstract byte[] Base64Decode(string s); /// /// Safe method /// - public abstract string base64Encode(byte[] data); + [DisplayName("base64Encode")] + public abstract string Base64Encode(byte[] data); /// /// Safe method /// - public abstract object deserialize(byte[] data); + [DisplayName("deserialize")] + public abstract object Deserialize(byte[] data); /// /// Safe method /// - public abstract string itoa(BigInteger value); + [DisplayName("itoa")] + public abstract string Itoa(BigInteger value); /// /// Safe method /// - public abstract string itoa(BigInteger value, BigInteger @base); + [DisplayName("itoa")] + public abstract string Itoa(BigInteger value, BigInteger @base); /// /// Safe method /// - public abstract object jsonDeserialize(byte[] json); + [DisplayName("jsonDeserialize")] + public abstract object JsonDeserialize(byte[] json); /// /// Safe method /// - public abstract byte[] jsonSerialize(object item); + [DisplayName("jsonSerialize")] + public abstract byte[] JsonSerialize(object item); /// /// Safe method /// - public abstract BigInteger memoryCompare(byte[] str1, byte[] str2); + [DisplayName("memoryCompare")] + public abstract BigInteger MemoryCompare(byte[] str1, byte[] str2); /// /// Safe method /// - public abstract BigInteger memorySearch(byte[] mem, byte[] value); + [DisplayName("memorySearch")] + public abstract BigInteger MemorySearch(byte[] mem, byte[] value); /// /// Safe method /// - public abstract BigInteger memorySearch(byte[] mem, byte[] value, BigInteger start); + [DisplayName("memorySearch")] + public abstract BigInteger MemorySearch(byte[] mem, byte[] value, BigInteger start); /// /// Safe method /// - public abstract BigInteger memorySearch(byte[] mem, byte[] value, BigInteger start, bool backward); + [DisplayName("memorySearch")] + public abstract BigInteger MemorySearch(byte[] mem, byte[] value, BigInteger start, bool backward); /// /// Safe method /// - public abstract byte[] serialize(object item); + [DisplayName("serialize")] + public abstract byte[] Serialize(object item); /// /// Safe method /// - public abstract List stringSplit(string str, string separator); + [DisplayName("stringSplit")] + public abstract List StringSplit(string str, string separator); /// /// Safe method /// - public abstract List stringSplit(string str, string separator, bool removeEmptyEntries); + [DisplayName("stringSplit")] + public abstract List StringSplit(string str, string separator, bool removeEmptyEntries); /// /// Safe method /// - public abstract BigInteger strLen(string str); + [DisplayName("strLen")] + public abstract BigInteger StrLen(string str); #endregion #region Constructor for internal use only protected StdLib(Neo.SmartContract.Testing.TestEngine testEngine, Neo.UInt160 hash) : base(testEngine, hash) {} diff --git a/src/Neo.SmartContract.Testing/SmartContract.cs b/src/Neo.SmartContract.Testing/SmartContract.cs index b3dcf9762..64544dee1 100644 --- a/src/Neo.SmartContract.Testing/SmartContract.cs +++ b/src/Neo.SmartContract.Testing/SmartContract.cs @@ -2,6 +2,9 @@ using Neo.VM; using Neo.VM.Types; using System; +using System.ComponentModel; +using System.ComponentModel.DataAnnotations; +using System.Linq; using System.Reflection; namespace Neo.SmartContract.Testing @@ -70,7 +73,11 @@ internal void InvokeOnNotify(string eventName, VM.Types.Array state) { var type = GetType().BaseType ?? GetType(); // Mock var ev = type.GetEvent(eventName); - if (ev is null) return; + if (ev is null) + { + ev = type.GetEvents().FirstOrDefault(u => u.GetCustomAttribute()?.DisplayName == eventName); + if (ev is null) return; + } var evField = type.GetField(ev.Name, BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.GetField); if (evField is null) return; diff --git a/src/Neo.SmartContract.Testing/SmartContractStorage.cs b/src/Neo.SmartContract.Testing/SmartContractStorage.cs index 1fbf2bfeb..f5ec1d87c 100644 --- a/src/Neo.SmartContract.Testing/SmartContractStorage.cs +++ b/src/Neo.SmartContract.Testing/SmartContractStorage.cs @@ -19,7 +19,7 @@ internal SmartContractStorage(SmartContract smartContract) private int GetContractId() { - _smartContractId ??= _smartContract.Engine.Native.ContractManagement.getContract(_smartContract.Hash).Id; + _smartContractId ??= _smartContract.Engine.Native.ContractManagement.GetContract(_smartContract.Hash).Id; return _smartContractId.Value; } diff --git a/src/Neo.SmartContract.Testing/TestEngine.cs b/src/Neo.SmartContract.Testing/TestEngine.cs index 9671d8607..1d476cee3 100644 --- a/src/Neo.SmartContract.Testing/TestEngine.cs +++ b/src/Neo.SmartContract.Testing/TestEngine.cs @@ -207,7 +207,7 @@ public T Deploy(NefFile nef, ContractManifest manifest, object? data = null, { // Deploy - var state = Native.ContractManagement.deploy(nef.ToArray(), Encoding.UTF8.GetBytes(manifest.ToJson().ToString(false)), data.ConvertToStackItem()); + var state = Native.ContractManagement.Deploy(nef.ToArray(), Encoding.UTF8.GetBytes(manifest.ToJson().ToString(false)), data.ConvertToStackItem()); // Mock contract @@ -242,7 +242,7 @@ public T FromHash(UInt160 hash, Action>? customMock = null, bool chec return MockContract(hash, customMock); } - var state = Native.ContractManagement.getContract(hash); + var state = Native.ContractManagement.GetContract(hash); return MockContract(state.Hash, customMock); } diff --git a/tests/Neo.SmartContract.Testing.UnitTests/Extensions/ArtifactExtensionsTests.cs b/tests/Neo.SmartContract.Testing.UnitTests/Extensions/ArtifactExtensionsTests.cs index cebac9e27..2668dfa29 100644 --- a/tests/Neo.SmartContract.Testing.UnitTests/Extensions/ArtifactExtensionsTests.cs +++ b/tests/Neo.SmartContract.Testing.UnitTests/Extensions/ArtifactExtensionsTests.cs @@ -35,47 +35,55 @@ public abstract class Contract1 : Neo.SmartContract.Testing.SmartContract public event delTransfer? Transfer; #endregion #region Properties - public abstract BigInteger decimals { [DisplayName(""decimals"")] get; } + public abstract BigInteger Decimals { [DisplayName(""decimals"")] get; } public abstract UInt160 Owner { [DisplayName(""getOwner"")] get; [DisplayName(""setOwner"")] set; } - public abstract string symbol { [DisplayName(""symbol"")] get; } - public abstract BigInteger totalSupply { [DisplayName(""totalSupply"")] get; } - public abstract bool verify { [DisplayName(""verify"")] get; } + public abstract string Symbol { [DisplayName(""symbol"")] get; } + public abstract BigInteger TotalSupply { [DisplayName(""totalSupply"")] get; } + public abstract bool Verify { [DisplayName(""verify"")] get; } #endregion #region Safe methods /// /// Safe method /// - public abstract BigInteger balanceOf(UInt160 owner); + [DisplayName(""balanceOf"")] + public abstract BigInteger BalanceOf(UInt160 owner); #endregion #region Unsafe methods /// /// Unsafe method /// - public abstract void burn(UInt160 account, BigInteger amount); + [DisplayName(""burn"")] + public abstract void Burn(UInt160 account, BigInteger amount); /// /// Unsafe method /// - public abstract void mint(UInt160 to, BigInteger amount); + [DisplayName(""mint"")] + public abstract void Mint(UInt160 to, BigInteger amount); /// /// Unsafe method /// - public abstract string myMethod(); + [DisplayName(""myMethod"")] + public abstract string MyMethod(); /// /// Unsafe method /// - public abstract void onNEP17Payment(UInt160 from, BigInteger amount, object data); + [DisplayName(""onNEP17Payment"")] + public abstract void OnNEP17Payment(UInt160 from, BigInteger amount, object data); /// /// Unsafe method /// - public abstract bool transfer(UInt160 from, UInt160 to, BigInteger amount, object data); + [DisplayName(""transfer"")] + public abstract bool Transfer(UInt160 from, UInt160 to, BigInteger amount, object data); /// /// Unsafe method /// - public abstract void update(byte[] nefFile, string manifest); + [DisplayName(""update"")] + public abstract void Update(byte[] nefFile, string manifest); /// /// Unsafe method /// - public abstract bool withdraw(UInt160 token, UInt160 to, BigInteger amount); + [DisplayName(""withdraw"")] + public abstract bool Withdraw(UInt160 token, UInt160 to, BigInteger amount); #endregion #region Constructor for internal use only protected Contract1(Neo.SmartContract.Testing.TestEngine testEngine, Neo.UInt160 hash) : base(testEngine, hash) {} diff --git a/tests/Neo.SmartContract.Testing.UnitTests/NativeArtifactsTests.cs b/tests/Neo.SmartContract.Testing.UnitTests/NativeArtifactsTests.cs index 109f0c701..c28b2a829 100644 --- a/tests/Neo.SmartContract.Testing.UnitTests/NativeArtifactsTests.cs +++ b/tests/Neo.SmartContract.Testing.UnitTests/NativeArtifactsTests.cs @@ -23,8 +23,8 @@ public void TestInitialize() // Ensure that the main address contains the totalSupply - Assert.AreEqual(100_000_000, engine.Native.NEO.totalSupply); - Assert.AreEqual(engine.Native.NEO.totalSupply, engine.Native.NEO.balanceOf(engine.BFTAddress)); + Assert.AreEqual(100_000_000, engine.Native.NEO.TotalSupply); + Assert.AreEqual(engine.Native.NEO.TotalSupply, engine.Native.NEO.BalanceOf(engine.BFTAddress)); } [TestMethod] @@ -49,7 +49,7 @@ public void TestTransfer() var raisedEvent = false; - engine.Native.NEO.Transfer += (UInt160 from, UInt160 to, BigInteger amount) => + engine.Native.NEO.OnTransfer += (UInt160 from, UInt160 to, BigInteger amount) => { // If the event is raised, the variable will be changed raisedEvent = true; @@ -59,16 +59,16 @@ public void TestTransfer() UInt160 addressTo = UInt160.Parse("0x1230000000000000000000000000000000000000"); - Assert.AreEqual(0, engine.Native.NEO.balanceOf(addressTo)); + Assert.AreEqual(0, engine.Native.NEO.BalanceOf(addressTo)); // Transfer funds - Assert.IsTrue(engine.Native.NEO.transfer(engine.Transaction.Sender, addressTo, 123, null)); + Assert.IsTrue(engine.Native.NEO.Transfer(engine.Transaction.Sender, addressTo, 123, null)); // Ensure that we have balance and the event was raised Assert.IsTrue(raisedEvent); - Assert.AreEqual(123, engine.Native.NEO.balanceOf(addressTo)); + Assert.AreEqual(123, engine.Native.NEO.BalanceOf(addressTo)); } [TestMethod] diff --git a/tests/Neo.SmartContract.Testing.UnitTests/TestEngineTests.cs b/tests/Neo.SmartContract.Testing.UnitTests/TestEngineTests.cs index 5073d89d6..e433f4315 100644 --- a/tests/Neo.SmartContract.Testing.UnitTests/TestEngineTests.cs +++ b/tests/Neo.SmartContract.Testing.UnitTests/TestEngineTests.cs @@ -51,18 +51,18 @@ public void TestCustomMock() // Get neo token smart contract and mock balanceOf to always return 123 var neo = engine.FromHash(engine.Native.NEO.Hash, - mock => mock.Setup(o => o.balanceOf(It.IsAny())).Returns(123), + mock => mock.Setup(o => o.BalanceOf(It.IsAny())).Returns(123), false); // Test direct call - Assert.AreEqual(123, neo.balanceOf(engine.BFTAddress)); + Assert.AreEqual(123, neo.BalanceOf(engine.BFTAddress)); // Test vm call using (ScriptBuilder script = new()) { - script.EmitDynamicCall(neo.Hash, nameof(neo.balanceOf), engine.BFTAddress); + script.EmitDynamicCall(neo.Hash, nameof(neo.BalanceOf), engine.BFTAddress); Assert.AreEqual(123, engine.Execute(script.ToArray()).GetInteger()); } @@ -120,8 +120,8 @@ public void FromHashTest() // Ensure that the main address contains the totalSupply - Assert.AreEqual(100_000_000, neo.totalSupply); - Assert.AreEqual(neo.totalSupply, neo.balanceOf(engine.BFTAddress)); + Assert.AreEqual(100_000_000, neo.TotalSupply); + Assert.AreEqual(neo.TotalSupply, neo.BalanceOf(engine.BFTAddress)); } } } From 1e868e74c96ce7a836f213671733a2d2fcb3fe0a Mon Sep 17 00:00:00 2001 From: Fernando Diaz Toledano Date: Sun, 11 Feb 2024 22:05:30 +0100 Subject: [PATCH 069/106] All events start with "On" (avoid native conflicts) --- .../Extensions/ArtifactExtensions.cs | 11 +++++++++-- src/Neo.SmartContract.Testing/Native/GasToken.cs | 2 +- src/Neo.SmartContract.Testing/Native/NeoToken.cs | 5 +++-- .../Native/OracleContract.cs | 6 ++++-- .../Native/RoleManagement.cs | 3 ++- .../Extensions/ArtifactExtensionsTests.cs | 6 ++++-- 6 files changed, 23 insertions(+), 10 deletions(-) diff --git a/src/Neo.SmartContract.Testing/Extensions/ArtifactExtensions.cs b/src/Neo.SmartContract.Testing/Extensions/ArtifactExtensions.cs index 353854a4f..4ec127fc0 100644 --- a/src/Neo.SmartContract.Testing/Extensions/ArtifactExtensions.cs +++ b/src/Neo.SmartContract.Testing/Extensions/ArtifactExtensions.cs @@ -152,6 +152,9 @@ private static (ContractMethodDescriptor[] methods, (ContractMethodDescriptor ge /// Source private static string CreateSourceEventFromManifest(ContractEventDescriptor ev) { + var evName = TongleLowercase(EscapeName(ev.Name), out _); + if (!evName.StartsWith("On")) evName = "On" + evName; + StringBuilder sourceCode = new(); sourceCode.Append($" public delegate void del{ev.Name}("); @@ -166,7 +169,11 @@ private static string CreateSourceEventFromManifest(ContractEventDescriptor ev) } sourceCode.AppendLine(");"); - sourceCode.AppendLine($" public event del{ev.Name}? {ev.Name};"); + if (ev.Name != evName) + { + sourceCode.AppendLine($" [DisplayName(\"{ev.Name}\")]"); + } + sourceCode.AppendLine($" public event del{ev.Name}? {evName};"); return sourceCode.ToString(); } @@ -202,7 +209,7 @@ private static string CreateSourceMethodFromManifest(ContractMethodDescriptor me sourceCode.AppendLine($" /// "); sourceCode.AppendLine($" /// {(method.Safe ? "Safe method" : "Unsafe method")}"); sourceCode.AppendLine($" /// "); - if (lcChanged) + if (method.Name != methodName) { sourceCode.AppendLine($" [DisplayName(\"{method.Name}\")]"); } diff --git a/src/Neo.SmartContract.Testing/Native/GasToken.cs b/src/Neo.SmartContract.Testing/Native/GasToken.cs index 8998424cb..dd75398a3 100644 --- a/src/Neo.SmartContract.Testing/Native/GasToken.cs +++ b/src/Neo.SmartContract.Testing/Native/GasToken.cs @@ -32,6 +32,6 @@ public abstract class GasToken : Neo.SmartContract.Testing.SmartContract public abstract bool Transfer(UInt160 from, UInt160 to, BigInteger amount, object data); #endregion #region Constructor for internal use only - protected GasToken(Neo.SmartContract.Testing.TestEngine testEngine, Neo.UInt160 hash) : base(testEngine, hash) {} + protected GasToken(Neo.SmartContract.Testing.TestEngine testEngine, Neo.UInt160 hash) : base(testEngine, hash) { } #endregion } diff --git a/src/Neo.SmartContract.Testing/Native/NeoToken.cs b/src/Neo.SmartContract.Testing/Native/NeoToken.cs index 3c6c1ddbd..4b6606ebb 100644 --- a/src/Neo.SmartContract.Testing/Native/NeoToken.cs +++ b/src/Neo.SmartContract.Testing/Native/NeoToken.cs @@ -9,7 +9,8 @@ public abstract class NeoToken : Neo.SmartContract.Testing.SmartContract { #region Events public delegate void delCandidateStateChanged(ECPoint pubkey, bool registered, BigInteger votes); - public event delCandidateStateChanged? CandidateStateChanged; + [DisplayName("CandidateStateChanged")] + public event delCandidateStateChanged? OnCandidateStateChanged; public delegate void delTransfer(UInt160 from, UInt160 to, BigInteger amount); [DisplayName("Transfer")] public event delTransfer? OnTransfer; @@ -75,4 +76,4 @@ public abstract class NeoToken : Neo.SmartContract.Testing.SmartContract #region Constructor for internal use only protected NeoToken(Neo.SmartContract.Testing.TestEngine testEngine, Neo.UInt160 hash) : base(testEngine, hash) {} #endregion -} +} \ No newline at end of file diff --git a/src/Neo.SmartContract.Testing/Native/OracleContract.cs b/src/Neo.SmartContract.Testing/Native/OracleContract.cs index fdafdb459..fd52cba6e 100644 --- a/src/Neo.SmartContract.Testing/Native/OracleContract.cs +++ b/src/Neo.SmartContract.Testing/Native/OracleContract.cs @@ -9,9 +9,11 @@ public abstract class OracleContract : Neo.SmartContract.Testing.SmartContract { #region Events public delegate void delOracleRequest(BigInteger Id, UInt160 RequestContract, string Url, string Filter); - public event delOracleRequest? OracleRequest; + [DisplayName("OracleRequest")] + public event delOracleRequest? OnOracleRequest; public delegate void delOracleResponse(BigInteger Id, UInt256 OriginalTx); - public event delOracleResponse? OracleResponse; + [DisplayName("OracleResponse")] + public event delOracleResponse? OnOracleResponse; #endregion #region Properties public abstract BigInteger Price { [DisplayName("getPrice")] get; [DisplayName("setPrice")] set; } diff --git a/src/Neo.SmartContract.Testing/Native/RoleManagement.cs b/src/Neo.SmartContract.Testing/Native/RoleManagement.cs index 99c530505..2f0db7497 100644 --- a/src/Neo.SmartContract.Testing/Native/RoleManagement.cs +++ b/src/Neo.SmartContract.Testing/Native/RoleManagement.cs @@ -9,7 +9,8 @@ public abstract class RoleManagement : Neo.SmartContract.Testing.SmartContract { #region Events public delegate void delDesignation(BigInteger Role, BigInteger BlockIndex); - public event delDesignation? Designation; + [DisplayName("Designation")] + public event delDesignation? OnDesignation; #endregion #region Safe methods /// diff --git a/tests/Neo.SmartContract.Testing.UnitTests/Extensions/ArtifactExtensionsTests.cs b/tests/Neo.SmartContract.Testing.UnitTests/Extensions/ArtifactExtensionsTests.cs index 2668dfa29..8ebe5a764 100644 --- a/tests/Neo.SmartContract.Testing.UnitTests/Extensions/ArtifactExtensionsTests.cs +++ b/tests/Neo.SmartContract.Testing.UnitTests/Extensions/ArtifactExtensionsTests.cs @@ -30,9 +30,11 @@ public abstract class Contract1 : Neo.SmartContract.Testing.SmartContract { #region Events public delegate void delSetOwner(UInt160 newOwner); - public event delSetOwner? SetOwner; + [DisplayName(""SetOwner"")] + public event delSetOwner? OnSetOwner; public delegate void delTransfer(UInt160 from, UInt160 to, BigInteger amount); - public event delTransfer? Transfer; + [DisplayName(""Transfer"")] + public event delTransfer? OnTransfer; #endregion #region Properties public abstract BigInteger Decimals { [DisplayName(""decimals"")] get; } From 55c73f71638a07cee67669daafa63de88ef866f0 Mon Sep 17 00:00:00 2001 From: Fernando Diaz Toledano Date: Sun, 11 Feb 2024 22:07:02 +0100 Subject: [PATCH 070/106] Rename log event --- src/Neo.SmartContract.Testing/SmartContract.cs | 9 ++++----- src/Neo.SmartContract.Testing/TestEngine.cs | 2 +- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/src/Neo.SmartContract.Testing/SmartContract.cs b/src/Neo.SmartContract.Testing/SmartContract.cs index 64544dee1..502709961 100644 --- a/src/Neo.SmartContract.Testing/SmartContract.cs +++ b/src/Neo.SmartContract.Testing/SmartContract.cs @@ -3,7 +3,6 @@ using Neo.VM.Types; using System; using System.ComponentModel; -using System.ComponentModel.DataAnnotations; using System.Linq; using System.Reflection; @@ -14,7 +13,7 @@ public class SmartContract internal readonly TestEngine Engine; public delegate void delOnLog(string message); - public event delOnLog? OnLog; + public event delOnLog? OnRuntimeLog; /// /// Contract hash @@ -56,12 +55,12 @@ internal StackItem Invoke(string methodName, params object[] args) } /// - /// OnLog + /// Invoke OnRuntimeLog /// /// Message - internal void InvokeOnLog(string message) + internal void InvokeOnRuntimeLog(string message) { - OnLog?.Invoke(message); + OnRuntimeLog?.Invoke(message); } /// diff --git a/src/Neo.SmartContract.Testing/TestEngine.cs b/src/Neo.SmartContract.Testing/TestEngine.cs index 1d476cee3..712776009 100644 --- a/src/Neo.SmartContract.Testing/TestEngine.cs +++ b/src/Neo.SmartContract.Testing/TestEngine.cs @@ -187,7 +187,7 @@ private void ApplicationEngine_Log(object? sender, LogEventArgs e) { foreach (var contract in contracts) { - contract.InvokeOnLog(e.Message); + contract.InvokeOnRuntimeLog(e.Message); } } } From 82899c27cade9cc76f880b3daa1fcaad9e394641 Mon Sep 17 00:00:00 2001 From: Fernando Diaz Toledano Date: Sun, 11 Feb 2024 22:17:30 +0100 Subject: [PATCH 071/106] Avoid re-query contract id if it was checked --- .../Extensions/ArtifactExtensions.cs | 2 +- .../Native/ContractManagement.cs | 2 +- .../Native/CryptoLib.cs | 4 ++-- .../Native/GasToken.cs | 2 +- .../Native/LedgerContract.cs | 4 ++-- .../Native/NeoToken.cs | 4 ++-- .../Native/OracleContract.cs | 4 ++-- .../Native/PolicyContract.cs | 4 ++-- .../Native/RoleManagement.cs | 4 ++-- .../Native/StdLib.cs | 4 ++-- .../SmartContract.cs | 11 +++++----- .../SmartContractInitialize.cs | 20 +++++++++++++++++++ .../SmartContractStorage.cs | 11 ++++++---- src/Neo.SmartContract.Testing/TestEngine.cs | 10 +++++----- .../Extensions/ArtifactExtensionsTests.cs | 2 +- .../TestEngineTests.cs | 2 +- 16 files changed, 56 insertions(+), 34 deletions(-) create mode 100644 src/Neo.SmartContract.Testing/SmartContractInitialize.cs diff --git a/src/Neo.SmartContract.Testing/Extensions/ArtifactExtensions.cs b/src/Neo.SmartContract.Testing/Extensions/ArtifactExtensions.cs index 4ec127fc0..9362c8db5 100644 --- a/src/Neo.SmartContract.Testing/Extensions/ArtifactExtensions.cs +++ b/src/Neo.SmartContract.Testing/Extensions/ArtifactExtensions.cs @@ -98,7 +98,7 @@ public static string GetArtifactsSource(this ContractAbi abi, string name, bool // Create constructor sourceCode.AppendLine(" #region Constructor for internal use only"); - sourceCode.AppendLine($" protected {name}(Neo.SmartContract.Testing.TestEngine testEngine, Neo.UInt160 hash) : base(testEngine, hash) {{}}"); + sourceCode.AppendLine($" protected {name}(Neo.SmartContract.Testing.SmartContractInitialize initialize) : base(initialize) {{}}"); sourceCode.AppendLine(" #endregion"); sourceCode.AppendLine("}"); diff --git a/src/Neo.SmartContract.Testing/Native/ContractManagement.cs b/src/Neo.SmartContract.Testing/Native/ContractManagement.cs index 66781ca65..e3df059c1 100644 --- a/src/Neo.SmartContract.Testing/Native/ContractManagement.cs +++ b/src/Neo.SmartContract.Testing/Native/ContractManagement.cs @@ -67,6 +67,6 @@ public abstract class ContractManagement : Neo.SmartContract.Testing.SmartContra public abstract void Update(byte[] nefFile, byte[] manifest, object data); #endregion #region Constructor for internal use only - protected ContractManagement(Neo.SmartContract.Testing.TestEngine testEngine, Neo.UInt160 hash) : base(testEngine, hash) { } + protected ContractManagement(Neo.SmartContract.Testing.SmartContractInitialize initialize) : base(initialize) { } #endregion } diff --git a/src/Neo.SmartContract.Testing/Native/CryptoLib.cs b/src/Neo.SmartContract.Testing/Native/CryptoLib.cs index 24afd8f3d..ec70f5cff 100644 --- a/src/Neo.SmartContract.Testing/Native/CryptoLib.cs +++ b/src/Neo.SmartContract.Testing/Native/CryptoLib.cs @@ -60,6 +60,6 @@ public abstract class CryptoLib : Neo.SmartContract.Testing.SmartContract public abstract bool VerifyWithECDsa(byte[] message, byte[] pubkey, byte[] signature, BigInteger curve); #endregion #region Constructor for internal use only - protected CryptoLib(Neo.SmartContract.Testing.TestEngine testEngine, Neo.UInt160 hash) : base(testEngine, hash) {} + protected CryptoLib(Neo.SmartContract.Testing.SmartContractInitialize initialize) : base(initialize) {} #endregion -} \ No newline at end of file +} diff --git a/src/Neo.SmartContract.Testing/Native/GasToken.cs b/src/Neo.SmartContract.Testing/Native/GasToken.cs index dd75398a3..47065bd30 100644 --- a/src/Neo.SmartContract.Testing/Native/GasToken.cs +++ b/src/Neo.SmartContract.Testing/Native/GasToken.cs @@ -32,6 +32,6 @@ public abstract class GasToken : Neo.SmartContract.Testing.SmartContract public abstract bool Transfer(UInt160 from, UInt160 to, BigInteger amount, object data); #endregion #region Constructor for internal use only - protected GasToken(Neo.SmartContract.Testing.TestEngine testEngine, Neo.UInt160 hash) : base(testEngine, hash) { } + protected GasToken(Neo.SmartContract.Testing.SmartContractInitialize initialize) : base(initialize) { } #endregion } diff --git a/src/Neo.SmartContract.Testing/Native/LedgerContract.cs b/src/Neo.SmartContract.Testing/Native/LedgerContract.cs index a479c34c6..4f52301bf 100644 --- a/src/Neo.SmartContract.Testing/Native/LedgerContract.cs +++ b/src/Neo.SmartContract.Testing/Native/LedgerContract.cs @@ -44,6 +44,6 @@ public abstract class LedgerContract : Neo.SmartContract.Testing.SmartContract public abstract BigInteger GetTransactionVMState(UInt256 hash); #endregion #region Constructor for internal use only - protected LedgerContract(Neo.SmartContract.Testing.TestEngine testEngine, Neo.UInt160 hash) : base(testEngine, hash) {} + protected LedgerContract(Neo.SmartContract.Testing.SmartContractInitialize initialize) : base(initialize) {} #endregion -} \ No newline at end of file +} diff --git a/src/Neo.SmartContract.Testing/Native/NeoToken.cs b/src/Neo.SmartContract.Testing/Native/NeoToken.cs index 4b6606ebb..b9cbf7248 100644 --- a/src/Neo.SmartContract.Testing/Native/NeoToken.cs +++ b/src/Neo.SmartContract.Testing/Native/NeoToken.cs @@ -74,6 +74,6 @@ public abstract class NeoToken : Neo.SmartContract.Testing.SmartContract public abstract bool Vote(UInt160 account, ECPoint voteTo); #endregion #region Constructor for internal use only - protected NeoToken(Neo.SmartContract.Testing.TestEngine testEngine, Neo.UInt160 hash) : base(testEngine, hash) {} + protected NeoToken(Neo.SmartContract.Testing.SmartContractInitialize initialize) : base(initialize) {} #endregion -} \ No newline at end of file +} diff --git a/src/Neo.SmartContract.Testing/Native/OracleContract.cs b/src/Neo.SmartContract.Testing/Native/OracleContract.cs index fd52cba6e..a7a7799dd 100644 --- a/src/Neo.SmartContract.Testing/Native/OracleContract.cs +++ b/src/Neo.SmartContract.Testing/Native/OracleContract.cs @@ -32,6 +32,6 @@ public abstract class OracleContract : Neo.SmartContract.Testing.SmartContract public abstract void Request(string url, string filter, string callback, object userData, BigInteger gasForResponse); #endregion #region Constructor for internal use only - protected OracleContract(Neo.SmartContract.Testing.TestEngine testEngine, Neo.UInt160 hash) : base(testEngine, hash) {} + protected OracleContract(Neo.SmartContract.Testing.SmartContractInitialize initialize) : base(initialize) {} #endregion -} \ No newline at end of file +} diff --git a/src/Neo.SmartContract.Testing/Native/PolicyContract.cs b/src/Neo.SmartContract.Testing/Native/PolicyContract.cs index 27abaf7cd..9ccaeb098 100644 --- a/src/Neo.SmartContract.Testing/Native/PolicyContract.cs +++ b/src/Neo.SmartContract.Testing/Native/PolicyContract.cs @@ -42,6 +42,6 @@ public abstract class PolicyContract : Neo.SmartContract.Testing.SmartContract public abstract bool UnblockAccount(UInt160 account); #endregion #region Constructor for internal use only - protected PolicyContract(Neo.SmartContract.Testing.TestEngine testEngine, Neo.UInt160 hash) : base(testEngine, hash) {} + protected PolicyContract(Neo.SmartContract.Testing.SmartContractInitialize initialize) : base(initialize) {} #endregion -} \ No newline at end of file +} diff --git a/src/Neo.SmartContract.Testing/Native/RoleManagement.cs b/src/Neo.SmartContract.Testing/Native/RoleManagement.cs index 2f0db7497..5e0aae2db 100644 --- a/src/Neo.SmartContract.Testing/Native/RoleManagement.cs +++ b/src/Neo.SmartContract.Testing/Native/RoleManagement.cs @@ -27,6 +27,6 @@ public abstract class RoleManagement : Neo.SmartContract.Testing.SmartContract public abstract void DesignateAsRole(BigInteger role, List nodes); #endregion #region Constructor for internal use only - protected RoleManagement(Neo.SmartContract.Testing.TestEngine testEngine, Neo.UInt160 hash) : base(testEngine, hash) {} + protected RoleManagement(Neo.SmartContract.Testing.SmartContractInitialize initialize) : base(initialize) {} #endregion -} \ No newline at end of file +} diff --git a/src/Neo.SmartContract.Testing/Native/StdLib.cs b/src/Neo.SmartContract.Testing/Native/StdLib.cs index ff8d27d5b..1751a5820 100644 --- a/src/Neo.SmartContract.Testing/Native/StdLib.cs +++ b/src/Neo.SmartContract.Testing/Native/StdLib.cs @@ -115,6 +115,6 @@ public abstract class StdLib : Neo.SmartContract.Testing.SmartContract public abstract BigInteger StrLen(string str); #endregion #region Constructor for internal use only - protected StdLib(Neo.SmartContract.Testing.TestEngine testEngine, Neo.UInt160 hash) : base(testEngine, hash) {} + protected StdLib(Neo.SmartContract.Testing.SmartContractInitialize initialize) : base(initialize) {} #endregion -} \ No newline at end of file +} diff --git a/src/Neo.SmartContract.Testing/SmartContract.cs b/src/Neo.SmartContract.Testing/SmartContract.cs index 502709961..5c7322df8 100644 --- a/src/Neo.SmartContract.Testing/SmartContract.cs +++ b/src/Neo.SmartContract.Testing/SmartContract.cs @@ -28,13 +28,12 @@ public class SmartContract /// /// Constructor /// - /// TestEngine - /// Contract hash - protected SmartContract(TestEngine testEngine, UInt160 hash) + /// Initialize object + protected SmartContract(SmartContractInitialize initialize) { - Engine = testEngine; - Hash = hash; - Storage = new SmartContractStorage(this); + Engine = initialize.Engine; + Hash = initialize.Hash; + Storage = new SmartContractStorage(this, initialize.ContractId); } /// diff --git a/src/Neo.SmartContract.Testing/SmartContractInitialize.cs b/src/Neo.SmartContract.Testing/SmartContractInitialize.cs new file mode 100644 index 000000000..9a7d72609 --- /dev/null +++ b/src/Neo.SmartContract.Testing/SmartContractInitialize.cs @@ -0,0 +1,20 @@ +namespace Neo.SmartContract.Testing +{ + public class SmartContractInitialize + { + /// + /// Engine + /// + public required TestEngine Engine { get; init; } + + /// + /// Hash + /// + public required UInt160 Hash { get; init; } + + /// + /// ContractId + /// + internal int? ContractId { get; init; } + } +} diff --git a/src/Neo.SmartContract.Testing/SmartContractStorage.cs b/src/Neo.SmartContract.Testing/SmartContractStorage.cs index f5ec1d87c..42c7f8f6f 100644 --- a/src/Neo.SmartContract.Testing/SmartContractStorage.cs +++ b/src/Neo.SmartContract.Testing/SmartContractStorage.cs @@ -6,21 +6,24 @@ namespace Neo.SmartContract.Testing public class SmartContractStorage { private readonly SmartContract _smartContract; - private int? _smartContractId; + private int? _contractId; /// /// Constructor /// /// Smart Contract - internal SmartContractStorage(SmartContract smartContract) + /// Contract id, can be null + internal SmartContractStorage(SmartContract smartContract, int? contractId = null) { _smartContract = smartContract; + _contractId = contractId; } private int GetContractId() { - _smartContractId ??= _smartContract.Engine.Native.ContractManagement.GetContract(_smartContract.Hash).Id; - return _smartContractId.Value; + // If it was not initialized checking the contract, we need to query the contract id + _contractId ??= _smartContract.Engine.Native.ContractManagement.GetContract(_smartContract.Hash).Id; + return _contractId.Value; } /// diff --git a/src/Neo.SmartContract.Testing/TestEngine.cs b/src/Neo.SmartContract.Testing/TestEngine.cs index 712776009..3e40feef7 100644 --- a/src/Neo.SmartContract.Testing/TestEngine.cs +++ b/src/Neo.SmartContract.Testing/TestEngine.cs @@ -212,7 +212,7 @@ public T Deploy(NefFile nef, ContractManifest manifest, object? data = null, // Mock contract //UInt160 hash = Helper.GetContractHash(Sender, nef.CheckSum, manifest.Name); - return MockContract(state.Hash, customMock); + return MockContract(state.Hash, state.Id, customMock); } /// @@ -239,17 +239,17 @@ public T FromHash(UInt160 hash, Action>? customMock = null, bool chec { if (!checkExistence) { - return MockContract(hash, customMock); + return MockContract(hash, null, customMock); } var state = Native.ContractManagement.GetContract(hash); - return MockContract(state.Hash, customMock); + return MockContract(state.Hash, state.Id, customMock); } - private T MockContract(UInt160 hash, Action>? customMock = null) where T : SmartContract + private T MockContract(UInt160 hash, int? contractId = null, Action>? customMock = null) where T : SmartContract { - var mock = new Mock(this, hash) + var mock = new Mock(new SmartContractInitialize() { Engine = this, Hash = hash, ContractId = contractId }) { CallBase = true }; diff --git a/tests/Neo.SmartContract.Testing.UnitTests/Extensions/ArtifactExtensionsTests.cs b/tests/Neo.SmartContract.Testing.UnitTests/Extensions/ArtifactExtensionsTests.cs index 8ebe5a764..bdd12fbfb 100644 --- a/tests/Neo.SmartContract.Testing.UnitTests/Extensions/ArtifactExtensionsTests.cs +++ b/tests/Neo.SmartContract.Testing.UnitTests/Extensions/ArtifactExtensionsTests.cs @@ -88,7 +88,7 @@ public abstract class Contract1 : Neo.SmartContract.Testing.SmartContract public abstract bool Withdraw(UInt160 token, UInt160 to, BigInteger amount); #endregion #region Constructor for internal use only - protected Contract1(Neo.SmartContract.Testing.TestEngine testEngine, Neo.UInt160 hash) : base(testEngine, hash) {} + protected Contract1(Neo.SmartContract.Testing.SmartContractInitialize initialize) : base(initialize) {} #endregion } ".Replace("\r\n", "\n").Trim()); diff --git a/tests/Neo.SmartContract.Testing.UnitTests/TestEngineTests.cs b/tests/Neo.SmartContract.Testing.UnitTests/TestEngineTests.cs index e433f4315..492cfce0a 100644 --- a/tests/Neo.SmartContract.Testing.UnitTests/TestEngineTests.cs +++ b/tests/Neo.SmartContract.Testing.UnitTests/TestEngineTests.cs @@ -13,7 +13,7 @@ public class TestEngineTests public abstract class MyUndeployedContract : SmartContract { public abstract int myReturnMethod(); - protected MyUndeployedContract(TestEngine testEngine, UInt160 hash) : base(testEngine, hash) { } + protected MyUndeployedContract(SmartContractInitialize initialize) : base(initialize) { } } //[TestMethod] From 7bcec899deeaaf5c1cd7462c5cc765b3c56cbdf1 Mon Sep 17 00:00:00 2001 From: Fernando Diaz Toledano Date: Sun, 11 Feb 2024 22:19:21 +0100 Subject: [PATCH 072/106] format --- src/Neo.SmartContract.Testing/Extensions/ArtifactExtensions.cs | 2 +- src/Neo.SmartContract.Testing/Native/CryptoLib.cs | 2 +- src/Neo.SmartContract.Testing/Native/LedgerContract.cs | 2 +- src/Neo.SmartContract.Testing/Native/NeoToken.cs | 2 +- src/Neo.SmartContract.Testing/Native/OracleContract.cs | 2 +- src/Neo.SmartContract.Testing/Native/PolicyContract.cs | 2 +- src/Neo.SmartContract.Testing/Native/RoleManagement.cs | 2 +- src/Neo.SmartContract.Testing/Native/StdLib.cs | 2 +- .../Extensions/ArtifactExtensionsTests.cs | 2 +- 9 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/Neo.SmartContract.Testing/Extensions/ArtifactExtensions.cs b/src/Neo.SmartContract.Testing/Extensions/ArtifactExtensions.cs index 9362c8db5..e0c5a2896 100644 --- a/src/Neo.SmartContract.Testing/Extensions/ArtifactExtensions.cs +++ b/src/Neo.SmartContract.Testing/Extensions/ArtifactExtensions.cs @@ -98,7 +98,7 @@ public static string GetArtifactsSource(this ContractAbi abi, string name, bool // Create constructor sourceCode.AppendLine(" #region Constructor for internal use only"); - sourceCode.AppendLine($" protected {name}(Neo.SmartContract.Testing.SmartContractInitialize initialize) : base(initialize) {{}}"); + sourceCode.AppendLine($" protected {name}(Neo.SmartContract.Testing.SmartContractInitialize initialize) : base(initialize) {{ }}"); sourceCode.AppendLine(" #endregion"); sourceCode.AppendLine("}"); diff --git a/src/Neo.SmartContract.Testing/Native/CryptoLib.cs b/src/Neo.SmartContract.Testing/Native/CryptoLib.cs index ec70f5cff..a6498111e 100644 --- a/src/Neo.SmartContract.Testing/Native/CryptoLib.cs +++ b/src/Neo.SmartContract.Testing/Native/CryptoLib.cs @@ -60,6 +60,6 @@ public abstract class CryptoLib : Neo.SmartContract.Testing.SmartContract public abstract bool VerifyWithECDsa(byte[] message, byte[] pubkey, byte[] signature, BigInteger curve); #endregion #region Constructor for internal use only - protected CryptoLib(Neo.SmartContract.Testing.SmartContractInitialize initialize) : base(initialize) {} + protected CryptoLib(Neo.SmartContract.Testing.SmartContractInitialize initialize) : base(initialize) { } #endregion } diff --git a/src/Neo.SmartContract.Testing/Native/LedgerContract.cs b/src/Neo.SmartContract.Testing/Native/LedgerContract.cs index 4f52301bf..868d59f56 100644 --- a/src/Neo.SmartContract.Testing/Native/LedgerContract.cs +++ b/src/Neo.SmartContract.Testing/Native/LedgerContract.cs @@ -44,6 +44,6 @@ public abstract class LedgerContract : Neo.SmartContract.Testing.SmartContract public abstract BigInteger GetTransactionVMState(UInt256 hash); #endregion #region Constructor for internal use only - protected LedgerContract(Neo.SmartContract.Testing.SmartContractInitialize initialize) : base(initialize) {} + protected LedgerContract(Neo.SmartContract.Testing.SmartContractInitialize initialize) : base(initialize) { } #endregion } diff --git a/src/Neo.SmartContract.Testing/Native/NeoToken.cs b/src/Neo.SmartContract.Testing/Native/NeoToken.cs index b9cbf7248..1bd480dbd 100644 --- a/src/Neo.SmartContract.Testing/Native/NeoToken.cs +++ b/src/Neo.SmartContract.Testing/Native/NeoToken.cs @@ -74,6 +74,6 @@ public abstract class NeoToken : Neo.SmartContract.Testing.SmartContract public abstract bool Vote(UInt160 account, ECPoint voteTo); #endregion #region Constructor for internal use only - protected NeoToken(Neo.SmartContract.Testing.SmartContractInitialize initialize) : base(initialize) {} + protected NeoToken(Neo.SmartContract.Testing.SmartContractInitialize initialize) : base(initialize) { } #endregion } diff --git a/src/Neo.SmartContract.Testing/Native/OracleContract.cs b/src/Neo.SmartContract.Testing/Native/OracleContract.cs index a7a7799dd..1964d8dfb 100644 --- a/src/Neo.SmartContract.Testing/Native/OracleContract.cs +++ b/src/Neo.SmartContract.Testing/Native/OracleContract.cs @@ -32,6 +32,6 @@ public abstract class OracleContract : Neo.SmartContract.Testing.SmartContract public abstract void Request(string url, string filter, string callback, object userData, BigInteger gasForResponse); #endregion #region Constructor for internal use only - protected OracleContract(Neo.SmartContract.Testing.SmartContractInitialize initialize) : base(initialize) {} + protected OracleContract(Neo.SmartContract.Testing.SmartContractInitialize initialize) : base(initialize) { } #endregion } diff --git a/src/Neo.SmartContract.Testing/Native/PolicyContract.cs b/src/Neo.SmartContract.Testing/Native/PolicyContract.cs index 9ccaeb098..6be01a1b8 100644 --- a/src/Neo.SmartContract.Testing/Native/PolicyContract.cs +++ b/src/Neo.SmartContract.Testing/Native/PolicyContract.cs @@ -42,6 +42,6 @@ public abstract class PolicyContract : Neo.SmartContract.Testing.SmartContract public abstract bool UnblockAccount(UInt160 account); #endregion #region Constructor for internal use only - protected PolicyContract(Neo.SmartContract.Testing.SmartContractInitialize initialize) : base(initialize) {} + protected PolicyContract(Neo.SmartContract.Testing.SmartContractInitialize initialize) : base(initialize) { } #endregion } diff --git a/src/Neo.SmartContract.Testing/Native/RoleManagement.cs b/src/Neo.SmartContract.Testing/Native/RoleManagement.cs index 5e0aae2db..d75624c80 100644 --- a/src/Neo.SmartContract.Testing/Native/RoleManagement.cs +++ b/src/Neo.SmartContract.Testing/Native/RoleManagement.cs @@ -27,6 +27,6 @@ public abstract class RoleManagement : Neo.SmartContract.Testing.SmartContract public abstract void DesignateAsRole(BigInteger role, List nodes); #endregion #region Constructor for internal use only - protected RoleManagement(Neo.SmartContract.Testing.SmartContractInitialize initialize) : base(initialize) {} + protected RoleManagement(Neo.SmartContract.Testing.SmartContractInitialize initialize) : base(initialize) { } #endregion } diff --git a/src/Neo.SmartContract.Testing/Native/StdLib.cs b/src/Neo.SmartContract.Testing/Native/StdLib.cs index 1751a5820..4c160ee98 100644 --- a/src/Neo.SmartContract.Testing/Native/StdLib.cs +++ b/src/Neo.SmartContract.Testing/Native/StdLib.cs @@ -115,6 +115,6 @@ public abstract class StdLib : Neo.SmartContract.Testing.SmartContract public abstract BigInteger StrLen(string str); #endregion #region Constructor for internal use only - protected StdLib(Neo.SmartContract.Testing.SmartContractInitialize initialize) : base(initialize) {} + protected StdLib(Neo.SmartContract.Testing.SmartContractInitialize initialize) : base(initialize) { } #endregion } diff --git a/tests/Neo.SmartContract.Testing.UnitTests/Extensions/ArtifactExtensionsTests.cs b/tests/Neo.SmartContract.Testing.UnitTests/Extensions/ArtifactExtensionsTests.cs index bdd12fbfb..77ec0f88e 100644 --- a/tests/Neo.SmartContract.Testing.UnitTests/Extensions/ArtifactExtensionsTests.cs +++ b/tests/Neo.SmartContract.Testing.UnitTests/Extensions/ArtifactExtensionsTests.cs @@ -88,7 +88,7 @@ public abstract class Contract1 : Neo.SmartContract.Testing.SmartContract public abstract bool Withdraw(UInt160 token, UInt160 to, BigInteger amount); #endregion #region Constructor for internal use only - protected Contract1(Neo.SmartContract.Testing.SmartContractInitialize initialize) : base(initialize) {} + protected Contract1(Neo.SmartContract.Testing.SmartContractInitialize initialize) : base(initialize) { } #endregion } ".Replace("\r\n", "\n").Trim()); From ba125d82f407a5e6ff2ea4d42ae57498a07e5cf4 Mon Sep 17 00:00:00 2001 From: Fernando Diaz Toledano Date: Sun, 11 Feb 2024 22:26:19 +0100 Subject: [PATCH 073/106] Update Readme examples --- src/Neo.SmartContract.Testing/README.md | 190 ++++++++++++------------ 1 file changed, 95 insertions(+), 95 deletions(-) diff --git a/src/Neo.SmartContract.Testing/README.md b/src/Neo.SmartContract.Testing/README.md index b013d06a9..6c368b3d0 100644 --- a/src/Neo.SmartContract.Testing/README.md +++ b/src/Neo.SmartContract.Testing/README.md @@ -96,8 +96,8 @@ var neo = engine.FromHash(engine.Native.NEO.Hash, false); // Ensure that the main address contains the totalSupply -Assert.AreEqual(100_000_000, neo.totalSupply()); -Assert.AreEqual(neo.totalSupply(), neo.balanceOf(engine.BFTAddress)); +Assert.AreEqual(100_000_000, neo.TotalSupply); +Assert.AreEqual(neo.TotalSupply, neo.BalanceOf(engine.BFTAddress)); ``` ### NativeArtifacts @@ -119,8 +119,8 @@ var engine = new TestEngine(true); // Ensure that the main address contains the totalSupply -Assert.AreEqual(100_000_000, engine.Native.NEO.totalSupply()); -Assert.AreEqual(engine.Native.NEO.totalSupply(), engine.Native.NEO.balanceOf(engine.BFTAddress)); +Assert.AreEqual(100_000_000, engine.Native.NEO.TotalSupply); +Assert.AreEqual(engine.Native.NEO.TotalSupply, engine.Native.NEO.BalanceOf(engine.BFTAddress)); ``` ### SmartContractStorage @@ -134,25 +134,25 @@ Mainly exposes the methods `Read`, `Put`, and `Remove`, all of them responsible #### Example of use ```csharp -// Defines the prefix used to store the registration price in neo - -byte[] registerPricePrefix = new byte[] { 13 }; - -// Engine an contract creation - -TestEngine engine = new(true); - -// Check previous data - -Assert.AreEqual(100000000000, engine.Native.NEO.getRegisterPrice()); - -// Alter data - -engine.Native.NEO.Storage.Put(registerPricePrefix, BigInteger.MinusOne); - -// Check altered data - -Assert.AreEqual(BigInteger.MinusOne, engine.Native.NEO.getRegisterPrice()); +// Defines the prefix used to store the registration price in neo + +byte[] registerPricePrefix = new byte[] { 13 }; + +// Engine an contract creation + +TestEngine engine = new(true); + +// Check previous data + +Assert.AreEqual(100000000000, engine.Native.NEO.RegisterPrice); + +// Alter data + +engine.Native.NEO.Storage.Put(registerPricePrefix, BigInteger.MinusOne); + +// Check altered data + +Assert.AreEqual(BigInteger.MinusOne, engine.Native.NEO.RegisterPrice); ``` ### Custom mocks @@ -174,18 +174,18 @@ TestEngine engine = new(true); // Get neo token smart contract and mock balanceOf to always return 123 var neo = engine.FromHash(engine.Native.NEO.Hash, - mock => mock.Setup(o => o.balanceOf(It.IsAny())).Returns(123), + mock => mock.Setup(o => o.BalanceOf(It.IsAny())).Returns(123), false); // Test direct call -Assert.AreEqual(123, neo.balanceOf(engine.BFTAddress)); +Assert.AreEqual(123, neo.BalanceOf(engine.BFTAddress)); // Test vm call using (ScriptBuilder script = new()) { - script.EmitDynamicCall(neo.Hash, nameof(neo.balanceOf), engine.BFTAddress); + script.EmitDynamicCall(neo.Hash, nameof(neo.BalanceOf), engine.BFTAddress); Assert.AreEqual(123, engine.Execute(script.ToArray()).GetInteger()); } @@ -198,36 +198,36 @@ To fake signatures and allow testing our contracts in authorized and unauthorize #### Example of use ```csharp -// Initialize out TestEngine - -var engine = new TestEngine(true); - -// Check initial value of getRegisterPrice - -Assert.AreEqual(100000000000, engine.Native.NEO.getRegisterPrice()); - -// Fake Committee Signature - -engine.Transaction.Signers = new Network.P2P.Payloads.Signer[] -{ - new Network.P2P.Payloads.Signer() - { - Account = engine.CommitteeAddress, - Scopes = Network.P2P.Payloads.WitnessScope.Global - } -}; - -// Change RegisterPrice to 123 - -engine.Native.NEO.setRegisterPrice(123); - -Assert.AreEqual(123, engine.Native.NEO.getRegisterPrice()); - -// Now test it without this signature - -engine.Transaction.Signers[0].Scopes = Network.P2P.Payloads.WitnessScope.None; - -Assert.ThrowsException(() => engine.Native.NEO.setRegisterPrice(123)); +// Initialize out TestEngine + +var engine = new TestEngine(true); + +// Check initial value of getRegisterPrice + +Assert.AreEqual(100000000000, engine.Native.NEO.RegisterPrice); + +// Fake Committee Signature + +engine.Transaction.Signers = new Network.P2P.Payloads.Signer[] +{ + new Network.P2P.Payloads.Signer() + { + Account = engine.CommitteeAddress, + Scopes = Network.P2P.Payloads.WitnessScope.Global + } +}; + +// Change RegisterPrice to 123 + +engine.Native.NEO.RegisterPrice = 123; + +Assert.AreEqual(123, engine.Native.NEO.RegisterPrice); + +// Now test it without this signature + +engine.Transaction.Signers[0].Scopes = Network.P2P.Payloads.WitnessScope.None; + +Assert.ThrowsException(() => engine.Native.NEO.RegisterPrice = 123); ``` ### Event testing @@ -237,43 +237,43 @@ Testing that our events have been triggered has never been so easy. Simply when #### Example of use ```csharp - // Create and initialize TestEngine - - var engine = new TestEngine(true); - - // Fake signature of BFTAddress - - engine.Transaction.Signers = new Network.P2P.Payloads.Signer[] - { - new Network.P2P.Payloads.Signer() - { - Account = engine.BFTAddress, - Scopes = Network.P2P.Payloads.WitnessScope.Global - } - }; - - // Attach to Transfer event - - var raisedEvent = false; - - engine.Native.NEO.Transfer += (UInt160 from, UInt160 to, BigInteger amount) => - { - // If the event is raised, the variable will be changed - raisedEvent = true; - }; - - // Define address to transfer funds - - UInt160 addressTo = UInt160.Parse("0x1230000000000000000000000000000000000000"); - - Assert.AreEqual(0, engine.Native.NEO.balanceOf(addressTo)); - - // Transfer funds - - Assert.IsTrue(engine.Native.NEO.transfer(engine.Transaction.Sender, addressTo, 123, null)); - - // Ensure that we have balance and the event was raised - - Assert.IsTrue(raisedEvent); - Assert.AreEqual(123, engine.Native.NEO.balanceOf(addressTo)); +// Create and initialize TestEngine + +var engine = new TestEngine(true); + +// Fake signature of BFTAddress + +engine.Transaction.Signers = new Network.P2P.Payloads.Signer[] +{ + new Network.P2P.Payloads.Signer() + { + Account = engine.BFTAddress, + Scopes = Network.P2P.Payloads.WitnessScope.Global + } +}; + +// Attach to Transfer event + +var raisedEvent = false; + +engine.Native.NEO.OnTransfer += (UInt160 from, UInt160 to, BigInteger amount) => +{ + // If the event is raised, the variable will be changed + raisedEvent = true; +}; + +// Define address to transfer funds + +UInt160 addressTo = UInt160.Parse("0x1230000000000000000000000000000000000000"); + +Assert.AreEqual(0, engine.Native.NEO.BalanceOf(addressTo)); + +// Transfer funds + +Assert.IsTrue(engine.Native.NEO.Transfer(engine.Transaction.Sender, addressTo, 123, null)); + +// Ensure that we have balance and the event was raised + +Assert.IsTrue(raisedEvent); +Assert.AreEqual(123, engine.Native.NEO.BalanceOf(addressTo)); ``` From c6863f1c6ddbd7940a05e006902012ae7333ae06 Mon Sep 17 00:00:00 2001 From: Fernando Diaz Toledano Date: Sun, 11 Feb 2024 22:53:43 +0100 Subject: [PATCH 074/106] Improve Mock.OnSysCall --- .../TestingApplicationEngine.cs | 32 ++++++------------- 1 file changed, 9 insertions(+), 23 deletions(-) diff --git a/src/Neo.SmartContract.Testing/TestingApplicationEngine.cs b/src/Neo.SmartContract.Testing/TestingApplicationEngine.cs index 2b5f547f1..87043da8f 100644 --- a/src/Neo.SmartContract.Testing/TestingApplicationEngine.cs +++ b/src/Neo.SmartContract.Testing/TestingApplicationEngine.cs @@ -1,7 +1,6 @@ using Neo.Network.P2P.Payloads; using Neo.Persistence; using Neo.SmartContract.Testing.Extensions; -using Neo.VM.Types; using System; namespace Neo.SmartContract.Testing @@ -30,20 +29,16 @@ protected override void OnSysCall(InteropDescriptor descriptor) { // Extract args - var originalArgs = new StackItem[descriptor.Parameters.Count]; - var parameters = new object[originalArgs.Length]; - for (int i = 0; i < parameters.Length; i++) - { - originalArgs[i] = Pop(); - parameters[i] = Convert(originalArgs[i], descriptor.Parameters[i]); - } - - if (parameters[0] is UInt160 contractHash && - parameters[1] is string method && - parameters[2] is CallFlags callFlags && - parameters[3] is VM.Types.Array args && + if (Convert(Peek(0), descriptor.Parameters[0]) is UInt160 contractHash && + Convert(Peek(1), descriptor.Parameters[1]) is string method && + Convert(Peek(2), descriptor.Parameters[2]) is CallFlags callFlags && + Convert(Peek(3), descriptor.Parameters[3]) is VM.Types.Array args && Engine.TryGetCustomMock(contractHash, method, args.Count, out var customMock)) { + // Drop items + + Pop(); Pop(); Pop(); Pop(); + // Do the same logic as ApplicationEngine ValidateCallFlags(descriptor.RequiredCallFlags); @@ -64,7 +59,7 @@ parameters[3] is VM.Types.Array args && // Convert args to mocked method var methodParameters = customMock.Method.GetParameters(); - parameters = new object[args.Count]; + var parameters = new object[args.Count]; for (int i = 0; i < args.Count; i++) { parameters[i] = args[i].ConvertTo(methodParameters[i].ParameterType)!; @@ -79,15 +74,6 @@ parameters[3] is VM.Types.Array args && return; } - else - { - // Revert Pops and do default - - for (int i = parameters.Length - 1; i >= 0; i--) - { - Push(originalArgs[i]); - } - } } base.OnSysCall(descriptor); From 5b2e819fec5c0df879370964af41202d272be2ce Mon Sep 17 00:00:00 2001 From: Fernando Diaz Toledano Date: Sun, 11 Feb 2024 23:07:55 +0100 Subject: [PATCH 075/106] Some small changes --- src/Neo.SmartContract.Testing/README.md | 384 +++++++++--------- .../SmartContract.cs | 7 +- .../SmartContractStorage.cs | 2 +- src/Neo.SmartContract.Testing/TestEngine.cs | 4 + src/Neo.SmartContract.Testing/TestStorage.cs | 10 +- 5 files changed, 205 insertions(+), 202 deletions(-) diff --git a/src/Neo.SmartContract.Testing/README.md b/src/Neo.SmartContract.Testing/README.md index 6c368b3d0..e7af557fe 100644 --- a/src/Neo.SmartContract.Testing/README.md +++ b/src/Neo.SmartContract.Testing/README.md @@ -1,139 +1,139 @@ -# Neo.SmartContract.Testing - -The **Neo.SmartContract.Testing** project is designed to facilitate the development of unit tests for smart contract developers in neo, it does not require the project to be done in C#, as it is possible to export artifacts from an `Abi`. - -## Table of Contents - -- [Installation and configuration](#installation-and-configuration) - - [Generating Artifacts](#generating-artifacts) - - [Example of use](#example-of-use) -- [TestEngine](#testengine) - - [Properties](#properties) - - [Methods](#methods) - - [Example of use](#example-of-use) -- [NativeArtifacts](#nativeartifacts) - - [Methods](#methods) - - [Example of use](#example-of-use) -- [SmartContractStorage](#smartcontractstorage) - - [Methods](#methods) - - [Example of use](#example-of-use) -- [Custom mocks](#custom-mocks) - - [Example of use](#example-of-use) -- [Forging signatures](#forging-signatures) - - [Example of use](#example-of-use) -- [Event testing](#event-testing) - - [Example of use](#example-of-use) - -### Installation and configuration - -#### Generating Artifacts - -The process of generating the artifacts, or the source code necessary to interact with the contract, is extremely simple. There are two main ways to do it: - -1. Using the `ABI` of a contract, the necessary source code to interact with the contract can be generated by calling the `GetArtifactsSource` method available in the `Neo.SmartContract.Testing.Extensions` namespace, we will only have to specify the name of our resulting class, which will usually be the same as the one existing in the `Name` field of the manifest. - -2. Through the Neo C# compiler, automatically when compiling a contract in C#, the necessary source code to interact with the contract is generated. This is available in the same path as the generated .nef file, and its extension is `.artifacts.cs`. - -##### Example of use - -```csharp -[TestClass] -public class MyUnitTestClass -{ - [TestMethod] - public void GenerateNativeArtifacts() - { - foreach (var n in Native.NativeContract.Contracts) - { - var manifest = n.Manifest; - var source = manifest.Abi.GetArtifactsSource(manifest.Name); - - File.WriteAllText($"{manifest.Name}.cs", source); - } - } -} -``` - -### TestEngine - -The `TestEngine` class is the main class of the library, providing a simple and intuitive interface for testing smart contracts. - -#### Properties - -The publicly exposed read-only properties are as follows: - -- **ProtocolSettings**: Assigned during the construction of the `TestEngine` and defines the configuration values of the test environment. It defaults to the current blockchain protocol. -- **Sender**: Returns the script hash of the transaction sender, which corresponds to the first `Signer` defined in the `Transaction` object. -- **Native**: Allows access to the native contracts, and their state. It facilitates access to the chain's native contracts through some precompiled artifacts. This point is further detailed in [NativeArtifacts](#nativeartifacts). -- **BFTAddress**: Defines the address for the validators of the defined *ProtocolSettings*. -- **CommitteeAddress**: Returns the address of the current chain's committee. - -For read and write, we have: - -- **Gas**: Sets the gas execution limit for contract calls. -- **CurrentBlock**: Defaults to `Genesis` for the defined `ProtocolSettings`, but the height has been incremented by 1 to avoid issues related to the generation of gas from native contracts. -- **Transaction**: Defines the transaction that will be used as `ScriptContainer` for the neo virtual machine, by default it updates the script of the same as calls are composed and executed, and the `Signers` will be used as validators for the `CheckWitness`, regardless of whether the signature is correct or not, so if you want to test with different wallets or scopes, you do not need to sign the transaction correctly, just set the desired signers. -- **Storage**: Abstracts access to storage, allowing for easy `Snapshots` as well as reverting them. It can only be set during the initialization of the class, and allows access to the storage of contracts, as well as manually altering their state. - -#### Methods - -It has two main methods: - -- **Execute(script)**: Executes a script on the neo virtual machine and returns the execution result. -- **Deploy(nef, manifest, data, customMock)**: Deploys the smart contract by calling the native method `ContractManagement.deploy`. It allows setting [custom mocks](#custom-mocks), which will be detailed later. And returns the instance of the contract that has been deployed. -- **FromHash(hash, customMocks, checkExistence)**: Creates an instance without needing a `NefFile` or `Manifest`, only requiring the contract's hash. It does not consider whether the contract exists on the chain unless `checkExistence` is set to `true`. - -#### Example of use - -```csharp -// Create the engine initializing the native contracts - -var engine = new TestEngine(true); - -// Instantiate neo contract from native hash, (not necessary if we use engine.Native.NEO) - -var neo = engine.FromHash(engine.Native.NEO.Hash, false); - -// Ensure that the main address contains the totalSupply - +# Neo.SmartContract.Testing + +The **Neo.SmartContract.Testing** project is designed to facilitate the development of unit tests for smart contract developers in neo, it does not require the project to be done in C#, as it is possible to export artifacts from an `Abi`. + +## Table of Contents + +- [Installation and configuration](#installation-and-configuration) + - [Generating Artifacts](#generating-artifacts) + - [Example of use](#example-of-use) +- [TestEngine](#testengine) + - [Properties](#properties) + - [Methods](#methods) + - [Example of use](#example-of-use) +- [NativeArtifacts](#nativeartifacts) + - [Methods](#methods) + - [Example of use](#example-of-use) +- [SmartContractStorage](#smartcontractstorage) + - [Methods](#methods) + - [Example of use](#example-of-use) +- [Custom mocks](#custom-mocks) + - [Example of use](#example-of-use) +- [Forging signatures](#forging-signatures) + - [Example of use](#example-of-use) +- [Event testing](#event-testing) + - [Example of use](#example-of-use) + +### Installation and configuration + +#### Generating Artifacts + +The process of generating the artifacts, or the source code necessary to interact with the contract, is extremely simple. There are two main ways to do it: + +1. Using the `ABI` of a contract, the necessary source code to interact with the contract can be generated by calling the `GetArtifactsSource` method available in the `Neo.SmartContract.Testing.Extensions` namespace, we will only have to specify the name of our resulting class, which will usually be the same as the one existing in the `Name` field of the manifest. + +2. Through the Neo C# compiler, automatically when compiling a contract in C#, the necessary source code to interact with the contract is generated. This is available in the same path as the generated .nef file, and its extension is `.artifacts.cs`. + +##### Example of use + +```csharp +[TestClass] +public class MyUnitTestClass +{ + [TestMethod] + public void GenerateNativeArtifacts() + { + foreach (var n in Native.NativeContract.Contracts) + { + var manifest = n.Manifest; + var source = manifest.Abi.GetArtifactsSource(manifest.Name); + + File.WriteAllText($"{manifest.Name}.cs", source); + } + } +} +``` + +### TestEngine + +The `TestEngine` class is the main class of the library, providing a simple and intuitive interface for testing smart contracts. + +#### Properties + +The publicly exposed read-only properties are as follows: + +- **ProtocolSettings**: Assigned during the construction of the `TestEngine` and defines the configuration values of the test environment. It defaults to the current blockchain protocol. +- **Sender**: Returns the script hash of the transaction sender, which corresponds to the first `Signer` defined in the `Transaction` object. +- **Native**: Allows access to the native contracts, and their state. It facilitates access to the chain's native contracts through some precompiled artifacts. This point is further detailed in [NativeArtifacts](#nativeartifacts). +- **BFTAddress**: Defines the address for the validators of the defined *ProtocolSettings*. +- **CommitteeAddress**: Returns the address of the current chain's committee. + +For read and write, we have: + +- **Gas**: Sets the gas execution limit for contract calls. +- **CurrentBlock**: Defaults to `Genesis` for the defined `ProtocolSettings`, but the height has been incremented by 1 to avoid issues related to the generation of gas from native contracts. +- **Transaction**: Defines the transaction that will be used as `ScriptContainer` for the neo virtual machine, by default it updates the script of the same as calls are composed and executed, and the `Signers` will be used as validators for the `CheckWitness`, regardless of whether the signature is correct or not, so if you want to test with different wallets or scopes, you do not need to sign the transaction correctly, just set the desired signers. +- **Storage**: Abstracts access to storage, allowing for easy `Snapshots` as well as reverting them. It can only be set during the initialization of the class, and allows access to the storage of contracts, as well as manually altering their state. + +#### Methods + +It has two main methods: + +- **Execute(script)**: Executes a script on the neo virtual machine and returns the execution result. +- **Deploy(nef, manifest, data, customMock)**: Deploys the smart contract by calling the native method `ContractManagement.deploy`. It allows setting [custom mocks](#custom-mocks), which will be detailed later. And returns the instance of the contract that has been deployed. +- **FromHash(hash, customMocks, checkExistence)**: Creates an instance without needing a `NefFile` or `Manifest`, only requiring the contract's hash. It does not consider whether the contract exists on the chain unless `checkExistence` is set to `true`. + +#### Example of use + +```csharp +// Create the engine initializing the native contracts + +var engine = new TestEngine(true); + +// Instantiate neo contract from native hash, (not necessary if we use engine.Native.NEO) + +var neo = engine.FromHash(engine.Native.NEO.Hash, false); + +// Ensure that the main address contains the totalSupply + Assert.AreEqual(100_000_000, neo.TotalSupply); Assert.AreEqual(neo.TotalSupply, neo.BalanceOf(engine.BFTAddress)); -``` - -### NativeArtifacts - -This class provides precompiled artifacts for neo's native contracts, thereby simplifying and facilitating calls to native contracts. - -#### Methods - -It has only one method: - -- **Initialize(bool commit = false)**: Initializes the native contract with the necessary parameters for its operation. It's important to note that this step must usually be performed, or deploying contracts won't be possible. However, if using a `Storage` that already contains chain data and these contracts have been initialized, calling this method should be avoided. The `commit` argument determines whether to commit to the active `Snapshot` of the `TestStorage` (default is `false`). - -#### Example of use - -```csharp -// Create the engine initializing the native contracts - -var engine = new TestEngine(true); - -// Ensure that the main address contains the totalSupply - -Assert.AreEqual(100_000_000, engine.Native.NEO.TotalSupply); -Assert.AreEqual(engine.Native.NEO.TotalSupply, engine.Native.NEO.BalanceOf(engine.BFTAddress)); -``` - -### SmartContractStorage - -Avoids dealing with prefixes foreign to the internal behavior of the storage, focusing the developer solely on accessing the storage of the contract, just as it is managed by the smart contract itself, allowing reading, injecting, and deleting entries of the contract in question. - -#### Methods - -Mainly exposes the methods `Read`, `Put`, and `Remove`, all of them responsible for reading and manipulating the contract's information. - -#### Example of use - -```csharp +``` + +### NativeArtifacts + +This class provides precompiled artifacts for neo's native contracts, thereby simplifying and facilitating calls to native contracts. + +#### Methods + +It has only one method: + +- **Initialize(bool commit = false)**: Initializes the native contract with the necessary parameters for its operation. It's important to note that this step must usually be performed, or deploying contracts won't be possible. However, if using a `Storage` that already contains chain data and these contracts have been initialized, calling this method should be avoided. The `commit` argument determines whether to commit to the active `Snapshot` of the `TestStorage` (default is `false`). + +#### Example of use + +```csharp +// Create the engine initializing the native contracts + +var engine = new TestEngine(true); + +// Ensure that the main address contains the totalSupply + +Assert.AreEqual(100_000_000, engine.Native.NEO.TotalSupply); +Assert.AreEqual(engine.Native.NEO.TotalSupply, engine.Native.NEO.BalanceOf(engine.BFTAddress)); +``` + +### SmartContractStorage + +Avoids dealing with prefixes foreign to the internal behavior of the storage, focusing the developer solely on accessing the storage of the contract, just as it is managed by the smart contract itself, allowing reading, injecting, and deleting entries of the contract in question. + +#### Methods + +Mainly exposes the methods `Read`, `Put`, and `Remove`, all of them responsible for reading and manipulating the contract's information. + +#### Example of use + +```csharp // Defines the prefix used to store the registration price in neo byte[] registerPricePrefix = new byte[] { 13 }; @@ -152,52 +152,52 @@ engine.Native.NEO.Storage.Put(registerPricePrefix, BigInteger.MinusOne); // Check altered data -Assert.AreEqual(BigInteger.MinusOne, engine.Native.NEO.RegisterPrice); -``` - -### Custom mocks - -Custom mocks allow redirecting certain calls to smart contracts so that instead of calling the underlying contract, the logic is redirected to a method in .NET, allowing the developer to test in complex environments without significant issues. - -Imagine that our project checks that our account has a balance of 123 NEO. It would be enough to redirect the calls to the NEO `balanceOf` method in the following way, so that it always returns 123. - -It's important to note that all syscalls going to this contract will also be redirected, not only the calls to the method in .NET. - - -#### Example of use - -```csharp -// Initialize TestEngine and native smart contracts - -TestEngine engine = new(true); - -// Get neo token smart contract and mock balanceOf to always return 123 - -var neo = engine.FromHash(engine.Native.NEO.Hash, - mock => mock.Setup(o => o.BalanceOf(It.IsAny())).Returns(123), - false); - -// Test direct call - -Assert.AreEqual(123, neo.BalanceOf(engine.BFTAddress)); - -// Test vm call - -using (ScriptBuilder script = new()) -{ - script.EmitDynamicCall(neo.Hash, nameof(neo.BalanceOf), engine.BFTAddress); - - Assert.AreEqual(123, engine.Execute(script.ToArray()).GetInteger()); -} -``` - -### Forging signatures - -To fake signatures and allow testing our contracts in authorized and unauthorized environments, it's enough to replace the signers of the `Transaction` object in our `TestEngine`. This way, we can simulate the signatures of other users. It's worth noting that it's not necessary to modify the `Witnesses` since it's not checked whether the transaction is well-formed. - -#### Example of use - -```csharp +Assert.AreEqual(BigInteger.MinusOne, engine.Native.NEO.RegisterPrice); +``` + +### Custom mocks + +Custom mocks allow redirecting certain calls to smart contracts so that instead of calling the underlying contract, the logic is redirected to a method in .NET, allowing the developer to test in complex environments without significant issues. + +Imagine that our project checks that our account has a balance of 123 NEO. It would be enough to redirect the calls to the NEO `balanceOf` method in the following way, so that it always returns 123. + +It's important to note that all syscalls going to this contract will also be redirected, not only the calls to the method in .NET. + + +#### Example of use + +```csharp +// Initialize TestEngine and native smart contracts + +TestEngine engine = new(true); + +// Get neo token smart contract and mock balanceOf to always return 123 + +var neo = engine.FromHash(engine.Native.NEO.Hash, + mock => mock.Setup(o => o.BalanceOf(It.IsAny())).Returns(123), + false); + +// Test direct call + +Assert.AreEqual(123, neo.BalanceOf(engine.BFTAddress)); + +// Test vm call + +using (ScriptBuilder script = new()) +{ + script.EmitDynamicCall(neo.Hash, nameof(neo.BalanceOf), engine.BFTAddress); + + Assert.AreEqual(123, engine.Execute(script.ToArray()).GetInteger()); +} +``` + +### Forging signatures + +To fake signatures and allow testing our contracts in authorized and unauthorized environments, it's enough to replace the signers of the `Transaction` object in our `TestEngine`. This way, we can simulate the signatures of other users. It's worth noting that it's not necessary to modify the `Witnesses` since it's not checked whether the transaction is well-formed. + +#### Example of use + +```csharp // Initialize out TestEngine var engine = new TestEngine(true); @@ -227,16 +227,16 @@ Assert.AreEqual(123, engine.Native.NEO.RegisterPrice); engine.Transaction.Signers[0].Scopes = Network.P2P.Payloads.WitnessScope.None; -Assert.ThrowsException(() => engine.Native.NEO.RegisterPrice = 123); -``` - -### Event testing - -Testing that our events have been triggered has never been so easy. Simply when a contract notification is launched, the corresponding event will be invoked, making it easier to capture and detect. - -#### Example of use - -```csharp +Assert.ThrowsException(() => engine.Native.NEO.RegisterPrice = 123); +``` + +### Event testing + +Testing that our events have been triggered has never been so easy. Simply when a contract notification is launched, the corresponding event will be invoked, making it easier to capture and detect. + +#### Example of use + +```csharp // Create and initialize TestEngine var engine = new TestEngine(true); @@ -275,5 +275,5 @@ Assert.IsTrue(engine.Native.NEO.Transfer(engine.Transaction.Sender, addressTo, 1 // Ensure that we have balance and the event was raised Assert.IsTrue(raisedEvent); -Assert.AreEqual(123, engine.Native.NEO.BalanceOf(addressTo)); -``` +Assert.AreEqual(123, engine.Native.NEO.BalanceOf(addressTo)); +``` diff --git a/src/Neo.SmartContract.Testing/SmartContract.cs b/src/Neo.SmartContract.Testing/SmartContract.cs index 5c7322df8..7b2b29b34 100644 --- a/src/Neo.SmartContract.Testing/SmartContract.cs +++ b/src/Neo.SmartContract.Testing/SmartContract.cs @@ -12,8 +12,8 @@ public class SmartContract { internal readonly TestEngine Engine; - public delegate void delOnLog(string message); - public event delOnLog? OnRuntimeLog; + public delegate void OnRuntimeLogDelegate(string message); + public event OnRuntimeLogDelegate? OnRuntimeLog; /// /// Contract hash @@ -48,7 +48,8 @@ internal StackItem Invoke(string methodName, params object[] args) using ScriptBuilder script = new(); script.EmitDynamicCall(Hash, methodName, args); - Engine.Transaction.Script = script.ToArray(); // Store the script in the current transaction + + // Execute return Engine.Execute(script.ToArray()); } diff --git a/src/Neo.SmartContract.Testing/SmartContractStorage.cs b/src/Neo.SmartContract.Testing/SmartContractStorage.cs index 42c7f8f6f..9fc580528 100644 --- a/src/Neo.SmartContract.Testing/SmartContractStorage.cs +++ b/src/Neo.SmartContract.Testing/SmartContractStorage.cs @@ -27,7 +27,7 @@ private int GetContractId() } /// - /// Remove an entry from the smart contract storage + /// Read an entry from the smart contract storage /// /// Key public ReadOnlyMemory Read(ReadOnlyMemory key) diff --git a/src/Neo.SmartContract.Testing/TestEngine.cs b/src/Neo.SmartContract.Testing/TestEngine.cs index 3e40feef7..6de8ae10a 100644 --- a/src/Neo.SmartContract.Testing/TestEngine.cs +++ b/src/Neo.SmartContract.Testing/TestEngine.cs @@ -343,6 +343,10 @@ internal bool TryGetCustomMock(UInt160 hash, string method, int rc, [NotNullWhen /// StackItem public StackItem Execute(Script script) { + // Store the script in current transaction + + Transaction.Script = script; + // Execute in neo VM var snapshot = Storage.Snapshot.CreateSnapshot(); diff --git a/src/Neo.SmartContract.Testing/TestStorage.cs b/src/Neo.SmartContract.Testing/TestStorage.cs index 2c053640b..9c8006d91 100644 --- a/src/Neo.SmartContract.Testing/TestStorage.cs +++ b/src/Neo.SmartContract.Testing/TestStorage.cs @@ -49,12 +49,10 @@ public void Rollback() } /// - /// Load data from json - /// - /// Expected data (in base64): - /// - /// - "key":"value" - /// - "prefix": { "key":"value" } + /// Load data from json, expected data (in base64): + /// - "key" : "value" + /// - "prefix" : { "key":"value" } + /// - "123" : { "key":"value" } /// /// Snapshot to be used /// Json Object From b556d43a028fe6b0218898e357818c1bbf03adb9 Mon Sep 17 00:00:00 2001 From: Fernando Diaz Toledano Date: Sun, 11 Feb 2024 23:35:11 +0100 Subject: [PATCH 076/106] Generate compiled artifacts (.dll) --- src/Neo.Compiler.CSharp/Options.cs | 83 +++++++++++++------------ src/Neo.Compiler.CSharp/Program.cs | 60 +++++++++++++++++- src/Neo.SmartContract.Testing/README.md | 2 +- 3 files changed, 101 insertions(+), 44 deletions(-) diff --git a/src/Neo.Compiler.CSharp/Options.cs b/src/Neo.Compiler.CSharp/Options.cs index 19a2c449b..0a441f7d2 100644 --- a/src/Neo.Compiler.CSharp/Options.cs +++ b/src/Neo.Compiler.CSharp/Options.cs @@ -1,41 +1,42 @@ -// Copyright (C) 2015-2023 The Neo Project. -// -// The Neo.Compiler.CSharp is free software distributed under the MIT -// software license, see the accompanying file LICENSE in the main directory -// of the project 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 Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.CSharp; -using System.Collections.Generic; - -namespace Neo.Compiler -{ - public class Options - { - public string? Output { get; set; } - public string? BaseName { get; set; } - public NullableContextOptions Nullable { get; set; } - public bool Checked { get; set; } - public bool Debug { get; set; } - public bool Assembly { get; set; } - public bool NoOptimize { get; set; } - public bool NoInline { get; set; } - public byte AddressVersion { get; set; } - - private CSharpParseOptions? parseOptions = null; - public CSharpParseOptions GetParseOptions() - { - if (parseOptions is null) - { - List preprocessorSymbols = new(); - if (Debug) preprocessorSymbols.Add("DEBUG"); - parseOptions = new CSharpParseOptions(preprocessorSymbols: preprocessorSymbols); - } - return parseOptions; - } - } -} +// Copyright (C) 2015-2023 The Neo Project. +// +// The Neo.Compiler.CSharp is free software distributed under the MIT +// software license, see the accompanying file LICENSE in the main directory +// of the project 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 Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; +using System.Collections.Generic; + +namespace Neo.Compiler +{ + public class Options + { + public string? Output { get; set; } + public string? BaseName { get; set; } + public NullableContextOptions Nullable { get; set; } + public bool Checked { get; set; } + public bool Debug { get; set; } + public bool Assembly { get; set; } + public bool NoArtifacts { get; set; } + public bool NoOptimize { get; set; } + public bool NoInline { get; set; } + public byte AddressVersion { get; set; } + + private CSharpParseOptions? parseOptions = null; + public CSharpParseOptions GetParseOptions() + { + if (parseOptions is null) + { + List preprocessorSymbols = new(); + if (Debug) preprocessorSymbols.Add("DEBUG"); + parseOptions = new CSharpParseOptions(preprocessorSymbols: preprocessorSymbols); + } + return parseOptions; + } + } +} diff --git a/src/Neo.Compiler.CSharp/Program.cs b/src/Neo.Compiler.CSharp/Program.cs index 08360d60a..0b121fe46 100644 --- a/src/Neo.Compiler.CSharp/Program.cs +++ b/src/Neo.Compiler.CSharp/Program.cs @@ -9,6 +9,8 @@ // modifications are permitted. using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.Emit; using Neo.IO; using Neo.Json; using Neo.Optimizer; @@ -19,6 +21,7 @@ using System.CommandLine; using System.CommandLine.Invocation; using System.CommandLine.NamingConventionBinder; +using System.ComponentModel; using System.IO; using System.IO.Compression; using System.Linq; @@ -39,6 +42,7 @@ static int Main(string[] args) new Option("--checked", "Indicates whether to check for overflow and underflow."), new Option(new[] { "-d", "--debug" }, "Indicates whether to generate debugging information."), new Option("--assembly", "Indicates whether to generate assembly."), + new Option("--no-artifacts", "Instruct the compiler not to generate artifacts."), new Option("--no-optimize", "Instruct the compiler not to optimize the code."), new Option("--no-inline", "Instruct the compiler not to insert inline code."), new Option("--address-version", () => ProtocolSettings.Default.AddressVersion, "Indicates the address version used by the compiler.") @@ -177,11 +181,63 @@ private static int ProcessOutputs(Options options, string folder, CompilationCon return 1; } Console.WriteLine($"Created {path}"); - // Create artifacts + if (!options.NoArtifacts) { + var artifact = manifest.Abi.GetArtifactsSource(baseName); path = Path.Combine(outputFolder, $"{baseName}.artifacts.cs"); - File.WriteAllText(path, manifest.Abi.GetArtifactsSource(baseName)); + File.WriteAllText(path, artifact); Console.WriteLine($"Created {path}"); + + try + { + // Try to compile the artifacts into a dll + + string coreDir = Path.GetDirectoryName(typeof(object).Assembly.Location)!; + + var syntaxTree = CSharpSyntaxTree.ParseText(artifact); + var references = new MetadataReference[] + { + MetadataReference.CreateFromFile(Path.Combine(coreDir, "System.Runtime.dll")), + MetadataReference.CreateFromFile(Path.Combine(coreDir, "System.Runtime.InteropServices.dll")), + MetadataReference.CreateFromFile(typeof(object).Assembly.Location), + MetadataReference.CreateFromFile(typeof(DisplayNameAttribute).Assembly.Location), + MetadataReference.CreateFromFile(typeof(System.Numerics.BigInteger).Assembly.Location), + MetadataReference.CreateFromFile(typeof(UInt160).Assembly.Location), + MetadataReference.CreateFromFile(typeof(SmartContract.Testing.SmartContract).Assembly.Location) + }; + + var compilation = CSharpCompilation.Create(baseName, new[] { syntaxTree }, references, + new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary)); + + using var ms = new MemoryStream(); + EmitResult result = compilation.Emit(ms); + + if (!result.Success) + { + var failures = result.Diagnostics.Where(diagnostic => + diagnostic.IsWarningAsError || + diagnostic.Severity == DiagnosticSeverity.Error); + + foreach (var diagnostic in failures) + { + Console.Error.WriteLine("{0}: {1}", diagnostic.Id, diagnostic.GetMessage()); + } + } + else + { + ms.Seek(0, SeekOrigin.Begin); + + // Write dll + + path = Path.Combine(outputFolder, $"{baseName}.artifacts.dll"); + File.WriteAllBytes(path, ms.ToArray()); + Console.WriteLine($"Created {path}"); + } + } + catch + { + Console.Error.WriteLine("Artifacts compilation error."); + } } if (options.Debug) { diff --git a/src/Neo.SmartContract.Testing/README.md b/src/Neo.SmartContract.Testing/README.md index e7af557fe..07bb8b3e5 100644 --- a/src/Neo.SmartContract.Testing/README.md +++ b/src/Neo.SmartContract.Testing/README.md @@ -32,7 +32,7 @@ The process of generating the artifacts, or the source code necessary to interac 1. Using the `ABI` of a contract, the necessary source code to interact with the contract can be generated by calling the `GetArtifactsSource` method available in the `Neo.SmartContract.Testing.Extensions` namespace, we will only have to specify the name of our resulting class, which will usually be the same as the one existing in the `Name` field of the manifest. -2. Through the Neo C# compiler, automatically when compiling a contract in C#, the necessary source code to interact with the contract is generated. This is available in the same path as the generated .nef file, and its extension is `.artifacts.cs`. +2. Through the Neo C# compiler, automatically when compiling a contract in C#, the necessary source code to interact with the contract is generated. This is available in the same path as the generated .nef file, and its extension are `.artifacts.cs` and `.artifacts.dll`. ##### Example of use From e6569b7a64987abb060ad139821f85a667359c28 Mon Sep 17 00:00:00 2001 From: Fernando Diaz Toledano Date: Sun, 11 Feb 2024 23:35:52 +0100 Subject: [PATCH 077/106] LF --- src/Neo.Compiler.CSharp/Options.cs | 84 +++++++++++++++--------------- 1 file changed, 42 insertions(+), 42 deletions(-) diff --git a/src/Neo.Compiler.CSharp/Options.cs b/src/Neo.Compiler.CSharp/Options.cs index 0a441f7d2..a6df13210 100644 --- a/src/Neo.Compiler.CSharp/Options.cs +++ b/src/Neo.Compiler.CSharp/Options.cs @@ -1,42 +1,42 @@ -// Copyright (C) 2015-2023 The Neo Project. -// -// The Neo.Compiler.CSharp is free software distributed under the MIT -// software license, see the accompanying file LICENSE in the main directory -// of the project 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 Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.CSharp; -using System.Collections.Generic; - -namespace Neo.Compiler -{ - public class Options - { - public string? Output { get; set; } - public string? BaseName { get; set; } - public NullableContextOptions Nullable { get; set; } - public bool Checked { get; set; } - public bool Debug { get; set; } - public bool Assembly { get; set; } - public bool NoArtifacts { get; set; } - public bool NoOptimize { get; set; } - public bool NoInline { get; set; } - public byte AddressVersion { get; set; } - - private CSharpParseOptions? parseOptions = null; - public CSharpParseOptions GetParseOptions() - { - if (parseOptions is null) - { - List preprocessorSymbols = new(); - if (Debug) preprocessorSymbols.Add("DEBUG"); - parseOptions = new CSharpParseOptions(preprocessorSymbols: preprocessorSymbols); - } - return parseOptions; - } - } -} +// Copyright (C) 2015-2023 The Neo Project. +// +// The Neo.Compiler.CSharp is free software distributed under the MIT +// software license, see the accompanying file LICENSE in the main directory +// of the project 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 Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; +using System.Collections.Generic; + +namespace Neo.Compiler +{ + public class Options + { + public string? Output { get; set; } + public string? BaseName { get; set; } + public NullableContextOptions Nullable { get; set; } + public bool Checked { get; set; } + public bool Debug { get; set; } + public bool Assembly { get; set; } + public bool NoArtifacts { get; set; } + public bool NoOptimize { get; set; } + public bool NoInline { get; set; } + public byte AddressVersion { get; set; } + + private CSharpParseOptions? parseOptions = null; + public CSharpParseOptions GetParseOptions() + { + if (parseOptions is null) + { + List preprocessorSymbols = new(); + if (Debug) preprocessorSymbols.Add("DEBUG"); + parseOptions = new CSharpParseOptions(preprocessorSymbols: preprocessorSymbols); + } + return parseOptions; + } + } +} From 3db2778b573f4011030717bae8abbb438cbc9394 Mon Sep 17 00:00:00 2001 From: Shargon Date: Mon, 12 Feb 2024 00:20:33 +0100 Subject: [PATCH 078/106] is 3 not 2 --- src/Neo.SmartContract.Testing/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Neo.SmartContract.Testing/README.md b/src/Neo.SmartContract.Testing/README.md index 07bb8b3e5..2732a3ad8 100644 --- a/src/Neo.SmartContract.Testing/README.md +++ b/src/Neo.SmartContract.Testing/README.md @@ -77,7 +77,7 @@ For read and write, we have: #### Methods -It has two main methods: +It has three methods: - **Execute(script)**: Executes a script on the neo virtual machine and returns the execution result. - **Deploy(nef, manifest, data, customMock)**: Deploys the smart contract by calling the native method `ContractManagement.deploy`. It allows setting [custom mocks](#custom-mocks), which will be detailed later. And returns the instance of the contract that has been deployed. From 46c525d7e4184a931101beaea9a7d6b701b21bc7 Mon Sep 17 00:00:00 2001 From: Shargon Date: Mon, 12 Feb 2024 00:43:31 +0100 Subject: [PATCH 079/106] Update src/Neo.SmartContract.Testing/README.md --- src/Neo.SmartContract.Testing/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Neo.SmartContract.Testing/README.md b/src/Neo.SmartContract.Testing/README.md index 2732a3ad8..e9a93fcce 100644 --- a/src/Neo.SmartContract.Testing/README.md +++ b/src/Neo.SmartContract.Testing/README.md @@ -138,7 +138,7 @@ Mainly exposes the methods `Read`, `Put`, and `Remove`, all of them responsible byte[] registerPricePrefix = new byte[] { 13 }; -// Engine an contract creation +// Create engine and initialize native contracts TestEngine engine = new(true); From e1186307ae7788f510e5f4f66d351de3450b5f11 Mon Sep 17 00:00:00 2001 From: Shargon Date: Mon, 12 Feb 2024 00:43:53 +0100 Subject: [PATCH 080/106] Update src/Neo.SmartContract.Testing/NativeArtifacts.cs --- src/Neo.SmartContract.Testing/NativeArtifacts.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Neo.SmartContract.Testing/NativeArtifacts.cs b/src/Neo.SmartContract.Testing/NativeArtifacts.cs index e3a2b674d..e34f95251 100644 --- a/src/Neo.SmartContract.Testing/NativeArtifacts.cs +++ b/src/Neo.SmartContract.Testing/NativeArtifacts.cs @@ -189,7 +189,7 @@ public void Initialize(bool commit = false) task.GetAwaiter().GetResult(); if (engine.Execute() != VM.VMState.HALT) - throw new Exception($"Error executing {native.Name}.OnPersist"); + throw new Exception($"Error executing {native.Name}.PostPersist"); } clonedSnapshot.Commit(); From f141fe9634f9206adf9bb3ba1f6c0922ea0b0dd9 Mon Sep 17 00:00:00 2001 From: Fernando Diaz Toledano Date: Mon, 12 Feb 2024 10:53:41 +0100 Subject: [PATCH 081/106] Sign by default with Validators and committee --- src/Neo.SmartContract.Testing/TestEngine.cs | 34 ++++++++++++++++----- 1 file changed, 27 insertions(+), 7 deletions(-) diff --git a/src/Neo.SmartContract.Testing/TestEngine.cs b/src/Neo.SmartContract.Testing/TestEngine.cs index 6de8ae10a..e6fa9afb0 100644 --- a/src/Neo.SmartContract.Testing/TestEngine.cs +++ b/src/Neo.SmartContract.Testing/TestEngine.cs @@ -78,7 +78,14 @@ public class TestEngine /// /// BFT Address /// - public UInt160 BFTAddress { get; } + public UInt160 BFTAddress + { + get + { + var validators = Neo.SmartContract.Native.NativeContract.NEO.ComputeNextBlockValidators(Storage.Snapshot, ProtocolSettings); + return Contract.GetBFTAddress(validators); + } + } /// /// Committee Address @@ -94,7 +101,7 @@ public class TestEngine /// /// Transaction /// - public Transaction Transaction { get; set; } + public Transaction Transaction { get; } /// /// Gas @@ -135,7 +142,9 @@ public TestEngine(ProtocolSettings settings, bool initializeNativeContracts = tr CurrentBlock = NeoSystem.CreateGenesisBlock(ProtocolSettings); CurrentBlock.Header.Index++; - BFTAddress = Contract.GetBFTAddress(ProtocolSettings.StandbyValidators); + var validatorsScript = Contract.CreateMultiSigRedeemScript(settings.StandbyValidators.Count - (settings.StandbyValidators.Count - 1) / 3, settings.StandbyValidators); + var committeeScript = Contract.CreateMultiSigRedeemScript(settings.StandbyCommittee.Count - (settings.StandbyCommittee.Count - 1) / 2, settings.StandbyCommittee); + Transaction = new Transaction() { Attributes = System.Array.Empty(), @@ -144,16 +153,27 @@ public TestEngine(ProtocolSettings settings, bool initializeNativeContracts = tr { new Signer() { - Account = BFTAddress, - Scopes = WitnessScope.Global + // BFTAddress + Account = validatorsScript.ToScriptHash(), + Scopes = WitnessScope.Global + }, + new Signer() + { + // CommitteeAddress + Account = committeeScript.ToScriptHash(), + Scopes = WitnessScope.Global } }, Witnesses = new Witness[] { new Witness() { - InvocationScript = Contract.CreateMultiSigRedeemScript( - settings.StandbyValidators.Count - (settings.StandbyValidators.Count - 1) / 3, settings.StandbyValidators), + InvocationScript = validatorsScript, + VerificationScript = System.Array.Empty() + }, + new Witness() + { + InvocationScript = committeeScript, VerificationScript = System.Array.Empty() } } From ef2e0f03bf4442b0d1eb943c3b4590c43d5a0b91 Mon Sep 17 00:00:00 2001 From: Fernando Diaz Toledano Date: Mon, 12 Feb 2024 10:58:46 +0100 Subject: [PATCH 082/106] Rename to ValidatorsAddress --- src/Neo.SmartContract.Testing/README.md | 13 ++++++++----- src/Neo.SmartContract.Testing/TestEngine.cs | 4 ++-- .../NativeArtifactsTests.cs | 4 ++-- .../TestEngineTests.cs | 6 +++--- 4 files changed, 15 insertions(+), 12 deletions(-) diff --git a/src/Neo.SmartContract.Testing/README.md b/src/Neo.SmartContract.Testing/README.md index e9a93fcce..a1d8c6042 100644 --- a/src/Neo.SmartContract.Testing/README.md +++ b/src/Neo.SmartContract.Testing/README.md @@ -65,16 +65,19 @@ The publicly exposed read-only properties are as follows: - **ProtocolSettings**: Assigned during the construction of the `TestEngine` and defines the configuration values of the test environment. It defaults to the current blockchain protocol. - **Sender**: Returns the script hash of the transaction sender, which corresponds to the first `Signer` defined in the `Transaction` object. - **Native**: Allows access to the native contracts, and their state. It facilitates access to the chain's native contracts through some precompiled artifacts. This point is further detailed in [NativeArtifacts](#nativeartifacts). -- **BFTAddress**: Defines the address for the validators of the defined *ProtocolSettings*. +- **ValidatorsAddress**: Defines the address for the validators of the defined *ProtocolSettings*. - **CommitteeAddress**: Returns the address of the current chain's committee. +- **Transaction**: Defines the transaction that will be used as `ScriptContainer` for the neo virtual machine, by default it updates the script of the same as calls are composed and executed, and the `Signers` will be used as validators for the `CheckWitness`, regardless of whether the signature is correct or not, so if you want to test with different wallets or scopes, you do not need to sign the transaction correctly, just set the desired signers. +- **CurrentBlock**: Defaults to `Genesis` for the defined `ProtocolSettings`, but the height has been incremented by 1 to avoid issues related to the generation of gas from native contracts. -For read and write, we have: +For initialize, we have: -- **Gas**: Sets the gas execution limit for contract calls. -- **CurrentBlock**: Defaults to `Genesis` for the defined `ProtocolSettings`, but the height has been incremented by 1 to avoid issues related to the generation of gas from native contracts. -- **Transaction**: Defines the transaction that will be used as `ScriptContainer` for the neo virtual machine, by default it updates the script of the same as calls are composed and executed, and the `Signers` will be used as validators for the `CheckWitness`, regardless of whether the signature is correct or not, so if you want to test with different wallets or scopes, you do not need to sign the transaction correctly, just set the desired signers. - **Storage**: Abstracts access to storage, allowing for easy `Snapshots` as well as reverting them. It can only be set during the initialization of the class, and allows access to the storage of contracts, as well as manually altering their state. +And for read and write, we have: + +- **Gas**: Sets the gas execution limit for contract calls. + #### Methods It has three methods: diff --git a/src/Neo.SmartContract.Testing/TestEngine.cs b/src/Neo.SmartContract.Testing/TestEngine.cs index e6fa9afb0..0b9d594af 100644 --- a/src/Neo.SmartContract.Testing/TestEngine.cs +++ b/src/Neo.SmartContract.Testing/TestEngine.cs @@ -76,9 +76,9 @@ public class TestEngine public ProtocolSettings ProtocolSettings { get; } /// - /// BFT Address + /// Validators Address /// - public UInt160 BFTAddress + public UInt160 ValidatorsAddress { get { diff --git a/tests/Neo.SmartContract.Testing.UnitTests/NativeArtifactsTests.cs b/tests/Neo.SmartContract.Testing.UnitTests/NativeArtifactsTests.cs index c28b2a829..b633e8bbd 100644 --- a/tests/Neo.SmartContract.Testing.UnitTests/NativeArtifactsTests.cs +++ b/tests/Neo.SmartContract.Testing.UnitTests/NativeArtifactsTests.cs @@ -24,7 +24,7 @@ public void TestInitialize() // Ensure that the main address contains the totalSupply Assert.AreEqual(100_000_000, engine.Native.NEO.TotalSupply); - Assert.AreEqual(engine.Native.NEO.TotalSupply, engine.Native.NEO.BalanceOf(engine.BFTAddress)); + Assert.AreEqual(engine.Native.NEO.TotalSupply, engine.Native.NEO.BalanceOf(engine.ValidatorsAddress)); } [TestMethod] @@ -40,7 +40,7 @@ public void TestTransfer() { new Network.P2P.Payloads.Signer() { - Account = engine.BFTAddress, + Account = engine.ValidatorsAddress, Scopes = Network.P2P.Payloads.WitnessScope.Global } }; diff --git a/tests/Neo.SmartContract.Testing.UnitTests/TestEngineTests.cs b/tests/Neo.SmartContract.Testing.UnitTests/TestEngineTests.cs index 492cfce0a..dbe763fcf 100644 --- a/tests/Neo.SmartContract.Testing.UnitTests/TestEngineTests.cs +++ b/tests/Neo.SmartContract.Testing.UnitTests/TestEngineTests.cs @@ -56,13 +56,13 @@ public void TestCustomMock() // Test direct call - Assert.AreEqual(123, neo.BalanceOf(engine.BFTAddress)); + Assert.AreEqual(123, neo.BalanceOf(engine.ValidatorsAddress)); // Test vm call using (ScriptBuilder script = new()) { - script.EmitDynamicCall(neo.Hash, nameof(neo.BalanceOf), engine.BFTAddress); + script.EmitDynamicCall(neo.Hash, nameof(neo.BalanceOf), engine.ValidatorsAddress); Assert.AreEqual(123, engine.Execute(script.ToArray()).GetInteger()); } @@ -121,7 +121,7 @@ public void FromHashTest() // Ensure that the main address contains the totalSupply Assert.AreEqual(100_000_000, neo.TotalSupply); - Assert.AreEqual(neo.TotalSupply, neo.BalanceOf(engine.BFTAddress)); + Assert.AreEqual(neo.TotalSupply, neo.BalanceOf(engine.ValidatorsAddress)); } } } From 57f9edc34dd078cd639097a3dda688af7be6492d Mon Sep 17 00:00:00 2001 From: Fernando Diaz Toledano Date: Mon, 12 Feb 2024 11:16:04 +0100 Subject: [PATCH 083/106] Allow to get address without initialize --- .../NativeArtifacts.cs | 18 ++++---- src/Neo.SmartContract.Testing/README.md | 2 +- .../SmartContractStorage.cs | 13 +++++- src/Neo.SmartContract.Testing/TestEngine.cs | 45 +++++++++++++++++-- 4 files changed, 63 insertions(+), 15 deletions(-) diff --git a/src/Neo.SmartContract.Testing/NativeArtifacts.cs b/src/Neo.SmartContract.Testing/NativeArtifacts.cs index e34f95251..a35b34791 100644 --- a/src/Neo.SmartContract.Testing/NativeArtifacts.cs +++ b/src/Neo.SmartContract.Testing/NativeArtifacts.cs @@ -32,7 +32,7 @@ public ContractManagement ContractManagement { get { - _contractManagement ??= _engine.FromHash(Native.NativeContract.ContractManagement.Hash, false); + _contractManagement ??= _engine.FromHash(Native.NativeContract.ContractManagement.Hash, Native.NativeContract.ContractManagement.Id); return _contractManagement; } } @@ -44,7 +44,7 @@ public CryptoLib CryptoLib { get { - _cryptoLib ??= _engine.FromHash(Native.NativeContract.CryptoLib.Hash, false); + _cryptoLib ??= _engine.FromHash(Native.NativeContract.CryptoLib.Hash, Native.NativeContract.CryptoLib.Id); return _cryptoLib; } } @@ -56,7 +56,7 @@ public GasToken GAS { get { - _gas ??= _engine.FromHash(Native.NativeContract.GAS.Hash, false); + _gas ??= _engine.FromHash(Native.NativeContract.GAS.Hash, Native.NativeContract.GAS.Id); return _gas; } } @@ -68,7 +68,7 @@ public NeoToken NEO { get { - _neo ??= _engine.FromHash(Native.NativeContract.NEO.Hash, false); + _neo ??= _engine.FromHash(Native.NativeContract.NEO.Hash, Native.NativeContract.NEO.Id); return _neo; } } @@ -80,7 +80,7 @@ public LedgerContract Ledger { get { - _ledger ??= _engine.FromHash(Native.NativeContract.Ledger.Hash, false); + _ledger ??= _engine.FromHash(Native.NativeContract.Ledger.Hash, Native.NativeContract.Ledger.Id); return _ledger; } } @@ -92,7 +92,7 @@ public OracleContract Oracle { get { - _oracle ??= _engine.FromHash(Native.NativeContract.Oracle.Hash, false); + _oracle ??= _engine.FromHash(Native.NativeContract.Oracle.Hash, Native.NativeContract.Oracle.Id); return _oracle; } } @@ -104,7 +104,7 @@ public PolicyContract Policy { get { - _policy ??= _engine.FromHash(Native.NativeContract.Policy.Hash, false); + _policy ??= _engine.FromHash(Native.NativeContract.Policy.Hash, Native.NativeContract.Policy.Id); return _policy; } } @@ -116,7 +116,7 @@ public RoleManagement RoleManagement { get { - _roleManagement ??= _engine.FromHash(Native.NativeContract.RoleManagement.Hash, false); + _roleManagement ??= _engine.FromHash(Native.NativeContract.RoleManagement.Hash, Native.NativeContract.RoleManagement.Id); return _roleManagement; } } @@ -128,7 +128,7 @@ public StdLib StdLib { get { - _stdLib ??= _engine.FromHash(Native.NativeContract.StdLib.Hash, false); + _stdLib ??= _engine.FromHash(Native.NativeContract.StdLib.Hash, Native.NativeContract.StdLib.Id); return _stdLib; } } diff --git a/src/Neo.SmartContract.Testing/README.md b/src/Neo.SmartContract.Testing/README.md index a1d8c6042..91e6cad5c 100644 --- a/src/Neo.SmartContract.Testing/README.md +++ b/src/Neo.SmartContract.Testing/README.md @@ -132,7 +132,7 @@ Avoids dealing with prefixes foreign to the internal behavior of the storage, fo #### Methods -Mainly exposes the methods `Read`, `Put`, and `Remove`, all of them responsible for reading and manipulating the contract's information. +Mainly exposes the methods `Contains`, `Get`, `Put`, and `Remove`, all of them responsible for reading and manipulating the contract's information. #### Example of use diff --git a/src/Neo.SmartContract.Testing/SmartContractStorage.cs b/src/Neo.SmartContract.Testing/SmartContractStorage.cs index 9fc580528..b1dd84a76 100644 --- a/src/Neo.SmartContract.Testing/SmartContractStorage.cs +++ b/src/Neo.SmartContract.Testing/SmartContractStorage.cs @@ -26,11 +26,22 @@ private int GetContractId() return _contractId.Value; } + /// + /// Check if the entry exist + /// + /// Key + public bool Contains(ReadOnlyMemory key) + { + var skey = new StorageKey() { Id = GetContractId(), Key = key }; + var entry = _smartContract.Engine.Storage.Snapshot.TryGet(skey); + return entry != null; + } + /// /// Read an entry from the smart contract storage /// /// Key - public ReadOnlyMemory Read(ReadOnlyMemory key) + public ReadOnlyMemory Get(ReadOnlyMemory key) { var skey = new StorageKey() { Id = GetContractId(), Key = key }; var entry = _smartContract.Engine.Storage.Snapshot.TryGet(skey); diff --git a/src/Neo.SmartContract.Testing/TestEngine.cs b/src/Neo.SmartContract.Testing/TestEngine.cs index 0b9d594af..c8c02768a 100644 --- a/src/Neo.SmartContract.Testing/TestEngine.cs +++ b/src/Neo.SmartContract.Testing/TestEngine.cs @@ -82,6 +82,16 @@ public UInt160 ValidatorsAddress { get { + var votersCountPrefix = new byte[] { 1 }; + + if (!Native.NEO.Storage.Contains(votersCountPrefix)) + { + // If is not initialized, return the ProtocolSettings + + var validatorsScript = Contract.CreateMultiSigRedeemScript(ProtocolSettings.StandbyValidators.Count - (ProtocolSettings.StandbyValidators.Count - 1) / 3, ProtocolSettings.StandbyValidators); + return validatorsScript.ToScriptHash(); + } + var validators = Neo.SmartContract.Native.NativeContract.NEO.ComputeNextBlockValidators(Storage.Snapshot, ProtocolSettings); return Contract.GetBFTAddress(validators); } @@ -90,8 +100,23 @@ public UInt160 ValidatorsAddress /// /// Committee Address /// - public UInt160 CommitteeAddress => - Neo.SmartContract.Native.NativeContract.NEO.GetCommitteeAddress(Storage.Snapshot); + public UInt160 CommitteeAddress + { + get + { + var votersCountPrefix = new byte[] { 1 }; + + if (!Native.NEO.Storage.Contains(votersCountPrefix)) + { + // If is not initialized, return the ProtocolSettings + + var committeeScript = Contract.CreateMultiSigRedeemScript(ProtocolSettings.StandbyCommittee.Count - (ProtocolSettings.StandbyCommittee.Count - 1) / 2, ProtocolSettings.StandbyCommittee); + return committeeScript.ToScriptHash(); + } + + return Neo.SmartContract.Native.NativeContract.NEO.GetCommitteeAddress(Storage.Snapshot); + } + } /// /// BFTAddress @@ -236,7 +261,7 @@ public T Deploy(NefFile nef, ContractManifest manifest, object? data = null, } /// - /// Deploy Smart contract + /// Smart contract from Hash /// /// Type /// Contract hash @@ -248,7 +273,7 @@ public T FromHash(UInt160 hash, bool checkExistence = true) where T : SmartCo } /// - /// Deploy Smart contract + /// Smart contract from Hash /// /// Type /// Contract hash @@ -267,6 +292,18 @@ public T FromHash(UInt160 hash, Action>? customMock = null, bool chec return MockContract(state.Hash, state.Id, customMock); } + /// + /// Used for native artifacts only + /// + /// + /// Contract hash + /// Contract Id + /// Mocked Smart Contract + internal T FromHash(UInt160 hash, int? contractId = null) where T : SmartContract + { + return MockContract(hash, contractId, null); + } + private T MockContract(UInt160 hash, int? contractId = null, Action>? customMock = null) where T : SmartContract { var mock = new Mock(new SmartContractInitialize() { Engine = this, Hash = hash, ContractId = contractId }) From 4e8a7d474921f58f013d8fb7aa582558470d69a1 Mon Sep 17 00:00:00 2001 From: Fernando Diaz Toledano Date: Mon, 12 Feb 2024 11:21:00 +0100 Subject: [PATCH 084/106] Clean comment --- src/Neo.SmartContract.Testing/TestEngine.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Neo.SmartContract.Testing/TestEngine.cs b/src/Neo.SmartContract.Testing/TestEngine.cs index c8c02768a..09b9607d0 100644 --- a/src/Neo.SmartContract.Testing/TestEngine.cs +++ b/src/Neo.SmartContract.Testing/TestEngine.cs @@ -178,7 +178,7 @@ public TestEngine(ProtocolSettings settings, bool initializeNativeContracts = tr { new Signer() { - // BFTAddress + // ValidatorsAddress Account = validatorsScript.ToScriptHash(), Scopes = WitnessScope.Global }, From 5576c9aa309e5d2484a38094308c50eb2c310023 Mon Sep 17 00:00:00 2001 From: Fernando Diaz Toledano Date: Mon, 12 Feb 2024 12:06:46 +0100 Subject: [PATCH 085/106] Allow deploy with byte[] --- src/Neo.SmartContract.Testing/TestEngine.cs | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/src/Neo.SmartContract.Testing/TestEngine.cs b/src/Neo.SmartContract.Testing/TestEngine.cs index 09b9607d0..8b07702ac 100644 --- a/src/Neo.SmartContract.Testing/TestEngine.cs +++ b/src/Neo.SmartContract.Testing/TestEngine.cs @@ -239,6 +239,20 @@ private void ApplicationEngine_Log(object? sender, LogEventArgs e) #endregion + /// + /// Deploy Smart contract + /// + /// Type + /// Nef file + /// Contract manifest + /// Construction data + /// Custom Mock + /// Mocked Smart Contract + public T Deploy(byte[] nef, string manifest, object? data = null, Action>? customMock = null) where T : SmartContract + { + return Deploy(nef.AsSerializable(), ContractManifest.Parse(manifest), data, customMock); + } + /// /// Deploy Smart contract /// @@ -252,7 +266,7 @@ public T Deploy(NefFile nef, ContractManifest manifest, object? data = null, { // Deploy - var state = Native.ContractManagement.Deploy(nef.ToArray(), Encoding.UTF8.GetBytes(manifest.ToJson().ToString(false)), data.ConvertToStackItem()); + var state = Native.ContractManagement.Deploy(nef.ToArray(), Encoding.UTF8.GetBytes(manifest.ToJson().ToString(false)), data); // Mock contract From bb548b2c81a37e2c6981c4a934254fbd39ab2259 Mon Sep 17 00:00:00 2001 From: Fernando Diaz Toledano Date: Mon, 12 Feb 2024 12:08:01 +0100 Subject: [PATCH 086/106] allow null on deploy and update --- src/Neo.SmartContract.Testing/Native/ContractManagement.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Neo.SmartContract.Testing/Native/ContractManagement.cs b/src/Neo.SmartContract.Testing/Native/ContractManagement.cs index e3df059c1..b348e26d1 100644 --- a/src/Neo.SmartContract.Testing/Native/ContractManagement.cs +++ b/src/Neo.SmartContract.Testing/Native/ContractManagement.cs @@ -49,7 +49,7 @@ public abstract class ContractManagement : Neo.SmartContract.Testing.SmartContra /// Unsafe method /// [DisplayName("deploy")] - public abstract ContractState Deploy(byte[] nefFile, byte[] manifest, object data); + public abstract ContractState Deploy(byte[] nefFile, byte[] manifest, object? data = null); /// /// Unsafe method /// @@ -64,7 +64,7 @@ public abstract class ContractManagement : Neo.SmartContract.Testing.SmartContra /// Unsafe method /// [DisplayName("update")] - public abstract void Update(byte[] nefFile, byte[] manifest, object data); + public abstract void Update(byte[] nefFile, byte[] manifest, object? data = null); #endregion #region Constructor for internal use only protected ContractManagement(Neo.SmartContract.Testing.SmartContractInitialize initialize) : base(initialize) { } From 23207a62c3515c925529b72285059f2a052a0c02 Mon Sep 17 00:00:00 2001 From: Fernando Diaz Toledano Date: Mon, 12 Feb 2024 12:21:59 +0100 Subject: [PATCH 087/106] Update readme --- src/Neo.SmartContract.Testing/README.md | 23 +++++++++++-------- .../NativeArtifactsTests.cs | 11 ++++++--- 2 files changed, 22 insertions(+), 12 deletions(-) diff --git a/src/Neo.SmartContract.Testing/README.md b/src/Neo.SmartContract.Testing/README.md index 91e6cad5c..de5a2a1a3 100644 --- a/src/Neo.SmartContract.Testing/README.md +++ b/src/Neo.SmartContract.Testing/README.md @@ -100,7 +100,7 @@ var neo = engine.FromHash(engine.Native.NEO.Hash, false); // Ensure that the main address contains the totalSupply Assert.AreEqual(100_000_000, neo.TotalSupply); -Assert.AreEqual(neo.TotalSupply, neo.BalanceOf(engine.BFTAddress)); +Assert.AreEqual(neo.TotalSupply, neo.BalanceOf(engine.ValidatorsAddress)); ``` ### NativeArtifacts @@ -123,7 +123,7 @@ var engine = new TestEngine(true); // Ensure that the main address contains the totalSupply Assert.AreEqual(100_000_000, engine.Native.NEO.TotalSupply); -Assert.AreEqual(engine.Native.NEO.TotalSupply, engine.Native.NEO.BalanceOf(engine.BFTAddress)); +Assert.AreEqual(engine.Native.NEO.TotalSupply, engine.Native.NEO.BalanceOf(engine.ValidatorsAddress)); ``` ### SmartContractStorage @@ -182,13 +182,13 @@ var neo = engine.FromHash(engine.Native.NEO.Hash, // Test direct call -Assert.AreEqual(123, neo.BalanceOf(engine.BFTAddress)); +Assert.AreEqual(123, neo.BalanceOf(engine.ValidatorsAddress)); // Test vm call using (ScriptBuilder script = new()) { - script.EmitDynamicCall(neo.Hash, nameof(neo.BalanceOf), engine.BFTAddress); + script.EmitDynamicCall(neo.Hash, nameof(neo.BalanceOf), engine.ValidatorsAddress); Assert.AreEqual(123, engine.Execute(script.ToArray()).GetInteger()); } @@ -244,30 +244,35 @@ Testing that our events have been triggered has never been so easy. Simply when var engine = new TestEngine(true); -// Fake signature of BFTAddress +// Fake signature of ValidatorsAddress engine.Transaction.Signers = new Network.P2P.Payloads.Signer[] { new Network.P2P.Payloads.Signer() { - Account = engine.BFTAddress, + Account = engine.ValidatorsAddress, Scopes = Network.P2P.Payloads.WitnessScope.Global } }; +// Define address to transfer funds + +UInt160 addressTo = UInt160.Parse("0x1230000000000000000000000000000000000000"); + // Attach to Transfer event var raisedEvent = false; engine.Native.NEO.OnTransfer += (UInt160 from, UInt160 to, BigInteger amount) => { + Assert.AreEqual(engine.Transaction.Sender, from); + Assert.AreEqual(addressTo, to); + Assert.AreEqual(123, amount); + // If the event is raised, the variable will be changed raisedEvent = true; }; -// Define address to transfer funds - -UInt160 addressTo = UInt160.Parse("0x1230000000000000000000000000000000000000"); Assert.AreEqual(0, engine.Native.NEO.BalanceOf(addressTo)); diff --git a/tests/Neo.SmartContract.Testing.UnitTests/NativeArtifactsTests.cs b/tests/Neo.SmartContract.Testing.UnitTests/NativeArtifactsTests.cs index b633e8bbd..7dba04d44 100644 --- a/tests/Neo.SmartContract.Testing.UnitTests/NativeArtifactsTests.cs +++ b/tests/Neo.SmartContract.Testing.UnitTests/NativeArtifactsTests.cs @@ -45,19 +45,24 @@ public void TestTransfer() } }; + // Define address to transfer funds + + UInt160 addressTo = UInt160.Parse("0x1230000000000000000000000000000000000000"); + // Attach to Transfer event var raisedEvent = false; engine.Native.NEO.OnTransfer += (UInt160 from, UInt160 to, BigInteger amount) => { + Assert.AreEqual(engine.Transaction.Sender, from); + Assert.AreEqual(addressTo, to); + Assert.AreEqual(123, amount); + // If the event is raised, the variable will be changed raisedEvent = true; }; - // Define address to transfer funds - - UInt160 addressTo = UInt160.Parse("0x1230000000000000000000000000000000000000"); Assert.AreEqual(0, engine.Native.NEO.BalanceOf(addressTo)); From ef96fda6df03c5de7c612253887f9fba097b1f11 Mon Sep 17 00:00:00 2001 From: Fernando Diaz Toledano Date: Mon, 12 Feb 2024 12:31:07 +0100 Subject: [PATCH 088/106] Fix static event --- src/Neo.SmartContract.Testing/TestEngine.cs | 23 ++++++++++++++----- .../NativeArtifactsTests.cs | 5 +--- 2 files changed, 18 insertions(+), 10 deletions(-) diff --git a/src/Neo.SmartContract.Testing/TestEngine.cs b/src/Neo.SmartContract.Testing/TestEngine.cs index 8b07702ac..745628feb 100644 --- a/src/Neo.SmartContract.Testing/TestEngine.cs +++ b/src/Neo.SmartContract.Testing/TestEngine.cs @@ -204,9 +204,6 @@ public TestEngine(ProtocolSettings settings, bool initializeNativeContracts = tr } }; - ApplicationEngine.Log += ApplicationEngine_Log; - ApplicationEngine.Notify += ApplicationEngine_Notify; - if (initializeNativeContracts) { Native.Initialize(false); @@ -427,15 +424,29 @@ public StackItem Execute(Script script) engine.LoadScript(script); - if (engine.Execute() != VMState.HALT) + // Attach to static event + + ApplicationEngine.Log += ApplicationEngine_Log; + ApplicationEngine.Notify += ApplicationEngine_Notify; + + // Execute + + var executionResult = engine.Execute(); + + // Detach to static event + + ApplicationEngine.Log -= ApplicationEngine_Log; + ApplicationEngine.Notify -= ApplicationEngine_Notify; + + // Process result + + if (executionResult != VMState.HALT) { throw engine.FaultException ?? new Exception($"Error while executing the script"); } snapshot.Commit(); - // Return - if (engine.ResultStack.Count == 0) return StackItem.Null; return engine.ResultStack.Pop(); } diff --git a/tests/Neo.SmartContract.Testing.UnitTests/NativeArtifactsTests.cs b/tests/Neo.SmartContract.Testing.UnitTests/NativeArtifactsTests.cs index 7dba04d44..22498fe62 100644 --- a/tests/Neo.SmartContract.Testing.UnitTests/NativeArtifactsTests.cs +++ b/tests/Neo.SmartContract.Testing.UnitTests/NativeArtifactsTests.cs @@ -48,11 +48,11 @@ public void TestTransfer() // Define address to transfer funds UInt160 addressTo = UInt160.Parse("0x1230000000000000000000000000000000000000"); + Assert.AreEqual(0, engine.Native.NEO.BalanceOf(addressTo)); // Attach to Transfer event var raisedEvent = false; - engine.Native.NEO.OnTransfer += (UInt160 from, UInt160 to, BigInteger amount) => { Assert.AreEqual(engine.Transaction.Sender, from); @@ -63,9 +63,6 @@ public void TestTransfer() raisedEvent = true; }; - - Assert.AreEqual(0, engine.Native.NEO.BalanceOf(addressTo)); - // Transfer funds Assert.IsTrue(engine.Native.NEO.Transfer(engine.Transaction.Sender, addressTo, 123, null)); From b4a1082a24157157ee471a692c95f58b67f25b97 Mon Sep 17 00:00:00 2001 From: Fernando Diaz Toledano Date: Mon, 12 Feb 2024 12:32:47 +0100 Subject: [PATCH 089/106] Allow native init notifications --- src/Neo.SmartContract.Testing/NativeArtifacts.cs | 12 ++++++++++++ src/Neo.SmartContract.Testing/TestEngine.cs | 12 ++++++------ 2 files changed, 18 insertions(+), 6 deletions(-) diff --git a/src/Neo.SmartContract.Testing/NativeArtifacts.cs b/src/Neo.SmartContract.Testing/NativeArtifacts.cs index a35b34791..fcf102dd0 100644 --- a/src/Neo.SmartContract.Testing/NativeArtifacts.cs +++ b/src/Neo.SmartContract.Testing/NativeArtifacts.cs @@ -152,6 +152,13 @@ public void Initialize(bool commit = false) var genesis = NeoSystem.CreateGenesisBlock(_engine.ProtocolSettings); + // Attach to static event + + ApplicationEngine.Log += _engine.ApplicationEngineLog; + ApplicationEngine.Notify += _engine.ApplicationEngineNotify; + + // Process native contracts + foreach (var native in new Native.NativeContract[] { Native.NativeContract.ContractManagement, @@ -199,6 +206,11 @@ public void Initialize(bool commit = false) { _engine.Storage.Commit(); } + + // Detach to static event + + ApplicationEngine.Log -= _engine.ApplicationEngineLog; + ApplicationEngine.Notify -= _engine.ApplicationEngineNotify; } } } diff --git a/src/Neo.SmartContract.Testing/TestEngine.cs b/src/Neo.SmartContract.Testing/TestEngine.cs index 745628feb..e2e890379 100644 --- a/src/Neo.SmartContract.Testing/TestEngine.cs +++ b/src/Neo.SmartContract.Testing/TestEngine.cs @@ -212,7 +212,7 @@ public TestEngine(ProtocolSettings settings, bool initializeNativeContracts = tr #region Invoke events - private void ApplicationEngine_Notify(object? sender, NotifyEventArgs e) + internal void ApplicationEngineNotify(object? sender, NotifyEventArgs e) { if (_contracts.TryGetValue(e.ScriptHash, out var contracts)) { @@ -223,7 +223,7 @@ private void ApplicationEngine_Notify(object? sender, NotifyEventArgs e) } } - private void ApplicationEngine_Log(object? sender, LogEventArgs e) + internal void ApplicationEngineLog(object? sender, LogEventArgs e) { if (_contracts.TryGetValue(e.ScriptHash, out var contracts)) { @@ -426,8 +426,8 @@ public StackItem Execute(Script script) // Attach to static event - ApplicationEngine.Log += ApplicationEngine_Log; - ApplicationEngine.Notify += ApplicationEngine_Notify; + ApplicationEngine.Log += ApplicationEngineLog; + ApplicationEngine.Notify += ApplicationEngineNotify; // Execute @@ -435,8 +435,8 @@ public StackItem Execute(Script script) // Detach to static event - ApplicationEngine.Log -= ApplicationEngine_Log; - ApplicationEngine.Notify -= ApplicationEngine_Notify; + ApplicationEngine.Log -= ApplicationEngineLog; + ApplicationEngine.Notify -= ApplicationEngineNotify; // Process result From 728098b17759a40c4be1ec8bbaa1e56b58281ca8 Mon Sep 17 00:00:00 2001 From: Fernando Diaz Toledano Date: Mon, 12 Feb 2024 12:58:36 +0100 Subject: [PATCH 090/106] Belane's feedback --- src/Neo.SmartContract.Testing/README.md | 30 +++++------- src/Neo.SmartContract.Testing/TestEngine.cs | 48 +++++++++++++------ .../NativeArtifactsTests.cs | 24 ++++------ 3 files changed, 56 insertions(+), 46 deletions(-) diff --git a/src/Neo.SmartContract.Testing/README.md b/src/Neo.SmartContract.Testing/README.md index de5a2a1a3..f06a86a69 100644 --- a/src/Neo.SmartContract.Testing/README.md +++ b/src/Neo.SmartContract.Testing/README.md @@ -76,15 +76,17 @@ For initialize, we have: And for read and write, we have: -- **Gas**: Sets the gas execution limit for contract calls. +- **Gas**: Sets the gas execution limit for contract calls. Sets the `NetworkFee` of the `Transaction` object. #### Methods -It has three methods: +It has four methods: - **Execute(script)**: Executes a script on the neo virtual machine and returns the execution result. - **Deploy(nef, manifest, data, customMock)**: Deploys the smart contract by calling the native method `ContractManagement.deploy`. It allows setting [custom mocks](#custom-mocks), which will be detailed later. And returns the instance of the contract that has been deployed. - **FromHash(hash, customMocks, checkExistence)**: Creates an instance without needing a `NefFile` or `Manifest`, only requiring the contract's hash. It does not consider whether the contract exists on the chain unless `checkExistence` is set to `true`. +- **SetTransactionSigners(signers)**: Set the `Signer` of the `Transaction`. +- **GetNewSigner(scope)**: A static method that provides us with a random `Signer` signed by default by `CalledByEntry`. #### Example of use @@ -211,14 +213,11 @@ Assert.AreEqual(100000000000, engine.Native.NEO.RegisterPrice); // Fake Committee Signature -engine.Transaction.Signers = new Network.P2P.Payloads.Signer[] +engine.SetTransactionSigners(new Network.P2P.Payloads.Signer() { - new Network.P2P.Payloads.Signer() - { - Account = engine.CommitteeAddress, - Scopes = Network.P2P.Payloads.WitnessScope.Global - } -}; + Account = engine.CommitteeAddress, + Scopes = Network.P2P.Payloads.WitnessScope.Global +}); // Change RegisterPrice to 123 @@ -228,7 +227,7 @@ Assert.AreEqual(123, engine.Native.NEO.RegisterPrice); // Now test it without this signature -engine.Transaction.Signers[0].Scopes = Network.P2P.Payloads.WitnessScope.None; +engine.SetTransactionSigners(TestEngine.GetNewSigner()); Assert.ThrowsException(() => engine.Native.NEO.RegisterPrice = 123); ``` @@ -246,14 +245,11 @@ var engine = new TestEngine(true); // Fake signature of ValidatorsAddress -engine.Transaction.Signers = new Network.P2P.Payloads.Signer[] +engine.SetTransactionSigners(new Network.P2P.Payloads.Signer() { - new Network.P2P.Payloads.Signer() - { - Account = engine.ValidatorsAddress, - Scopes = Network.P2P.Payloads.WitnessScope.Global - } -}; + Account = engine.ValidatorsAddress, + Scopes = Network.P2P.Payloads.WitnessScope.Global +}); // Define address to transfer funds diff --git a/src/Neo.SmartContract.Testing/TestEngine.cs b/src/Neo.SmartContract.Testing/TestEngine.cs index e2e890379..500b224ca 100644 --- a/src/Neo.SmartContract.Testing/TestEngine.cs +++ b/src/Neo.SmartContract.Testing/TestEngine.cs @@ -131,7 +131,11 @@ public UInt160 CommitteeAddress /// /// Gas /// - public long Gas { get; set; } = ApplicationEngine.TestModeGas; + public long Gas + { + get => Transaction.NetworkFee; + set { Transaction.NetworkFee = value; } + } /// /// Sender @@ -174,6 +178,7 @@ public TestEngine(ProtocolSettings settings, bool initializeNativeContracts = tr { Attributes = System.Array.Empty(), Script = System.Array.Empty(), + NetworkFee = ApplicationEngine.TestModeGas, Signers = new Signer[] { new Signer() @@ -189,19 +194,7 @@ public TestEngine(ProtocolSettings settings, bool initializeNativeContracts = tr Scopes = WitnessScope.Global } }, - Witnesses = new Witness[] - { - new Witness() - { - InvocationScript = validatorsScript, - VerificationScript = System.Array.Empty() - }, - new Witness() - { - InvocationScript = committeeScript, - VerificationScript = System.Array.Empty() - } - } + Witnesses = System.Array.Empty() // Not required }; if (initializeNativeContracts) @@ -450,5 +443,32 @@ public StackItem Execute(Script script) if (engine.ResultStack.Count == 0) return StackItem.Null; return engine.ResultStack.Pop(); } + + /// + /// Set Transaction signers + /// + /// signers + public void SetTransactionSigners(params Signer[] signers) + { + Transaction.Signers = signers; + } + + /// + /// Generate a random new signer + /// + /// Witness scope + /// Signer + public static Signer GetNewSigner(WitnessScope scope = WitnessScope.CalledByEntry) + { + var rand = new Random(); + var data = new byte[UInt160.Length]; + rand.NextBytes(data); + + return new Signer() + { + Account = new UInt160(data), + Scopes = scope, + }; + } } } diff --git a/tests/Neo.SmartContract.Testing.UnitTests/NativeArtifactsTests.cs b/tests/Neo.SmartContract.Testing.UnitTests/NativeArtifactsTests.cs index 22498fe62..4d064e0af 100644 --- a/tests/Neo.SmartContract.Testing.UnitTests/NativeArtifactsTests.cs +++ b/tests/Neo.SmartContract.Testing.UnitTests/NativeArtifactsTests.cs @@ -36,14 +36,11 @@ public void TestTransfer() // Fake signature of BFTAddress - engine.Transaction.Signers = new Network.P2P.Payloads.Signer[] + engine.SetTransactionSigners(new Network.P2P.Payloads.Signer() { - new Network.P2P.Payloads.Signer() - { - Account = engine.ValidatorsAddress, - Scopes = Network.P2P.Payloads.WitnessScope.Global - } - }; + Account = engine.ValidatorsAddress, + Scopes = Network.P2P.Payloads.WitnessScope.Global + }); // Define address to transfer funds @@ -86,14 +83,11 @@ public void TestSignature() // Fake Committee Signature - engine.Transaction.Signers = new Network.P2P.Payloads.Signer[] + engine.SetTransactionSigners(new Network.P2P.Payloads.Signer() { - new Network.P2P.Payloads.Signer() - { - Account = engine.CommitteeAddress, - Scopes = Network.P2P.Payloads.WitnessScope.Global - } - }; + Account = engine.CommitteeAddress, + Scopes = Network.P2P.Payloads.WitnessScope.Global + }); // Change RegisterPrice to 123 @@ -103,7 +97,7 @@ public void TestSignature() // Now test it without this signature - engine.Transaction.Signers[0].Scopes = Network.P2P.Payloads.WitnessScope.None; + engine.SetTransactionSigners(TestEngine.GetNewSigner()); Assert.ThrowsException(() => engine.Native.NEO.RegisterPrice = 123); } From b6f10663ea86730921f04bf12f685d402f380388 Mon Sep 17 00:00:00 2001 From: Fernando Diaz Toledano Date: Mon, 12 Feb 2024 13:13:06 +0100 Subject: [PATCH 091/106] Nullable when ends in object argument --- .../Extensions/ArtifactExtensions.cs | 36 +++++++++++++------ .../Native/GasToken.cs | 2 +- .../Native/NeoToken.cs | 4 +-- .../Native/StdLib.cs | 4 +-- .../Extensions/ArtifactExtensionsTests.cs | 4 +-- 5 files changed, 32 insertions(+), 18 deletions(-) diff --git a/src/Neo.SmartContract.Testing/Extensions/ArtifactExtensions.cs b/src/Neo.SmartContract.Testing/Extensions/ArtifactExtensions.cs index e0c5a2896..f526c7555 100644 --- a/src/Neo.SmartContract.Testing/Extensions/ArtifactExtensions.cs +++ b/src/Neo.SmartContract.Testing/Extensions/ArtifactExtensions.cs @@ -152,14 +152,14 @@ private static (ContractMethodDescriptor[] methods, (ContractMethodDescriptor ge /// Source private static string CreateSourceEventFromManifest(ContractEventDescriptor ev) { - var evName = TongleLowercase(EscapeName(ev.Name), out _); + var evName = TongleLowercase(EscapeName(ev.Name)); if (!evName.StartsWith("On")) evName = "On" + evName; StringBuilder sourceCode = new(); sourceCode.Append($" public delegate void del{ev.Name}("); - bool isFirst = true; + var isFirst = true; foreach (var arg in ev.Parameters) { if (!isFirst) sourceCode.Append(", "); @@ -186,7 +186,7 @@ private static string CreateSourceEventFromManifest(ContractEventDescriptor ev) /// Source private static string CreateSourcePropertyFromManifest(ContractMethodDescriptor getter, ContractMethodDescriptor? setter) { - var propertyName = TongleLowercase(EscapeName(getter.Name.StartsWith("get") ? getter.Name[3..] : getter.Name), out _); + var propertyName = TongleLowercase(EscapeName(getter.Name.StartsWith("get") ? getter.Name[3..] : getter.Name)); var getset = setter is not null ? $"{{ [DisplayName(\"{getter.Name}\")] get; [DisplayName(\"{setter.Name}\")] set; }}" : $"{{ [DisplayName(\"{getter.Name}\")] get; }}"; StringBuilder sourceCode = new(); @@ -202,7 +202,7 @@ private static string CreateSourcePropertyFromManifest(ContractMethodDescriptor /// Source private static string CreateSourceMethodFromManifest(ContractMethodDescriptor method) { - var methodName = TongleLowercase(EscapeName(method.Name), out var lcChanged); + var methodName = TongleLowercase(EscapeName(method.Name)); StringBuilder sourceCode = new(); @@ -215,30 +215,44 @@ private static string CreateSourceMethodFromManifest(ContractMethodDescriptor me } sourceCode.Append($" public abstract {TypeToSource(method.ReturnType)} {methodName}("); - bool isFirst = true; - foreach (var arg in method.Parameters) + var isFirst = true; + for (int x = 0; x < method.Parameters.Length; x++) { if (!isFirst) sourceCode.Append(", "); else isFirst = false; - sourceCode.Append($"{TypeToSource(arg.Type)} {EscapeName(arg.Name)}"); + var isLast = x == method.Parameters.Length - 1; + var arg = method.Parameters[x]; + + if (isLast && arg.Type == ContractParameterType.Any) + { + // it will be object X, we can add a default value + + sourceCode.Append($"{TypeToSource(arg.Type)}? {EscapeName(arg.Name)} = null"); + } + else + { + sourceCode.Append($"{TypeToSource(arg.Type)} {EscapeName(arg.Name)}"); + } } + sourceCode.AppendLine(");"); return sourceCode.ToString(); } - private static string TongleLowercase(string value, out bool lcChanged) + private static string TongleLowercase(string value) { if (value.Length == 0) { - lcChanged = false; return value; } - lcChanged = char.IsLower(value[0]); - if (lcChanged) return value[0].ToString().ToUpperInvariant() + value[1..]; + if (char.IsLower(value[0])) + { + return value[0].ToString().ToUpperInvariant() + value[1..]; + } return value; } diff --git a/src/Neo.SmartContract.Testing/Native/GasToken.cs b/src/Neo.SmartContract.Testing/Native/GasToken.cs index 47065bd30..9816da823 100644 --- a/src/Neo.SmartContract.Testing/Native/GasToken.cs +++ b/src/Neo.SmartContract.Testing/Native/GasToken.cs @@ -29,7 +29,7 @@ public abstract class GasToken : Neo.SmartContract.Testing.SmartContract /// Unsafe method /// [DisplayName("transfer")] - public abstract bool Transfer(UInt160 from, UInt160 to, BigInteger amount, object data); + public abstract bool Transfer(UInt160 from, UInt160 to, BigInteger amount, object? data = null); #endregion #region Constructor for internal use only protected GasToken(Neo.SmartContract.Testing.SmartContractInitialize initialize) : base(initialize) { } diff --git a/src/Neo.SmartContract.Testing/Native/NeoToken.cs b/src/Neo.SmartContract.Testing/Native/NeoToken.cs index 1bd480dbd..26cd6090a 100644 --- a/src/Neo.SmartContract.Testing/Native/NeoToken.cs +++ b/src/Neo.SmartContract.Testing/Native/NeoToken.cs @@ -61,7 +61,7 @@ public abstract class NeoToken : Neo.SmartContract.Testing.SmartContract /// Unsafe method /// [DisplayName("transfer")] - public abstract bool Transfer(UInt160 from, UInt160 to, BigInteger amount, object data); + public abstract bool Transfer(UInt160 from, UInt160 to, BigInteger amount, object? data = null); /// /// Unsafe method /// @@ -76,4 +76,4 @@ public abstract class NeoToken : Neo.SmartContract.Testing.SmartContract #region Constructor for internal use only protected NeoToken(Neo.SmartContract.Testing.SmartContractInitialize initialize) : base(initialize) { } #endregion -} +} \ No newline at end of file diff --git a/src/Neo.SmartContract.Testing/Native/StdLib.cs b/src/Neo.SmartContract.Testing/Native/StdLib.cs index 4c160ee98..3fabfd7ef 100644 --- a/src/Neo.SmartContract.Testing/Native/StdLib.cs +++ b/src/Neo.SmartContract.Testing/Native/StdLib.cs @@ -72,7 +72,7 @@ public abstract class StdLib : Neo.SmartContract.Testing.SmartContract /// Safe method /// [DisplayName("jsonSerialize")] - public abstract byte[] JsonSerialize(object item); + public abstract byte[] JsonSerialize(object? item = null); /// /// Safe method /// @@ -97,7 +97,7 @@ public abstract class StdLib : Neo.SmartContract.Testing.SmartContract /// Safe method /// [DisplayName("serialize")] - public abstract byte[] Serialize(object item); + public abstract byte[] Serialize(object? item = null); /// /// Safe method /// diff --git a/tests/Neo.SmartContract.Testing.UnitTests/Extensions/ArtifactExtensionsTests.cs b/tests/Neo.SmartContract.Testing.UnitTests/Extensions/ArtifactExtensionsTests.cs index 77ec0f88e..2062dfa40 100644 --- a/tests/Neo.SmartContract.Testing.UnitTests/Extensions/ArtifactExtensionsTests.cs +++ b/tests/Neo.SmartContract.Testing.UnitTests/Extensions/ArtifactExtensionsTests.cs @@ -70,12 +70,12 @@ public abstract class Contract1 : Neo.SmartContract.Testing.SmartContract /// Unsafe method /// [DisplayName(""onNEP17Payment"")] - public abstract void OnNEP17Payment(UInt160 from, BigInteger amount, object data); + public abstract void OnNEP17Payment(UInt160 from, BigInteger amount, object? data = null); /// /// Unsafe method /// [DisplayName(""transfer"")] - public abstract bool Transfer(UInt160 from, UInt160 to, BigInteger amount, object data); + public abstract bool Transfer(UInt160 from, UInt160 to, BigInteger amount, object? data = null); /// /// Unsafe method /// From 5ba45f68f15721bce5682951b527b65d1c80a273 Mon Sep 17 00:00:00 2001 From: Fernando Diaz Toledano Date: Mon, 12 Feb 2024 13:22:14 +0100 Subject: [PATCH 092/106] Speedup InvokeOnNotify --- .../SmartContract.cs | 24 ++++++++++++++----- 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/src/Neo.SmartContract.Testing/SmartContract.cs b/src/Neo.SmartContract.Testing/SmartContract.cs index 7b2b29b34..7d8e130b7 100644 --- a/src/Neo.SmartContract.Testing/SmartContract.cs +++ b/src/Neo.SmartContract.Testing/SmartContract.cs @@ -2,6 +2,7 @@ using Neo.VM; using Neo.VM.Types; using System; +using System.Collections.Generic; using System.ComponentModel; using System.Linq; using System.Reflection; @@ -11,6 +12,8 @@ namespace Neo.SmartContract.Testing public class SmartContract { internal readonly TestEngine Engine; + private readonly Type ContractType; + private readonly Dictionary NotifyCache = new(); public delegate void OnRuntimeLogDelegate(string message); public event OnRuntimeLogDelegate? OnRuntimeLog; @@ -34,6 +37,7 @@ protected SmartContract(SmartContractInitialize initialize) Engine = initialize.Engine; Hash = initialize.Hash; Storage = new SmartContractStorage(this, initialize.ContractId); + ContractType = GetType().BaseType ?? GetType(); // Mock } /// @@ -70,15 +74,23 @@ internal void InvokeOnRuntimeLog(string message) /// State internal void InvokeOnNotify(string eventName, VM.Types.Array state) { - var type = GetType().BaseType ?? GetType(); // Mock - var ev = type.GetEvent(eventName); - if (ev is null) + if (!NotifyCache.TryGetValue(eventName, out var evField)) { - ev = type.GetEvents().FirstOrDefault(u => u.GetCustomAttribute()?.DisplayName == eventName); - if (ev is null) return; + var ev = ContractType.GetEvent(eventName); + if (ev is null) + { + ev = ContractType.GetEvents().FirstOrDefault(u => u.GetCustomAttribute()?.DisplayName == eventName); + if (ev is null) + { + NotifyCache[eventName] = null; + return; + } + } + + NotifyCache[eventName] = evField = ContractType.GetField(ev.Name, BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.GetField); } - var evField = type.GetField(ev.Name, BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.GetField); + // Not found if (evField is null) return; var del = evField.GetValue(this) as Delegate; From fa74be248c2b88d37af7311be34568d7db8fa866 Mon Sep 17 00:00:00 2001 From: Fernando Diaz Toledano Date: Mon, 12 Feb 2024 13:29:26 +0100 Subject: [PATCH 093/106] Increase protected words --- .../Extensions/ArtifactExtensions.cs | 28 +++++++++++++------ .../SmartContract.cs | 20 ++++++------- 2 files changed, 28 insertions(+), 20 deletions(-) diff --git a/src/Neo.SmartContract.Testing/Extensions/ArtifactExtensions.cs b/src/Neo.SmartContract.Testing/Extensions/ArtifactExtensions.cs index f526c7555..bee62811c 100644 --- a/src/Neo.SmartContract.Testing/Extensions/ArtifactExtensions.cs +++ b/src/Neo.SmartContract.Testing/Extensions/ArtifactExtensions.cs @@ -8,6 +8,22 @@ namespace Neo.SmartContract.Testing.Extensions { public static class ArtifactExtensions { + static readonly string[] _protectedWords = new string[] { + "abstract", "as", "base", "bool", "break", "byte", + "case", "catch", "char", "checked", "class", "const", + "continue", "decimal", "default", "delegate", "do", "double", + "else", "enum", "event", "explicit", "extern", "false", + "finally", "fixed", "float", "for", "foreach", "goto", + "if", "implicit", "in", "int", "interface", "internal", + "is", "lock", "long", "namespace", "new", "null", + "object", "operator", "out", "override", "params", "private", + "protected", "public", "readonly", "ref", "return", "sbyte", + "sealed", "short", "sizeof", "stackalloc", "static", "string", + "struct", "switch", "this", "throw", "true", "try", + "typeof", "uint", "ulong", "unchecked", "unsafe", "ushort", + "using", "virtual", "void", "volatile", "while" + }; + /// /// Get source code from contract Abi /// @@ -264,16 +280,10 @@ private static string TongleLowercase(string value) /// Escaped name private static string EscapeName(string name) { - return name switch - { - "base" => "@" + name, - "lock" => "@" + name, - "params" => "@" + name, - "struct" => "@" + name, - "class" => "@" + name, + if (_protectedWords.Contains(name)) + return "@" + name; - _ => name - }; + return name; } /// diff --git a/src/Neo.SmartContract.Testing/SmartContract.cs b/src/Neo.SmartContract.Testing/SmartContract.cs index 7d8e130b7..21fb37847 100644 --- a/src/Neo.SmartContract.Testing/SmartContract.cs +++ b/src/Neo.SmartContract.Testing/SmartContract.cs @@ -12,8 +12,8 @@ namespace Neo.SmartContract.Testing public class SmartContract { internal readonly TestEngine Engine; - private readonly Type ContractType; - private readonly Dictionary NotifyCache = new(); + private readonly Type _contractType; + private readonly Dictionary _notifyCache = new(); public delegate void OnRuntimeLogDelegate(string message); public event OnRuntimeLogDelegate? OnRuntimeLog; @@ -37,7 +37,7 @@ protected SmartContract(SmartContractInitialize initialize) Engine = initialize.Engine; Hash = initialize.Hash; Storage = new SmartContractStorage(this, initialize.ContractId); - ContractType = GetType().BaseType ?? GetType(); // Mock + _contractType = GetType().BaseType ?? GetType(); // Mock } /// @@ -74,27 +74,25 @@ internal void InvokeOnRuntimeLog(string message) /// State internal void InvokeOnNotify(string eventName, VM.Types.Array state) { - if (!NotifyCache.TryGetValue(eventName, out var evField)) + if (!_notifyCache.TryGetValue(eventName, out var evField)) { - var ev = ContractType.GetEvent(eventName); + var ev = _contractType.GetEvent(eventName); if (ev is null) { - ev = ContractType.GetEvents().FirstOrDefault(u => u.GetCustomAttribute()?.DisplayName == eventName); + ev = _contractType.GetEvents().FirstOrDefault(u => u.GetCustomAttribute()?.DisplayName == eventName); if (ev is null) { - NotifyCache[eventName] = null; + _notifyCache[eventName] = null; return; } } - NotifyCache[eventName] = evField = ContractType.GetField(ev.Name, BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.GetField); + _notifyCache[eventName] = evField = _contractType.GetField(ev.Name, BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.GetField); } // Not found if (evField is null) return; - - var del = evField.GetValue(this) as Delegate; - if (del is null) return; + if (evField.GetValue(this) is not Delegate del) return; // Avoid parse if is not needed From 6908a11b8802abe04a0e67368c1e4572c5480c44 Mon Sep 17 00:00:00 2001 From: Fernando Diaz Toledano Date: Mon, 12 Feb 2024 14:15:50 +0100 Subject: [PATCH 094/106] Allow Export and Import contract storage --- .../NativeArtifacts.cs | 4 +- src/Neo.SmartContract.Testing/README.md | 2 +- .../SmartContractStorage.cs | 84 +++++++++++++++++++ src/Neo.SmartContract.Testing/TestEngine.cs | 3 +- src/Neo.SmartContract.Testing/TestStorage.cs | 69 +++++++++++---- .../TestingApplicationEngine.cs | 4 +- .../SmartContractStorageTests.cs | 31 ++++++- .../TestStorageTests.cs | 23 ++++- 8 files changed, 192 insertions(+), 28 deletions(-) diff --git a/src/Neo.SmartContract.Testing/NativeArtifacts.cs b/src/Neo.SmartContract.Testing/NativeArtifacts.cs index fcf102dd0..77875a8f1 100644 --- a/src/Neo.SmartContract.Testing/NativeArtifacts.cs +++ b/src/Neo.SmartContract.Testing/NativeArtifacts.cs @@ -173,7 +173,7 @@ public void Initialize(bool commit = false) var method = native.GetType().GetMethod("OnPersist", BindingFlags.NonPublic | BindingFlags.Instance); DataCache clonedSnapshot = _engine.Storage.Snapshot.CreateSnapshot(); - using (var engine = new TestingApplicationEngine(_engine, TriggerType.OnPersist, genesis, clonedSnapshot, genesis, _engine.ProtocolSettings, _engine.Gas)) + using (var engine = new TestingApplicationEngine(_engine, TriggerType.OnPersist, genesis, clonedSnapshot, genesis)) { engine.LoadScript(Array.Empty()); if (method!.Invoke(native, new object[] { engine }) is not ContractTask task) @@ -188,7 +188,7 @@ public void Initialize(bool commit = false) method = native.GetType().GetMethod("PostPersist", BindingFlags.NonPublic | BindingFlags.Instance); - using (var engine = new TestingApplicationEngine(_engine, TriggerType.OnPersist, genesis, clonedSnapshot, genesis, _engine.ProtocolSettings, _engine.Gas)) + using (var engine = new TestingApplicationEngine(_engine, TriggerType.OnPersist, genesis, clonedSnapshot, genesis)) { engine.LoadScript(Array.Empty()); if (method!.Invoke(native, new object[] { engine }) is not ContractTask task) diff --git a/src/Neo.SmartContract.Testing/README.md b/src/Neo.SmartContract.Testing/README.md index f06a86a69..359491e16 100644 --- a/src/Neo.SmartContract.Testing/README.md +++ b/src/Neo.SmartContract.Testing/README.md @@ -134,7 +134,7 @@ Avoids dealing with prefixes foreign to the internal behavior of the storage, fo #### Methods -Mainly exposes the methods `Contains`, `Get`, `Put`, and `Remove`, all of them responsible for reading and manipulating the contract's information. +Mainly exposes the methods `Export`, `Import`, `Contains`, `Get`, `Put`, and `Remove`, all of them responsible for reading and manipulating the contract's information. #### Example of use diff --git a/src/Neo.SmartContract.Testing/SmartContractStorage.cs b/src/Neo.SmartContract.Testing/SmartContractStorage.cs index b1dd84a76..ea1e5f599 100644 --- a/src/Neo.SmartContract.Testing/SmartContractStorage.cs +++ b/src/Neo.SmartContract.Testing/SmartContractStorage.cs @@ -1,4 +1,6 @@ +using Neo.Json; using System; +using System.Buffers.Binary; using System.Numerics; namespace Neo.SmartContract.Testing @@ -90,5 +92,87 @@ public void Remove(ReadOnlyMemory key) _smartContract.Engine.Storage.Snapshot.Delete(skey); } + + /// + /// Import data from json, expected data (in base64): + /// - "key": "value" + /// + /// Snapshot to be used + /// Json Object + public void Import(string json) + { + if (JToken.Parse(json) is not JObject jo) + { + throw new FormatException("The json is not a valid JObject"); + } + + Import(jo); + } + + /// + /// Import data from json, expected data (in base64): + /// - "key": "value" + /// + /// Snapshot to be used + /// Json Object + public void Import(JObject json) + { + var buffer = new byte[(sizeof(int))]; + BinaryPrimitives.WriteInt32LittleEndian(buffer, GetContractId()); + var keyId = Convert.ToBase64String(buffer); + + JObject prefix; + + // Find prefix + + if (json.ContainsProperty(keyId)) + { + if (json[keyId] is not JObject jo) + { + throw new FormatException("Invalid json"); + } + + prefix = jo; + } + else + { + return; + } + + // Read values + + foreach (var entry in prefix.Properties) + { + if (entry.Value is JString str) + { + // "key":"value" in base64 + + Put(Convert.FromBase64String(entry.Key), Convert.FromBase64String(str.Value)); + } + } + } + + /// + /// Export data to json + /// + public JObject Export() + { + var buffer = new byte[(sizeof(int))]; + BinaryPrimitives.WriteInt32LittleEndian(buffer, GetContractId()); + var keyId = Convert.ToBase64String(buffer); + + JObject ret = new(); + JObject prefix = new(); + ret[keyId] = prefix; + + foreach (var entry in _smartContract.Engine.Storage.Snapshot.Seek(Array.Empty(), Persistence.SeekDirection.Forward)) + { + // "key":"value" in base64 + + prefix[Convert.ToBase64String(entry.Key.Key.ToArray())] = Convert.ToBase64String(entry.Value.Value.ToArray()); + } + + return ret; + } } } diff --git a/src/Neo.SmartContract.Testing/TestEngine.cs b/src/Neo.SmartContract.Testing/TestEngine.cs index 500b224ca..6d6bf4251 100644 --- a/src/Neo.SmartContract.Testing/TestEngine.cs +++ b/src/Neo.SmartContract.Testing/TestEngine.cs @@ -412,8 +412,7 @@ public StackItem Execute(Script script) var snapshot = Storage.Snapshot.CreateSnapshot(); - using var engine = new TestingApplicationEngine(this, TriggerType.Application, - Transaction, snapshot, CurrentBlock, ProtocolSettings, Gas); + using var engine = new TestingApplicationEngine(this, TriggerType.Application, Transaction, snapshot, CurrentBlock); engine.LoadScript(script); diff --git a/src/Neo.SmartContract.Testing/TestStorage.cs b/src/Neo.SmartContract.Testing/TestStorage.cs index 9c8006d91..d5d059bf3 100644 --- a/src/Neo.SmartContract.Testing/TestStorage.cs +++ b/src/Neo.SmartContract.Testing/TestStorage.cs @@ -1,3 +1,4 @@ +using Akka.Util; using Neo.Json; using Neo.Persistence; using System; @@ -49,14 +50,32 @@ public void Rollback() } /// - /// Load data from json, expected data (in base64): + /// Import data from json, expected data (in base64): /// - "key" : "value" /// - "prefix" : { "key":"value" } /// - "123" : { "key":"value" } /// /// Snapshot to be used /// Json Object - public void LoadFromJson(JObject json) + public void Import(string json) + { + if (JToken.Parse(json) is not JObject jo) + { + throw new FormatException("The json is not a valid JObject"); + } + + Import(jo); + } + + /// + /// Import data from json, expected data (in base64): + /// - "key" : "value" + /// - "prefix" : { "key":"value" } + /// - "123" : { "key":"value" } + /// + /// Snapshot to be used + /// Json Object + public void Import(JObject json) { foreach (var entry in json.Properties) { @@ -70,19 +89,7 @@ public void LoadFromJson(JObject json) { // "prefix": { "key":"value" } in base64 - byte[] prefix; - - try - { - prefix = Convert.FromBase64String(entry.Key); - } - catch - { - // It's a number? - - prefix = new byte[sizeof(int)]; - BinaryPrimitives.WriteInt32LittleEndian(prefix, int.Parse(entry.Key)); - } + byte[] prefix = Convert.FromBase64String(entry.Key); foreach (var subEntry in obj.Properties) { @@ -97,5 +104,37 @@ public void LoadFromJson(JObject json) } } } + + /// + /// Export data to json + /// + public JObject Export() + { + var buffer = new byte[(sizeof(int))]; + JObject ret = new(); + + foreach (var entry in Snapshot.Seek(Array.Empty(), SeekDirection.Forward)) + { + // "key":"value" in base64 + + JObject prefix; + BinaryPrimitives.WriteInt32LittleEndian(buffer, entry.Key.Id); + var keyId = Convert.ToBase64String(buffer); + + if (ret.ContainsProperty(keyId)) + { + prefix = (JObject)ret[keyId]!; + } + else + { + prefix = new(); + ret[keyId] = prefix; + } + + prefix[Convert.ToBase64String(entry.Key.Key.ToArray())] = Convert.ToBase64String(entry.Value.Value.ToArray()); + } + + return ret; + } } } diff --git a/src/Neo.SmartContract.Testing/TestingApplicationEngine.cs b/src/Neo.SmartContract.Testing/TestingApplicationEngine.cs index 87043da8f..3110c7a68 100644 --- a/src/Neo.SmartContract.Testing/TestingApplicationEngine.cs +++ b/src/Neo.SmartContract.Testing/TestingApplicationEngine.cs @@ -15,8 +15,8 @@ internal class TestingApplicationEngine : ApplicationEngine /// public TestEngine Engine { get; } - public TestingApplicationEngine(TestEngine engine, TriggerType trigger, IVerifiable container, DataCache snapshot, Block persistingBlock, ProtocolSettings settings, long gas) - : base(trigger, container, snapshot, persistingBlock, settings, gas, null) + public TestingApplicationEngine(TestEngine engine, TriggerType trigger, IVerifiable container, DataCache snapshot, Block persistingBlock) + : base(trigger, container, snapshot, persistingBlock, engine.ProtocolSettings, engine.Gas, null) { Engine = engine; } diff --git a/tests/Neo.SmartContract.Testing.UnitTests/SmartContractStorageTests.cs b/tests/Neo.SmartContract.Testing.UnitTests/SmartContractStorageTests.cs index 11b9b784c..2c6204234 100644 --- a/tests/Neo.SmartContract.Testing.UnitTests/SmartContractStorageTests.cs +++ b/tests/Neo.SmartContract.Testing.UnitTests/SmartContractStorageTests.cs @@ -1,4 +1,6 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; +using System; +using System.Linq; using System.Numerics; namespace Neo.SmartContract.Testing.UnitTests @@ -6,13 +8,33 @@ namespace Neo.SmartContract.Testing.UnitTests [TestClass] public class SmartContractStorageTests { + // Defines the prefix used to store the registration price in neo + + private readonly byte[] _registerPricePrefix = new byte[] { 13 }; + [TestMethod] public void TestAlterStorage() { - // Defines the prefix used to store the registration price in neo + // Engine an contract creation + + TestEngine engine = new(true); - byte[] registerPricePrefix = new byte[] { 13 }; + // Check previous data + + Assert.AreEqual(100000000000, engine.Native.NEO.RegisterPrice); + + // Alter data + engine.Native.NEO.Storage.Put(_registerPricePrefix, BigInteger.MinusOne); + + // Check altered data + + Assert.AreEqual(BigInteger.MinusOne, engine.Native.NEO.RegisterPrice); + } + + [TestMethod] + public void TestExportImport() + { // Engine an contract creation TestEngine engine = new(true); @@ -21,9 +43,12 @@ public void TestAlterStorage() Assert.AreEqual(100000000000, engine.Native.NEO.RegisterPrice); + var storage = engine.Native.NEO.Storage.Export(); + // Alter data - engine.Native.NEO.Storage.Put(registerPricePrefix, BigInteger.MinusOne); + storage[storage.Properties.First().Key.ToString()][Convert.ToBase64String(_registerPricePrefix)] = Convert.ToBase64String(BigInteger.MinusOne.ToByteArray()); + engine.Native.NEO.Storage.Import(storage); // Check altered data diff --git a/tests/Neo.SmartContract.Testing.UnitTests/TestStorageTests.cs b/tests/Neo.SmartContract.Testing.UnitTests/TestStorageTests.cs index 369496e5a..8337c3fcb 100644 --- a/tests/Neo.SmartContract.Testing.UnitTests/TestStorageTests.cs +++ b/tests/Neo.SmartContract.Testing.UnitTests/TestStorageTests.cs @@ -11,7 +11,7 @@ namespace Neo.SmartContract.Testing.UnitTests public class TestStorageTests { [TestMethod] - public void LoadFromJsonTest() + public void LoadExportImport() { TestStorage store = new(new MemoryStore()); @@ -24,7 +24,7 @@ public void LoadFromJsonTest() var json = @"{""bXlSYXdLZXk="":""dmFsdWU=""}"; - store.LoadFromJson((JObject)JToken.Parse(json)); + store.Import((JObject)JToken.Parse(json)); store.Commit(); entries = store.Store.Seek(Array.Empty(), SeekDirection.Forward).ToArray(); @@ -37,7 +37,7 @@ public void LoadFromJsonTest() json = @"{""bXk="":{""UmF3S2V5LTI="":""dmFsdWUtMg==""}}"; - store.LoadFromJson((JObject)JToken.Parse(json)); + store.Import((JObject)JToken.Parse(json)); store.Commit(); entries = store.Store.Seek(Array.Empty(), SeekDirection.Forward).ToArray(); @@ -48,6 +48,23 @@ public void LoadFromJsonTest() Assert.AreEqual("myRawKey-2", Encoding.ASCII.GetString(entries[1].Key)); Assert.AreEqual("value-2", Encoding.ASCII.GetString(entries[1].Value)); + + // Test import + + TestStorage storeCopy = new(new MemoryStore()); + + store.Commit(); + storeCopy.Import(store.Export()); + storeCopy.Commit(); + + entries = storeCopy.Store.Seek(Array.Empty(), SeekDirection.Forward).ToArray(); + Assert.AreEqual(entries.Length, 2); + + Assert.AreEqual("myRawKey", Encoding.ASCII.GetString(entries[0].Key)); + Assert.AreEqual("value", Encoding.ASCII.GetString(entries[0].Value)); + + Assert.AreEqual("myRawKey-2", Encoding.ASCII.GetString(entries[1].Key)); + Assert.AreEqual("value-2", Encoding.ASCII.GetString(entries[1].Value)); } } } From 6512e95e4de6393819cb3f9d529f4cff396cd7aa Mon Sep 17 00:00:00 2001 From: Fernando Diaz Toledano Date: Mon, 12 Feb 2024 14:22:51 +0100 Subject: [PATCH 095/106] format --- src/Neo.SmartContract.Testing/Native/NeoToken.cs | 2 +- src/Neo.SmartContract.Testing/SmartContractStorage.cs | 2 +- src/Neo.SmartContract.Testing/TestStorage.cs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Neo.SmartContract.Testing/Native/NeoToken.cs b/src/Neo.SmartContract.Testing/Native/NeoToken.cs index 26cd6090a..1a4eff060 100644 --- a/src/Neo.SmartContract.Testing/Native/NeoToken.cs +++ b/src/Neo.SmartContract.Testing/Native/NeoToken.cs @@ -76,4 +76,4 @@ public abstract class NeoToken : Neo.SmartContract.Testing.SmartContract #region Constructor for internal use only protected NeoToken(Neo.SmartContract.Testing.SmartContractInitialize initialize) : base(initialize) { } #endregion -} \ No newline at end of file +} diff --git a/src/Neo.SmartContract.Testing/SmartContractStorage.cs b/src/Neo.SmartContract.Testing/SmartContractStorage.cs index ea1e5f599..b480c51dc 100644 --- a/src/Neo.SmartContract.Testing/SmartContractStorage.cs +++ b/src/Neo.SmartContract.Testing/SmartContractStorage.cs @@ -1,4 +1,4 @@ -using Neo.Json; +using Neo.Json; using System; using System.Buffers.Binary; using System.Numerics; diff --git a/src/Neo.SmartContract.Testing/TestStorage.cs b/src/Neo.SmartContract.Testing/TestStorage.cs index d5d059bf3..a0ccfb3aa 100644 --- a/src/Neo.SmartContract.Testing/TestStorage.cs +++ b/src/Neo.SmartContract.Testing/TestStorage.cs @@ -1,4 +1,4 @@ -using Akka.Util; +using Akka.Util; using Neo.Json; using Neo.Persistence; using System; From ab1ea20431890d5044d4866b891252379169e31e Mon Sep 17 00:00:00 2001 From: Fernando Diaz Toledano Date: Mon, 12 Feb 2024 14:26:00 +0100 Subject: [PATCH 096/106] Fix summary --- src/Neo.SmartContract.Testing/SmartContractStorage.cs | 8 ++++---- src/Neo.SmartContract.Testing/TestStorage.cs | 4 ---- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/src/Neo.SmartContract.Testing/SmartContractStorage.cs b/src/Neo.SmartContract.Testing/SmartContractStorage.cs index b480c51dc..c23248a1f 100644 --- a/src/Neo.SmartContract.Testing/SmartContractStorage.cs +++ b/src/Neo.SmartContract.Testing/SmartContractStorage.cs @@ -95,9 +95,8 @@ public void Remove(ReadOnlyMemory key) /// /// Import data from json, expected data (in base64): - /// - "key": "value" + /// - "prefix" : { "key":"value" } /// - /// Snapshot to be used /// Json Object public void Import(string json) { @@ -111,9 +110,8 @@ public void Import(string json) /// /// Import data from json, expected data (in base64): - /// - "key": "value" + /// - "prefix" : { "key":"value" } /// - /// Snapshot to be used /// Json Object public void Import(JObject json) { @@ -161,6 +159,8 @@ public JObject Export() BinaryPrimitives.WriteInt32LittleEndian(buffer, GetContractId()); var keyId = Convert.ToBase64String(buffer); + // Write prefix + JObject ret = new(); JObject prefix = new(); ret[keyId] = prefix; diff --git a/src/Neo.SmartContract.Testing/TestStorage.cs b/src/Neo.SmartContract.Testing/TestStorage.cs index a0ccfb3aa..7834f13db 100644 --- a/src/Neo.SmartContract.Testing/TestStorage.cs +++ b/src/Neo.SmartContract.Testing/TestStorage.cs @@ -53,9 +53,7 @@ public void Rollback() /// Import data from json, expected data (in base64): /// - "key" : "value" /// - "prefix" : { "key":"value" } - /// - "123" : { "key":"value" } /// - /// Snapshot to be used /// Json Object public void Import(string json) { @@ -71,9 +69,7 @@ public void Import(string json) /// Import data from json, expected data (in base64): /// - "key" : "value" /// - "prefix" : { "key":"value" } - /// - "123" : { "key":"value" } /// - /// Snapshot to be used /// Json Object public void Import(JObject json) { From 03d57563af2b605d97c89a9d0bcfc95bcadd744f Mon Sep 17 00:00:00 2001 From: Fernando Diaz Toledano Date: Mon, 12 Feb 2024 15:35:15 +0100 Subject: [PATCH 097/106] Known limitations --- src/Neo.SmartContract.Testing/README.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/Neo.SmartContract.Testing/README.md b/src/Neo.SmartContract.Testing/README.md index 359491e16..7cd03e004 100644 --- a/src/Neo.SmartContract.Testing/README.md +++ b/src/Neo.SmartContract.Testing/README.md @@ -23,6 +23,7 @@ The **Neo.SmartContract.Testing** project is designed to facilitate the developm - [Example of use](#example-of-use) - [Event testing](#event-testing) - [Example of use](#example-of-use) +- [Known limitations](#known-limitations) ### Installation and configuration @@ -281,3 +282,9 @@ Assert.IsTrue(engine.Native.NEO.Transfer(engine.Transaction.Sender, addressTo, 1 Assert.IsTrue(raisedEvent); Assert.AreEqual(123, engine.Native.NEO.BalanceOf(addressTo)); ``` + +### Known limitations + +The currently known limitations are: + +- Receive events during the deploy, because the object is returned after performing the deploy, it is not possible to intercept notifications for the deploy unless the contract is previously created with `FromHash` knowing the hash of the contract to be created. From d962fa8180b0ab7a6e1bca05566962329e7ab5f2 Mon Sep 17 00:00:00 2001 From: Fernando Diaz Toledano Date: Mon, 12 Feb 2024 15:45:29 +0100 Subject: [PATCH 098/106] Fix comments --- .../NativeArtifactsTests.cs | 2 +- .../SmartContractStorageTests.cs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/Neo.SmartContract.Testing.UnitTests/NativeArtifactsTests.cs b/tests/Neo.SmartContract.Testing.UnitTests/NativeArtifactsTests.cs index 4d064e0af..09f139f77 100644 --- a/tests/Neo.SmartContract.Testing.UnitTests/NativeArtifactsTests.cs +++ b/tests/Neo.SmartContract.Testing.UnitTests/NativeArtifactsTests.cs @@ -73,7 +73,7 @@ public void TestTransfer() [TestMethod] public void TestSignature() { - // Initialize out TestEngine + // Create and initialize TestEngine var engine = new TestEngine(true); diff --git a/tests/Neo.SmartContract.Testing.UnitTests/SmartContractStorageTests.cs b/tests/Neo.SmartContract.Testing.UnitTests/SmartContractStorageTests.cs index 2c6204234..c9dbca420 100644 --- a/tests/Neo.SmartContract.Testing.UnitTests/SmartContractStorageTests.cs +++ b/tests/Neo.SmartContract.Testing.UnitTests/SmartContractStorageTests.cs @@ -15,7 +15,7 @@ public class SmartContractStorageTests [TestMethod] public void TestAlterStorage() { - // Engine an contract creation + // Create and initialize TestEngine TestEngine engine = new(true); @@ -35,7 +35,7 @@ public void TestAlterStorage() [TestMethod] public void TestExportImport() { - // Engine an contract creation + // Create and initialize TestEngine TestEngine engine = new(true); From 8431bcaf75fc3a9a92cc79359a95bb0ed1116b47 Mon Sep 17 00:00:00 2001 From: Fernando Diaz Toledano Date: Mon, 12 Feb 2024 15:54:55 +0100 Subject: [PATCH 099/106] Fix "Value" string --- src/Neo.SmartContract.Testing/Extensions/TestExtensions.cs | 3 ++- .../NativeArtifactsTests.cs | 5 +++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/Neo.SmartContract.Testing/Extensions/TestExtensions.cs b/src/Neo.SmartContract.Testing/Extensions/TestExtensions.cs index 2dcbdfdaf..b325b2972 100644 --- a/src/Neo.SmartContract.Testing/Extensions/TestExtensions.cs +++ b/src/Neo.SmartContract.Testing/Extensions/TestExtensions.cs @@ -1,4 +1,5 @@ using Neo.IO; +using Neo.VM; using Neo.VM.Types; using System; using System.Collections.Generic; @@ -97,7 +98,7 @@ public static StackItem ConvertToStackItem(this object? data) if (stackItem is null || stackItem.IsNull) return null; if (type == typeof(bool)) return stackItem.GetBoolean(); - if (type == typeof(string)) return stackItem.ToString(); + if (type == typeof(string)) return stackItem.GetSpan().TryGetString(out var str) ? str : Convert.ToBase64String(stackItem.GetSpan()); if (type == typeof(byte[])) return stackItem.GetSpan().ToArray(); if (type == typeof(byte)) return (byte)stackItem.GetInteger(); diff --git a/tests/Neo.SmartContract.Testing.UnitTests/NativeArtifactsTests.cs b/tests/Neo.SmartContract.Testing.UnitTests/NativeArtifactsTests.cs index 09f139f77..ff543e042 100644 --- a/tests/Neo.SmartContract.Testing.UnitTests/NativeArtifactsTests.cs +++ b/tests/Neo.SmartContract.Testing.UnitTests/NativeArtifactsTests.cs @@ -21,6 +21,11 @@ public void TestInitialize() engine.Native.Initialize(false); + // Check symbols + + Assert.AreEqual("NEO", engine.Native.NEO.Symbol); + Assert.AreEqual("GAS", engine.Native.GAS.Symbol); + // Ensure that the main address contains the totalSupply Assert.AreEqual(100_000_000, engine.Native.NEO.TotalSupply); From 04cc1ef12ac1ec266c54638a7b827e173d0309e7 Mon Sep 17 00:00:00 2001 From: Vitor Nazario Coelho Date: Mon, 12 Feb 2024 12:08:15 -0300 Subject: [PATCH 100/106] devcontainer ready for testing PR --- .devcontainer/devcontainer.json | 14 ++++++++++++++ .vscode/settings.json | 3 +++ 2 files changed, 17 insertions(+) create mode 100644 .devcontainer/devcontainer.json create mode 100644 .vscode/settings.json diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json new file mode 100644 index 000000000..f9907f071 --- /dev/null +++ b/.devcontainer/devcontainer.json @@ -0,0 +1,14 @@ +// For format details, see https://aka.ms/devcontainer.json. For config options, see the +// README at: https://github.com/devcontainers/templates/tree/main/src/dotnet +{ + "name": "C# (.NET)", + "image": "mcr.microsoft.com/devcontainers/dotnet:1-7.0-jammy", + "onCreateCommand": "git submodule init && git submodule update", + "customizations": { + "vscode": { + "extensions": [ + "ms-dotnettools.csdevkit" + ] + } + } +} diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 000000000..872748a44 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "dotnet.defaultSolution": "neo-devpack-dotnet.sln" +} \ No newline at end of file From 5941f26bb57cacdb4aec236ac75e0ef140a986ea Mon Sep 17 00:00:00 2001 From: Fernando Diaz Toledano Date: Mon, 12 Feb 2024 17:13:19 +0100 Subject: [PATCH 101/106] Revert "devcontainer ready for testing PR" This reverts commit 04cc1ef12ac1ec266c54638a7b827e173d0309e7. --- .devcontainer/devcontainer.json | 14 -------------- .vscode/settings.json | 3 --- 2 files changed, 17 deletions(-) delete mode 100644 .devcontainer/devcontainer.json delete mode 100644 .vscode/settings.json diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json deleted file mode 100644 index f9907f071..000000000 --- a/.devcontainer/devcontainer.json +++ /dev/null @@ -1,14 +0,0 @@ -// For format details, see https://aka.ms/devcontainer.json. For config options, see the -// README at: https://github.com/devcontainers/templates/tree/main/src/dotnet -{ - "name": "C# (.NET)", - "image": "mcr.microsoft.com/devcontainers/dotnet:1-7.0-jammy", - "onCreateCommand": "git submodule init && git submodule update", - "customizations": { - "vscode": { - "extensions": [ - "ms-dotnettools.csdevkit" - ] - } - } -} diff --git a/.vscode/settings.json b/.vscode/settings.json deleted file mode 100644 index 872748a44..000000000 --- a/.vscode/settings.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "dotnet.defaultSolution": "neo-devpack-dotnet.sln" -} \ No newline at end of file From 44b5cdddb00fa92cc40b8a6414a7ea42a689c065 Mon Sep 17 00:00:00 2001 From: Fernando Diaz Toledano Date: Mon, 12 Feb 2024 18:41:59 +0100 Subject: [PATCH 102/106] Add more ways to set the signers easy --- src/Neo.SmartContract.Testing/TestEngine.cs | 23 +++++++++++++++++-- .../NativeArtifactsTests.cs | 22 ++++++++---------- 2 files changed, 30 insertions(+), 15 deletions(-) diff --git a/src/Neo.SmartContract.Testing/TestEngine.cs b/src/Neo.SmartContract.Testing/TestEngine.cs index 6d6bf4251..423792ac1 100644 --- a/src/Neo.SmartContract.Testing/TestEngine.cs +++ b/src/Neo.SmartContract.Testing/TestEngine.cs @@ -446,14 +446,33 @@ public StackItem Execute(Script script) /// /// Set Transaction signers /// - /// signers + /// Signers public void SetTransactionSigners(params Signer[] signers) { Transaction.Signers = signers; } /// - /// Generate a random new signer + /// Set Transaction Signers using CalledByEntry + /// + /// Signers + public void SetTransactionSigners(params UInt160[] signers) + { + Transaction.Signers = signers.Select(u => new Signer() { Account = u, Scopes = WitnessScope.CalledByEntry }).ToArray(); + } + + /// + /// Set Transaction Signers + /// + /// Scope + /// Signers + public void SetTransactionSigners(WitnessScope scope, params UInt160[] signers) + { + Transaction.Signers = signers.Select(u => new Signer() { Account = u, Scopes = scope }).ToArray(); + } + + /// + /// Generate a random new Signers with CalledByEntry scope by default /// /// Witness scope /// Signer diff --git a/tests/Neo.SmartContract.Testing.UnitTests/NativeArtifactsTests.cs b/tests/Neo.SmartContract.Testing.UnitTests/NativeArtifactsTests.cs index ff543e042..f670241d8 100644 --- a/tests/Neo.SmartContract.Testing.UnitTests/NativeArtifactsTests.cs +++ b/tests/Neo.SmartContract.Testing.UnitTests/NativeArtifactsTests.cs @@ -41,11 +41,7 @@ public void TestTransfer() // Fake signature of BFTAddress - engine.SetTransactionSigners(new Network.P2P.Payloads.Signer() - { - Account = engine.ValidatorsAddress, - Scopes = Network.P2P.Payloads.WitnessScope.Global - }); + engine.SetTransactionSigners(Network.P2P.Payloads.WitnessScope.Global, engine.ValidatorsAddress); // Define address to transfer funds @@ -56,14 +52,14 @@ public void TestTransfer() var raisedEvent = false; engine.Native.NEO.OnTransfer += (UInt160 from, UInt160 to, BigInteger amount) => - { - Assert.AreEqual(engine.Transaction.Sender, from); - Assert.AreEqual(addressTo, to); - Assert.AreEqual(123, amount); - - // If the event is raised, the variable will be changed - raisedEvent = true; - }; + { + Assert.AreEqual(engine.Transaction.Sender, from); + Assert.AreEqual(addressTo, to); + Assert.AreEqual(123, amount); + + // If the event is raised, the variable will be changed + raisedEvent = true; + }; // Transfer funds From caaa9ff2e4397bda9732a3d6a790ea3ac9122df5 Mon Sep 17 00:00:00 2001 From: Fernando Diaz Toledano Date: Mon, 12 Feb 2024 19:48:09 +0100 Subject: [PATCH 103/106] Avoid base64 strings --- src/Neo.SmartContract.Testing/Extensions/MockExtensions.cs | 4 ++-- src/Neo.SmartContract.Testing/Extensions/TestExtensions.cs | 2 +- src/Neo.SmartContract.Testing/TestEngine.cs | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Neo.SmartContract.Testing/Extensions/MockExtensions.cs b/src/Neo.SmartContract.Testing/Extensions/MockExtensions.cs index 8666937cf..857456612 100644 --- a/src/Neo.SmartContract.Testing/Extensions/MockExtensions.cs +++ b/src/Neo.SmartContract.Testing/Extensions/MockExtensions.cs @@ -50,7 +50,7 @@ private static Expression BuildIsAnyExpressions(Mock mock, string name, Ty return Expression.Lambda(callExpression, parameterExpression); } - public static void MockMethodWithReturn(this Mock mock, string name, Type[] args, Type returnType) + public static void MockFunction(this Mock mock, string name, Type[] args, Type returnType) where T : SmartContract { Expression exp = BuildIsAnyExpressions(mock, name, args); @@ -78,7 +78,7 @@ public static void MockMethodWithReturn(this Mock mock, string name, Type[ }); } - public static void MockMethod(this Mock mock, string name, Type[] args) + public static void MockAction(this Mock mock, string name, Type[] args) where T : SmartContract { Expression exp = BuildIsAnyExpressions(mock, name, args); diff --git a/src/Neo.SmartContract.Testing/Extensions/TestExtensions.cs b/src/Neo.SmartContract.Testing/Extensions/TestExtensions.cs index b325b2972..9da1c0e49 100644 --- a/src/Neo.SmartContract.Testing/Extensions/TestExtensions.cs +++ b/src/Neo.SmartContract.Testing/Extensions/TestExtensions.cs @@ -98,7 +98,7 @@ public static StackItem ConvertToStackItem(this object? data) if (stackItem is null || stackItem.IsNull) return null; if (type == typeof(bool)) return stackItem.GetBoolean(); - if (type == typeof(string)) return stackItem.GetSpan().TryGetString(out var str) ? str : Convert.ToBase64String(stackItem.GetSpan()); + if (type == typeof(string)) return Utility.StrictUTF8.GetString(stackItem.GetSpan()); if (type == typeof(byte[])) return stackItem.GetSpan().ToArray(); if (type == typeof(byte)) return (byte)stackItem.GetInteger(); diff --git a/src/Neo.SmartContract.Testing/TestEngine.cs b/src/Neo.SmartContract.Testing/TestEngine.cs index 423792ac1..801d0ab58 100644 --- a/src/Neo.SmartContract.Testing/TestEngine.cs +++ b/src/Neo.SmartContract.Testing/TestEngine.cs @@ -355,11 +355,11 @@ private T MockContract(UInt160 hash, int? contractId = null, Action>? if (method.ReturnType != typeof(void)) { - mock.MockMethodWithReturn(method.Name, args, method.ReturnType); + mock.MockFunction(method.Name, args, method.ReturnType); } else { - mock.MockMethod(method.Name, args); + mock.MockAction(method.Name, args); } } From 9228ccaf8e6bd9e1722fc2f1fc0619201ce2bcce Mon Sep 17 00:00:00 2001 From: Fernando Diaz Toledano Date: Mon, 12 Feb 2024 23:42:28 +0100 Subject: [PATCH 104/106] cschuchardt88's feedback --- .../Extensions/ArtifactExtensions.cs | 120 +++++++++-------- .../Extensions/TestExtensions.cs | 124 +++++++----------- .../NativeArtifacts.cs | 105 +++------------ 3 files changed, 134 insertions(+), 215 deletions(-) diff --git a/src/Neo.SmartContract.Testing/Extensions/ArtifactExtensions.cs b/src/Neo.SmartContract.Testing/Extensions/ArtifactExtensions.cs index bee62811c..7afb1a1dd 100644 --- a/src/Neo.SmartContract.Testing/Extensions/ArtifactExtensions.cs +++ b/src/Neo.SmartContract.Testing/Extensions/ArtifactExtensions.cs @@ -1,6 +1,7 @@ using Neo.SmartContract.Manifest; using System; using System.Collections.Generic; +using System.IO; using System.Linq; using System.Text; @@ -33,30 +34,34 @@ public static class ArtifactExtensions /// Source public static string GetArtifactsSource(this ContractAbi abi, string name, bool generateProperties = true) { - StringBuilder sourceCode = new(); - - sourceCode.AppendLine("using Neo.Cryptography.ECC;"); - sourceCode.AppendLine("using System.Collections.Generic;"); - sourceCode.AppendLine("using System.ComponentModel;"); - sourceCode.AppendLine("using System.Numerics;"); - sourceCode.AppendLine(""); - sourceCode.AppendLine("namespace Neo.SmartContract.Testing;"); - sourceCode.AppendLine(""); - sourceCode.AppendLine($"public abstract class {name} : Neo.SmartContract.Testing.SmartContract"); - sourceCode.AppendLine("{"); + var builder = new StringBuilder(); + using var sourceCode = new StringWriter(builder) + { + NewLine = "\n" + }; + + sourceCode.WriteLine("using Neo.Cryptography.ECC;"); + sourceCode.WriteLine("using System.Collections.Generic;"); + sourceCode.WriteLine("using System.ComponentModel;"); + sourceCode.WriteLine("using System.Numerics;"); + sourceCode.WriteLine(""); + sourceCode.WriteLine("namespace Neo.SmartContract.Testing;"); + sourceCode.WriteLine(""); + sourceCode.WriteLine($"public abstract class {name} : Neo.SmartContract.Testing.SmartContract"); + sourceCode.WriteLine("{"); // Crete events if (abi.Events.Any()) { - sourceCode.AppendLine(" #region Events"); + sourceCode.WriteLine(" #region Events"); foreach (var ev in abi.Events.OrderBy(u => u.Name)) { - sourceCode.Append(CreateSourceEventFromManifest(ev)); + sourceCode.Write(CreateSourceEventFromManifest(ev)); } - sourceCode.AppendLine(" #endregion"); + sourceCode.WriteLine(" #endregion"); } // Create methods @@ -69,20 +74,20 @@ public static string GetArtifactsSource(this ContractAbi abi, string name, bool if (properties.Any()) { - sourceCode.AppendLine(" #region Properties"); + sourceCode.WriteLine(" #region Properties"); foreach (var property in properties.OrderBy(u => u.getter.Name)) { - sourceCode.Append(CreateSourcePropertyFromManifest(property.getter, property.setter)); + sourceCode.Write(CreateSourcePropertyFromManifest(property.getter, property.setter)); } - sourceCode.AppendLine(" #endregion"); + sourceCode.WriteLine(" #endregion"); } } if (methods.Any(u => u.Safe)) { - sourceCode.AppendLine(" #region Safe methods"); + sourceCode.WriteLine(" #region Safe methods"); foreach (var method in methods.Where(u => u.Safe).OrderBy(u => u.Name)) { @@ -90,15 +95,15 @@ public static string GetArtifactsSource(this ContractAbi abi, string name, bool if (method.Name.StartsWith("_")) continue; - sourceCode.Append(CreateSourceMethodFromManifest(method)); + sourceCode.Write(CreateSourceMethodFromManifest(method)); } - sourceCode.AppendLine(" #endregion"); + sourceCode.WriteLine(" #endregion"); } if (methods.Any(u => !u.Safe)) { - sourceCode.AppendLine(" #region Unsafe methods"); + sourceCode.WriteLine(" #region Unsafe methods"); foreach (var method in methods.Where(u => !u.Safe).OrderBy(u => u.Name)) { @@ -106,23 +111,18 @@ public static string GetArtifactsSource(this ContractAbi abi, string name, bool if (method.Name.StartsWith("_")) continue; - sourceCode.Append(CreateSourceMethodFromManifest(method)); + sourceCode.Write(CreateSourceMethodFromManifest(method)); } - sourceCode.AppendLine(" #endregion"); + sourceCode.WriteLine(" #endregion"); } // Create constructor - sourceCode.AppendLine(" #region Constructor for internal use only"); - sourceCode.AppendLine($" protected {name}(Neo.SmartContract.Testing.SmartContractInitialize initialize) : base(initialize) {{ }}"); - sourceCode.AppendLine(" #endregion"); + sourceCode.WriteLine(" #region Constructor for internal use only"); + sourceCode.WriteLine($" protected {name}(Neo.SmartContract.Testing.SmartContractInitialize initialize) : base(initialize) {{ }}"); + sourceCode.WriteLine(" #endregion"); - sourceCode.AppendLine("}"); - - if (Environment.NewLine.Length == 2) - { - return sourceCode.ToString().Replace("\r\n", "\n").Trim(); - } + sourceCode.WriteLine("}"); return sourceCode.ToString().TrimEnd(); } @@ -171,27 +171,31 @@ private static string CreateSourceEventFromManifest(ContractEventDescriptor ev) var evName = TongleLowercase(EscapeName(ev.Name)); if (!evName.StartsWith("On")) evName = "On" + evName; - StringBuilder sourceCode = new(); + var builder = new StringBuilder(); + using var sourceCode = new StringWriter(builder) + { + NewLine = "\n" + }; - sourceCode.Append($" public delegate void del{ev.Name}("); + sourceCode.Write($" public delegate void del{ev.Name}("); var isFirst = true; foreach (var arg in ev.Parameters) { - if (!isFirst) sourceCode.Append(", "); + if (!isFirst) sourceCode.Write(", "); else isFirst = false; - sourceCode.Append($"{TypeToSource(arg.Type)} {EscapeName(arg.Name)}"); + sourceCode.Write($"{TypeToSource(arg.Type)} {EscapeName(arg.Name)}"); } - sourceCode.AppendLine(");"); + sourceCode.WriteLine(");"); if (ev.Name != evName) { - sourceCode.AppendLine($" [DisplayName(\"{ev.Name}\")]"); + sourceCode.WriteLine($" [DisplayName(\"{ev.Name}\")]"); } - sourceCode.AppendLine($" public event del{ev.Name}? {evName};"); + sourceCode.WriteLine($" public event del{ev.Name}? {evName};"); - return sourceCode.ToString(); + return builder.ToString(); } /// @@ -205,10 +209,14 @@ private static string CreateSourcePropertyFromManifest(ContractMethodDescriptor var propertyName = TongleLowercase(EscapeName(getter.Name.StartsWith("get") ? getter.Name[3..] : getter.Name)); var getset = setter is not null ? $"{{ [DisplayName(\"{getter.Name}\")] get; [DisplayName(\"{setter.Name}\")] set; }}" : $"{{ [DisplayName(\"{getter.Name}\")] get; }}"; - StringBuilder sourceCode = new(); - sourceCode.AppendLine($" public abstract {TypeToSource(getter.ReturnType)} {propertyName} {getset}"); + var builder = new StringBuilder(); + using var sourceCode = new StringWriter(builder) + { + NewLine = "\n" + }; + sourceCode.WriteLine($" public abstract {TypeToSource(getter.ReturnType)} {propertyName} {getset}"); - return sourceCode.ToString(); + return builder.ToString(); } /// @@ -220,21 +228,25 @@ private static string CreateSourceMethodFromManifest(ContractMethodDescriptor me { var methodName = TongleLowercase(EscapeName(method.Name)); - StringBuilder sourceCode = new(); + var builder = new StringBuilder(); + using var sourceCode = new StringWriter(builder) + { + NewLine = "\n" + }; - sourceCode.AppendLine($" /// "); - sourceCode.AppendLine($" /// {(method.Safe ? "Safe method" : "Unsafe method")}"); - sourceCode.AppendLine($" /// "); + sourceCode.WriteLine($" /// "); + sourceCode.WriteLine($" /// {(method.Safe ? "Safe method" : "Unsafe method")}"); + sourceCode.WriteLine($" /// "); if (method.Name != methodName) { - sourceCode.AppendLine($" [DisplayName(\"{method.Name}\")]"); + sourceCode.WriteLine($" [DisplayName(\"{method.Name}\")]"); } - sourceCode.Append($" public abstract {TypeToSource(method.ReturnType)} {methodName}("); + sourceCode.Write($" public abstract {TypeToSource(method.ReturnType)} {methodName}("); var isFirst = true; for (int x = 0; x < method.Parameters.Length; x++) { - if (!isFirst) sourceCode.Append(", "); + if (!isFirst) sourceCode.Write(", "); else isFirst = false; var isLast = x == method.Parameters.Length - 1; @@ -244,18 +256,18 @@ private static string CreateSourceMethodFromManifest(ContractMethodDescriptor me { // it will be object X, we can add a default value - sourceCode.Append($"{TypeToSource(arg.Type)}? {EscapeName(arg.Name)} = null"); + sourceCode.Write($"{TypeToSource(arg.Type)}? {EscapeName(arg.Name)} = null"); } else { - sourceCode.Append($"{TypeToSource(arg.Type)} {EscapeName(arg.Name)}"); + sourceCode.Write($"{TypeToSource(arg.Type)} {EscapeName(arg.Name)}"); } } - sourceCode.AppendLine(");"); + sourceCode.WriteLine(");"); - return sourceCode.ToString(); + return builder.ToString(); } private static string TongleLowercase(string value) diff --git a/src/Neo.SmartContract.Testing/Extensions/TestExtensions.cs b/src/Neo.SmartContract.Testing/Extensions/TestExtensions.cs index 9da1c0e49..379927630 100644 --- a/src/Neo.SmartContract.Testing/Extensions/TestExtensions.cs +++ b/src/Neo.SmartContract.Testing/Extensions/TestExtensions.cs @@ -1,8 +1,8 @@ using Neo.IO; -using Neo.VM; using Neo.VM.Types; using System; using System.Collections.Generic; +using System.Linq; using System.Numerics; using System.Reflection; @@ -17,51 +17,29 @@ public static class TestExtensions /// StackItem public static StackItem ConvertToStackItem(this object? data) { - if (data is null) return StackItem.Null; - if (data is bool b) return (VM.Types.Boolean)b; - if (data is string s) return (ByteString)s; - if (data is byte[] d) return (ByteString)d; - if (data is ReadOnlyMemory r) return (ByteString)r; - - if (data is byte by) return (Integer)by; - if (data is sbyte sby) return (Integer)sby; - if (data is short i16) return (Integer)i16; - if (data is ushort ui16) return (Integer)ui16; - if (data is int i32) return (Integer)i32; - if (data is uint ui32) return (Integer)ui32; - if (data is long i64) return (Integer)i64; - if (data is ulong ui64) return (Integer)ui64; - if (data is BigInteger bi) return (Integer)bi; - - if (data is UInt160 u160) return (ByteString)u160.ToArray(); - if (data is UInt256 u256) return (ByteString)u256.ToArray(); - if (data is Cryptography.ECC.ECPoint ec) return (ByteString)ec.ToArray(); - - if (data is object[] arr) + return data switch { - VM.Types.Array ar = new(); - - foreach (object o in arr) - { - ar.Add(o.ConvertToStackItem()); - } - - return ar; - } - - if (data is IEnumerable iarr) - { - VM.Types.Array ar = new(); - - foreach (object o in iarr) - { - ar.Add(o.ConvertToStackItem()); - } - - return ar; - } - - return StackItem.Null; + null => StackItem.Null, + bool b => (VM.Types.Boolean)b, + string s => (ByteString)s, + byte[] d => (ByteString)d, + ReadOnlyMemory r => (ByteString)r, + byte by => (Integer)by, + sbyte sby => (Integer)sby, + short i16 => (Integer)i16, + ushort ui16 => (Integer)ui16, + int i32 => (Integer)i32, + uint ui32 => (Integer)ui32, + long i64 => (Integer)i64, + ulong ui64 => (Integer)ui64, + BigInteger bi => (Integer)bi, + UInt160 u160 => (ByteString)u160.ToArray(), + UInt256 u256 => (ByteString)u256.ToArray(), + Cryptography.ECC.ECPoint ec => (ByteString)ec.ToArray(), + object[] arr => new VM.Types.Array(arr.Select(ConvertToStackItem)), + IEnumerable iarr => new VM.Types.Array(iarr.Select(ConvertToStackItem)), + _ => StackItem.Null, + }; } /// @@ -97,38 +75,34 @@ public static StackItem ConvertToStackItem(this object? data) { if (stackItem is null || stackItem.IsNull) return null; - if (type == typeof(bool)) return stackItem.GetBoolean(); - if (type == typeof(string)) return Utility.StrictUTF8.GetString(stackItem.GetSpan()); - if (type == typeof(byte[])) return stackItem.GetSpan().ToArray(); - - if (type == typeof(byte)) return (byte)stackItem.GetInteger(); - if (type == typeof(sbyte)) return (sbyte)stackItem.GetInteger(); - if (type == typeof(short)) return (short)stackItem.GetInteger(); - if (type == typeof(ushort)) return (ushort)stackItem.GetInteger(); - if (type == typeof(int)) return (int)stackItem.GetInteger(); - if (type == typeof(uint)) return (uint)stackItem.GetInteger(); - if (type == typeof(long)) return (long)stackItem.GetInteger(); - if (type == typeof(ulong)) return (ulong)stackItem.GetInteger(); - if (type == typeof(BigInteger)) return stackItem.GetInteger(); - - if (type == typeof(UInt160)) return new UInt160(stackItem.GetSpan().ToArray()); - if (type == typeof(UInt256)) return new UInt256(stackItem.GetSpan().ToArray()); - if (type == typeof(Cryptography.ECC.ECPoint)) - return Cryptography.ECC.ECPoint.FromBytes(stackItem.GetSpan().ToArray(), Cryptography.ECC.ECCurve.Secp256r1); - - if (type == typeof(List) && stackItem is CompoundType cp) + return type switch { - return new List(cp.SubItems); - } - - if (typeof(IInteroperable).IsAssignableFrom(type)) - { - var interoperable = (IInteroperable)Activator.CreateInstance(type)!; - interoperable.FromStackItem(stackItem); - return interoperable; - } + _ when type == typeof(bool) => stackItem.GetBoolean(), + _ when type == typeof(string) => Utility.StrictUTF8.GetString(stackItem.GetSpan()), + _ when type == typeof(byte[]) => stackItem.GetSpan().ToArray(), + _ when type == typeof(byte) => (byte)stackItem.GetInteger(), + _ when type == typeof(sbyte) => (sbyte)stackItem.GetInteger(), + _ when type == typeof(short) => (short)stackItem.GetInteger(), + _ when type == typeof(ushort) => (ushort)stackItem.GetInteger(), + _ when type == typeof(int) => (int)stackItem.GetInteger(), + _ when type == typeof(uint) => (uint)stackItem.GetInteger(), + _ when type == typeof(long) => (long)stackItem.GetInteger(), + _ when type == typeof(ulong) => (ulong)stackItem.GetInteger(), + _ when type == typeof(BigInteger) => stackItem.GetInteger(), + _ when type == typeof(UInt160) => new UInt160(stackItem.GetSpan().ToArray()), + _ when type == typeof(UInt256) => new UInt256(stackItem.GetSpan().ToArray()), + _ when type == typeof(Cryptography.ECC.ECPoint) => Cryptography.ECC.ECPoint.FromBytes(stackItem.GetSpan().ToArray(), Cryptography.ECC.ECCurve.Secp256r1), + _ when type == typeof(List) && stackItem is CompoundType cp => new List(cp.SubItems), // SubItems in StackItem type + _ when typeof(IInteroperable).IsAssignableFrom(type) => CreateInteroperable(stackItem, type), + _ => throw new FormatException($"Impossible to convert {stackItem} to {type}"), + }; + } - throw new FormatException($"Impossible to convert {stackItem} to {type}"); + private static IInteroperable CreateInteroperable(StackItem stackItem, Type type) + { + var interoperable = (IInteroperable)Activator.CreateInstance(type)!; + interoperable.FromStackItem(stackItem); + return interoperable; } } } diff --git a/src/Neo.SmartContract.Testing/NativeArtifacts.cs b/src/Neo.SmartContract.Testing/NativeArtifacts.cs index 77875a8f1..caa7b5f73 100644 --- a/src/Neo.SmartContract.Testing/NativeArtifacts.cs +++ b/src/Neo.SmartContract.Testing/NativeArtifacts.cs @@ -11,127 +11,50 @@ public class NativeArtifacts { private readonly TestEngine _engine; - #region Native contracts - - private ContractManagement? _contractManagement; - private CryptoLib? _cryptoLib; - private GasToken? _gas; - private NeoToken? _neo; - private LedgerContract? _ledger; - private OracleContract? _oracle; - private PolicyContract? _policy; - private RoleManagement? _roleManagement; - private StdLib? _stdLib; - - #endregion - /// /// ContractManagement /// - public ContractManagement ContractManagement - { - get - { - _contractManagement ??= _engine.FromHash(Native.NativeContract.ContractManagement.Hash, Native.NativeContract.ContractManagement.Id); - return _contractManagement; - } - } + public ContractManagement ContractManagement { get; } /// /// CryptoLib /// - public CryptoLib CryptoLib - { - get - { - _cryptoLib ??= _engine.FromHash(Native.NativeContract.CryptoLib.Hash, Native.NativeContract.CryptoLib.Id); - return _cryptoLib; - } - } + public CryptoLib CryptoLib { get; } /// /// GasToken /// - public GasToken GAS - { - get - { - _gas ??= _engine.FromHash(Native.NativeContract.GAS.Hash, Native.NativeContract.GAS.Id); - return _gas; - } - } + public GasToken GAS { get; } /// /// NeoToken /// - public NeoToken NEO - { - get - { - _neo ??= _engine.FromHash(Native.NativeContract.NEO.Hash, Native.NativeContract.NEO.Id); - return _neo; - } - } + public NeoToken NEO { get; } /// /// LedgerContract /// - public LedgerContract Ledger - { - get - { - _ledger ??= _engine.FromHash(Native.NativeContract.Ledger.Hash, Native.NativeContract.Ledger.Id); - return _ledger; - } - } + public LedgerContract Ledger { get; } /// /// OracleContract /// - public OracleContract Oracle - { - get - { - _oracle ??= _engine.FromHash(Native.NativeContract.Oracle.Hash, Native.NativeContract.Oracle.Id); - return _oracle; - } - } + public OracleContract Oracle { get; } /// /// PolicyContract /// - public PolicyContract Policy - { - get - { - _policy ??= _engine.FromHash(Native.NativeContract.Policy.Hash, Native.NativeContract.Policy.Id); - return _policy; - } - } + public PolicyContract Policy { get; } /// /// RoleManagement /// - public RoleManagement RoleManagement - { - get - { - _roleManagement ??= _engine.FromHash(Native.NativeContract.RoleManagement.Hash, Native.NativeContract.RoleManagement.Id); - return _roleManagement; - } - } + public RoleManagement RoleManagement { get; } /// /// OracleContract /// - public StdLib StdLib - { - get - { - _stdLib ??= _engine.FromHash(Native.NativeContract.StdLib.Hash, Native.NativeContract.StdLib.Id); - return _stdLib; - } - } + public StdLib StdLib { get; } /// /// Constructor @@ -140,6 +63,16 @@ public StdLib StdLib public NativeArtifacts(TestEngine engine) { _engine = engine; + + ContractManagement = _engine.FromHash(Native.NativeContract.ContractManagement.Hash, Native.NativeContract.ContractManagement.Id); + CryptoLib = _engine.FromHash(Native.NativeContract.CryptoLib.Hash, Native.NativeContract.CryptoLib.Id); + GAS = _engine.FromHash(Native.NativeContract.GAS.Hash, Native.NativeContract.GAS.Id); + NEO = _engine.FromHash(Native.NativeContract.NEO.Hash, Native.NativeContract.NEO.Id); + Ledger = _engine.FromHash(Native.NativeContract.Ledger.Hash, Native.NativeContract.Ledger.Id); + Oracle = _engine.FromHash(Native.NativeContract.Oracle.Hash, Native.NativeContract.Oracle.Id); + Policy = _engine.FromHash(Native.NativeContract.Policy.Hash, Native.NativeContract.Policy.Id); + RoleManagement = _engine.FromHash(Native.NativeContract.RoleManagement.Hash, Native.NativeContract.RoleManagement.Id); + StdLib = _engine.FromHash(Native.NativeContract.StdLib.Hash, Native.NativeContract.StdLib.Id); } /// From 7d4a8ed15df3b02dc7bb0c1ab3f55874d7fb1532 Mon Sep 17 00:00:00 2001 From: Fernando Diaz Toledano Date: Mon, 12 Feb 2024 23:53:13 +0100 Subject: [PATCH 105/106] Change to IList when Array --- .../Extensions/ArtifactExtensions.cs | 4 ++-- src/Neo.SmartContract.Testing/Native/LedgerContract.cs | 8 ++++---- src/Neo.SmartContract.Testing/Native/NeoToken.cs | 8 ++++---- src/Neo.SmartContract.Testing/Native/RoleManagement.cs | 4 ++-- src/Neo.SmartContract.Testing/Native/StdLib.cs | 4 ++-- 5 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/Neo.SmartContract.Testing/Extensions/ArtifactExtensions.cs b/src/Neo.SmartContract.Testing/Extensions/ArtifactExtensions.cs index 7afb1a1dd..e91810bac 100644 --- a/src/Neo.SmartContract.Testing/Extensions/ArtifactExtensions.cs +++ b/src/Neo.SmartContract.Testing/Extensions/ArtifactExtensions.cs @@ -315,8 +315,8 @@ private static string TypeToSource(ContractParameterType type) ContractParameterType.PublicKey => "ECPoint", ContractParameterType.ByteArray => "byte[]", ContractParameterType.Signature => "byte[]", - ContractParameterType.Array => "List", - ContractParameterType.Map => "IDictionary", + ContractParameterType.Array => "IList", + ContractParameterType.Map => "IDictionary", ContractParameterType.Void => "void", _ => "object", }; diff --git a/src/Neo.SmartContract.Testing/Native/LedgerContract.cs b/src/Neo.SmartContract.Testing/Native/LedgerContract.cs index 868d59f56..ac6c663b1 100644 --- a/src/Neo.SmartContract.Testing/Native/LedgerContract.cs +++ b/src/Neo.SmartContract.Testing/Native/LedgerContract.cs @@ -16,17 +16,17 @@ public abstract class LedgerContract : Neo.SmartContract.Testing.SmartContract /// Safe method /// [DisplayName("getBlock")] - public abstract List GetBlock(byte[] indexOrHash); + public abstract IList GetBlock(byte[] indexOrHash); /// /// Safe method /// [DisplayName("getTransaction")] - public abstract List GetTransaction(UInt256 hash); + public abstract IList GetTransaction(UInt256 hash); /// /// Safe method /// [DisplayName("getTransactionFromBlock")] - public abstract List GetTransactionFromBlock(byte[] blockIndexOrHash, BigInteger txIndex); + public abstract IList GetTransactionFromBlock(byte[] blockIndexOrHash, BigInteger txIndex); /// /// Safe method /// @@ -36,7 +36,7 @@ public abstract class LedgerContract : Neo.SmartContract.Testing.SmartContract /// Safe method /// [DisplayName("getTransactionSigners")] - public abstract List GetTransactionSigners(UInt256 hash); + public abstract IList GetTransactionSigners(UInt256 hash); /// /// Safe method /// diff --git a/src/Neo.SmartContract.Testing/Native/NeoToken.cs b/src/Neo.SmartContract.Testing/Native/NeoToken.cs index 1a4eff060..79e5599e4 100644 --- a/src/Neo.SmartContract.Testing/Native/NeoToken.cs +++ b/src/Neo.SmartContract.Testing/Native/NeoToken.cs @@ -21,10 +21,10 @@ public abstract class NeoToken : Neo.SmartContract.Testing.SmartContract #region Properties public abstract BigInteger Decimals { [DisplayName("decimals")] get; } public abstract object AllCandidates { [DisplayName("getAllCandidates")] get; } - public abstract List Candidates { [DisplayName("getCandidates")] get; } - public abstract List Committee { [DisplayName("getCommittee")] get; } + public abstract IList Candidates { [DisplayName("getCandidates")] get; } + public abstract IList Committee { [DisplayName("getCommittee")] get; } public abstract BigInteger GasPerBlock { [DisplayName("getGasPerBlock")] get; [DisplayName("setGasPerBlock")] set; } - public abstract List NextBlockValidators { [DisplayName("getNextBlockValidators")] get; } + public abstract IList NextBlockValidators { [DisplayName("getNextBlockValidators")] get; } public abstract BigInteger RegisterPrice { [DisplayName("getRegisterPrice")] get; [DisplayName("setRegisterPrice")] set; } public abstract string Symbol { [DisplayName("symbol")] get; } public abstract BigInteger TotalSupply { [DisplayName("totalSupply")] get; } @@ -39,7 +39,7 @@ public abstract class NeoToken : Neo.SmartContract.Testing.SmartContract /// Safe method /// [DisplayName("getAccountState")] - public abstract List GetAccountState(UInt160 account); + public abstract IList GetAccountState(UInt160 account); /// /// Safe method /// diff --git a/src/Neo.SmartContract.Testing/Native/RoleManagement.cs b/src/Neo.SmartContract.Testing/Native/RoleManagement.cs index d75624c80..1bb7aa07d 100644 --- a/src/Neo.SmartContract.Testing/Native/RoleManagement.cs +++ b/src/Neo.SmartContract.Testing/Native/RoleManagement.cs @@ -17,14 +17,14 @@ public abstract class RoleManagement : Neo.SmartContract.Testing.SmartContract /// Safe method /// [DisplayName("getDesignatedByRole")] - public abstract List GetDesignatedByRole(BigInteger role, BigInteger index); + public abstract IList GetDesignatedByRole(BigInteger role, BigInteger index); #endregion #region Unsafe methods /// /// Unsafe method /// [DisplayName("designateAsRole")] - public abstract void DesignateAsRole(BigInteger role, List nodes); + public abstract void DesignateAsRole(BigInteger role, IList nodes); #endregion #region Constructor for internal use only protected RoleManagement(Neo.SmartContract.Testing.SmartContractInitialize initialize) : base(initialize) { } diff --git a/src/Neo.SmartContract.Testing/Native/StdLib.cs b/src/Neo.SmartContract.Testing/Native/StdLib.cs index 3fabfd7ef..04fe6f613 100644 --- a/src/Neo.SmartContract.Testing/Native/StdLib.cs +++ b/src/Neo.SmartContract.Testing/Native/StdLib.cs @@ -102,12 +102,12 @@ public abstract class StdLib : Neo.SmartContract.Testing.SmartContract /// Safe method /// [DisplayName("stringSplit")] - public abstract List StringSplit(string str, string separator); + public abstract IList StringSplit(string str, string separator); /// /// Safe method /// [DisplayName("stringSplit")] - public abstract List StringSplit(string str, string separator, bool removeEmptyEntries); + public abstract IList StringSplit(string str, string separator, bool removeEmptyEntries); /// /// Safe method /// From b9b48e6a4ce6b7eb7090458b8462c2929a7c9755 Mon Sep 17 00:00:00 2001 From: Fernando Diaz Toledano Date: Tue, 13 Feb 2024 08:59:16 +0100 Subject: [PATCH 106/106] Clean Check initialized --- src/Neo.SmartContract.Testing/TestEngine.cs | 8 ++------ src/Neo.SmartContract.Testing/TestStorage.cs | 9 ++++++++- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/src/Neo.SmartContract.Testing/TestEngine.cs b/src/Neo.SmartContract.Testing/TestEngine.cs index 801d0ab58..37e807a2f 100644 --- a/src/Neo.SmartContract.Testing/TestEngine.cs +++ b/src/Neo.SmartContract.Testing/TestEngine.cs @@ -82,9 +82,7 @@ public UInt160 ValidatorsAddress { get { - var votersCountPrefix = new byte[] { 1 }; - - if (!Native.NEO.Storage.Contains(votersCountPrefix)) + if (!Storage.IsInitialized) { // If is not initialized, return the ProtocolSettings @@ -104,9 +102,7 @@ public UInt160 CommitteeAddress { get { - var votersCountPrefix = new byte[] { 1 }; - - if (!Native.NEO.Storage.Contains(votersCountPrefix)) + if (!Storage.IsInitialized) { // If is not initialized, return the ProtocolSettings diff --git a/src/Neo.SmartContract.Testing/TestStorage.cs b/src/Neo.SmartContract.Testing/TestStorage.cs index 7834f13db..5919c25e5 100644 --- a/src/Neo.SmartContract.Testing/TestStorage.cs +++ b/src/Neo.SmartContract.Testing/TestStorage.cs @@ -1,4 +1,3 @@ -using Akka.Util; using Neo.Json; using Neo.Persistence; using System; @@ -12,6 +11,9 @@ namespace Neo.SmartContract.Testing /// public class TestStorage { + // Key to check if native contracts are initialized, by default: Neo.votersCountPrefix + private static readonly StorageKey _initKey = new() { Id = Native.NativeContract.NEO.Id, Key = new byte[] { 1 } }; + /// /// Store /// @@ -22,6 +24,11 @@ public class TestStorage /// public SnapshotCache Snapshot { get; private set; } + /// + /// Return true if native contract are initialized + /// + public bool IsInitialized => Snapshot.Contains(_initKey); + /// /// Constructor ///