From e9cf99b9de13f4d13078874a954d00776ae4ea55 Mon Sep 17 00:00:00 2001 From: Jin Qiao Date: Tue, 21 Jan 2020 17:23:18 +0800 Subject: [PATCH 01/16] Enable converting between public keys, script hashes and address --- .../SmartContract/InteropService.Encode.cs | 52 +++++++++++++++++++ 1 file changed, 52 insertions(+) create mode 100644 src/neo/SmartContract/InteropService.Encode.cs diff --git a/src/neo/SmartContract/InteropService.Encode.cs b/src/neo/SmartContract/InteropService.Encode.cs new file mode 100644 index 0000000000..484b6a4f44 --- /dev/null +++ b/src/neo/SmartContract/InteropService.Encode.cs @@ -0,0 +1,52 @@ +using Neo.Cryptography; +using Neo.IO; +using Neo.VM; +using Neo.Wallets; +using System; +using System.Linq; + +namespace Neo.SmartContract +{ + partial class InteropService + { + public static class Encode + { + public static readonly InteropDescriptor PubKey2Address = Register("Neo.Crypto.PubKey2Address", Crypto_PubKey2Address, 0_01000000, TriggerType.All, CallFlags.None); + public static readonly InteropDescriptor PubKey2ScriptHash = Register("Neo.Crypto.PubKey2ScriptHash", Crypto_PubKey2ScriptHash, 0_01000000, TriggerType.All, CallFlags.None); + public static readonly InteropDescriptor Address2ScriptHash = Register("Neo.Crypto.Address2ScriptHash", Crypto_Address2ScriptHash, 0_01000000, TriggerType.All, CallFlags.None); + public static readonly InteropDescriptor ScriptHash2Address = Register("Neo.Crypto.ScriptHash2Address", Crypto_ScriptHash2Address, 0_01000000, TriggerType.All, CallFlags.None); + + private static bool Crypto_PubKey2Address(ApplicationEngine engine) + { + ReadOnlySpan pubKey = engine.CurrentContext.EvaluationStack.Pop().GetSpan(); + byte[] scriptHash = Cryptography.ECC.ECPoint.FromBytes(pubKey.ToArray(), Cryptography.ECC.ECCurve.Secp256r1).EncodePoint(true).ToScriptHash().ToAddress().HexToBytes(); ; + engine.CurrentContext.EvaluationStack.Push(scriptHash); + return true; + } + + private static bool Crypto_PubKey2ScriptHash(ApplicationEngine engine) + { + ReadOnlySpan pubKey = engine.CurrentContext.EvaluationStack.Pop().GetSpan(); + byte[] scriptHash = Cryptography.ECC.ECPoint.FromBytes(pubKey.ToArray(), Cryptography.ECC.ECCurve.Secp256r1).EncodePoint(true).ToScriptHash().ToArray(); + engine.CurrentContext.EvaluationStack.Push(scriptHash); + return true; + } + + private static bool Crypto_Address2ScriptHash(ApplicationEngine engine) + { + ReadOnlySpan address = engine.CurrentContext.EvaluationStack.Pop().GetSpan(); + byte[] scriptHash = address.ToHexString().ToScriptHash().ToArray(); + engine.CurrentContext.EvaluationStack.Push(scriptHash); + return true; + } + + private static bool Crypto_ScriptHash2Address(ApplicationEngine engine) + { + ReadOnlySpan hash = engine.CurrentContext.EvaluationStack.Pop().GetSpan(); + byte[] address = new UInt160(hash).ToAddress().HexToBytes(); + engine.CurrentContext.EvaluationStack.Push(address); + return true; + } + } + } +} From 2e5dbda7eb46fed279487707ec14b152b6c6ff1b Mon Sep 17 00:00:00 2001 From: Jin Qiao Date: Wed, 22 Jan 2020 15:54:47 +0800 Subject: [PATCH 02/16] Add test cases --- .../SmartContract/InteropService.Encode.cs | 10 ++--- .../SmartContract/UT_InteropService.cs | 40 +++++++++++++++++++ 2 files changed, 45 insertions(+), 5 deletions(-) diff --git a/src/neo/SmartContract/InteropService.Encode.cs b/src/neo/SmartContract/InteropService.Encode.cs index 484b6a4f44..b6ab9f9132 100644 --- a/src/neo/SmartContract/InteropService.Encode.cs +++ b/src/neo/SmartContract/InteropService.Encode.cs @@ -19,8 +19,8 @@ public static class Encode private static bool Crypto_PubKey2Address(ApplicationEngine engine) { ReadOnlySpan pubKey = engine.CurrentContext.EvaluationStack.Pop().GetSpan(); - byte[] scriptHash = Cryptography.ECC.ECPoint.FromBytes(pubKey.ToArray(), Cryptography.ECC.ECCurve.Secp256r1).EncodePoint(true).ToScriptHash().ToAddress().HexToBytes(); ; - engine.CurrentContext.EvaluationStack.Push(scriptHash); + string address = Cryptography.ECC.ECPoint.FromBytes(pubKey.ToArray(), Cryptography.ECC.ECCurve.Secp256r1).EncodePoint(true).ToScriptHash().ToAddress(); + engine.CurrentContext.EvaluationStack.Push(address); return true; } @@ -34,8 +34,8 @@ private static bool Crypto_PubKey2ScriptHash(ApplicationEngine engine) private static bool Crypto_Address2ScriptHash(ApplicationEngine engine) { - ReadOnlySpan address = engine.CurrentContext.EvaluationStack.Pop().GetSpan(); - byte[] scriptHash = address.ToHexString().ToScriptHash().ToArray(); + string address = engine.CurrentContext.EvaluationStack.Pop().GetString(); + byte[] scriptHash = address.ToScriptHash().ToArray(); engine.CurrentContext.EvaluationStack.Push(scriptHash); return true; } @@ -43,7 +43,7 @@ private static bool Crypto_Address2ScriptHash(ApplicationEngine engine) private static bool Crypto_ScriptHash2Address(ApplicationEngine engine) { ReadOnlySpan hash = engine.CurrentContext.EvaluationStack.Pop().GetSpan(); - byte[] address = new UInt160(hash).ToAddress().HexToBytes(); + string address = new UInt160(hash).ToAddress(); engine.CurrentContext.EvaluationStack.Push(address); return true; } diff --git a/tests/neo.UnitTests/SmartContract/UT_InteropService.cs b/tests/neo.UnitTests/SmartContract/UT_InteropService.cs index 1fa676af60..f0ca120934 100644 --- a/tests/neo.UnitTests/SmartContract/UT_InteropService.cs +++ b/tests/neo.UnitTests/SmartContract/UT_InteropService.cs @@ -873,6 +873,46 @@ public void TestContract_Destroy() InteropService.Invoke(engine, InteropService.Contract.Destroy).Should().BeTrue(); } + [TestMethod] + public void TestEncode_PubKey2Address() + { + var engine = GetEngine(true, true); + byte[] data = "02486fd15702c4490a26703112a5cc1d0923fd697a33406bd5a1c00e0013b09a70".HexToBytes(); + engine.CurrentContext.EvaluationStack.Push(data); + InteropService.Invoke(engine, InteropService.Encode.PubKey2Address).Should().BeTrue(); + engine.CurrentContext.EvaluationStack.Pop().GetString().Should().BeEquivalentTo("Ng7aXNP1wfsQfcqHU9A12gPFJLdZUvvfpZ"); + } + + [TestMethod] + public void TestEncode_PubKey2ScriptHash() + { + var engine = GetEngine(true, true); + byte[] data = "02486fd15702c4490a26703112a5cc1d0923fd697a33406bd5a1c00e0013b09a70".HexToBytes(); + engine.CurrentContext.EvaluationStack.Push(data); + InteropService.Invoke(engine, InteropService.Encode.PubKey2ScriptHash).Should().BeTrue(); + engine.CurrentContext.EvaluationStack.Pop().GetSpan().ToArray().ToHexString().Should().BeEquivalentTo("dd94970ebb347304bc5e52583b2cbf49c4ce5af7"); + } + + [TestMethod] + public void TestEncode_Address2ScriptHash() + { + var engine = GetEngine(true, true); + string data = "NdtB8RXRmJ7Nhw1FPTm7E6HoDZGnDw37nf"; + engine.CurrentContext.EvaluationStack.Push(data); + InteropService.Invoke(engine, InteropService.Encode.Address2ScriptHash).Should().BeTrue(); + engine.CurrentContext.EvaluationStack.Pop().GetSpan().ToArray().Should().BeEquivalentTo(Crypto.Hash160(new byte[] { 0x01 })); + } + + [TestMethod] + public void TestEncode_ScriptHash2Address() + { + var engine = GetEngine(true, true); + byte[] data = "NdtB8RXRmJ7Nhw1FPTm7E6HoDZGnDw37nf".ToScriptHash().ToArray(); + engine.CurrentContext.EvaluationStack.Push(data); + InteropService.Invoke(engine, InteropService.Encode.ScriptHash2Address).Should().BeTrue(); + engine.CurrentContext.EvaluationStack.Pop().GetString().Should().BeEquivalentTo("NdtB8RXRmJ7Nhw1FPTm7E6HoDZGnDw37nf"); + } + public static void LogEvent(object sender, LogEventArgs args) { Transaction tx = (Transaction)args.ScriptContainer; From 7af4612be889c5ee9cdba8bf49eb8d60571adc7a Mon Sep 17 00:00:00 2001 From: Jin Qiao Date: Wed, 19 Feb 2020 13:58:28 +0800 Subject: [PATCH 03/16] Code optimization --- src/neo/SmartContract/InteropService.Encode.cs | 4 ++-- .../SmartContract/UT_InteropService.cs | 16 ++++++++-------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/neo/SmartContract/InteropService.Encode.cs b/src/neo/SmartContract/InteropService.Encode.cs index b6ab9f9132..0842b8ec9d 100644 --- a/src/neo/SmartContract/InteropService.Encode.cs +++ b/src/neo/SmartContract/InteropService.Encode.cs @@ -19,7 +19,7 @@ public static class Encode private static bool Crypto_PubKey2Address(ApplicationEngine engine) { ReadOnlySpan pubKey = engine.CurrentContext.EvaluationStack.Pop().GetSpan(); - string address = Cryptography.ECC.ECPoint.FromBytes(pubKey.ToArray(), Cryptography.ECC.ECCurve.Secp256r1).EncodePoint(true).ToScriptHash().ToAddress(); + string address = SmartContract.Contract.CreateSignatureRedeemScript(Cryptography.ECC.ECPoint.FromBytes(pubKey.ToArray(), Cryptography.ECC.ECCurve.Secp256r1)).ToScriptHash().ToAddress(); engine.CurrentContext.EvaluationStack.Push(address); return true; } @@ -27,7 +27,7 @@ private static bool Crypto_PubKey2Address(ApplicationEngine engine) private static bool Crypto_PubKey2ScriptHash(ApplicationEngine engine) { ReadOnlySpan pubKey = engine.CurrentContext.EvaluationStack.Pop().GetSpan(); - byte[] scriptHash = Cryptography.ECC.ECPoint.FromBytes(pubKey.ToArray(), Cryptography.ECC.ECCurve.Secp256r1).EncodePoint(true).ToScriptHash().ToArray(); + byte[] scriptHash = SmartContract.Contract.CreateSignatureRedeemScript(Cryptography.ECC.ECPoint.FromBytes(pubKey.ToArray(), Cryptography.ECC.ECCurve.Secp256r1)).ToScriptHash().ToArray(); engine.CurrentContext.EvaluationStack.Push(scriptHash); return true; } diff --git a/tests/neo.UnitTests/SmartContract/UT_InteropService.cs b/tests/neo.UnitTests/SmartContract/UT_InteropService.cs index 2ffd7f2007..0d0bf30c24 100644 --- a/tests/neo.UnitTests/SmartContract/UT_InteropService.cs +++ b/tests/neo.UnitTests/SmartContract/UT_InteropService.cs @@ -862,40 +862,40 @@ public void TestContract_Destroy() public void TestEncode_PubKey2Address() { var engine = GetEngine(true, true); - byte[] data = "02486fd15702c4490a26703112a5cc1d0923fd697a33406bd5a1c00e0013b09a70".HexToBytes(); + byte[] data = "024b817ef37f2fc3d4a33fe36687e592d9f30fe24b3e28187dc8f12b3b3b2b839e".HexToBytes(); engine.CurrentContext.EvaluationStack.Push(data); InteropService.Invoke(engine, InteropService.Encode.PubKey2Address).Should().BeTrue(); - engine.CurrentContext.EvaluationStack.Pop().GetString().Should().BeEquivalentTo("Ng7aXNP1wfsQfcqHU9A12gPFJLdZUvvfpZ"); + engine.CurrentContext.EvaluationStack.Pop().GetString().Should().BeEquivalentTo("NYXBPFgUM2Wa9wUdtEZV3zk1pLWamNEJB1"); } [TestMethod] public void TestEncode_PubKey2ScriptHash() { var engine = GetEngine(true, true); - byte[] data = "02486fd15702c4490a26703112a5cc1d0923fd697a33406bd5a1c00e0013b09a70".HexToBytes(); + byte[] data = "024b817ef37f2fc3d4a33fe36687e592d9f30fe24b3e28187dc8f12b3b3b2b839e".HexToBytes(); engine.CurrentContext.EvaluationStack.Push(data); InteropService.Invoke(engine, InteropService.Encode.PubKey2ScriptHash).Should().BeTrue(); - engine.CurrentContext.EvaluationStack.Pop().GetSpan().ToArray().ToHexString().Should().BeEquivalentTo("dd94970ebb347304bc5e52583b2cbf49c4ce5af7"); + engine.CurrentContext.EvaluationStack.Pop().GetSpan().ToArray().Should().BeEquivalentTo(UInt160.Parse("0x2c847208959ec1cc94dd13bfe231fa622a404a8a").ToArray()); } [TestMethod] public void TestEncode_Address2ScriptHash() { var engine = GetEngine(true, true); - string data = "NdtB8RXRmJ7Nhw1FPTm7E6HoDZGnDw37nf"; + string data = "NYXBPFgUM2Wa9wUdtEZV3zk1pLWamNEJB1"; engine.CurrentContext.EvaluationStack.Push(data); InteropService.Invoke(engine, InteropService.Encode.Address2ScriptHash).Should().BeTrue(); - engine.CurrentContext.EvaluationStack.Pop().GetSpan().ToArray().Should().BeEquivalentTo(Crypto.Hash160(new byte[] { 0x01 })); + engine.CurrentContext.EvaluationStack.Pop().GetSpan().ToArray().Should().BeEquivalentTo(UInt160.Parse("0x2c847208959ec1cc94dd13bfe231fa622a404a8a").ToArray()); } [TestMethod] public void TestEncode_ScriptHash2Address() { var engine = GetEngine(true, true); - byte[] data = "NdtB8RXRmJ7Nhw1FPTm7E6HoDZGnDw37nf".ToScriptHash().ToArray(); + byte[] data = "NYXBPFgUM2Wa9wUdtEZV3zk1pLWamNEJB1".ToScriptHash().ToArray(); engine.CurrentContext.EvaluationStack.Push(data); InteropService.Invoke(engine, InteropService.Encode.ScriptHash2Address).Should().BeTrue(); - engine.CurrentContext.EvaluationStack.Pop().GetString().Should().BeEquivalentTo("NdtB8RXRmJ7Nhw1FPTm7E6HoDZGnDw37nf"); + engine.CurrentContext.EvaluationStack.Pop().GetString().Should().BeEquivalentTo("NYXBPFgUM2Wa9wUdtEZV3zk1pLWamNEJB1"); } public static void LogEvent(object sender, LogEventArgs args) From a5d6d898c02f5b48dc6443d471392d64210b6ccc Mon Sep 17 00:00:00 2001 From: Jin Qiao Date: Wed, 19 Feb 2020 14:02:57 +0800 Subject: [PATCH 04/16] Fee adjusting --- src/neo/SmartContract/InteropService.Encode.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/neo/SmartContract/InteropService.Encode.cs b/src/neo/SmartContract/InteropService.Encode.cs index 0842b8ec9d..c156cf7268 100644 --- a/src/neo/SmartContract/InteropService.Encode.cs +++ b/src/neo/SmartContract/InteropService.Encode.cs @@ -11,10 +11,10 @@ partial class InteropService { public static class Encode { - public static readonly InteropDescriptor PubKey2Address = Register("Neo.Crypto.PubKey2Address", Crypto_PubKey2Address, 0_01000000, TriggerType.All, CallFlags.None); - public static readonly InteropDescriptor PubKey2ScriptHash = Register("Neo.Crypto.PubKey2ScriptHash", Crypto_PubKey2ScriptHash, 0_01000000, TriggerType.All, CallFlags.None); - public static readonly InteropDescriptor Address2ScriptHash = Register("Neo.Crypto.Address2ScriptHash", Crypto_Address2ScriptHash, 0_01000000, TriggerType.All, CallFlags.None); - public static readonly InteropDescriptor ScriptHash2Address = Register("Neo.Crypto.ScriptHash2Address", Crypto_ScriptHash2Address, 0_01000000, TriggerType.All, CallFlags.None); + public static readonly InteropDescriptor PubKey2Address = Register("Neo.Crypto.PubKey2Address", Crypto_PubKey2Address, 0_00010000, TriggerType.All, CallFlags.None); + public static readonly InteropDescriptor PubKey2ScriptHash = Register("Neo.Crypto.PubKey2ScriptHash", Crypto_PubKey2ScriptHash, 0_00010000, TriggerType.All, CallFlags.None); + public static readonly InteropDescriptor Address2ScriptHash = Register("Neo.Crypto.Address2ScriptHash", Crypto_Address2ScriptHash, 0_00010000, TriggerType.All, CallFlags.None); + public static readonly InteropDescriptor ScriptHash2Address = Register("Neo.Crypto.ScriptHash2Address", Crypto_ScriptHash2Address, 0_00010000, TriggerType.All, CallFlags.None); private static bool Crypto_PubKey2Address(ApplicationEngine engine) { From f747e5a551d37ad15bfee322347ef82ef68a3558 Mon Sep 17 00:00:00 2001 From: Jin Qiao Date: Wed, 19 Feb 2020 16:55:11 +0800 Subject: [PATCH 05/16] Code optimization --- src/neo/SmartContract/InteropService.Encode.cs | 16 ++++++++-------- .../SmartContract/UT_InteropService.cs | 16 ++++++++-------- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/src/neo/SmartContract/InteropService.Encode.cs b/src/neo/SmartContract/InteropService.Encode.cs index c156cf7268..6b0b3b030d 100644 --- a/src/neo/SmartContract/InteropService.Encode.cs +++ b/src/neo/SmartContract/InteropService.Encode.cs @@ -11,12 +11,12 @@ partial class InteropService { public static class Encode { - public static readonly InteropDescriptor PubKey2Address = Register("Neo.Crypto.PubKey2Address", Crypto_PubKey2Address, 0_00010000, TriggerType.All, CallFlags.None); - public static readonly InteropDescriptor PubKey2ScriptHash = Register("Neo.Crypto.PubKey2ScriptHash", Crypto_PubKey2ScriptHash, 0_00010000, TriggerType.All, CallFlags.None); - public static readonly InteropDescriptor Address2ScriptHash = Register("Neo.Crypto.Address2ScriptHash", Crypto_Address2ScriptHash, 0_00010000, TriggerType.All, CallFlags.None); - public static readonly InteropDescriptor ScriptHash2Address = Register("Neo.Crypto.ScriptHash2Address", Crypto_ScriptHash2Address, 0_00010000, TriggerType.All, CallFlags.None); + public static readonly InteropDescriptor PubKeyToAddress = Register("Neo.Encode.PubKeyToAddress", Encode_PubKeyToAddress, 0_00010000, TriggerType.All, CallFlags.None); + public static readonly InteropDescriptor PubKeyToScriptHash = Register("Neo.Encode.PubKeyToScriptHash", Encode_PubKeyToScriptHash, 0_00010000, TriggerType.All, CallFlags.None); + public static readonly InteropDescriptor AddressToScriptHash = Register("Neo.Encode.AddressToScriptHash", Encode_AddressToScriptHash, 0_00010000, TriggerType.All, CallFlags.None); + public static readonly InteropDescriptor ScriptHashToAddress = Register("Neo.Encode.ScriptHashToAddress", Encode_ScriptHashToAddress, 0_00010000, TriggerType.All, CallFlags.None); - private static bool Crypto_PubKey2Address(ApplicationEngine engine) + private static bool Encode_PubKeyToAddress(ApplicationEngine engine) { ReadOnlySpan pubKey = engine.CurrentContext.EvaluationStack.Pop().GetSpan(); string address = SmartContract.Contract.CreateSignatureRedeemScript(Cryptography.ECC.ECPoint.FromBytes(pubKey.ToArray(), Cryptography.ECC.ECCurve.Secp256r1)).ToScriptHash().ToAddress(); @@ -24,7 +24,7 @@ private static bool Crypto_PubKey2Address(ApplicationEngine engine) return true; } - private static bool Crypto_PubKey2ScriptHash(ApplicationEngine engine) + private static bool Encode_PubKeyToScriptHash(ApplicationEngine engine) { ReadOnlySpan pubKey = engine.CurrentContext.EvaluationStack.Pop().GetSpan(); byte[] scriptHash = SmartContract.Contract.CreateSignatureRedeemScript(Cryptography.ECC.ECPoint.FromBytes(pubKey.ToArray(), Cryptography.ECC.ECCurve.Secp256r1)).ToScriptHash().ToArray(); @@ -32,7 +32,7 @@ private static bool Crypto_PubKey2ScriptHash(ApplicationEngine engine) return true; } - private static bool Crypto_Address2ScriptHash(ApplicationEngine engine) + private static bool Encode_AddressToScriptHash(ApplicationEngine engine) { string address = engine.CurrentContext.EvaluationStack.Pop().GetString(); byte[] scriptHash = address.ToScriptHash().ToArray(); @@ -40,7 +40,7 @@ private static bool Crypto_Address2ScriptHash(ApplicationEngine engine) return true; } - private static bool Crypto_ScriptHash2Address(ApplicationEngine engine) + private static bool Encode_ScriptHashToAddress(ApplicationEngine engine) { ReadOnlySpan hash = engine.CurrentContext.EvaluationStack.Pop().GetSpan(); string address = new UInt160(hash).ToAddress(); diff --git a/tests/neo.UnitTests/SmartContract/UT_InteropService.cs b/tests/neo.UnitTests/SmartContract/UT_InteropService.cs index 0d0bf30c24..0a6c47f1f5 100644 --- a/tests/neo.UnitTests/SmartContract/UT_InteropService.cs +++ b/tests/neo.UnitTests/SmartContract/UT_InteropService.cs @@ -859,42 +859,42 @@ public void TestContract_Destroy() } [TestMethod] - public void TestEncode_PubKey2Address() + public void TestEncode_PubKeyToAddress() { var engine = GetEngine(true, true); byte[] data = "024b817ef37f2fc3d4a33fe36687e592d9f30fe24b3e28187dc8f12b3b3b2b839e".HexToBytes(); engine.CurrentContext.EvaluationStack.Push(data); - InteropService.Invoke(engine, InteropService.Encode.PubKey2Address).Should().BeTrue(); + InteropService.Invoke(engine, InteropService.Encode.PubKeyToAddress).Should().BeTrue(); engine.CurrentContext.EvaluationStack.Pop().GetString().Should().BeEquivalentTo("NYXBPFgUM2Wa9wUdtEZV3zk1pLWamNEJB1"); } [TestMethod] - public void TestEncode_PubKey2ScriptHash() + public void TestEncode_PubKeyToScriptHash() { var engine = GetEngine(true, true); byte[] data = "024b817ef37f2fc3d4a33fe36687e592d9f30fe24b3e28187dc8f12b3b3b2b839e".HexToBytes(); engine.CurrentContext.EvaluationStack.Push(data); - InteropService.Invoke(engine, InteropService.Encode.PubKey2ScriptHash).Should().BeTrue(); + InteropService.Invoke(engine, InteropService.Encode.PubKeyToScriptHash).Should().BeTrue(); engine.CurrentContext.EvaluationStack.Pop().GetSpan().ToArray().Should().BeEquivalentTo(UInt160.Parse("0x2c847208959ec1cc94dd13bfe231fa622a404a8a").ToArray()); } [TestMethod] - public void TestEncode_Address2ScriptHash() + public void TestEncode_AddressToScriptHash() { var engine = GetEngine(true, true); string data = "NYXBPFgUM2Wa9wUdtEZV3zk1pLWamNEJB1"; engine.CurrentContext.EvaluationStack.Push(data); - InteropService.Invoke(engine, InteropService.Encode.Address2ScriptHash).Should().BeTrue(); + InteropService.Invoke(engine, InteropService.Encode.AddressToScriptHash).Should().BeTrue(); engine.CurrentContext.EvaluationStack.Pop().GetSpan().ToArray().Should().BeEquivalentTo(UInt160.Parse("0x2c847208959ec1cc94dd13bfe231fa622a404a8a").ToArray()); } [TestMethod] - public void TestEncode_ScriptHash2Address() + public void TestEncode_ScriptHashToAddress() { var engine = GetEngine(true, true); byte[] data = "NYXBPFgUM2Wa9wUdtEZV3zk1pLWamNEJB1".ToScriptHash().ToArray(); engine.CurrentContext.EvaluationStack.Push(data); - InteropService.Invoke(engine, InteropService.Encode.ScriptHash2Address).Should().BeTrue(); + InteropService.Invoke(engine, InteropService.Encode.ScriptHashToAddress).Should().BeTrue(); engine.CurrentContext.EvaluationStack.Pop().GetString().Should().BeEquivalentTo("NYXBPFgUM2Wa9wUdtEZV3zk1pLWamNEJB1"); } From b7c04c583b690f6340706953c5dd337e98cd47d3 Mon Sep 17 00:00:00 2001 From: Jin Qiao Date: Tue, 25 Feb 2020 15:16:46 +0800 Subject: [PATCH 06/16] Add comment --- src/neo/SmartContract/InteropService.Encode.cs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/neo/SmartContract/InteropService.Encode.cs b/src/neo/SmartContract/InteropService.Encode.cs index 6b0b3b030d..cee14fcdae 100644 --- a/src/neo/SmartContract/InteropService.Encode.cs +++ b/src/neo/SmartContract/InteropService.Encode.cs @@ -11,9 +11,24 @@ partial class InteropService { public static class Encode { + /// + /// Convert public key to corresponding wallet account address + /// public static readonly InteropDescriptor PubKeyToAddress = Register("Neo.Encode.PubKeyToAddress", Encode_PubKeyToAddress, 0_00010000, TriggerType.All, CallFlags.None); + + /// + /// Convert public key to corresponding wallet account scripthash + /// public static readonly InteropDescriptor PubKeyToScriptHash = Register("Neo.Encode.PubKeyToScriptHash", Encode_PubKeyToScriptHash, 0_00010000, TriggerType.All, CallFlags.None); + + /// + /// Convert wallet account address to corresponding scripthash + /// public static readonly InteropDescriptor AddressToScriptHash = Register("Neo.Encode.AddressToScriptHash", Encode_AddressToScriptHash, 0_00010000, TriggerType.All, CallFlags.None); + + /// + /// Convert wallet account scripthash to corresponding address + /// public static readonly InteropDescriptor ScriptHashToAddress = Register("Neo.Encode.ScriptHashToAddress", Encode_ScriptHashToAddress, 0_00010000, TriggerType.All, CallFlags.None); private static bool Encode_PubKeyToAddress(ApplicationEngine engine) From e7df5b1b266d92141687145cb8aa7e6a68460d0e Mon Sep 17 00:00:00 2001 From: Jin Qiao Date: Mon, 9 Mar 2020 11:26:41 +0800 Subject: [PATCH 07/16] Code optimization --- .../SmartContract/InteropService.Encode.cs | 32 ++----------------- .../SmartContract/UT_InteropService.cs | 24 ++------------ 2 files changed, 5 insertions(+), 51 deletions(-) diff --git a/src/neo/SmartContract/InteropService.Encode.cs b/src/neo/SmartContract/InteropService.Encode.cs index cee14fcdae..e09a5e868e 100644 --- a/src/neo/SmartContract/InteropService.Encode.cs +++ b/src/neo/SmartContract/InteropService.Encode.cs @@ -17,19 +17,9 @@ public static class Encode public static readonly InteropDescriptor PubKeyToAddress = Register("Neo.Encode.PubKeyToAddress", Encode_PubKeyToAddress, 0_00010000, TriggerType.All, CallFlags.None); /// - /// Convert public key to corresponding wallet account scripthash + /// Calculate corresponding account scripthash for given public key /// - public static readonly InteropDescriptor PubKeyToScriptHash = Register("Neo.Encode.PubKeyToScriptHash", Encode_PubKeyToScriptHash, 0_00010000, TriggerType.All, CallFlags.None); - - /// - /// Convert wallet account address to corresponding scripthash - /// - public static readonly InteropDescriptor AddressToScriptHash = Register("Neo.Encode.AddressToScriptHash", Encode_AddressToScriptHash, 0_00010000, TriggerType.All, CallFlags.None); - - /// - /// Convert wallet account scripthash to corresponding address - /// - public static readonly InteropDescriptor ScriptHashToAddress = Register("Neo.Encode.ScriptHashToAddress", Encode_ScriptHashToAddress, 0_00010000, TriggerType.All, CallFlags.None); + public static readonly InteropDescriptor CreateStandardAccount = Register("System.Contract.CreateStandardAccount", Encode_CreateStandardAccount, 0_00010000, TriggerType.All, CallFlags.None); private static bool Encode_PubKeyToAddress(ApplicationEngine engine) { @@ -39,29 +29,13 @@ private static bool Encode_PubKeyToAddress(ApplicationEngine engine) return true; } - private static bool Encode_PubKeyToScriptHash(ApplicationEngine engine) + private static bool Encode_CreateStandardAccount(ApplicationEngine engine) { ReadOnlySpan pubKey = engine.CurrentContext.EvaluationStack.Pop().GetSpan(); byte[] scriptHash = SmartContract.Contract.CreateSignatureRedeemScript(Cryptography.ECC.ECPoint.FromBytes(pubKey.ToArray(), Cryptography.ECC.ECCurve.Secp256r1)).ToScriptHash().ToArray(); engine.CurrentContext.EvaluationStack.Push(scriptHash); return true; } - - private static bool Encode_AddressToScriptHash(ApplicationEngine engine) - { - string address = engine.CurrentContext.EvaluationStack.Pop().GetString(); - byte[] scriptHash = address.ToScriptHash().ToArray(); - engine.CurrentContext.EvaluationStack.Push(scriptHash); - return true; - } - - private static bool Encode_ScriptHashToAddress(ApplicationEngine engine) - { - ReadOnlySpan hash = engine.CurrentContext.EvaluationStack.Pop().GetSpan(); - string address = new UInt160(hash).ToAddress(); - engine.CurrentContext.EvaluationStack.Push(address); - return true; - } } } } diff --git a/tests/neo.UnitTests/SmartContract/UT_InteropService.cs b/tests/neo.UnitTests/SmartContract/UT_InteropService.cs index 0a6c47f1f5..4dd8265950 100644 --- a/tests/neo.UnitTests/SmartContract/UT_InteropService.cs +++ b/tests/neo.UnitTests/SmartContract/UT_InteropService.cs @@ -869,35 +869,15 @@ public void TestEncode_PubKeyToAddress() } [TestMethod] - public void TestEncode_PubKeyToScriptHash() + public void TestEncode_CreateStandardAccount() { var engine = GetEngine(true, true); byte[] data = "024b817ef37f2fc3d4a33fe36687e592d9f30fe24b3e28187dc8f12b3b3b2b839e".HexToBytes(); engine.CurrentContext.EvaluationStack.Push(data); - InteropService.Invoke(engine, InteropService.Encode.PubKeyToScriptHash).Should().BeTrue(); + InteropService.Invoke(engine, InteropService.Encode.CreateStandardAccount).Should().BeTrue(); engine.CurrentContext.EvaluationStack.Pop().GetSpan().ToArray().Should().BeEquivalentTo(UInt160.Parse("0x2c847208959ec1cc94dd13bfe231fa622a404a8a").ToArray()); } - [TestMethod] - public void TestEncode_AddressToScriptHash() - { - var engine = GetEngine(true, true); - string data = "NYXBPFgUM2Wa9wUdtEZV3zk1pLWamNEJB1"; - engine.CurrentContext.EvaluationStack.Push(data); - InteropService.Invoke(engine, InteropService.Encode.AddressToScriptHash).Should().BeTrue(); - engine.CurrentContext.EvaluationStack.Pop().GetSpan().ToArray().Should().BeEquivalentTo(UInt160.Parse("0x2c847208959ec1cc94dd13bfe231fa622a404a8a").ToArray()); - } - - [TestMethod] - public void TestEncode_ScriptHashToAddress() - { - var engine = GetEngine(true, true); - byte[] data = "NYXBPFgUM2Wa9wUdtEZV3zk1pLWamNEJB1".ToScriptHash().ToArray(); - engine.CurrentContext.EvaluationStack.Push(data); - InteropService.Invoke(engine, InteropService.Encode.ScriptHashToAddress).Should().BeTrue(); - engine.CurrentContext.EvaluationStack.Pop().GetString().Should().BeEquivalentTo("NYXBPFgUM2Wa9wUdtEZV3zk1pLWamNEJB1"); - } - public static void LogEvent(object sender, LogEventArgs args) { Transaction tx = (Transaction)args.ScriptContainer; From b100d39a5f5e140394002d944c2045be23759c94 Mon Sep 17 00:00:00 2001 From: Jin Qiao Date: Fri, 13 Mar 2020 10:40:08 +0800 Subject: [PATCH 08/16] Code optimization --- src/neo/SmartContract/InteropService.Contract.cs | 13 +++++++++++++ src/neo/SmartContract/InteropService.Encode.cs | 13 ------------- .../SmartContract/UT_InteropService.cs | 4 ++-- 3 files changed, 15 insertions(+), 15 deletions(-) diff --git a/src/neo/SmartContract/InteropService.Contract.cs b/src/neo/SmartContract/InteropService.Contract.cs index 14823db8c8..a56ba91667 100644 --- a/src/neo/SmartContract/InteropService.Contract.cs +++ b/src/neo/SmartContract/InteropService.Contract.cs @@ -19,6 +19,11 @@ public static class Contract public static readonly InteropDescriptor CallEx = Register("System.Contract.CallEx", Contract_CallEx, 0_01000000, TriggerType.System | TriggerType.Application, CallFlags.AllowCall); public static readonly InteropDescriptor IsStandard = Register("System.Contract.IsStandard", Contract_IsStandard, 0_00030000, TriggerType.All, CallFlags.None); + /// + /// Calculate corresponding account scripthash for given public key + /// + public static readonly InteropDescriptor CreateStandardAccount = Register("System.Contract.CreateStandardAccount", Contract_CreateStandardAccount, 0_00010000, TriggerType.All, CallFlags.None); + private static long GetDeploymentPrice(EvaluationStack stack) { int size = stack.Peek(0).GetByteLength() + stack.Peek(1).GetByteLength(); @@ -165,6 +170,14 @@ private static bool Contract_IsStandard(ApplicationEngine engine) engine.CurrentContext.EvaluationStack.Push(isStandard); return true; } + + private static bool Contract_CreateStandardAccount(ApplicationEngine engine) + { + ReadOnlySpan pubKey = engine.CurrentContext.EvaluationStack.Pop().GetSpan(); + byte[] scriptHash = SmartContract.Contract.CreateSignatureRedeemScript(Cryptography.ECC.ECPoint.FromBytes(pubKey.ToArray(), Cryptography.ECC.ECCurve.Secp256r1)).ToScriptHash().ToArray(); + engine.CurrentContext.EvaluationStack.Push(scriptHash); + return true; + } } } } diff --git a/src/neo/SmartContract/InteropService.Encode.cs b/src/neo/SmartContract/InteropService.Encode.cs index e09a5e868e..b6ae883d0b 100644 --- a/src/neo/SmartContract/InteropService.Encode.cs +++ b/src/neo/SmartContract/InteropService.Encode.cs @@ -16,11 +16,6 @@ public static class Encode /// public static readonly InteropDescriptor PubKeyToAddress = Register("Neo.Encode.PubKeyToAddress", Encode_PubKeyToAddress, 0_00010000, TriggerType.All, CallFlags.None); - /// - /// Calculate corresponding account scripthash for given public key - /// - public static readonly InteropDescriptor CreateStandardAccount = Register("System.Contract.CreateStandardAccount", Encode_CreateStandardAccount, 0_00010000, TriggerType.All, CallFlags.None); - private static bool Encode_PubKeyToAddress(ApplicationEngine engine) { ReadOnlySpan pubKey = engine.CurrentContext.EvaluationStack.Pop().GetSpan(); @@ -28,14 +23,6 @@ private static bool Encode_PubKeyToAddress(ApplicationEngine engine) engine.CurrentContext.EvaluationStack.Push(address); return true; } - - private static bool Encode_CreateStandardAccount(ApplicationEngine engine) - { - ReadOnlySpan pubKey = engine.CurrentContext.EvaluationStack.Pop().GetSpan(); - byte[] scriptHash = SmartContract.Contract.CreateSignatureRedeemScript(Cryptography.ECC.ECPoint.FromBytes(pubKey.ToArray(), Cryptography.ECC.ECCurve.Secp256r1)).ToScriptHash().ToArray(); - engine.CurrentContext.EvaluationStack.Push(scriptHash); - return true; - } } } } diff --git a/tests/neo.UnitTests/SmartContract/UT_InteropService.cs b/tests/neo.UnitTests/SmartContract/UT_InteropService.cs index 4dd8265950..b669c3d288 100644 --- a/tests/neo.UnitTests/SmartContract/UT_InteropService.cs +++ b/tests/neo.UnitTests/SmartContract/UT_InteropService.cs @@ -869,12 +869,12 @@ public void TestEncode_PubKeyToAddress() } [TestMethod] - public void TestEncode_CreateStandardAccount() + public void TestContract_CreateStandardAccount() { var engine = GetEngine(true, true); byte[] data = "024b817ef37f2fc3d4a33fe36687e592d9f30fe24b3e28187dc8f12b3b3b2b839e".HexToBytes(); engine.CurrentContext.EvaluationStack.Push(data); - InteropService.Invoke(engine, InteropService.Encode.CreateStandardAccount).Should().BeTrue(); + InteropService.Invoke(engine, InteropService.Contract.CreateStandardAccount).Should().BeTrue(); engine.CurrentContext.EvaluationStack.Pop().GetSpan().ToArray().Should().BeEquivalentTo(UInt160.Parse("0x2c847208959ec1cc94dd13bfe231fa622a404a8a").ToArray()); } From c7a332b50e70c4e9196c5f9735e4fdc5654f962f Mon Sep 17 00:00:00 2001 From: Jin Qiao Date: Mon, 16 Mar 2020 10:42:23 +0800 Subject: [PATCH 09/16] Merge from master --- src/neo/SmartContract/ApplicationEngine.cs | 3 +- src/neo/SmartContract/InteropDescriptor.cs | 9 +- .../SmartContract/InteropService.Contract.cs | 3 +- .../SmartContract/InteropService.Crypto.cs | 3 +- .../SmartContract/InteropService.Storage.cs | 26 ++- src/neo/SmartContract/InteropService.cs | 7 +- .../SmartContract/Native/NativeContract.cs | 3 +- src/neo/Wallets/Wallet.cs | 4 +- .../SmartContract/UT_InteropPrices.cs | 206 +++++++++++++++++- tests/neo.UnitTests/TestUtils.cs | 28 +++ 10 files changed, 270 insertions(+), 22 deletions(-) diff --git a/src/neo/SmartContract/ApplicationEngine.cs b/src/neo/SmartContract/ApplicationEngine.cs index 53bc8c68a8..500e75a6b5 100644 --- a/src/neo/SmartContract/ApplicationEngine.cs +++ b/src/neo/SmartContract/ApplicationEngine.cs @@ -25,6 +25,7 @@ public partial class ApplicationEngine : ExecutionEngine public IVerifiable ScriptContainer { get; } public StoreView Snapshot { get; } public long GasConsumed { get; private set; } = 0; + public UInt160 CurrentScriptHash => CurrentContext?.GetState().ScriptHash; public UInt160 CallingScriptHash => CurrentContext?.GetState().CallingScriptHash; public UInt160 EntryScriptHash => EntryContext?.GetState().ScriptHash; @@ -78,7 +79,7 @@ public override void Dispose() protected override bool OnSysCall(uint method) { - if (!AddGas(InteropService.GetPrice(method, CurrentContext.EvaluationStack))) + if (!AddGas(InteropService.GetPrice(method, CurrentContext.EvaluationStack, Snapshot))) return false; return InteropService.Invoke(this, method); } diff --git a/src/neo/SmartContract/InteropDescriptor.cs b/src/neo/SmartContract/InteropDescriptor.cs index 6984eba13c..ebc94c2f3e 100644 --- a/src/neo/SmartContract/InteropDescriptor.cs +++ b/src/neo/SmartContract/InteropDescriptor.cs @@ -1,3 +1,4 @@ +using Neo.Persistence; using Neo.VM; using System; @@ -9,7 +10,7 @@ public class InteropDescriptor public uint Hash { get; } internal Func Handler { get; } public long Price { get; } - public Func PriceCalculator { get; } + public Func PriceCalculator { get; } public TriggerType AllowedTriggers { get; } public CallFlags RequiredCallFlags { get; } @@ -19,7 +20,7 @@ internal InteropDescriptor(string method, Func handler, this.Price = price; } - internal InteropDescriptor(string method, Func handler, Func priceCalculator, TriggerType allowedTriggers, CallFlags requiredCallFlags) + internal InteropDescriptor(string method, Func handler, Func priceCalculator, TriggerType allowedTriggers, CallFlags requiredCallFlags) : this(method, handler, allowedTriggers, requiredCallFlags) { this.PriceCalculator = priceCalculator; @@ -34,9 +35,9 @@ private InteropDescriptor(string method, Func handler, this.RequiredCallFlags = requiredCallFlags; } - public long GetPrice(EvaluationStack stack) + public long GetPrice(EvaluationStack stack, StoreView snapshot) { - return PriceCalculator is null ? Price : PriceCalculator(stack); + return PriceCalculator is null ? Price : PriceCalculator(stack, snapshot); } public static implicit operator uint(InteropDescriptor descriptor) diff --git a/src/neo/SmartContract/InteropService.Contract.cs b/src/neo/SmartContract/InteropService.Contract.cs index a56ba91667..0e70ec7603 100644 --- a/src/neo/SmartContract/InteropService.Contract.cs +++ b/src/neo/SmartContract/InteropService.Contract.cs @@ -1,5 +1,6 @@ using Neo.IO; using Neo.Ledger; +using Neo.Persistence; using Neo.SmartContract.Manifest; using Neo.VM; using Neo.VM.Types; @@ -24,7 +25,7 @@ public static class Contract /// public static readonly InteropDescriptor CreateStandardAccount = Register("System.Contract.CreateStandardAccount", Contract_CreateStandardAccount, 0_00010000, TriggerType.All, CallFlags.None); - private static long GetDeploymentPrice(EvaluationStack stack) + private static long GetDeploymentPrice(EvaluationStack stack, StoreView snapshot) { int size = stack.Peek(0).GetByteLength() + stack.Peek(1).GetByteLength(); return Storage.GasPerByte * size; diff --git a/src/neo/SmartContract/InteropService.Crypto.cs b/src/neo/SmartContract/InteropService.Crypto.cs index 448d312ea4..9678f321ce 100644 --- a/src/neo/SmartContract/InteropService.Crypto.cs +++ b/src/neo/SmartContract/InteropService.Crypto.cs @@ -1,6 +1,7 @@ using Neo.Cryptography; using Neo.Network.P2P; using Neo.Network.P2P.Payloads; +using Neo.Persistence; using Neo.VM; using Neo.VM.Types; using System; @@ -16,7 +17,7 @@ public static class Crypto public static readonly InteropDescriptor ECDsaVerify = Register("Neo.Crypto.ECDsaVerify", Crypto_ECDsaVerify, 0_01000000, TriggerType.All, CallFlags.None); public static readonly InteropDescriptor ECDsaCheckMultiSig = Register("Neo.Crypto.ECDsaCheckMultiSig", Crypto_ECDsaCheckMultiSig, GetECDsaCheckMultiSigPrice, TriggerType.All, CallFlags.None); - private static long GetECDsaCheckMultiSigPrice(EvaluationStack stack) + private static long GetECDsaCheckMultiSigPrice(EvaluationStack stack, StoreView snapshot) { if (stack.Count < 2) return 0; var item = stack.Peek(1); diff --git a/src/neo/SmartContract/InteropService.Storage.cs b/src/neo/SmartContract/InteropService.Storage.cs index 3355a5f83c..a9fc9e9303 100644 --- a/src/neo/SmartContract/InteropService.Storage.cs +++ b/src/neo/SmartContract/InteropService.Storage.cs @@ -1,4 +1,5 @@ using Neo.Ledger; +using Neo.Persistence; using Neo.SmartContract.Iterators; using Neo.VM; using Neo.VM.Types; @@ -22,11 +23,30 @@ public static class Storage public static readonly InteropDescriptor Find = Register("System.Storage.Find", Storage_Find, 0_01000000, TriggerType.Application, CallFlags.None); public static readonly InteropDescriptor Put = Register("System.Storage.Put", Storage_Put, GetStoragePrice, TriggerType.Application, CallFlags.AllowModifyStates); public static readonly InteropDescriptor PutEx = Register("System.Storage.PutEx", Storage_PutEx, GetStoragePrice, TriggerType.Application, CallFlags.AllowModifyStates); - public static readonly InteropDescriptor Delete = Register("System.Storage.Delete", Storage_Delete, 0_01000000, TriggerType.Application, CallFlags.AllowModifyStates); + public static readonly InteropDescriptor Delete = Register("System.Storage.Delete", Storage_Delete, 1 * GasPerByte, TriggerType.Application, CallFlags.AllowModifyStates); - private static long GetStoragePrice(EvaluationStack stack) + private static long GetStoragePrice(EvaluationStack stack, StoreView snapshot) { - return (stack.Peek(1).GetByteLength() + stack.Peek(2).GetByteLength()) * GasPerByte; + var key = stack.Peek(1); + var value = stack.Peek(2); + var newDataSize = value.IsNull ? 0 : value.GetByteLength(); + if (!(stack.Peek() is InteropInterface _interface)) + throw new InvalidOperationException(); + + StorageContext context = _interface.GetInterface(); + StorageKey skey = new StorageKey + { + Id = context.Id, + Key = key.GetSpan().ToArray() + }; + var skeyValue = snapshot.Storages.TryGet(skey); + if (skeyValue is null) + newDataSize += key.GetByteLength(); + else if (newDataSize <= skeyValue.Value.Length) + newDataSize = 1; + else + newDataSize -= skeyValue.Value.Length; + return newDataSize * GasPerByte; } private static bool PutExInternal(ApplicationEngine engine, StorageContext context, byte[] key, byte[] value, StorageFlags flags) diff --git a/src/neo/SmartContract/InteropService.cs b/src/neo/SmartContract/InteropService.cs index c87ad277ea..f2a673c82f 100644 --- a/src/neo/SmartContract/InteropService.cs +++ b/src/neo/SmartContract/InteropService.cs @@ -1,3 +1,4 @@ +using Neo.Persistence; using Neo.VM; using System; using System.Collections.Generic; @@ -15,9 +16,9 @@ static InteropService() t.GetFields()[0].GetValue(null); } - public static long GetPrice(uint hash, EvaluationStack stack) + public static long GetPrice(uint hash, EvaluationStack stack, StoreView snapshot) { - return methods[hash].GetPrice(stack); + return methods[hash].GetPrice(stack, snapshot); } public static IEnumerable SupportedMethods() @@ -44,7 +45,7 @@ private static InteropDescriptor Register(string method, Func handler, Func priceCalculator, TriggerType allowedTriggers, CallFlags requiredCallFlags) + private static InteropDescriptor Register(string method, Func handler, Func priceCalculator, TriggerType allowedTriggers, CallFlags requiredCallFlags) { InteropDescriptor descriptor = new InteropDescriptor(method, handler, priceCalculator, allowedTriggers, requiredCallFlags); methods.Add(descriptor.Hash, descriptor); diff --git a/src/neo/SmartContract/Native/NativeContract.cs b/src/neo/SmartContract/Native/NativeContract.cs index b7c7f85251..b28f55be14 100644 --- a/src/neo/SmartContract/Native/NativeContract.cs +++ b/src/neo/SmartContract/Native/NativeContract.cs @@ -2,6 +2,7 @@ using Neo.IO; using Neo.Ledger; +using Neo.Persistence; using Neo.SmartContract.Manifest; using Neo.SmartContract.Native.Tokens; using Neo.VM; @@ -101,7 +102,7 @@ internal bool Invoke(ApplicationEngine engine) return true; } - internal long GetPrice(EvaluationStack stack) + internal long GetPrice(EvaluationStack stack, StoreView snapshot) { return methods.TryGetValue(stack.Peek().GetString(), out ContractMethodMetadata method) ? method.Price : 0; } diff --git a/src/neo/Wallets/Wallet.cs b/src/neo/Wallets/Wallet.cs index 3fe4c61652..c0bf012c2a 100644 --- a/src/neo/Wallets/Wallet.cs +++ b/src/neo/Wallets/Wallet.cs @@ -354,7 +354,7 @@ public static long CalculateNetworkFee(byte[] witness_script, ref int size) if (witness_script.IsSignatureContract()) { size += 67 + witness_script.GetVarSize(); - networkFee += ApplicationEngine.OpCodePrices[OpCode.PUSHDATA1] + ApplicationEngine.OpCodePrices[OpCode.PUSHDATA1] + ApplicationEngine.OpCodePrices[OpCode.PUSHNULL] + InteropService.GetPrice(InteropService.Crypto.ECDsaVerify, null); + networkFee += ApplicationEngine.OpCodePrices[OpCode.PUSHDATA1] + ApplicationEngine.OpCodePrices[OpCode.PUSHDATA1] + ApplicationEngine.OpCodePrices[OpCode.PUSHNULL] + InteropService.GetPrice(InteropService.Crypto.ECDsaVerify, null, null); } else if (witness_script.IsMultiSigContract(out int m, out int n)) { @@ -366,7 +366,7 @@ public static long CalculateNetworkFee(byte[] witness_script, ref int size) networkFee += ApplicationEngine.OpCodePrices[OpCode.PUSHDATA1] * n; using (ScriptBuilder sb = new ScriptBuilder()) networkFee += ApplicationEngine.OpCodePrices[(OpCode)sb.EmitPush(n).ToArray()[0]]; - networkFee += ApplicationEngine.OpCodePrices[OpCode.PUSHNULL] + InteropService.GetPrice(InteropService.Crypto.ECDsaVerify, null) * n; + networkFee += ApplicationEngine.OpCodePrices[OpCode.PUSHNULL] + InteropService.GetPrice(InteropService.Crypto.ECDsaVerify, null, null) * n; } else { diff --git a/tests/neo.UnitTests/SmartContract/UT_InteropPrices.cs b/tests/neo.UnitTests/SmartContract/UT_InteropPrices.cs index 19eb7a5d38..e34c80eb96 100644 --- a/tests/neo.UnitTests/SmartContract/UT_InteropPrices.cs +++ b/tests/neo.UnitTests/SmartContract/UT_InteropPrices.cs @@ -1,13 +1,22 @@ using FluentAssertions; using Microsoft.VisualStudio.TestTools.UnitTesting; +using Neo.Ledger; using Neo.SmartContract; +using Neo.SmartContract.Manifest; using Neo.VM; +using System; namespace Neo.UnitTests.SmartContract { [TestClass] public class UT_InteropPrices { + [TestInitialize] + public void Initialize() + { + TestBlockchain.InitializeMockNeoSystem(); + } + [TestMethod] public void ApplicationEngineFixedPrices() { @@ -16,7 +25,7 @@ public void ApplicationEngineFixedPrices() using (ApplicationEngine ae = new ApplicationEngine(TriggerType.Application, null, null, 0)) { ae.LoadScript(SyscallSystemRuntimeCheckWitnessHash); - InteropService.GetPrice(InteropService.Runtime.CheckWitness, ae.CurrentContext.EvaluationStack).Should().Be(0_00030000L); + InteropService.GetPrice(InteropService.Runtime.CheckWitness, ae.CurrentContext.EvaluationStack, ae.Snapshot).Should().Be(0_00030000L); } // System.Storage.GetContext: 9bf667ce (price is 1) @@ -24,7 +33,7 @@ public void ApplicationEngineFixedPrices() using (ApplicationEngine ae = new ApplicationEngine(TriggerType.Application, null, null, 0)) { ae.LoadScript(SyscallSystemStorageGetContextHash); - InteropService.GetPrice(InteropService.Storage.GetContext, ae.CurrentContext.EvaluationStack).Should().Be(0_00000400L); + InteropService.GetPrice(InteropService.Storage.GetContext, ae.CurrentContext.EvaluationStack, ae.Snapshot).Should().Be(0_00000400L); } // System.Storage.Get: 925de831 (price is 100) @@ -32,7 +41,7 @@ public void ApplicationEngineFixedPrices() using (ApplicationEngine ae = new ApplicationEngine(TriggerType.Application, null, null, 0)) { ae.LoadScript(SyscallSystemStorageGetHash); - InteropService.GetPrice(InteropService.Storage.Get, ae.CurrentContext.EvaluationStack).Should().Be(0_01000000L); + InteropService.GetPrice(InteropService.Storage.Get, ae.CurrentContext.EvaluationStack, ae.Snapshot).Should().Be(0_01000000L); } } @@ -47,7 +56,7 @@ public void ApplicationEngineVariablePrices() ae.LoadScript(SyscallContractCreateHash00); debugger.StepInto(); // PUSHDATA1 debugger.StepInto(); // PUSHDATA1 - InteropService.GetPrice(InteropService.Contract.Create, ae.CurrentContext.EvaluationStack).Should().Be(0_00300000L); + InteropService.GetPrice(InteropService.Contract.Create, ae.CurrentContext.EvaluationStack, ae.Snapshot).Should().Be(0_00300000L); } // System.Storage.Put: e63f1884 (requires push key and value) @@ -59,7 +68,8 @@ public void ApplicationEngineVariablePrices() debugger.StepInto(); // push 03 (length 1) debugger.StepInto(); // push 03 (length 1) debugger.StepInto(); // push 00 - InteropService.GetPrice(InteropService.Storage.Put, ae.CurrentContext.EvaluationStack).Should().Be(200000L); + Action act = () => InteropService.GetPrice(InteropService.Storage.Put, ae.CurrentContext.EvaluationStack, ae.Snapshot); + act.Should().Throw(); } // System.Storage.PutEx: 73e19b3a (requires push key and value) @@ -71,8 +81,192 @@ public void ApplicationEngineVariablePrices() debugger.StepInto(); // push 03 (length 1) debugger.StepInto(); // push 03 (length 1) debugger.StepInto(); // push 00 - InteropService.GetPrice(InteropService.Storage.PutEx, ae.CurrentContext.EvaluationStack).Should().Be(200000L); + Action act = () => InteropService.GetPrice(InteropService.Storage.Put, ae.CurrentContext.EvaluationStack, ae.Snapshot); + act.Should().Throw(); + } + } + + /// + /// Put without previous content (should charge per byte used) + /// + [TestMethod] + public void ApplicationEngineRegularPut() + { + var key = new byte[] { (byte)OpCode.PUSH1 }; + var value = new byte[] { (byte)OpCode.PUSH1 }; + + byte[] script = CreatePutScript(key, value); + + ContractState contractState = TestUtils.GetContract(script); + contractState.Manifest.Features = ContractFeatures.HasStorage; + + StorageKey skey = TestUtils.GetStorageKey(contractState.Id, key); + StorageItem sItem = TestUtils.GetStorageItem(new byte[0] { }); + + var snapshot = Blockchain.Singleton.GetSnapshot(); + snapshot.Storages.Add(skey, sItem); + snapshot.Contracts.Add(script.ToScriptHash(), contractState); + + using (ApplicationEngine ae = new ApplicationEngine(TriggerType.Application, null, snapshot, 0, testMode: true)) + { + Debugger debugger = new Debugger(ae); + ae.LoadScript(script); + debugger.StepInto(); + debugger.StepInto(); + debugger.StepInto(); + var setupPrice = ae.GasConsumed; + var defaultDataPrice = InteropService.GetPrice(InteropService.Storage.Put, ae.CurrentContext.EvaluationStack, ae.Snapshot); + defaultDataPrice.Should().Be(InteropService.Storage.GasPerByte * value.Length); + var expectedCost = defaultDataPrice + setupPrice; + debugger.Execute(); + ae.GasConsumed.Should().Be(expectedCost); } } + + /// + /// Reuses the same amount of storage. Should cost 0. + /// + [TestMethod] + public void ApplicationEngineReusedStorage_FullReuse() + { + var key = new byte[] { (byte)OpCode.PUSH1 }; + var value = new byte[] { (byte)OpCode.PUSH1 }; + + byte[] script = CreatePutScript(key, value); + + ContractState contractState = TestUtils.GetContract(script); + contractState.Manifest.Features = ContractFeatures.HasStorage; + + StorageKey skey = TestUtils.GetStorageKey(contractState.Id, key); + StorageItem sItem = TestUtils.GetStorageItem(value); + + var snapshot = Blockchain.Singleton.GetSnapshot(); + snapshot.Storages.Add(skey, sItem); + snapshot.Contracts.Add(script.ToScriptHash(), contractState); + + using (ApplicationEngine applicationEngine = new ApplicationEngine(TriggerType.Application, null, snapshot, 0, testMode: true)) + { + Debugger debugger = new Debugger(applicationEngine); + applicationEngine.LoadScript(script); + debugger.StepInto(); + debugger.StepInto(); + debugger.StepInto(); + var setupPrice = applicationEngine.GasConsumed; + var reusedDataPrice = InteropService.GetPrice(InteropService.Storage.Put, applicationEngine.CurrentContext.EvaluationStack, applicationEngine.Snapshot); + reusedDataPrice.Should().Be(1 * InteropService.Storage.GasPerByte); + debugger.Execute(); + var expectedCost = reusedDataPrice + setupPrice; + applicationEngine.GasConsumed.Should().Be(expectedCost); + } + } + + /// + /// Reuses one byte and allocates a new one + /// It should only pay for the second byte. + /// + [TestMethod] + public void ApplicationEngineReusedStorage_PartialReuse() + { + var key = new byte[] { (byte)OpCode.PUSH1 }; + var oldValue = new byte[] { (byte)OpCode.PUSH1 }; + var value = new byte[] { (byte)OpCode.PUSH1, (byte)OpCode.PUSH1 }; + + byte[] script = CreatePutScript(key, value); + + ContractState contractState = TestUtils.GetContract(script); + contractState.Manifest.Features = ContractFeatures.HasStorage; + + StorageKey skey = TestUtils.GetStorageKey(contractState.Id, key); + StorageItem sItem = TestUtils.GetStorageItem(oldValue); + + var snapshot = Blockchain.Singleton.GetSnapshot(); + snapshot.Storages.Add(skey, sItem); + snapshot.Contracts.Add(script.ToScriptHash(), contractState); + + using (ApplicationEngine ae = new ApplicationEngine(TriggerType.Application, null, snapshot, 0, testMode: true)) + { + Debugger debugger = new Debugger(ae); + ae.LoadScript(script); + debugger.StepInto(); + debugger.StepInto(); + debugger.StepInto(); + var setupPrice = ae.GasConsumed; + var reusedDataPrice = InteropService.GetPrice(InteropService.Storage.Put, ae.CurrentContext.EvaluationStack, ae.Snapshot); + reusedDataPrice.Should().Be(1 * InteropService.Storage.GasPerByte); + debugger.StepInto(); + var expectedCost = reusedDataPrice + setupPrice; + debugger.StepInto(); + ae.GasConsumed.Should().Be(expectedCost); + } + } + + /// + /// Use put for the same key twice. + /// Pays for 1 extra byte for the first Put and 1 byte for the second basic fee (as value2.length == value1.length). + /// + [TestMethod] + public void ApplicationEngineReusedStorage_PartialReuseTwice() + { + var key = new byte[] { (byte)OpCode.PUSH1 }; + var oldValue = new byte[] { (byte)OpCode.PUSH1 }; + var value = new byte[] { (byte)OpCode.PUSH1, (byte)OpCode.PUSH1 }; + + byte[] script = CreateMultiplePutScript(key, value); + + ContractState contractState = TestUtils.GetContract(script); + contractState.Manifest.Features = ContractFeatures.HasStorage; + + StorageKey skey = TestUtils.GetStorageKey(contractState.Id, key); + StorageItem sItem = TestUtils.GetStorageItem(oldValue); + + var snapshot = Blockchain.Singleton.GetSnapshot(); + snapshot.Storages.Add(skey, sItem); + snapshot.Contracts.Add(script.ToScriptHash(), contractState); + + using (ApplicationEngine ae = new ApplicationEngine(TriggerType.Application, null, snapshot, 0, testMode: true)) + { + Debugger debugger = new Debugger(ae); + ae.LoadScript(script); + debugger.StepInto(); //push key + debugger.StepInto(); //push value + debugger.StepInto(); //syscall Storage.GetContext + var setupPrice = ae.GasConsumed; + var incrementDataPrice = InteropService.GetPrice(InteropService.Storage.Put, ae.CurrentContext.EvaluationStack, ae.Snapshot); + incrementDataPrice.Should().Be(1 * InteropService.Storage.GasPerByte); + debugger.StepInto(); // syscall Storage.Put + + debugger.StepInto(); //push key + debugger.StepInto(); //push value + debugger.StepInto(); + setupPrice = ae.GasConsumed; + var reusedDataPrice = InteropService.GetPrice(InteropService.Storage.Put, ae.CurrentContext.EvaluationStack, ae.Snapshot); + reusedDataPrice.Should().Be(1 * InteropService.Storage.GasPerByte); // = PUT basic fee + } + } + + private byte[] CreateMultiplePutScript(byte[] key, byte[] value, int times = 2) + { + var scriptBuilder = new ScriptBuilder(); + + for (int i = 0; i < times; i++) + { + scriptBuilder.EmitPush(value); + scriptBuilder.EmitPush(key); + scriptBuilder.EmitSysCall(InteropService.Storage.GetContext); + scriptBuilder.EmitSysCall(InteropService.Storage.Put); + } + + return scriptBuilder.ToArray(); + } + + private byte[] CreatePutScript(byte[] key, byte[] value) + { + var scriptBuilder = new ScriptBuilder(); + scriptBuilder.EmitPush(value); + scriptBuilder.EmitPush(key); + scriptBuilder.EmitSysCall(InteropService.Storage.GetContext); + scriptBuilder.EmitSysCall(InteropService.Storage.Put); + return scriptBuilder.ToArray(); + } } } diff --git a/tests/neo.UnitTests/TestUtils.cs b/tests/neo.UnitTests/TestUtils.cs index a68eba49a0..dfbd973a26 100644 --- a/tests/neo.UnitTests/TestUtils.cs +++ b/tests/neo.UnitTests/TestUtils.cs @@ -4,6 +4,7 @@ using Neo.Ledger; using Neo.Network.P2P.Payloads; using Neo.SmartContract.Manifest; +using Neo.SmartContract; using Neo.VM; using Neo.Wallets.NEP6; using System; @@ -64,6 +65,33 @@ internal static ContractState GetContract() }; } + internal static ContractState GetContract(byte[] script) + { + return new ContractState + { + Id = 1, + Script = script, + Manifest = ContractManifest.CreateDefault(script.ToScriptHash()) + }; + } + + internal static StorageItem GetStorageItem(byte[] value) + { + return new StorageItem + { + Value = value + }; + } + + internal static StorageKey GetStorageKey(int id, byte[] keyValue) + { + return new StorageKey + { + Id = id, + Key = keyValue + }; + } + public static void SetupHeaderWithValues(Header header, UInt256 val256, out UInt256 merkRootVal, out UInt160 val160, out ulong timestampVal, out uint indexVal, out Witness scriptVal) { setupBlockBaseWithValues(header, val256, out merkRootVal, out val160, out timestampVal, out indexVal, out scriptVal); From 9cbcfdc5a191b08d369fb2b941a6fba3858e60cc Mon Sep 17 00:00:00 2001 From: erikzhang Date: Tue, 17 Mar 2020 16:00:05 +0800 Subject: [PATCH 10/16] Update InteropService.Contract.cs --- src/neo/SmartContract/InteropService.Contract.cs | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/neo/SmartContract/InteropService.Contract.cs b/src/neo/SmartContract/InteropService.Contract.cs index e889b45311..a8fe795d43 100644 --- a/src/neo/SmartContract/InteropService.Contract.cs +++ b/src/neo/SmartContract/InteropService.Contract.cs @@ -1,3 +1,4 @@ +using Neo.Cryptography.ECC; using Neo.IO; using Neo.Ledger; using Neo.Persistence; @@ -19,12 +20,12 @@ public static class Contract public static readonly InteropDescriptor Call = Register("System.Contract.Call", Contract_Call, 0_01000000, TriggerType.System | TriggerType.Application, CallFlags.AllowCall); public static readonly InteropDescriptor CallEx = Register("System.Contract.CallEx", Contract_CallEx, 0_01000000, TriggerType.System | TriggerType.Application, CallFlags.AllowCall); public static readonly InteropDescriptor IsStandard = Register("System.Contract.IsStandard", Contract_IsStandard, 0_00030000, TriggerType.All, CallFlags.None); - + /// /// Calculate corresponding account scripthash for given public key /// public static readonly InteropDescriptor CreateStandardAccount = Register("System.Contract.CreateStandardAccount", Contract_CreateStandardAccount, 0_00010000, TriggerType.All, CallFlags.None); - + private static long GetDeploymentPrice(EvaluationStack stack, StoreView snapshot) { int size = stack.Peek(0).GetByteLength() + stack.Peek(1).GetByteLength(); @@ -174,9 +175,9 @@ private static bool Contract_IsStandard(ApplicationEngine engine) private static bool Contract_CreateStandardAccount(ApplicationEngine engine) { - ReadOnlySpan pubKey = engine.CurrentContext.EvaluationStack.Pop().GetSpan(); - byte[] scriptHash = SmartContract.Contract.CreateSignatureRedeemScript(Cryptography.ECC.ECPoint.FromBytes(pubKey.ToArray(), Cryptography.ECC.ECCurve.Secp256r1)).ToScriptHash().ToArray(); - engine.CurrentContext.EvaluationStack.Push(scriptHash); + if (!engine.TryPop(out ReadOnlySpan pubKey)) return false; + UInt160 scriptHash = SmartContract.Contract.CreateSignatureRedeemScript(ECPoint.DecodePoint(pubKey, ECCurve.Secp256r1)).ToScriptHash(); + engine.CurrentContext.EvaluationStack.Push(scriptHash.ToArray()); return true; } } From 93fe8a70e06b11452b057ec726dac82d0dc963d4 Mon Sep 17 00:00:00 2001 From: Jin Qiao Date: Wed, 18 Mar 2020 11:08:38 +0800 Subject: [PATCH 11/16] Code optimization --- .../SmartContract/InteropService.Encode.cs | 28 ------------------- .../SmartContract/UT_InteropService.cs | 10 ------- 2 files changed, 38 deletions(-) delete mode 100644 src/neo/SmartContract/InteropService.Encode.cs diff --git a/src/neo/SmartContract/InteropService.Encode.cs b/src/neo/SmartContract/InteropService.Encode.cs deleted file mode 100644 index b6ae883d0b..0000000000 --- a/src/neo/SmartContract/InteropService.Encode.cs +++ /dev/null @@ -1,28 +0,0 @@ -using Neo.Cryptography; -using Neo.IO; -using Neo.VM; -using Neo.Wallets; -using System; -using System.Linq; - -namespace Neo.SmartContract -{ - partial class InteropService - { - public static class Encode - { - /// - /// Convert public key to corresponding wallet account address - /// - public static readonly InteropDescriptor PubKeyToAddress = Register("Neo.Encode.PubKeyToAddress", Encode_PubKeyToAddress, 0_00010000, TriggerType.All, CallFlags.None); - - private static bool Encode_PubKeyToAddress(ApplicationEngine engine) - { - ReadOnlySpan pubKey = engine.CurrentContext.EvaluationStack.Pop().GetSpan(); - string address = SmartContract.Contract.CreateSignatureRedeemScript(Cryptography.ECC.ECPoint.FromBytes(pubKey.ToArray(), Cryptography.ECC.ECCurve.Secp256r1)).ToScriptHash().ToAddress(); - engine.CurrentContext.EvaluationStack.Push(address); - return true; - } - } - } -} diff --git a/tests/neo.UnitTests/SmartContract/UT_InteropService.cs b/tests/neo.UnitTests/SmartContract/UT_InteropService.cs index b669c3d288..d28b017a83 100644 --- a/tests/neo.UnitTests/SmartContract/UT_InteropService.cs +++ b/tests/neo.UnitTests/SmartContract/UT_InteropService.cs @@ -858,16 +858,6 @@ public void TestContract_Destroy() InteropService.Invoke(engine, InteropService.Contract.Destroy).Should().BeTrue(); } - [TestMethod] - public void TestEncode_PubKeyToAddress() - { - var engine = GetEngine(true, true); - byte[] data = "024b817ef37f2fc3d4a33fe36687e592d9f30fe24b3e28187dc8f12b3b3b2b839e".HexToBytes(); - engine.CurrentContext.EvaluationStack.Push(data); - InteropService.Invoke(engine, InteropService.Encode.PubKeyToAddress).Should().BeTrue(); - engine.CurrentContext.EvaluationStack.Pop().GetString().Should().BeEquivalentTo("NYXBPFgUM2Wa9wUdtEZV3zk1pLWamNEJB1"); - } - [TestMethod] public void TestContract_CreateStandardAccount() { From 5efda666426909e754f9d11c0c553bc4f5bc892d Mon Sep 17 00:00:00 2001 From: Jin Qiao Date: Thu, 19 Mar 2020 11:40:45 +0800 Subject: [PATCH 12/16] Add wrong public key test cases --- .../SmartContract/UT_InteropService.cs | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/tests/neo.UnitTests/SmartContract/UT_InteropService.cs b/tests/neo.UnitTests/SmartContract/UT_InteropService.cs index 3f69ec8065..3723282dc8 100644 --- a/tests/neo.UnitTests/SmartContract/UT_InteropService.cs +++ b/tests/neo.UnitTests/SmartContract/UT_InteropService.cs @@ -869,6 +869,34 @@ public void TestContract_CreateStandardAccount() engine.CurrentContext.EvaluationStack.Push(data); InteropService.Invoke(engine, InteropService.Contract.CreateStandardAccount).Should().BeTrue(); engine.CurrentContext.EvaluationStack.Pop().GetSpan().ToArray().Should().BeEquivalentTo(UInt160.Parse("0x2c847208959ec1cc94dd13bfe231fa622a404a8a").ToArray()); + + data = "064b817ef37f2fc3d4a33fe36687e592d9f30fe24b3e28187dc8f12b3b3b2b839e".HexToBytes(); + engine.CurrentContext.EvaluationStack.Push(data); + Assert.ThrowsException(()=>InteropService.Invoke(engine, InteropService.Contract.CreateStandardAccount)).Message.Should().BeEquivalentTo("Invalid point encoding 6"); + + data = "024b817ef37f2fc3d4a33fe36687e599f30fe24b3e28187dc8f12b3b3b2b839e".HexToBytes(); + engine.CurrentContext.EvaluationStack.Push(data); + Assert.ThrowsException(()=>InteropService.Invoke(engine, InteropService.Contract.CreateStandardAccount)).Message.Should().BeEquivalentTo("Incorrect length for compressed encoding"); + + data = "02ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff".HexToBytes(); + engine.CurrentContext.EvaluationStack.Push(data); + Assert.ThrowsException(() => InteropService.Invoke(engine, InteropService.Contract.CreateStandardAccount)).Message.Should().BeEquivalentTo("x value too large in field element"); + + data = "020fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff".HexToBytes(); + engine.CurrentContext.EvaluationStack.Push(data); + Assert.ThrowsException(() => InteropService.Invoke(engine, InteropService.Contract.CreateStandardAccount)).Message.Should().BeEquivalentTo("Invalid point compression"); + + data = "044b817ef37f2fc3d4a33fe36687e592d9f30fe24b3e28187dc8f12b3b3b2b839e".HexToBytes(); + engine.CurrentContext.EvaluationStack.Push(data); + Assert.ThrowsException(() => InteropService.Invoke(engine, InteropService.Contract.CreateStandardAccount)).Message.Should().BeEquivalentTo("Incorrect length for uncompressed/hybrid encoding"); + + data = "04ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff".HexToBytes(); + engine.CurrentContext.EvaluationStack.Push(data); + Assert.ThrowsException(() => InteropService.Invoke(engine, InteropService.Contract.CreateStandardAccount)).Message.Should().BeEquivalentTo("x value too large in field element"); + + data = "040fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff".HexToBytes(); + engine.CurrentContext.EvaluationStack.Push(data); + Assert.ThrowsException(() => InteropService.Invoke(engine, InteropService.Contract.CreateStandardAccount)).Message.Should().BeEquivalentTo("x value too large in field element"); } public static void LogEvent(object sender, LogEventArgs args) From fa70610474005e7ec33454b73e200ab9c12c94c3 Mon Sep 17 00:00:00 2001 From: Jin Qiao Date: Thu, 19 Mar 2020 15:22:22 +0800 Subject: [PATCH 13/16] Kick off new test --- tests/neo.UnitTests/SmartContract/UT_InteropService.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/neo.UnitTests/SmartContract/UT_InteropService.cs b/tests/neo.UnitTests/SmartContract/UT_InteropService.cs index 3723282dc8..838c21d943 100644 --- a/tests/neo.UnitTests/SmartContract/UT_InteropService.cs +++ b/tests/neo.UnitTests/SmartContract/UT_InteropService.cs @@ -866,6 +866,7 @@ public void TestContract_CreateStandardAccount() { var engine = GetEngine(true, true); byte[] data = "024b817ef37f2fc3d4a33fe36687e592d9f30fe24b3e28187dc8f12b3b3b2b839e".HexToBytes(); + engine.CurrentContext.EvaluationStack.Push(data); InteropService.Invoke(engine, InteropService.Contract.CreateStandardAccount).Should().BeTrue(); engine.CurrentContext.EvaluationStack.Pop().GetSpan().ToArray().Should().BeEquivalentTo(UInt160.Parse("0x2c847208959ec1cc94dd13bfe231fa622a404a8a").ToArray()); From 0e2a04be23c822214c68c754398fb947f35c220d Mon Sep 17 00:00:00 2001 From: Jin Qiao Date: Thu, 19 Mar 2020 15:30:09 +0800 Subject: [PATCH 14/16] format changing --- tests/neo.UnitTests/SmartContract/UT_InteropService.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/neo.UnitTests/SmartContract/UT_InteropService.cs b/tests/neo.UnitTests/SmartContract/UT_InteropService.cs index 838c21d943..a1a222723b 100644 --- a/tests/neo.UnitTests/SmartContract/UT_InteropService.cs +++ b/tests/neo.UnitTests/SmartContract/UT_InteropService.cs @@ -873,11 +873,11 @@ public void TestContract_CreateStandardAccount() data = "064b817ef37f2fc3d4a33fe36687e592d9f30fe24b3e28187dc8f12b3b3b2b839e".HexToBytes(); engine.CurrentContext.EvaluationStack.Push(data); - Assert.ThrowsException(()=>InteropService.Invoke(engine, InteropService.Contract.CreateStandardAccount)).Message.Should().BeEquivalentTo("Invalid point encoding 6"); + Assert.ThrowsException(() => InteropService.Invoke(engine, InteropService.Contract.CreateStandardAccount)).Message.Should().BeEquivalentTo("Invalid point encoding 6"); data = "024b817ef37f2fc3d4a33fe36687e599f30fe24b3e28187dc8f12b3b3b2b839e".HexToBytes(); engine.CurrentContext.EvaluationStack.Push(data); - Assert.ThrowsException(()=>InteropService.Invoke(engine, InteropService.Contract.CreateStandardAccount)).Message.Should().BeEquivalentTo("Incorrect length for compressed encoding"); + Assert.ThrowsException(() => InteropService.Invoke(engine, InteropService.Contract.CreateStandardAccount)).Message.Should().BeEquivalentTo("Incorrect length for compressed encoding"); data = "02ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff".HexToBytes(); engine.CurrentContext.EvaluationStack.Push(data); From 0a37b33f2fb90fe5cf99b3026cba9967d25c70e5 Mon Sep 17 00:00:00 2001 From: Jin Qiao Date: Fri, 27 Mar 2020 14:02:19 +0800 Subject: [PATCH 15/16] Code optimization --- src/neo/SmartContract/InteropService.Contract.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/neo/SmartContract/InteropService.Contract.cs b/src/neo/SmartContract/InteropService.Contract.cs index fa1f1a42c0..41c6bbe358 100644 --- a/src/neo/SmartContract/InteropService.Contract.cs +++ b/src/neo/SmartContract/InteropService.Contract.cs @@ -177,7 +177,7 @@ private static bool Contract_CreateStandardAccount(ApplicationEngine engine) { if (!engine.TryPop(out ReadOnlySpan pubKey)) return false; UInt160 scriptHash = SmartContract.Contract.CreateSignatureRedeemScript(ECPoint.DecodePoint(pubKey, ECCurve.Secp256r1)).ToScriptHash(); - engine.CurrentContext.EvaluationStack.Push(scriptHash.ToArray()); + engine.Push(scriptHash.ToArray()); return true; } } From 09b285201df9b93ccae475a6bfe0b26e9037ee67 Mon Sep 17 00:00:00 2001 From: Jin Qiao Date: Wed, 1 Apr 2020 10:59:43 +0800 Subject: [PATCH 16/16] Add comment --- src/neo/SmartContract/InteropService.Contract.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/neo/SmartContract/InteropService.Contract.cs b/src/neo/SmartContract/InteropService.Contract.cs index 41c6bbe358..bb85af6091 100644 --- a/src/neo/SmartContract/InteropService.Contract.cs +++ b/src/neo/SmartContract/InteropService.Contract.cs @@ -23,6 +23,7 @@ public static class Contract /// /// Calculate corresponding account scripthash for given public key + /// Warning: check first that input public key is valid, before creating the script. /// public static readonly InteropDescriptor CreateStandardAccount = Register("System.Contract.CreateStandardAccount", Contract_CreateStandardAccount, 0_00010000, TriggerType.All, CallFlags.None);