From 1e624bb3c646514f7ff38391153c1fbf4ff46701 Mon Sep 17 00:00:00 2001 From: Jim8y Date: Sat, 2 Mar 2024 20:40:42 +0800 Subject: [PATCH 1/5] allow direct assignment to UInt160 and ECPoint. --- .../TransferContract.cs | 4 +- .../MethodConvert/Expression/Expression.cs | 48 +++++++++++++++++-- .../MethodConvert/MethodConvert.cs | 2 +- src/Neo.SmartContract.Framework/ECPoint.cs | 21 ++++++-- src/Neo.SmartContract.Framework/UInt160.cs | 29 +++++++++-- .../Contract_StaticVar.cs | 17 ++++--- .../UnitTest_StaticVar.cs | 11 +++++ 7 files changed, 110 insertions(+), 22 deletions(-) diff --git a/examples/Example.SmartContract.Transfer/TransferContract.cs b/examples/Example.SmartContract.Transfer/TransferContract.cs index 237aafa93..2d72165b1 100644 --- a/examples/Example.SmartContract.Transfer/TransferContract.cs +++ b/examples/Example.SmartContract.Transfer/TransferContract.cs @@ -31,8 +31,8 @@ namespace Transfer; [ContractPermission(Permission.WildCard, Method.WildCard)] public class TransferContract : SmartContract { - [Hash160("NUuJw4C4XJFzxAvSZnFTfsNoWZytmQKXQP")] - private static readonly UInt160 Owner = default; + // [Hash160("NUuJw4C4XJFzxAvSZnFTfsNoWZytmQKXQP")] + private static readonly UInt160 Owner = "NUuJw4C4XJFzxAvSZnFTfsNoWZytmQKXQP"; /// /// Transfer method that demonstrate how to transfer NEO and GAS diff --git a/src/Neo.Compiler.CSharp/MethodConvert/Expression/Expression.cs b/src/Neo.Compiler.CSharp/MethodConvert/Expression/Expression.cs index 89ae863de..bb3e562e2 100644 --- a/src/Neo.Compiler.CSharp/MethodConvert/Expression/Expression.cs +++ b/src/Neo.Compiler.CSharp/MethodConvert/Expression/Expression.cs @@ -15,19 +15,61 @@ using Neo.SmartContract.Native; using Neo.VM; using System.Numerics; +using Neo.Cryptography.ECC; +using Neo.IO; +using Neo.Wallets; namespace Neo.Compiler; partial class MethodConvert { - private void ConvertExpression(SemanticModel model, ExpressionSyntax syntax) + private void ConvertExpression(SemanticModel model, ExpressionSyntax syntax, SyntaxNode? syntaxNode = null) { using var sequence = InsertSequencePoint(syntax); Optional constant = model.GetConstantValue(syntax); if (constant.HasValue) { - Push(constant.Value); + var value = constant.Value; + + ITypeSymbol? typeSymbol = null; + if (syntaxNode is VariableDeclaratorSyntax variableDeclarator) + { + var declaration = variableDeclarator.Parent as VariableDeclarationSyntax; + if (declaration != null) + { + typeSymbol = ModelExtensions.GetTypeInfo(model, declaration.Type).Type; + } + } + else if (syntaxNode is PropertyDeclarationSyntax propertyDeclaration) + { + typeSymbol = ModelExtensions.GetTypeInfo(model, propertyDeclaration.Type).Type; + } + + if (typeSymbol != null) + { + string fullName = typeSymbol.ToDisplayString(); + + switch (fullName) + { + case "Neo.SmartContract.Framework.UInt160": + var strValue = (string)value; + value = (UInt160.TryParse(strValue, out var hash) + ? hash + : strValue.ToScriptHash(_context.Options.AddressVersion)).ToArray(); + break; + case "Neo.SmartContract.Framework.ECPoint": + strValue = (string)value; + value = ECPoint.Parse(strValue, ECCurve.Secp256r1).EncodePoint(true); + break; + case "Neo.SmartContract.Framework.ByteArray": + strValue = (string)value; + value = strValue.HexToBytes(true); + break; + } + } + + Push(value); return; } @@ -165,7 +207,7 @@ private void EnsureIntegerInRange(ITypeSymbol type) private void ConvertObjectToString(SemanticModel model, ExpressionSyntax expression) { - ITypeSymbol? type = model.GetTypeInfo(expression).Type; + ITypeSymbol? type = ModelExtensions.GetTypeInfo(model, expression).Type; switch (type?.ToString()) { case "sbyte": diff --git a/src/Neo.Compiler.CSharp/MethodConvert/MethodConvert.cs b/src/Neo.Compiler.CSharp/MethodConvert/MethodConvert.cs index ae1fea81b..20ff4c58f 100644 --- a/src/Neo.Compiler.CSharp/MethodConvert/MethodConvert.cs +++ b/src/Neo.Compiler.CSharp/MethodConvert/MethodConvert.cs @@ -279,7 +279,7 @@ private void ProcessFieldInitializer(SemanticModel model, IFieldSymbol field, Ac using (InsertSequencePoint(syntaxNode)) { preInitialize?.Invoke(); - ConvertExpression(model, initializer.Value); + ConvertExpression(model, initializer.Value, syntaxNode); postInitialize?.Invoke(); } } diff --git a/src/Neo.SmartContract.Framework/ECPoint.cs b/src/Neo.SmartContract.Framework/ECPoint.cs index d622498ff..2687e32d2 100644 --- a/src/Neo.SmartContract.Framework/ECPoint.cs +++ b/src/Neo.SmartContract.Framework/ECPoint.cs @@ -1,13 +1,14 @@ // Copyright (C) 2015-2023 The Neo Project. -// -// The Neo.SmartContract.Framework 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 +// +// The Neo.SmartContract.Framework 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 System; using Neo.SmartContract.Framework.Attributes; namespace Neo.SmartContract.Framework @@ -39,5 +40,15 @@ public extern bool IsValid [OpCode(OpCode.CONVERT, StackItemType.Buffer)] public static extern explicit operator byte[](ECPoint value); + + /// + /// Implicitly converts a hexadecimal string to a PublicKey object. + /// Assumes the string is a valid hexadecimal representation. + /// + public static implicit operator ECPoint(string value) + { + return value; + } + } } diff --git a/src/Neo.SmartContract.Framework/UInt160.cs b/src/Neo.SmartContract.Framework/UInt160.cs index c62ff090f..01096b704 100644 --- a/src/Neo.SmartContract.Framework/UInt160.cs +++ b/src/Neo.SmartContract.Framework/UInt160.cs @@ -1,13 +1,14 @@ // Copyright (C) 2015-2023 The Neo Project. -// -// The Neo.SmartContract.Framework 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 +// +// The Neo.SmartContract.Framework 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 System; using Neo.SmartContract.Framework.Attributes; using Neo.SmartContract.Framework.Native; using Neo.SmartContract.Framework.Services; @@ -71,5 +72,23 @@ public string ToAddress(byte version) data = Helper.Concat(data, this); return StdLib.Base58CheckEncode((ByteString)data); } + + + /// + /// Implicitly converts a hexadecimal string to a UInt160 object. + /// Assumes the string is a valid hexadecimal representation. + /// + public static implicit operator UInt160(string value) + { + // Convert the hexadecimal string to a byte array. + // Ensure the byte array is of the expected size for a UInt160. + if (value.Length != 20) // UInt160 is expected to be 20 bytes. + { + throw new Exception("The provided string does not represent a valid UInt160 value."); + } + // Use the explicit byte[] to UInt160 conversion defined earlier. + return value; + } + } } diff --git a/tests/Neo.Compiler.CSharp.TestContracts/Contract_StaticVar.cs b/tests/Neo.Compiler.CSharp.TestContracts/Contract_StaticVar.cs index ddc90e724..7d8b0dc62 100644 --- a/tests/Neo.Compiler.CSharp.TestContracts/Contract_StaticVar.cs +++ b/tests/Neo.Compiler.CSharp.TestContracts/Contract_StaticVar.cs @@ -23,21 +23,21 @@ public class Contract_StaticVar : SmartContract.Framework.SmartContract /// A static field of type ECPoint initialized with the InitialValue attribute. This is used to demonstrate initializing /// complex types like ECPoint at compile time to avoid runtime overhead. /// - [PublicKey("024700db2e90d9f02c4f9fc862abaca92725f95b4fddcc8d7ffa538693ecf463a9")] - private static readonly ECPoint eCPoint = default; + // [PublicKey("024700db2e90d9f02c4f9fc862abaca92725f95b4fddcc8d7ffa538693ecf463a9")] + private static readonly ECPoint eCPoint = "024700db2e90d9f02c4f9fc862abaca92725f95b4fddcc8d7ffa538693ecf463a9"; /// /// A static field of type UInt160 initialized with the InitialValue attribute. This allows for compile-time /// initialization of blockchain-specific types like addresses, represented here as Hash160. /// - [Hash160("NXV7ZhHiyM1aHXwpVsRZC6BwNFP2jghXAq")] - private static readonly UInt160 uInt160 = default; + // [Hash160("NXV7ZhHiyM1aHXwpVsRZC6BwNFP2jghXAq")] + private static readonly UInt160 uInt160 = "NXV7ZhHiyM1aHXwpVsRZC6BwNFP2jghXAq"; /// /// A static string field initialized with the InitialValue attribute. This demonstrates initializing contract fields that cannot be directly assigned with their value at compile time. /// - [String("hello world")] - public static readonly string a4 = default; + // [String("hello world")] + public static readonly string a4 = "hello world"; /// /// Tests retrieval of the static field initialized with an initial value. @@ -81,5 +81,10 @@ public static ECPoint testGetECPoint() { return eCPoint; } + + public static string testGetString() + { + return a4; + } } } diff --git a/tests/Neo.Compiler.CSharp.UnitTests/UnitTest_StaticVar.cs b/tests/Neo.Compiler.CSharp.UnitTests/UnitTest_StaticVar.cs index e8fe8c405..0fdf92a11 100644 --- a/tests/Neo.Compiler.CSharp.UnitTests/UnitTest_StaticVar.cs +++ b/tests/Neo.Compiler.CSharp.UnitTests/UnitTest_StaticVar.cs @@ -124,5 +124,16 @@ public void Test_GetECPoint() Assert.AreEqual(value.ToArray().ToHexString(), "024700db2e90d9f02c4f9fc862abaca92725f95b4fddcc8d7ffa538693ecf463a9"); } + + [TestMethod] + public void Test_GetString() + { + using var testengine = new TestEngine(snapshot: new TestDataCache()); + testengine.AddEntryScript(Utils.Extensions.TestContractRoot + "Contract_StaticVar.cs"); + var result = testengine.ExecuteTestCaseStandard("testGetString"); + var value = result.Pop().GetString(); + + Assert.AreEqual(value, "hello world"); + } } } From 0c2e2e9864f8de0495d8fedd3492af291d1c553b Mon Sep 17 00:00:00 2001 From: Shargon Date: Sat, 2 Mar 2024 14:39:00 -0800 Subject: [PATCH 2/5] Apply suggestions from code review --- src/Neo.SmartContract.Framework/ECPoint.cs | 1 - src/Neo.SmartContract.Framework/UInt160.cs | 2 -- 2 files changed, 3 deletions(-) diff --git a/src/Neo.SmartContract.Framework/ECPoint.cs b/src/Neo.SmartContract.Framework/ECPoint.cs index 2687e32d2..66b0ae541 100644 --- a/src/Neo.SmartContract.Framework/ECPoint.cs +++ b/src/Neo.SmartContract.Framework/ECPoint.cs @@ -49,6 +49,5 @@ public static implicit operator ECPoint(string value) { return value; } - } } diff --git a/src/Neo.SmartContract.Framework/UInt160.cs b/src/Neo.SmartContract.Framework/UInt160.cs index 01096b704..914416c71 100644 --- a/src/Neo.SmartContract.Framework/UInt160.cs +++ b/src/Neo.SmartContract.Framework/UInt160.cs @@ -73,7 +73,6 @@ public string ToAddress(byte version) return StdLib.Base58CheckEncode((ByteString)data); } - /// /// Implicitly converts a hexadecimal string to a UInt160 object. /// Assumes the string is a valid hexadecimal representation. @@ -89,6 +88,5 @@ public static implicit operator UInt160(string value) // Use the explicit byte[] to UInt160 conversion defined earlier. return value; } - } } From ee9f0e24f98b6370c2e01f6d27a83fc456a0b3a7 Mon Sep 17 00:00:00 2001 From: Jim8y Date: Sun, 3 Mar 2024 10:34:27 +0800 Subject: [PATCH 3/5] add UInt 256 and add unit tests and fix comments. --- .../MethodConvert/Expression/Expression.cs | 6 ++ src/Neo.SmartContract.Framework/ECPoint.cs | 5 +- src/Neo.SmartContract.Framework/UInt160.cs | 18 ++---- src/Neo.SmartContract.Framework/UInt256.cs | 20 +++++-- .../Contract_DirectInit.cs | 59 +++++++++++++++++++ .../Contract_StaticVarInit.cs | 2 +- .../Contract_TryCatch.cs | 4 +- .../UnitTest_DirectInit.cs | 55 +++++++++++++++++ 8 files changed, 145 insertions(+), 24 deletions(-) create mode 100644 tests/Neo.Compiler.CSharp.TestContracts/Contract_DirectInit.cs create mode 100644 tests/Neo.Compiler.CSharp.UnitTests/UnitTest_DirectInit.cs diff --git a/src/Neo.Compiler.CSharp/MethodConvert/Expression/Expression.cs b/src/Neo.Compiler.CSharp/MethodConvert/Expression/Expression.cs index bb3e562e2..b317ddf7c 100644 --- a/src/Neo.Compiler.CSharp/MethodConvert/Expression/Expression.cs +++ b/src/Neo.Compiler.CSharp/MethodConvert/Expression/Expression.cs @@ -58,6 +58,12 @@ private void ConvertExpression(SemanticModel model, ExpressionSyntax syntax, Syn ? hash : strValue.ToScriptHash(_context.Options.AddressVersion)).ToArray(); break; + case "Neo.SmartContract.Framework.UInt256": + strValue = (string)value; + value = strValue.HexToBytes(true); + if (((byte[])value).Length != 32) + throw new CompilationException(syntax, DiagnosticId.InvalidInitialValue, "Invalid UInt256 literal"); + break; case "Neo.SmartContract.Framework.ECPoint": strValue = (string)value; value = ECPoint.Parse(strValue, ECCurve.Secp256r1).EncodePoint(true); diff --git a/src/Neo.SmartContract.Framework/ECPoint.cs b/src/Neo.SmartContract.Framework/ECPoint.cs index 66b0ae541..79ec8dd60 100644 --- a/src/Neo.SmartContract.Framework/ECPoint.cs +++ b/src/Neo.SmartContract.Framework/ECPoint.cs @@ -45,9 +45,6 @@ public extern bool IsValid /// Implicitly converts a hexadecimal string to a PublicKey object. /// Assumes the string is a valid hexadecimal representation. /// - public static implicit operator ECPoint(string value) - { - return value; - } + public static extern implicit operator ECPoint(string value); } } diff --git a/src/Neo.SmartContract.Framework/UInt160.cs b/src/Neo.SmartContract.Framework/UInt160.cs index 914416c71..75dfee709 100644 --- a/src/Neo.SmartContract.Framework/UInt160.cs +++ b/src/Neo.SmartContract.Framework/UInt160.cs @@ -75,18 +75,12 @@ public string ToAddress(byte version) /// /// Implicitly converts a hexadecimal string to a UInt160 object. - /// Assumes the string is a valid hexadecimal representation. + /// This can be a 20 bytes hex string or a neo address. + /// + /// 20 bytes hex string: "01ff00ff00ff00ff00ff00ff00ff00ff00ff00a4" (no prefix) + /// Address: "NZNosnRn6FpRjwGKx8VdXv5Sn7BvzrjZVb" + /// /// - public static implicit operator UInt160(string value) - { - // Convert the hexadecimal string to a byte array. - // Ensure the byte array is of the expected size for a UInt160. - if (value.Length != 20) // UInt160 is expected to be 20 bytes. - { - throw new Exception("The provided string does not represent a valid UInt160 value."); - } - // Use the explicit byte[] to UInt160 conversion defined earlier. - return value; - } + public static extern implicit operator UInt160(string value); } } diff --git a/src/Neo.SmartContract.Framework/UInt256.cs b/src/Neo.SmartContract.Framework/UInt256.cs index db61ade04..cbc2f55e7 100644 --- a/src/Neo.SmartContract.Framework/UInt256.cs +++ b/src/Neo.SmartContract.Framework/UInt256.cs @@ -1,10 +1,10 @@ // Copyright (C) 2015-2023 The Neo Project. -// -// The Neo.SmartContract.Framework 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 +// +// The Neo.SmartContract.Framework 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. @@ -48,5 +48,15 @@ public extern bool IsValid [OpCode(OpCode.CONVERT, StackItemType.Buffer)] public static extern explicit operator byte[](UInt256 value); + + /// + /// Implicitly converts a hexadecimal string to a UInt256 object. + /// Assumes the string is a valid hexadecimal representation. + /// + /// 32 bytes (64 characters) hexadecimal string: "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f" (no prefix) + /// + /// The input `MUST` be a valid hex string of a 32 bytes data. + /// + public static extern implicit operator UInt256(string value); } } diff --git a/tests/Neo.Compiler.CSharp.TestContracts/Contract_DirectInit.cs b/tests/Neo.Compiler.CSharp.TestContracts/Contract_DirectInit.cs new file mode 100644 index 000000000..b372d76c6 --- /dev/null +++ b/tests/Neo.Compiler.CSharp.TestContracts/Contract_DirectInit.cs @@ -0,0 +1,59 @@ +using Neo.SmartContract.Framework; +using Neo.SmartContract.Framework.Attributes; +using System.Numerics; + +namespace Neo.Compiler.CSharp.UnitTests.TestClasses +{ + + public class Contract_DirectInit : SmartContract.Framework.SmartContract + { + + /// + /// A static field of type ECPoint initialized directly from a string. This is used to demonstrate initializing + /// complex types like ECPoint at compile time to avoid runtime overhead. + /// + // [PublicKey("024700db2e90d9f02c4f9fc862abaca92725f95b4fddcc8d7ffa538693ecf463a9")] + private static readonly ECPoint eCPoint = "024700db2e90d9f02c4f9fc862abaca92725f95b4fddcc8d7ffa538693ecf463a9"; + + /// + /// A static field of type UInt160 initialized directly from a string. This allows for compile-time + /// initialization of blockchain-specific types like addresses, represented here as Hash160. + /// + // [Hash160("NXV7ZhHiyM1aHXwpVsRZC6BwNFP2jghXAq")] + private static readonly UInt160 uInt160 = "NXV7ZhHiyM1aHXwpVsRZC6BwNFP2jghXAq"; + + /// + /// A static field of type UInt160 initialized directly from a hex string. This allows for compile-time + /// initialization of blockchain-specific types like addresses, represented here as Hash256. + /// + // [ByteArray("edcf8679104ec2911a4fe29ad7db232a493e5b990fb1da7af0c7b989948c8925")] + private static readonly UInt256 validUInt256 = "edcf8679104ec2911a4fe29ad7db232a493e5b990fb1da7af0c7b989948c8925"; + + /// + /// A static string field initialized directly. + /// This demonstrates initializing contract fields that cannot be directly assigned with their value at compile time. + /// + // [String("hello world")] + public static readonly string a4 = "hello world"; + + public static UInt160 testGetUInt160() + { + return uInt160; + } + + public static ECPoint testGetECPoint() + { + return eCPoint; + } + + public static UInt256 testGetUInt256() + { + return validUInt256; + } + + public static string testGetString() + { + return a4; + } + } +} diff --git a/tests/Neo.Compiler.CSharp.TestContracts/Contract_StaticVarInit.cs b/tests/Neo.Compiler.CSharp.TestContracts/Contract_StaticVarInit.cs index e94c79044..606dc6721 100644 --- a/tests/Neo.Compiler.CSharp.TestContracts/Contract_StaticVarInit.cs +++ b/tests/Neo.Compiler.CSharp.TestContracts/Contract_StaticVarInit.cs @@ -4,7 +4,7 @@ namespace Neo.Compiler.CSharp.UnitTests.TestClasses { public class Contract_staticvar : SmartContract.Framework.SmartContract { - //define and staticvar and initit with a runtime code. + //define and static var and init it with a runtime code. static byte[] callscript = (byte[])Runtime.EntryScriptHash; public static object StaticInit() diff --git a/tests/Neo.Compiler.CSharp.TestContracts/Contract_TryCatch.cs b/tests/Neo.Compiler.CSharp.TestContracts/Contract_TryCatch.cs index 681b735d2..e3663bb4c 100644 --- a/tests/Neo.Compiler.CSharp.TestContracts/Contract_TryCatch.cs +++ b/tests/Neo.Compiler.CSharp.TestContracts/Contract_TryCatch.cs @@ -11,8 +11,8 @@ public class Contract_TryCatch : SmartContract.Framework.SmartContract private static readonly ByteString byteString2Ecpoint = default; [Hash160("NXV7ZhHiyM1aHXwpVsRZC6BwNFP2jghXAq")] private static readonly ByteString validUInt160 = default; - [ByteArray("edcf8679104ec2911a4fe29ad7db232a493e5b990fb1da7af0c7b989948c8925")] - private static readonly byte[] validUInt256 = default; + // [ByteArray("edcf8679104ec2911a4fe29ad7db232a493e5b990fb1da7af0c7b989948c8925")] + private static readonly UInt256 validUInt256 = "edcf8679104ec2911a4fe29ad7db232a493e5b990fb1da7af0c7b989948c8925"; public static object try01() { int v = 0; diff --git a/tests/Neo.Compiler.CSharp.UnitTests/UnitTest_DirectInit.cs b/tests/Neo.Compiler.CSharp.UnitTests/UnitTest_DirectInit.cs new file mode 100644 index 000000000..75ae8cf96 --- /dev/null +++ b/tests/Neo.Compiler.CSharp.UnitTests/UnitTest_DirectInit.cs @@ -0,0 +1,55 @@ +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Neo.VM.Types; +using System; +using Neo.SmartContract.TestEngine; + +namespace Neo.Compiler.CSharp.UnitTests +{ + [TestClass] + public class UnitTest_DirectInit + { + + [TestMethod] + public void Test_GetUInt160() + { + using var testengine = new TestEngine(snapshot: new TestDataCache()); + testengine.AddEntryScript(Utils.Extensions.TestContractRoot + "Contract_DirectInit.cs"); + var result = testengine.ExecuteTestCaseStandard("testGetUInt160"); + var value = result.Pop().GetSpan(); + + Assert.AreEqual(value.ToArray().ToHexString(), "7eee1aabeb67ed1d791d44e4f5fcf3ae9171a871"); + } + + [TestMethod] + public void Test_GetECPoint() + { + using var testengine = new TestEngine(snapshot: new TestDataCache()); + testengine.AddEntryScript(Utils.Extensions.TestContractRoot + "Contract_DirectInit.cs"); + var result = testengine.ExecuteTestCaseStandard("testGetECPoint"); + var value = result.Pop().GetSpan(); + Assert.AreEqual(value.ToHexString(), "024700db2e90d9f02c4f9fc862abaca92725f95b4fddcc8d7ffa538693ecf463a9"); + } + + [TestMethod] + public void Test_GetUInt256() + { + using var testengine = new TestEngine(snapshot: new TestDataCache()); + testengine.AddEntryScript(Utils.Extensions.TestContractRoot + "Contract_DirectInit.cs"); + var result = testengine.ExecuteTestCaseStandard("testGetUInt256"); + var value = result.Pop().GetSpan(); + + Assert.AreEqual(value.ToArray().ToHexString(), "edcf8679104ec2911a4fe29ad7db232a493e5b990fb1da7af0c7b989948c8925"); + } + + [TestMethod] + public void Test_GetString() + { + using var testengine = new TestEngine(snapshot: new TestDataCache()); + testengine.AddEntryScript(Utils.Extensions.TestContractRoot + "Contract_DirectInit.cs"); + var result = testengine.ExecuteTestCaseStandard("testGetString"); + var value = result.Pop().GetString(); + + Assert.AreEqual(value, "hello world"); + } + } +} From 9783dbf4d67ea821b5a1ba8ae4276094c51a955d Mon Sep 17 00:00:00 2001 From: Jim8y Date: Sun, 3 Mar 2024 10:42:22 +0800 Subject: [PATCH 4/5] example to ECPoint --- src/Neo.SmartContract.Framework/ECPoint.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/Neo.SmartContract.Framework/ECPoint.cs b/src/Neo.SmartContract.Framework/ECPoint.cs index 79ec8dd60..4f5724cae 100644 --- a/src/Neo.SmartContract.Framework/ECPoint.cs +++ b/src/Neo.SmartContract.Framework/ECPoint.cs @@ -45,6 +45,10 @@ public extern bool IsValid /// Implicitly converts a hexadecimal string to a PublicKey object. /// Assumes the string is a valid hexadecimal representation. /// + /// + /// PublicKey from a 33 bytes (66 characters) hexadecimal string: + /// "024700db2e90d9f02c4f9fc862abaca92725f95b4fddcc8d7ffa538693ecf463a9" + /// public static extern implicit operator ECPoint(string value); } } From a4071e87e229fb02c986777bade67675048a0bd7 Mon Sep 17 00:00:00 2001 From: Jim8y Date: Sun, 3 Mar 2024 10:58:43 +0800 Subject: [PATCH 5/5] more specific comments --- src/Neo.SmartContract.Framework/ECPoint.cs | 4 ++++ src/Neo.SmartContract.Framework/UInt160.cs | 4 ++++ src/Neo.SmartContract.Framework/UInt256.cs | 4 ++++ 3 files changed, 12 insertions(+) diff --git a/src/Neo.SmartContract.Framework/ECPoint.cs b/src/Neo.SmartContract.Framework/ECPoint.cs index 4f5724cae..b71004d5f 100644 --- a/src/Neo.SmartContract.Framework/ECPoint.cs +++ b/src/Neo.SmartContract.Framework/ECPoint.cs @@ -49,6 +49,10 @@ public extern bool IsValid /// PublicKey from a 33 bytes (66 characters) hexadecimal string: /// "024700db2e90d9f02c4f9fc862abaca92725f95b4fddcc8d7ffa538693ecf463a9" /// + /// + /// This is a compile time conversion, only work with constant string. + /// If you want to convert a runtime string, convert it to byte[] first. + /// public static extern implicit operator ECPoint(string value); } } diff --git a/src/Neo.SmartContract.Framework/UInt160.cs b/src/Neo.SmartContract.Framework/UInt160.cs index 75dfee709..69b26a2f3 100644 --- a/src/Neo.SmartContract.Framework/UInt160.cs +++ b/src/Neo.SmartContract.Framework/UInt160.cs @@ -80,6 +80,10 @@ public string ToAddress(byte version) /// 20 bytes hex string: "01ff00ff00ff00ff00ff00ff00ff00ff00ff00a4" (no prefix) /// Address: "NZNosnRn6FpRjwGKx8VdXv5Sn7BvzrjZVb" /// + /// + /// This is a compile time conversion, only work with constant string. + /// If you want to convert a runtime string, convert it to byte[] first. + /// /// public static extern implicit operator UInt160(string value); } diff --git a/src/Neo.SmartContract.Framework/UInt256.cs b/src/Neo.SmartContract.Framework/UInt256.cs index cbc2f55e7..a1762ec3b 100644 --- a/src/Neo.SmartContract.Framework/UInt256.cs +++ b/src/Neo.SmartContract.Framework/UInt256.cs @@ -56,6 +56,10 @@ public extern bool IsValid /// 32 bytes (64 characters) hexadecimal string: "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f" (no prefix) /// /// The input `MUST` be a valid hex string of a 32 bytes data. + /// + /// This is a compile time conversion, only work with constant string. + /// If you want to convert a runtime string, convert it to byte[] first. + /// /// public static extern implicit operator UInt256(string value); }