diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml
index c5f315dd27..71602a6df2 100644
--- a/.github/workflows/main.yml
+++ b/.github/workflows/main.yml
@@ -24,7 +24,7 @@ jobs:
- name: Check Format (*.cs)
run: dotnet format --verify-no-changes --verbosity diagnostic
- Build-Test-Neo-Cli:
+ Test-Everything:
needs: [Format]
timeout-minutes: 15
runs-on: ubuntu-latest
@@ -37,16 +37,16 @@ jobs:
with:
dotnet-version: ${{ env.DOTNET_VERSION }}
- - name: Build (Neo.CLI)
- run: dotnet build ./src/Neo.CLI --output ./out/Neo.CLI
+ - name: Build (Everything)
+ run: dotnet build
- name: Install dependencies
run: |
sudo apt-get install libleveldb-dev expect
- find ./out -name 'config.json' | xargs perl -pi -e 's|LevelDBStore|MemoryStore|g'
+ find ./bin -name 'config.json' | xargs perl -pi -e 's|LevelDBStore|MemoryStore|g'
- name: Run tests with expect
- run: expect ./scripts/Neo.CLI/test-neo-cli.expect
+ run: expect ./scripts/Neo.CLI/test-neo-cli.exp
Test:
needs: [Format]
@@ -124,19 +124,13 @@ jobs:
- name: Set Version
run: git rev-list --count HEAD | xargs printf 'CI%05d' | xargs -I{} echo 'VERSION_SUFFIX={}' >> $GITHUB_ENV
- - name : Pack (Neo)
+ - name : Pack (Everything)
run: |
dotnet pack \
--configuration Release \
--output ./out \
--version-suffix ${{ env.VERSION_SUFFIX }}
- - name: Remove Unwanted Files
- working-directory: ./out
- run: |
- rm -v Neo.CLI*
- rm -v Neo.GUI*
-
- name: Publish to Github Packages
working-directory: ./out
run: |
diff --git a/scripts/Neo.CLI/test-neo-cli.expect b/scripts/Neo.CLI/test-neo-cli.exp
similarity index 80%
rename from scripts/Neo.CLI/test-neo-cli.expect
rename to scripts/Neo.CLI/test-neo-cli.exp
index 8319c18f8e..e7124402c3 100644
--- a/scripts/Neo.CLI/test-neo-cli.expect
+++ b/scripts/Neo.CLI/test-neo-cli.exp
@@ -1,12 +1,12 @@
-#!/usr/bin/expect -f
+#!/usr/bin/expect -d -f
#
# This script uses expect to test neo-cli
#
set timeout 10
-
+exp_internal true
# Start neo-cli
-spawn dotnet out/Neo.CLI/neo-cli.dll
+spawn dotnet ./bin/Neo.CLI/net8.0/neo-cli.dll
# Expect the main input prompt
expect {
@@ -18,7 +18,7 @@ expect {
#
# Test 'create wallet'
#
-send "create wallet test-wallet1.json\n"
+send "create wallet ./bin/Neo.CLI/test-wallet1.json\n"
expect {
"password:" { send "asd\n" }
@@ -42,7 +42,7 @@ expect {
#
# Test 'create wallet'
#
-send "create wallet test-wallet2.json L2ArHTuiDL4FHu4nfyhamrG8XVYB4QyRbmhj7vD6hFMB5iAMSTf6\n"
+send "create wallet ./bin/Neo.CLI/test-wallet2.json L2ArHTuiDL4FHu4nfyhamrG8XVYB4QyRbmhj7vD6hFMB5iAMSTf6\n"
expect {
"password:" { send "abcd\n" }
diff --git a/src/Neo.Json/Neo.Json.csproj b/src/Neo.Json/Neo.Json.csproj
index 15924436e7..8d8fd33ac9 100644
--- a/src/Neo.Json/Neo.Json.csproj
+++ b/src/Neo.Json/Neo.Json.csproj
@@ -10,7 +10,7 @@
-
+
diff --git a/src/Neo/Ledger/MemoryPool.cs b/src/Neo/Ledger/MemoryPool.cs
index 7f59bc6e92..ff9c6b1069 100644
--- a/src/Neo/Ledger/MemoryPool.cs
+++ b/src/Neo/Ledger/MemoryPool.cs
@@ -659,5 +659,24 @@ internal bool ReVerifyTopUnverifiedTransactionsIfNeeded(int maxToVerify, DataCac
return _unverifiedTransactions.Count > 0;
}
+
+ // This method is only for test purpose
+ // Do not use this method outside of unit tests
+ internal void Clear()
+ {
+ _txRwLock.EnterReadLock();
+ try
+ {
+ _unsortedTransactions.Clear();
+ _conflicts.Clear();
+ _sortedTransactions.Clear();
+ _unverifiedTransactions.Clear();
+ _unverifiedSortedTransactions.Clear();
+ }
+ finally
+ {
+ _txRwLock.ExitReadLock();
+ }
+ }
}
}
diff --git a/src/Neo/SmartContract/Manifest/ContractAbi.cs b/src/Neo/SmartContract/Manifest/ContractAbi.cs
index 3660d1a99e..cedd431d62 100644
--- a/src/Neo/SmartContract/Manifest/ContractAbi.cs
+++ b/src/Neo/SmartContract/Manifest/ContractAbi.cs
@@ -62,8 +62,8 @@ public static ContractAbi FromJson(JObject json)
{
ContractAbi abi = new()
{
- Methods = ((JArray)json["methods"]).Select(u => ContractMethodDescriptor.FromJson((JObject)u)).ToArray(),
- Events = ((JArray)json["events"]).Select(u => ContractEventDescriptor.FromJson((JObject)u)).ToArray()
+ Methods = ((JArray)json!["methods"])?.Select(u => ContractMethodDescriptor.FromJson((JObject)u)).ToArray() ?? [],
+ Events = ((JArray)json!["events"])?.Select(u => ContractEventDescriptor.FromJson((JObject)u)).ToArray() ?? []
};
if (abi.Methods.Length == 0) throw new FormatException();
return abi;
diff --git a/src/Neo/SmartContract/Manifest/ContractManifest.cs b/src/Neo/SmartContract/Manifest/ContractManifest.cs
index 078e8fd35e..b1bd317e41 100644
--- a/src/Neo/SmartContract/Manifest/ContractManifest.cs
+++ b/src/Neo/SmartContract/Manifest/ContractManifest.cs
@@ -112,20 +112,21 @@ public static ContractManifest FromJson(JObject json)
{
ContractManifest manifest = new()
{
- Name = json["name"].GetString(),
- Groups = ((JArray)json["groups"]).Select(u => ContractGroup.FromJson((JObject)u)).ToArray(),
- SupportedStandards = ((JArray)json["supportedstandards"]).Select(u => u.GetString()).ToArray(),
+ Name = json["name"]!.GetString(),
+ Groups = ((JArray)json["groups"])?.Select(u => ContractGroup.FromJson((JObject)u)).ToArray() ?? [],
+ SupportedStandards = ((JArray)json["supportedstandards"])?.Select(u => u.GetString()).ToArray() ?? [],
Abi = ContractAbi.FromJson((JObject)json["abi"]),
- Permissions = ((JArray)json["permissions"]).Select(u => ContractPermission.FromJson((JObject)u)).ToArray(),
+ Permissions = ((JArray)json["permissions"])?.Select(u => ContractPermission.FromJson((JObject)u)).ToArray() ?? [],
Trusts = WildcardContainer.FromJson(json["trusts"], u => ContractPermissionDescriptor.FromJson((JString)u)),
Extra = (JObject)json["extra"]
};
+
if (string.IsNullOrEmpty(manifest.Name))
throw new FormatException();
_ = manifest.Groups.ToDictionary(p => p.PubKey);
if (json["features"] is not JObject features || features.Count != 0)
throw new FormatException();
- if (manifest.SupportedStandards.Any(p => string.IsNullOrEmpty(p)))
+ if (manifest.SupportedStandards.Any(string.IsNullOrEmpty))
throw new FormatException();
_ = manifest.SupportedStandards.ToDictionary(p => p);
_ = manifest.Permissions.ToDictionary(p => p.Contract);
diff --git a/src/Plugins/RpcServer/RpcServer.Node.cs b/src/Plugins/RpcServer/RpcServer.Node.cs
index 79a8884a0f..21ca583090 100644
--- a/src/Plugins/RpcServer/RpcServer.Node.cs
+++ b/src/Plugins/RpcServer/RpcServer.Node.cs
@@ -110,7 +110,7 @@ private static JObject GetRelayResult(VerifyResult reason, UInt256 hash)
}
[RpcMethod]
- protected virtual JToken GetVersion(JArray _params)
+ protected internal virtual JToken GetVersion(JArray _params)
{
JObject json = new();
json["tcpport"] = localNode.ListenerTcpPort;
@@ -150,7 +150,7 @@ private static string StripPrefix(string s, string prefix)
}
[RpcMethod]
- protected virtual JToken SendRawTransaction(JArray _params)
+ protected internal virtual JToken SendRawTransaction(JArray _params)
{
Transaction tx = Result.Ok_Or(() => Convert.FromBase64String(_params[0].AsString()).AsSerializable(), RpcError.InvalidParams.WithData($"Invalid Transaction Format: {_params[0]}"));
RelayResult reason = system.Blockchain.Ask(tx).Result;
@@ -158,7 +158,7 @@ protected virtual JToken SendRawTransaction(JArray _params)
}
[RpcMethod]
- protected virtual JToken SubmitBlock(JArray _params)
+ protected internal virtual JToken SubmitBlock(JArray _params)
{
Block block = Result.Ok_Or(() => Convert.FromBase64String(_params[0].AsString()).AsSerializable(), RpcError.InvalidParams.WithData($"Invalid Block Format: {_params[0]}"));
RelayResult reason = system.Blockchain.Ask(block).Result;
diff --git a/tests/Neo.Json.UnitTests/UT_JArray.cs b/tests/Neo.Json.UnitTests/UT_JArray.cs
index 40388d11fc..b6c603ca2a 100644
--- a/tests/Neo.Json.UnitTests/UT_JArray.cs
+++ b/tests/Neo.Json.UnitTests/UT_JArray.cs
@@ -254,5 +254,18 @@ public void TestAsString()
var s = jArray.AsString();
Assert.AreEqual(s, "{\"name\":\"alice\",\"age\":30,\"score\":100.001,\"gender\":\"female\",\"isMarried\":true,\"pet\":{\"name\":\"Tom\",\"type\":\"cat\"}},{\"name\":\"bob\",\"age\":100000,\"score\":0.001,\"gender\":\"male\",\"isMarried\":false,\"pet\":{\"name\":\"Paul\",\"type\":\"dog\"}}");
}
+
+ [TestMethod]
+ public void TestClone()
+ {
+ var jArray = new JArray
+ {
+ alice,
+ bob,
+ };
+ var a = jArray.AsString();
+ var b = jArray.Clone().AsString();
+ a.Should().Be(b);
+ }
}
}
diff --git a/tests/Neo.Json.UnitTests/UT_JBoolean.cs b/tests/Neo.Json.UnitTests/UT_JBoolean.cs
index 3ab19bd1b3..0e81e99c35 100644
--- a/tests/Neo.Json.UnitTests/UT_JBoolean.cs
+++ b/tests/Neo.Json.UnitTests/UT_JBoolean.cs
@@ -36,8 +36,10 @@ public void TestEqual()
{
Assert.IsTrue(jTrue.Equals(new JBoolean(true)));
Assert.IsTrue(jTrue == new JBoolean(true));
+ Assert.IsTrue(jTrue != new JBoolean(false));
Assert.IsTrue(jFalse.Equals(new JBoolean()));
Assert.IsTrue(jFalse == new JBoolean());
+ Assert.IsTrue(jFalse.GetBoolean().ToString().ToLowerInvariant() == jFalse.ToString());
}
}
}
diff --git a/tests/Neo.Json.UnitTests/UT_JNumber.cs b/tests/Neo.Json.UnitTests/UT_JNumber.cs
index 6eb0598fd3..df8bdca619 100644
--- a/tests/Neo.Json.UnitTests/UT_JNumber.cs
+++ b/tests/Neo.Json.UnitTests/UT_JNumber.cs
@@ -9,6 +9,8 @@
// Redistribution and use in source and binary forms with or without
// modifications are permitted.
+using System.Numerics;
+
namespace Neo.Json.UnitTests
{
enum Woo
@@ -72,6 +74,27 @@ public void TestEqual()
Assert.IsTrue(minInt.Equals(JNumber.MIN_SAFE_INTEGER));
Assert.IsTrue(minInt == JNumber.MIN_SAFE_INTEGER);
Assert.IsTrue(zero == new JNumber());
+ Assert.IsFalse(zero != new JNumber());
+ Assert.IsTrue(zero.AsNumber() == zero.GetNumber());
+ Assert.IsFalse(zero == null);
+
+ var jnum = new JNumber(1);
+ jnum.Equals(new JNumber(1)).Should().BeTrue();
+ jnum.Equals((uint)1).Should().BeTrue();
+ jnum.Equals((int)1).Should().BeTrue();
+ jnum.Equals((ulong)1).Should().BeTrue();
+ jnum.Equals((long)1).Should().BeTrue();
+ jnum.Equals((byte)1).Should().BeTrue();
+ jnum.Equals((sbyte)1).Should().BeTrue();
+ jnum.Equals((short)1).Should().BeTrue();
+ jnum.Equals((ushort)1).Should().BeTrue();
+ jnum.Equals((decimal)1).Should().BeTrue();
+ jnum.Equals((float)1).Should().BeTrue();
+ jnum.Equals((double)1).Should().BeTrue();
+ jnum.Equals(null).Should().BeFalse();
+ var x = jnum;
+ jnum.Equals(x).Should().BeTrue();
+ Assert.ThrowsException(() => jnum.Equals(new BigInteger(1)));
}
}
}
diff --git a/tests/Neo.Json.UnitTests/UT_JString.cs b/tests/Neo.Json.UnitTests/UT_JString.cs
index 7e2bec9834..3f0ca159ab 100644
--- a/tests/Neo.Json.UnitTests/UT_JString.cs
+++ b/tests/Neo.Json.UnitTests/UT_JString.cs
@@ -63,10 +63,22 @@ public void TestGetEnum()
public void TestEqual()
{
var str = "hello world";
+ var str2 = "hello world2";
var jString = new JString(str);
- Assert.IsTrue(jString.Equals(str));
+ var jString2 = new JString(str2);
+
Assert.IsTrue(jString == str);
- Assert.IsTrue(jString != "hello world2");
+ Assert.IsFalse(jString == null);
+ Assert.IsTrue(jString != str2);
+ Assert.IsFalse(jString == str2);
+
+ Assert.AreEqual(str, jString.GetString());
+ Assert.IsTrue(jString.Equals(str));
+ Assert.IsFalse(jString.Equals(jString2));
+ Assert.IsFalse(jString.Equals(null));
+ Assert.IsFalse(jString.Equals(123));
+ var reference = jString;
+ Assert.IsTrue(jString.Equals(reference));
}
}
}
diff --git a/tests/Neo.Plugins.RpcServer.Tests/TestBlockchain.cs b/tests/Neo.Plugins.RpcServer.Tests/TestBlockchain.cs
index 7708db6fdc..3ed48e982c 100644
--- a/tests/Neo.Plugins.RpcServer.Tests/TestBlockchain.cs
+++ b/tests/Neo.Plugins.RpcServer.Tests/TestBlockchain.cs
@@ -12,6 +12,7 @@
using Akka.Actor;
using Neo.Ledger;
using Neo.Persistence;
+using Neo.UnitTests;
using System;
namespace Neo.Plugins.RpcServer.Tests
diff --git a/tests/Neo.Plugins.RpcServer.Tests/TestProtocolSettings.cs b/tests/Neo.Plugins.RpcServer.Tests/TestProtocolSettings.cs
deleted file mode 100644
index edf2df39fb..0000000000
--- a/tests/Neo.Plugins.RpcServer.Tests/TestProtocolSettings.cs
+++ /dev/null
@@ -1,65 +0,0 @@
-// Copyright (C) 2015-2024 The Neo Project.
-//
-// TestProtocolSettings.cs file belongs to the neo project and is free
-// software distributed under the MIT software license, see the
-// accompanying file LICENSE in the main directory of the
-// repository or http://www.opensource.org/licenses/mit-license.php
-// for more details.
-//
-// Redistribution and use in source and binary forms with or without
-// modifications are permitted.
-
-using Neo.Cryptography.ECC;
-
-namespace Neo.Plugins.RpcServer.Tests
-{
- public static class TestProtocolSettings
- {
- public static readonly ProtocolSettings Default = new()
- {
- Network = 0x334F454Eu,
- AddressVersion = ProtocolSettings.Default.AddressVersion,
- StandbyCommittee = new[]
- {
- //Validators
- ECPoint.Parse("03b209fd4f53a7170ea4444e0cb0a6bb6a53c2bd016926989cf85f9b0fba17a70c", ECCurve.Secp256r1),
- ECPoint.Parse("02df48f60e8f3e01c48ff40b9b7f1310d7a8b2a193188befe1c2e3df740e895093", ECCurve.Secp256r1),
- ECPoint.Parse("03b8d9d5771d8f513aa0869b9cc8d50986403b78c6da36890638c3d46a5adce04a", ECCurve.Secp256r1),
- ECPoint.Parse("02ca0e27697b9c248f6f16e085fd0061e26f44da85b58ee835c110caa5ec3ba554", ECCurve.Secp256r1),
- ECPoint.Parse("024c7b7fb6c310fccf1ba33b082519d82964ea93868d676662d4a59ad548df0e7d", ECCurve.Secp256r1),
- ECPoint.Parse("02aaec38470f6aad0042c6e877cfd8087d2676b0f516fddd362801b9bd3936399e", ECCurve.Secp256r1),
- ECPoint.Parse("02486fd15702c4490a26703112a5cc1d0923fd697a33406bd5a1c00e0013b09a70", ECCurve.Secp256r1),
- //Other Members
- ECPoint.Parse("023a36c72844610b4d34d1968662424011bf783ca9d984efa19a20babf5582f3fe", ECCurve.Secp256r1),
- ECPoint.Parse("03708b860c1de5d87f5b151a12c2a99feebd2e8b315ee8e7cf8aa19692a9e18379", ECCurve.Secp256r1),
- ECPoint.Parse("03c6aa6e12638b36e88adc1ccdceac4db9929575c3e03576c617c49cce7114a050", ECCurve.Secp256r1),
- ECPoint.Parse("03204223f8c86b8cd5c89ef12e4f0dbb314172e9241e30c9ef2293790793537cf0", ECCurve.Secp256r1),
- ECPoint.Parse("02a62c915cf19c7f19a50ec217e79fac2439bbaad658493de0c7d8ffa92ab0aa62", ECCurve.Secp256r1),
- ECPoint.Parse("03409f31f0d66bdc2f70a9730b66fe186658f84a8018204db01c106edc36553cd0", ECCurve.Secp256r1),
- ECPoint.Parse("0288342b141c30dc8ffcde0204929bb46aed5756b41ef4a56778d15ada8f0c6654", ECCurve.Secp256r1),
- ECPoint.Parse("020f2887f41474cfeb11fd262e982051c1541418137c02a0f4961af911045de639", ECCurve.Secp256r1),
- ECPoint.Parse("0222038884bbd1d8ff109ed3bdef3542e768eef76c1247aea8bc8171f532928c30", ECCurve.Secp256r1),
- ECPoint.Parse("03d281b42002647f0113f36c7b8efb30db66078dfaaa9ab3ff76d043a98d512fde", ECCurve.Secp256r1),
- ECPoint.Parse("02504acbc1f4b3bdad1d86d6e1a08603771db135a73e61c9d565ae06a1938cd2ad", ECCurve.Secp256r1),
- ECPoint.Parse("0226933336f1b75baa42d42b71d9091508b638046d19abd67f4e119bf64a7cfb4d", ECCurve.Secp256r1),
- ECPoint.Parse("03cdcea66032b82f5c30450e381e5295cae85c5e6943af716cc6b646352a6067dc", ECCurve.Secp256r1),
- ECPoint.Parse("02cd5a5547119e24feaa7c2a0f37b8c9366216bab7054de0065c9be42084003c8a", ECCurve.Secp256r1)
- },
- ValidatorsCount = 7,
- SeedList = new[]
- {
- "seed1.neo.org:10333",
- "seed2.neo.org:10333",
- "seed3.neo.org:10333",
- "seed4.neo.org:10333",
- "seed5.neo.org:10333"
- },
- MillisecondsPerBlock = ProtocolSettings.Default.MillisecondsPerBlock,
- MaxTransactionsPerBlock = ProtocolSettings.Default.MaxTransactionsPerBlock,
- MemoryPoolMaxTransactions = ProtocolSettings.Default.MemoryPoolMaxTransactions,
- MaxTraceableBlocks = ProtocolSettings.Default.MaxTraceableBlocks,
- InitialGasDistribution = ProtocolSettings.Default.InitialGasDistribution,
- Hardforks = ProtocolSettings.Default.Hardforks
- };
- }
-}
diff --git a/tests/Neo.Plugins.RpcServer.Tests/UT_RpcServer.Blockchain.cs b/tests/Neo.Plugins.RpcServer.Tests/UT_RpcServer.Blockchain.cs
index 0dc89f7ba5..c9007f6580 100644
--- a/tests/Neo.Plugins.RpcServer.Tests/UT_RpcServer.Blockchain.cs
+++ b/tests/Neo.Plugins.RpcServer.Tests/UT_RpcServer.Blockchain.cs
@@ -9,6 +9,7 @@
// Redistribution and use in source and binary forms with or without
// modifications are permitted.
+using Akka.Actor;
using Akka.Util.Internal;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Neo.IO;
@@ -101,8 +102,9 @@ public void TestGetBlockHash()
{
var snapshot = _neoSystem.GetSnapshotCache();
var block = TestUtils.CreateBlockWithValidTransactions(snapshot, _wallet, _walletAccount, 3);
- TestUtils.BlocksAdd(snapshot, block.Hash, block);
- snapshot.Commit();
+ // TestUtils.BlocksAdd(snapshot, block.Hash, block);
+ // snapshot.Commit();
+ var reason = _neoSystem.Blockchain.Ask(block).Result;
var expectedHash = block.Hash.ToString();
var result = _rpcServer.GetBlockHash(new JArray(block.Index));
Assert.AreEqual(expectedHash, result.AsString());
diff --git a/tests/Neo.Plugins.RpcServer.Tests/UT_RpcServer.Node.cs b/tests/Neo.Plugins.RpcServer.Tests/UT_RpcServer.Node.cs
new file mode 100644
index 0000000000..b75706e001
--- /dev/null
+++ b/tests/Neo.Plugins.RpcServer.Tests/UT_RpcServer.Node.cs
@@ -0,0 +1,291 @@
+// Copyright (C) 2015-2024 The Neo Project.
+//
+// UT_RpcServer.Node.cs file belongs to the neo project and is free
+// software distributed under the MIT software license, see the
+// accompanying file LICENSE in the main directory of the
+// repository or http://www.opensource.org/licenses/mit-license.php
+// for more details.
+//
+// Redistribution and use in source and binary forms with or without
+// modifications are permitted.
+
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using Neo.IO;
+using Neo.Json;
+using Neo.Network.P2P.Payloads;
+using Neo.SmartContract.Native;
+using Neo.UnitTests;
+using System;
+
+namespace Neo.Plugins.RpcServer.Tests
+{
+ partial class UT_RpcServer
+ {
+ [TestMethod]
+ public void TestGetVersion()
+ {
+ var result = _rpcServer.GetVersion(new JArray());
+ Assert.IsInstanceOfType(result, typeof(JObject));
+
+ var json = (JObject)result;
+ Assert.IsTrue(json.ContainsProperty("tcpport"));
+ Assert.IsTrue(json.ContainsProperty("nonce"));
+ Assert.IsTrue(json.ContainsProperty("useragent"));
+
+ Assert.IsTrue(json.ContainsProperty("protocol"));
+ var protocol = (JObject)json["protocol"];
+ Assert.IsTrue(protocol.ContainsProperty("addressversion"));
+ Assert.IsTrue(protocol.ContainsProperty("network"));
+ Assert.IsTrue(protocol.ContainsProperty("validatorscount"));
+ Assert.IsTrue(protocol.ContainsProperty("msperblock"));
+ Assert.IsTrue(protocol.ContainsProperty("maxtraceableblocks"));
+ Assert.IsTrue(protocol.ContainsProperty("maxvaliduntilblockincrement"));
+ Assert.IsTrue(protocol.ContainsProperty("maxtransactionsperblock"));
+ Assert.IsTrue(protocol.ContainsProperty("memorypoolmaxtransactions"));
+ }
+
+ #region SendRawTransaction Tests
+
+ [TestMethod]
+ public void TestSendRawTransaction_Normal()
+ {
+ var snapshot = _neoSystem.GetSnapshot();
+ var tx = TestUtils.CreateValidTx(snapshot, _wallet, _walletAccount);
+ var txString = Convert.ToBase64String(tx.ToArray());
+
+ var result = _rpcServer.SendRawTransaction(new JArray(txString));
+ Assert.IsInstanceOfType(result, typeof(JObject));
+ Assert.IsTrue(((JObject)result).ContainsProperty("hash"));
+ }
+
+ [TestMethod]
+ public void TestSendRawTransaction_InvalidTransactionFormat()
+ {
+ Assert.ThrowsException(() =>
+ _rpcServer.SendRawTransaction(new JArray("invalid_transaction_string")),
+ "Should throw RpcException for invalid transaction format");
+ }
+
+ [TestMethod]
+ public void TestSendRawTransaction_InsufficientBalance()
+ {
+ var snapshot = _neoSystem.GetSnapshot();
+ var tx = TestUtils.CreateInvalidTransaction(snapshot, _wallet, _walletAccount, TestUtils.InvalidTransactionType.InsufficientBalance);
+ var txString = Convert.ToBase64String(tx.ToArray());
+
+ var exception = Assert.ThrowsException(() =>
+ _rpcServer.SendRawTransaction(new JArray(txString)),
+ "Should throw RpcException for insufficient balance");
+ Assert.AreEqual(RpcError.InsufficientFunds.Code, exception.HResult);
+ }
+
+ [TestMethod]
+ public void TestSendRawTransaction_InvalidSignature()
+ {
+ var snapshot = _neoSystem.GetSnapshot();
+ var tx = TestUtils.CreateInvalidTransaction(snapshot, _wallet, _walletAccount, TestUtils.InvalidTransactionType.InvalidSignature);
+ var txString = Convert.ToBase64String(tx.ToArray());
+
+ var exception = Assert.ThrowsException(() =>
+ _rpcServer.SendRawTransaction(new JArray(txString)),
+ "Should throw RpcException for invalid signature");
+ Assert.AreEqual(RpcError.InvalidSignature.Code, exception.HResult);
+ }
+
+ [TestMethod]
+ public void TestSendRawTransaction_InvalidScript()
+ {
+ var snapshot = _neoSystem.GetSnapshot();
+ var tx = TestUtils.CreateInvalidTransaction(snapshot, _wallet, _walletAccount, TestUtils.InvalidTransactionType.InvalidScript);
+ var txString = Convert.ToBase64String(tx.ToArray());
+
+ var exception = Assert.ThrowsException(() =>
+ _rpcServer.SendRawTransaction(new JArray(txString)),
+ "Should throw RpcException for invalid script");
+ Assert.AreEqual(RpcError.InvalidScript.Code, exception.HResult);
+ }
+
+ [TestMethod]
+ public void TestSendRawTransaction_InvalidAttribute()
+ {
+ var snapshot = _neoSystem.GetSnapshot();
+ var tx = TestUtils.CreateInvalidTransaction(snapshot, _wallet, _walletAccount, TestUtils.InvalidTransactionType.InvalidAttribute);
+ var txString = Convert.ToBase64String(tx.ToArray());
+
+ var exception = Assert.ThrowsException(() =>
+ _rpcServer.SendRawTransaction(new JArray(txString)),
+ "Should throw RpcException for invalid attribute");
+ // Transaction with invalid attribute can not pass the Transaction deserialization
+ // and will throw invalid params exception.
+ Assert.AreEqual(RpcError.InvalidParams.Code, exception.HResult);
+ }
+
+ [TestMethod]
+ public void TestSendRawTransaction_Oversized()
+ {
+ var snapshot = _neoSystem.GetSnapshot();
+ var tx = TestUtils.CreateInvalidTransaction(snapshot, _wallet, _walletAccount, TestUtils.InvalidTransactionType.Oversized);
+ var txString = Convert.ToBase64String(tx.ToArray());
+
+ var exception = Assert.ThrowsException(() =>
+ _rpcServer.SendRawTransaction(new JArray(txString)),
+ "Should throw RpcException for invalid format transaction");
+ // Oversized transaction will not pass the deserialization.
+ Assert.AreEqual(RpcError.InvalidParams.Code, exception.HResult);
+ }
+
+ [TestMethod]
+ public void TestSendRawTransaction_Expired()
+ {
+ var snapshot = _neoSystem.GetSnapshot();
+ var tx = TestUtils.CreateInvalidTransaction(snapshot, _wallet, _walletAccount, TestUtils.InvalidTransactionType.Expired);
+ var txString = Convert.ToBase64String(tx.ToArray());
+
+ var exception = Assert.ThrowsException(() =>
+ _rpcServer.SendRawTransaction(new JArray(txString)),
+ "Should throw RpcException for expired transaction");
+ Assert.AreEqual(RpcError.ExpiredTransaction.Code, exception.HResult);
+ }
+
+ [TestMethod]
+ public void TestSendRawTransaction_PolicyFailed()
+ {
+ var snapshot = _neoSystem.GetSnapshot();
+ var tx = TestUtils.CreateValidTx(snapshot, _wallet, _walletAccount);
+ var txString = Convert.ToBase64String(tx.ToArray());
+ NativeContract.Policy.BlockAccount(snapshot, _walletAccount.ScriptHash);
+ snapshot.Commit();
+
+ var exception = Assert.ThrowsException(() =>
+ _rpcServer.SendRawTransaction(new JArray(txString)),
+ "Should throw RpcException for conflicting transaction");
+ Assert.AreEqual(RpcError.PolicyFailed.Code, exception.HResult);
+ }
+
+ [TestMethod]
+ public void TestSendRawTransaction_AlreadyInPool()
+ {
+ var snapshot = _neoSystem.GetSnapshot();
+ var tx = TestUtils.CreateValidTx(snapshot, _wallet, _walletAccount);
+ _neoSystem.MemPool.TryAdd(tx, snapshot);
+ var txString = Convert.ToBase64String(tx.ToArray());
+
+ var exception = Assert.ThrowsException(() =>
+ _rpcServer.SendRawTransaction(new JArray(txString)),
+ "Should throw RpcException for transaction already in memory pool");
+ Assert.AreEqual(RpcError.AlreadyInPool.Code, exception.HResult);
+ }
+
+ [TestMethod]
+ public void TestSendRawTransaction_AlreadyInBlockchain()
+ {
+ var snapshot = _neoSystem.GetSnapshot();
+ var tx = TestUtils.CreateValidTx(snapshot, _wallet, _walletAccount);
+ TestUtils.AddTransactionToBlockchain(snapshot, tx);
+ snapshot.Commit();
+ var txString = Convert.ToBase64String(tx.ToArray());
+ var exception = Assert.ThrowsException(() => _rpcServer.SendRawTransaction(new JArray(txString)));
+ Assert.AreEqual(RpcError.AlreadyExists.Code, exception.HResult);
+ }
+
+ #endregion
+
+ #region SubmitBlock Tests
+
+ [TestMethod]
+ public void TestSubmitBlock_Normal()
+ {
+ var snapshot = _neoSystem.GetSnapshot();
+ var block = TestUtils.CreateBlockWithValidTransactions(snapshot, _wallet, _walletAccount, 1);
+ var blockString = Convert.ToBase64String(block.ToArray());
+
+ var result = _rpcServer.SubmitBlock(new JArray(blockString));
+ Assert.IsInstanceOfType(result, typeof(JObject));
+ Assert.IsTrue(((JObject)result).ContainsProperty("hash"));
+ }
+
+ [TestMethod]
+ public void TestSubmitBlock_InvalidBlockFormat()
+ {
+ string invalidBlockString = TestUtils.CreateInvalidBlockFormat();
+
+ var exception = Assert.ThrowsException(() =>
+ _rpcServer.SubmitBlock(new JArray(invalidBlockString)),
+ "Should throw RpcException for invalid block format");
+
+ Assert.AreEqual(RpcError.InvalidParams.Code, exception.HResult);
+ StringAssert.Contains(exception.Message, "Invalid Block Format");
+ }
+
+ [TestMethod]
+ public void TestSubmitBlock_AlreadyExists()
+ {
+ var snapshot = _neoSystem.GetSnapshot();
+ var block = TestUtils.CreateBlockWithValidTransactions(snapshot, _wallet, _walletAccount, 1);
+ TestUtils.BlocksAdd(snapshot, block.Hash, block);
+ snapshot.Commit();
+ var blockString = Convert.ToBase64String(block.ToArray());
+
+ var exception = Assert.ThrowsException(() =>
+ _rpcServer.SubmitBlock(new JArray(blockString)),
+ "Should throw RpcException when block already exists");
+ Assert.AreEqual(RpcError.AlreadyExists.Code, exception.HResult);
+ }
+
+ [TestMethod]
+ public void TestSubmitBlock_InvalidBlock()
+ {
+ var snapshot = _neoSystem.GetSnapshot();
+ var block = TestUtils.CreateBlockWithValidTransactions(snapshot, _wallet, _walletAccount, 1);
+ block.Header.Witness = new Witness();
+ var blockString = Convert.ToBase64String(block.ToArray());
+
+ var exception = Assert.ThrowsException(() =>
+ _rpcServer.SubmitBlock(new JArray(blockString)),
+ "Should throw RpcException for invalid block");
+ Assert.AreEqual(RpcError.VerificationFailed.Code, exception.HResult);
+ }
+
+ #endregion
+
+ #region Edge Cases and Error Handling
+
+ [TestMethod]
+ public void TestSendRawTransaction_NullInput()
+ {
+ var exception = Assert.ThrowsException(() =>
+ _rpcServer.SendRawTransaction(new JArray((string)null)),
+ "Should throw RpcException for null input");
+ Assert.AreEqual(RpcError.InvalidParams.Code, exception.HResult);
+ }
+
+ [TestMethod]
+ public void TestSendRawTransaction_EmptyInput()
+ {
+ var exception = Assert.ThrowsException(() =>
+ _rpcServer.SendRawTransaction(new JArray(string.Empty)),
+ "Should throw RpcException for empty input");
+ Assert.AreEqual(RpcError.InvalidParams.Code, exception.HResult);
+ }
+
+ [TestMethod]
+ public void TestSubmitBlock_NullInput()
+ {
+ var exception = Assert.ThrowsException(() =>
+ _rpcServer.SubmitBlock(new JArray((string)null)),
+ "Should throw RpcException for null input");
+ Assert.AreEqual(RpcError.InvalidParams.Code, exception.HResult);
+ }
+
+ [TestMethod]
+ public void TestSubmitBlock_EmptyInput()
+ {
+ var exception = Assert.ThrowsException(() =>
+ _rpcServer.SubmitBlock(new JArray(string.Empty)),
+ "Should throw RpcException for empty input");
+ Assert.AreEqual(RpcError.InvalidParams.Code, exception.HResult);
+ }
+
+ #endregion
+ }
+}
diff --git a/tests/Neo.Plugins.RpcServer.Tests/UT_RpcServer.cs b/tests/Neo.Plugins.RpcServer.Tests/UT_RpcServer.cs
index beed9a1883..2561171c81 100644
--- a/tests/Neo.Plugins.RpcServer.Tests/UT_RpcServer.cs
+++ b/tests/Neo.Plugins.RpcServer.Tests/UT_RpcServer.cs
@@ -11,6 +11,7 @@
using Microsoft.AspNetCore.Http;
using Microsoft.VisualStudio.TestTools.UnitTesting;
+using Neo.Ledger;
using Neo.Persistence;
using Neo.SmartContract;
using Neo.SmartContract.Native;
@@ -37,10 +38,9 @@ public void TestSetup()
{
_memoryStore = new MemoryStore();
_memoryStoreProvider = new TestMemoryStoreProvider(_memoryStore);
- var protocolSettings = TestProtocolSettings.Default;
- _neoSystem = new NeoSystem(protocolSettings, _memoryStoreProvider);
+ _neoSystem = new NeoSystem(TestProtocolSettings.SoleNode, _memoryStoreProvider);
_rpcServer = new RpcServer(_neoSystem, RpcServerSettings.Default);
- _walletAccount = _wallet.CreateAccount();
+ _walletAccount = _wallet.Import("KxuRSsHgJMb3AMSN6B9P3JHNGMFtxmuimqgR9MmXPcv3CLLfusTd");
var key = new KeyBuilder(NativeContract.GAS.Id, 20).Add(_walletAccount.ScriptHash);
var snapshot = _neoSystem.GetSnapshotCache();
var entry = snapshot.GetAndChange(key, () => new StorageItem(new AccountState()));
@@ -51,6 +51,8 @@ public void TestSetup()
[TestCleanup]
public void TestCleanup()
{
+ // Please build and test in debug mode
+ _neoSystem.MemPool.Clear();
_memoryStore.Reset();
var snapshot = _neoSystem.GetSnapshotCache();
var key = new KeyBuilder(NativeContract.GAS.Id, 20).Add(_walletAccount.ScriptHash);
diff --git a/tests/Neo.Plugins.Storage.Tests/StoreTest.cs b/tests/Neo.Plugins.Storage.Tests/StoreTest.cs
index 2773f92e80..189e212bc2 100644
--- a/tests/Neo.Plugins.Storage.Tests/StoreTest.cs
+++ b/tests/Neo.Plugins.Storage.Tests/StoreTest.cs
@@ -21,9 +21,19 @@ public class StoreTest
{
private const string path_leveldb = "Data_LevelDB_UT";
private const string path_rocksdb = "Data_RocksDB_UT";
+ private static LevelDBStore levelDbStore;
+ private static RocksDBStore rocksDBStore;
[TestInitialize]
public void OnStart()
+ {
+ levelDbStore ??= new LevelDBStore();
+ rocksDBStore ??= new RocksDBStore();
+ OnEnd();
+ }
+
+ [TestCleanup]
+ public void OnEnd()
{
if (Directory.Exists(path_leveldb)) Directory.Delete(path_leveldb, true);
if (Directory.Exists(path_rocksdb)) Directory.Delete(path_rocksdb, true);
@@ -49,35 +59,138 @@ public void TestMemory()
[TestMethod]
public void TestLevelDb()
{
- using var plugin = new LevelDBStore();
- TestPersistenceDelete(plugin.GetStore(path_leveldb));
+ TestPersistenceDelete(levelDbStore.GetStore(path_leveldb));
// Test all with the same store
- TestStorage(plugin.GetStore(path_leveldb));
+ TestStorage(levelDbStore.GetStore(path_leveldb));
// Test with different storages
- TestPersistenceWrite(plugin.GetStore(path_leveldb));
- TestPersistenceRead(plugin.GetStore(path_leveldb), true);
- TestPersistenceDelete(plugin.GetStore(path_leveldb));
- TestPersistenceRead(plugin.GetStore(path_leveldb), false);
+ TestPersistenceWrite(levelDbStore.GetStore(path_leveldb));
+ TestPersistenceRead(levelDbStore.GetStore(path_leveldb), true);
+ TestPersistenceDelete(levelDbStore.GetStore(path_leveldb));
+ TestPersistenceRead(levelDbStore.GetStore(path_leveldb), false);
+ }
+
+ [TestMethod]
+ public void TestLevelDbSnapshot()
+ {
+ using var store = levelDbStore.GetStore(path_leveldb);
+
+ var snapshot = store.GetSnapshot();
+
+ var testKey = new byte[] { 0x01, 0x02, 0x03 };
+ var testValue = new byte[] { 0x04, 0x05, 0x06 };
+
+ snapshot.Put(testKey, testValue);
+ // Data saved to the leveldb snapshot shall not be visible to the store
+ Assert.IsNull(snapshot.TryGet(testKey));
+
+ // Value is in the write batch, not visible to the store and snapshot
+ Assert.AreEqual(false, snapshot.Contains(testKey));
+ Assert.AreEqual(false, store.Contains(testKey));
+
+ snapshot.Commit();
+
+ // After commit, the data shall be visible to the store but not to the snapshot
+ Assert.IsNull(snapshot.TryGet(testKey));
+ CollectionAssert.AreEqual(testValue, store.TryGet(testKey));
+ Assert.AreEqual(false, snapshot.Contains(testKey));
+ Assert.AreEqual(true, store.Contains(testKey));
+
+ snapshot.Dispose();
+ }
+
+ [TestMethod]
+ public void TestLevelDbMultiSnapshot()
+ {
+ using var store = levelDbStore.GetStore(path_leveldb);
+
+ var snapshot = store.GetSnapshot();
+
+ var testKey = new byte[] { 0x01, 0x02, 0x03 };
+ var testValue = new byte[] { 0x04, 0x05, 0x06 };
+
+ snapshot.Put(testKey, testValue);
+ snapshot.Commit();
+ CollectionAssert.AreEqual(testValue, store.TryGet(testKey));
+
+ var snapshot2 = store.GetSnapshot();
+
+ // Data saved to the leveldb from snapshot1 shall be visible to snapshot2 but not visible to snapshot1
+ CollectionAssert.AreEqual(testValue, snapshot2.TryGet(testKey));
+ Assert.IsNull(snapshot.TryGet(testKey));
+
+ snapshot.Dispose();
+ snapshot2.Dispose();
}
[TestMethod]
public void TestRocksDb()
{
- using var plugin = new RocksDBStore();
- TestPersistenceDelete(plugin.GetStore(path_rocksdb));
+ TestPersistenceDelete(rocksDBStore.GetStore(path_rocksdb));
// Test all with the same store
- TestStorage(plugin.GetStore(path_rocksdb));
+ TestStorage(rocksDBStore.GetStore(path_rocksdb));
// Test with different storages
- TestPersistenceWrite(plugin.GetStore(path_rocksdb));
- TestPersistenceRead(plugin.GetStore(path_rocksdb), true);
- TestPersistenceDelete(plugin.GetStore(path_rocksdb));
- TestPersistenceRead(plugin.GetStore(path_rocksdb), false);
+ TestPersistenceWrite(rocksDBStore.GetStore(path_rocksdb));
+ TestPersistenceRead(rocksDBStore.GetStore(path_rocksdb), true);
+ TestPersistenceDelete(rocksDBStore.GetStore(path_rocksdb));
+ TestPersistenceRead(rocksDBStore.GetStore(path_rocksdb), false);
+ }
+
+ [TestMethod]
+ public void TestRocksDbSnapshot()
+ {
+ using var store = rocksDBStore.GetStore(path_leveldb);
+
+ var snapshot = store.GetSnapshot();
+
+ var testKey = new byte[] { 0x01, 0x02, 0x03 };
+ var testValue = new byte[] { 0x04, 0x05, 0x06 };
+
+ snapshot.Put(testKey, testValue);
+ // Data saved to the leveldb snapshot shall not be visible
+ Assert.IsNull(snapshot.TryGet(testKey));
+ Assert.IsNull(store.TryGet(testKey));
+
+ // Value is in the write batch, not visible to the store and snapshot
+ Assert.AreEqual(false, snapshot.Contains(testKey));
+ Assert.AreEqual(false, store.Contains(testKey));
+
+ snapshot.Commit();
+
+ // After commit, the data shall be visible to the store but not to the snapshot
+ Assert.IsNull(snapshot.TryGet(testKey));
+ CollectionAssert.AreEqual(testValue, store.TryGet(testKey));
+ Assert.AreEqual(false, snapshot.Contains(testKey));
+ Assert.AreEqual(true, store.Contains(testKey));
+
+ snapshot.Dispose();
+ }
+
+ [TestMethod]
+ public void TestRocksDbMultiSnapshot()
+ {
+ using var store = rocksDBStore.GetStore(path_leveldb);
+
+ var snapshot = store.GetSnapshot();
+
+ var testKey = new byte[] { 0x01, 0x02, 0x03 };
+ var testValue = new byte[] { 0x04, 0x05, 0x06 };
+
+ snapshot.Put(testKey, testValue);
+ snapshot.Commit();
+ CollectionAssert.AreEqual(testValue, store.TryGet(testKey));
+
+ var snapshot2 = store.GetSnapshot();
+ // Data saved to the leveldb from snapshot1 shall only be visible to snapshot2
+ CollectionAssert.AreEqual(testValue, snapshot2.TryGet(testKey));
+
+ snapshot.Dispose();
+ snapshot2.Dispose();
}
///
diff --git a/tests/Neo.UnitTests/Cryptography/UT_BloomFilter.cs b/tests/Neo.UnitTests/Cryptography/UT_BloomFilter.cs
index 907a5df2b9..f7bc1789dd 100644
--- a/tests/Neo.UnitTests/Cryptography/UT_BloomFilter.cs
+++ b/tests/Neo.UnitTests/Cryptography/UT_BloomFilter.cs
@@ -39,6 +39,8 @@ public void TestBloomFIlterConstructorGetKMTweak()
uint nTweak = 123456;
Action action = () => new BloomFilter(m, n, nTweak);
action.Should().Throw();
+ action = () => new BloomFilter(m, n, nTweak, new byte[] { 0, 1, 2, 3, 4 });
+ action.Should().Throw();
m = 7;
n = -10;
diff --git a/tests/Neo.UnitTests/Cryptography/UT_Cryptography_Helper.cs b/tests/Neo.UnitTests/Cryptography/UT_Cryptography_Helper.cs
index 01022baab9..4bfde89ba2 100644
--- a/tests/Neo.UnitTests/Cryptography/UT_Cryptography_Helper.cs
+++ b/tests/Neo.UnitTests/Cryptography/UT_Cryptography_Helper.cs
@@ -41,6 +41,17 @@ public void TestBase58CheckDecode()
input = "3vQB7B6MrGQZaxCuFg4og";
action = () => input.Base58CheckDecode();
action.Should().Throw();
+
+ Assert.ThrowsException(() => string.Empty.Base58CheckDecode());
+ }
+
+ [TestMethod]
+ public void TestMurmurReadOnlySpan()
+ {
+ ReadOnlySpan input = "Hello, world!"u8;
+ byte[] input2 = input.ToArray();
+ input.Murmur32(0).Should().Be(input2.Murmur32(0));
+ input.Murmur128(0).Should().Equal(input2.Murmur128(0));
}
[TestMethod]
@@ -50,6 +61,19 @@ public void TestSha256()
byte[] result = value.Sha256(0, value.Length);
string resultStr = result.ToHexString();
resultStr.Should().Be("b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9");
+ value.Sha256().Should().Equal(result);
+ ((Span)value).Sha256().Should().Equal(result);
+ ((ReadOnlySpan)value).Sha256().Should().Equal(result);
+ }
+
+ [TestMethod]
+ public void TestKeccak256()
+ {
+ var input = "Hello, world!"u8.ToArray();
+ var result = input.Keccak256();
+ result.ToHexString().Should().Be("b6e16d27ac5ab427a7f68900ac5559ce272dc6c37c82b3e052246c82244c50e4");
+ ((Span)input).Keccak256().Should().Equal(result);
+ ((ReadOnlySpan)input).Keccak256().Should().Equal(result);
}
[TestMethod]
diff --git a/tests/Neo.UnitTests/Neo.UnitTests.csproj b/tests/Neo.UnitTests/Neo.UnitTests.csproj
index fb246cbdc3..ce6d3b41a4 100644
--- a/tests/Neo.UnitTests/Neo.UnitTests.csproj
+++ b/tests/Neo.UnitTests/Neo.UnitTests.csproj
@@ -12,6 +12,9 @@
+
+ PreserveNewest
+
PreserveNewest
PreserveNewest
diff --git a/tests/Neo.UnitTests/Network/P2P/Payloads/UT_Block.cs b/tests/Neo.UnitTests/Network/P2P/Payloads/UT_Block.cs
index 2021e5a187..7793e27597 100644
--- a/tests/Neo.UnitTests/Network/P2P/Payloads/UT_Block.cs
+++ b/tests/Neo.UnitTests/Network/P2P/Payloads/UT_Block.cs
@@ -13,7 +13,10 @@
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Neo.IO;
using Neo.Json;
+using Neo.Ledger;
using Neo.Network.P2P.Payloads;
+using Neo.SmartContract;
+using Neo.SmartContract.Native;
namespace Neo.UnitTests.Network.P2P.Payloads
{
@@ -21,6 +24,15 @@ namespace Neo.UnitTests.Network.P2P.Payloads
public class UT_Block
{
Block uut;
+ private static ApplicationEngine GetEngine(bool hasContainer = false, bool hasSnapshot = false, bool hasBlock = false, bool addScript = true, long gas = 20_00000000)
+ {
+ var tx = hasContainer ? TestUtils.GetTransaction(UInt160.Zero) : null;
+ var snapshot = hasSnapshot ? TestBlockchain.GetTestSnapshot() : null;
+ var block = hasBlock ? new Block { Header = new Header() } : null;
+ var engine = ApplicationEngine.Create(TriggerType.Application, tx, snapshot, block, TestBlockchain.TheNeoSystem.Settings, gas: gas);
+ if (addScript) engine.LoadScript(new byte[] { 0x01 });
+ return engine;
+ }
[TestInitialize]
public void TestSetup()
@@ -38,7 +50,7 @@ public void Transactions_Get()
public void Header_Get()
{
UInt256 val256 = UInt256.Zero;
- TestUtils.SetupBlockWithValues(uut, val256, out var merkRootVal, out _, out var timestampVal, out var nonceVal, out var indexVal, out var scriptVal, out _, 0);
+ TestUtils.SetupBlockWithValues(null, uut, val256, out var merkRootVal, out _, out var timestampVal, out var nonceVal, out var indexVal, out var scriptVal, out _, 0);
uut.Header.Should().NotBeNull();
uut.Header.PrevHash.Should().Be(val256);
@@ -53,7 +65,7 @@ public void Header_Get()
public void Size_Get()
{
UInt256 val256 = UInt256.Zero;
- TestUtils.SetupBlockWithValues(uut, val256, out var _, out var _, out var _, out var _, out var _, out var _, out var _, 0);
+ TestUtils.SetupBlockWithValues(null, uut, val256, out var _, out var _, out var _, out var _, out var _, out var _, out var _, 0);
// header 4 + 32 + 32 + 8 + 4 + 1 + 20 + 4
// tx 1
uut.Size.Should().Be(114); // 106 + nonce
@@ -63,7 +75,7 @@ public void Size_Get()
public void Size_Get_1_Transaction()
{
UInt256 val256 = UInt256.Zero;
- TestUtils.SetupBlockWithValues(uut, val256, out var _, out var _, out var _, out var _, out var _, out var _, out var _, 0);
+ TestUtils.SetupBlockWithValues(null, uut, val256, out var _, out var _, out var _, out var _, out var _, out var _, out var _, 0);
uut.Transactions = new[]
{
@@ -77,7 +89,7 @@ public void Size_Get_1_Transaction()
public void Size_Get_3_Transaction()
{
UInt256 val256 = UInt256.Zero;
- TestUtils.SetupBlockWithValues(uut, val256, out var _, out var _, out var _, out var _, out var _, out var _, out var _, 0);
+ TestUtils.SetupBlockWithValues(null, uut, val256, out var _, out var _, out var _, out var _, out var _, out var _, out var _, 0);
uut.Transactions = new[]
{
@@ -93,9 +105,9 @@ public void Size_Get_3_Transaction()
public void Serialize()
{
UInt256 val256 = UInt256.Zero;
- TestUtils.SetupBlockWithValues(uut, val256, out var _, out var _, out var _, out var _, out var _, out var _, out var _, 1);
+ TestUtils.SetupBlockWithValues(null, uut, val256, out var _, out var _, out var _, out var _, out var _, out var _, out var _, 1);
- var hex = "0000000000000000000000000000000000000000000000000000000000000000000000006c23be5d32679baa9c5c2aa0d329fd2a2441d7875d0f34d42f58f70428fbbbb9e913ff854c00000000000000000000000000000000000000000000000000000000000000000000000001000111010000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000001000112010000";
+ var hex = "0000000000000000000000000000000000000000000000000000000000000000000000006c23be5d32679baa9c5c2aa0d329fd2a2441d7875d0f34d42f58f70428fbbbb9493ed0e58f01000000000000000000000000000000000000000000000000000000000000000000000001000111010000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000001000112010000";
uut.ToArray().ToHexString().Should().Be(hex);
}
@@ -103,9 +115,9 @@ public void Serialize()
public void Deserialize()
{
UInt256 val256 = UInt256.Zero;
- TestUtils.SetupBlockWithValues(new Block(), val256, out _, out var val160, out var timestampVal, out var indexVal, out var nonceVal, out var scriptVal, out var transactionsVal, 1);
+ TestUtils.SetupBlockWithValues(null, new Block(), val256, out _, out var val160, out var timestampVal, out var indexVal, out var nonceVal, out var scriptVal, out var transactionsVal, 1);
- var hex = "0000000000000000000000000000000000000000000000000000000000000000000000006c23be5d32679baa9c5c2aa0d329fd2a2441d7875d0f34d42f58f70428fbbbb9e913ff854c00000000000000000000000000000000000000000000000000000000000000000000000001000111010000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000001000112010000";
+ var hex = "0000000000000000000000000000000000000000000000000000000000000000000000006c23be5d32679baa9c5c2aa0d329fd2a2441d7875d0f34d42f58f70428fbbbb9493ed0e58f01000000000000000000000000000000000000000000000000000000000000000000000001000111010000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000001000112010000";
MemoryReader reader = new(hex.HexToBytes());
uut.Deserialize(ref reader);
@@ -136,6 +148,15 @@ private void AssertStandardBlockTestVals(UInt256 val256, UInt256 merkRoot, UInt1
public void Equals_SameObj()
{
uut.Equals(uut).Should().BeTrue();
+ var obj = uut as object;
+ uut.Equals(obj).Should().BeTrue();
+ }
+
+ [TestMethod]
+ public void TestGetHashCode()
+ {
+ var snapshot = GetEngine(true, true).Snapshot;
+ NativeContract.Ledger.GetBlock(snapshot, 0).GetHashCode().Should().Be(-626492395);
}
[TestMethod]
@@ -144,8 +165,8 @@ public void Equals_DiffObj()
Block newBlock = new();
UInt256 val256 = UInt256.Zero;
UInt256 prevHash = new(TestUtils.GetByteArray(32, 0x42));
- TestUtils.SetupBlockWithValues(newBlock, val256, out _, out _, out _, out ulong _, out uint _, out _, out _, 1);
- TestUtils.SetupBlockWithValues(uut, prevHash, out _, out _, out _, out _, out _, out _, out _, 0);
+ TestUtils.SetupBlockWithValues(null, newBlock, val256, out _, out _, out _, out ulong _, out uint _, out _, out _, 1);
+ TestUtils.SetupBlockWithValues(null, uut, prevHash, out _, out _, out _, out _, out _, out _, out _, 0);
uut.Equals(newBlock).Should().BeFalse();
}
@@ -161,8 +182,8 @@ public void Equals_SameHash()
{
Block newBlock = new();
UInt256 prevHash = new(TestUtils.GetByteArray(32, 0x42));
- TestUtils.SetupBlockWithValues(newBlock, prevHash, out _, out _, out _, out _, out _, out _, out _, 1);
- TestUtils.SetupBlockWithValues(uut, prevHash, out _, out _, out _, out _, out _, out _, out _, 1);
+ TestUtils.SetupBlockWithValues(null, newBlock, prevHash, out _, out _, out _, out _, out _, out _, out _, 1);
+ TestUtils.SetupBlockWithValues(null, uut, prevHash, out _, out _, out _, out _, out _, out _, out _, 1);
uut.Equals(newBlock).Should().BeTrue();
}
@@ -171,11 +192,11 @@ public void Equals_SameHash()
public void ToJson()
{
UInt256 val256 = UInt256.Zero;
- TestUtils.SetupBlockWithValues(uut, val256, out _, out _, out var timeVal, out var indexVal, out var nonceVal, out _, out _, 1);
+ TestUtils.SetupBlockWithValues(null, uut, val256, out _, out _, out var timeVal, out var indexVal, out var nonceVal, out _, out _, 1);
JObject jObj = uut.ToJson(TestProtocolSettings.Default);
jObj.Should().NotBeNull();
- jObj["hash"].AsString().Should().Be("0x60193a05005c433787d8a9b95da332bbeebb311e904525e9fb1bacc34ff1ead7");
+ jObj["hash"].AsString().Should().Be("0x942065e93848732c2e7844061fa92d20c5d9dc0bc71d420a1ea71b3431fc21b4");
jObj["size"].AsNumber().Should().Be(167); // 159 + nonce
jObj["version"].AsNumber().Should().Be(0);
jObj["previousblockhash"].AsString().Should().Be("0x0000000000000000000000000000000000000000000000000000000000000000");
diff --git a/tests/Neo.UnitTests/Network/P2P/Payloads/UT_Header.cs b/tests/Neo.UnitTests/Network/P2P/Payloads/UT_Header.cs
index 55419fc8bc..17e0cb894f 100644
--- a/tests/Neo.UnitTests/Network/P2P/Payloads/UT_Header.cs
+++ b/tests/Neo.UnitTests/Network/P2P/Payloads/UT_Header.cs
@@ -34,7 +34,7 @@ public void TestSetup()
public void Size_Get()
{
UInt256 val256 = UInt256.Zero;
- TestUtils.SetupHeaderWithValues(uut, val256, out _, out _, out _, out _, out _, out _);
+ TestUtils.SetupHeaderWithValues(null, uut, val256, out _, out _, out _, out _, out _, out _);
// blockbase 4 + 64 + 1 + 32 + 4 + 4 + 20 + 4
// header 1
uut.Size.Should().Be(113); // 105 + nonce
@@ -44,7 +44,7 @@ public void Size_Get()
public void GetHashCodeTest()
{
UInt256 val256 = UInt256.Zero;
- TestUtils.SetupHeaderWithValues(uut, val256, out _, out _, out _, out _, out _, out _);
+ TestUtils.SetupHeaderWithValues(null, uut, val256, out _, out _, out _, out _, out _, out _);
uut.GetHashCode().Should().Be(uut.Hash.GetHashCode());
}
@@ -52,8 +52,8 @@ public void GetHashCodeTest()
public void TrimTest()
{
UInt256 val256 = UInt256.Zero;
- var snapshot = TestBlockchain.GetTestSnapshot().CloneCache();
- TestUtils.SetupHeaderWithValues(uut, val256, out _, out _, out _, out _, out _, out _);
+ var snapshot = TestBlockchain.GetTestSnapshot().CreateSnapshot();
+ TestUtils.SetupHeaderWithValues(null, uut, val256, out _, out _, out _, out _, out _, out _);
uut.Witness = new Witness() { InvocationScript = Array.Empty(), VerificationScript = Array.Empty() };
TestUtils.BlocksAdd(snapshot, uut.Hash, new TrimmedBlock()
@@ -87,11 +87,11 @@ public void TrimTest()
public void Deserialize()
{
UInt256 val256 = UInt256.Zero;
- TestUtils.SetupHeaderWithValues(new Header(), val256, out UInt256 merkRoot, out UInt160 val160, out ulong timestampVal, out ulong nonceVal, out uint indexVal, out Witness scriptVal);
+ TestUtils.SetupHeaderWithValues(null, new Header(), val256, out UInt256 merkRoot, out UInt160 val160, out ulong timestampVal, out ulong nonceVal, out uint indexVal, out Witness scriptVal);
uut.MerkleRoot = merkRoot; // need to set for deserialise to be valid
- var hex = "0000000000000000000000000000000000000000000000000000000000000000000000007227ba7b747f1a98f68679d4a98b68927646ab195a6f56b542ca5a0e6a412662e913ff854c00000000000000000000000000000000000000000000000000000000000000000000000001000111";
+ var hex = "0000000000000000000000000000000000000000000000000000000000000000000000007227ba7b747f1a98f68679d4a98b68927646ab195a6f56b542ca5a0e6a412662493ed0e58f01000000000000000000000000000000000000000000000000000000000000000000000001000111";
MemoryReader reader = new(hex.HexToBytes());
uut.Deserialize(ref reader);
@@ -130,8 +130,8 @@ public void Equals_SameHash()
{
Header newHeader = new();
UInt256 prevHash = new(TestUtils.GetByteArray(32, 0x42));
- TestUtils.SetupHeaderWithValues(newHeader, prevHash, out _, out _, out _, out _, out _, out _);
- TestUtils.SetupHeaderWithValues(uut, prevHash, out _, out _, out _, out _, out _, out _);
+ TestUtils.SetupHeaderWithValues(null, newHeader, prevHash, out _, out _, out _, out _, out _, out _);
+ TestUtils.SetupHeaderWithValues(null, uut, prevHash, out _, out _, out _, out _, out _, out _);
uut.Equals(newHeader).Should().BeTrue();
}
@@ -146,9 +146,9 @@ public void Equals_SameObject()
public void Serialize()
{
UInt256 val256 = UInt256.Zero;
- TestUtils.SetupHeaderWithValues(uut, val256, out _, out _, out _, out _, out _, out _);
+ TestUtils.SetupHeaderWithValues(null, uut, val256, out _, out _, out _, out _, out _, out _);
- var hex = "0000000000000000000000000000000000000000000000000000000000000000000000007227ba7b747f1a98f68679d4a98b68927646ab195a6f56b542ca5a0e6a412662e913ff854c00000000000000000000000000000000000000000000000000000000000000000000000001000111";
+ var hex = "0000000000000000000000000000000000000000000000000000000000000000000000007227ba7b747f1a98f68679d4a98b68927646ab195a6f56b542ca5a0e6a412662493ed0e58f01000000000000000000000000000000000000000000000000000000000000000000000001000111";
uut.ToArray().ToHexString().Should().Be(hex);
}
}
diff --git a/tests/Neo.UnitTests/Network/P2P/Payloads/UT_HeadersPayload.cs b/tests/Neo.UnitTests/Network/P2P/Payloads/UT_HeadersPayload.cs
index 2ac486ef06..9ecdd7f5e4 100644
--- a/tests/Neo.UnitTests/Network/P2P/Payloads/UT_HeadersPayload.cs
+++ b/tests/Neo.UnitTests/Network/P2P/Payloads/UT_HeadersPayload.cs
@@ -23,7 +23,7 @@ public class UT_HeadersPayload
public void Size_Get()
{
var header = new Header();
- TestUtils.SetupHeaderWithValues(header, UInt256.Zero, out _, out _, out _, out _, out _, out _);
+ TestUtils.SetupHeaderWithValues(null, header, UInt256.Zero, out _, out _, out _, out _, out _, out _);
var test = HeadersPayload.Create();
test.Size.Should().Be(1);
@@ -35,7 +35,7 @@ public void Size_Get()
public void DeserializeAndSerialize()
{
var header = new Header();
- TestUtils.SetupHeaderWithValues(header, UInt256.Zero, out _, out _, out _, out _, out _, out _);
+ TestUtils.SetupHeaderWithValues(null, header, UInt256.Zero, out _, out _, out _, out _, out _, out _);
var test = HeadersPayload.Create(header);
var clone = test.ToArray().AsSerializable();
diff --git a/tests/Neo.UnitTests/SmartContract/Manifest/TestFile/SampleContractCall.manifest.json b/tests/Neo.UnitTests/SmartContract/Manifest/TestFile/SampleContractCall.manifest.json
new file mode 100644
index 0000000000..bfbee88473
--- /dev/null
+++ b/tests/Neo.UnitTests/SmartContract/Manifest/TestFile/SampleContractCall.manifest.json
@@ -0,0 +1 @@
+{"name":"SampleContractCall","groups":[],"features":{},"supportedstandards":[],"abi":{"methods":[{"name":"onNEP17Payment","parameters":[{"name":"from","type":"Hash160"},{"name":"amount","type":"Integer"},{"name":"data","type":"Integer"}],"returntype":"Void","offset":0,"safe":false},{"name":"_initialize","parameters":[],"returntype":"Void","offset":91,"safe":false}],"events":[]},"permissions":[],"trusts":[],"extra":{"Author":"core-dev","Version":"0.0.1","Description":"A sample contract to demonstrate how to call a contract","Sourcecode":"https://github.com/neo-project/neo-devpack-dotnet/tree/master/examples/"}}
\ No newline at end of file
diff --git a/tests/Neo.UnitTests/SmartContract/Manifest/TestFile/SampleEvent.manifest.json b/tests/Neo.UnitTests/SmartContract/Manifest/TestFile/SampleEvent.manifest.json
new file mode 100644
index 0000000000..7e71a2f2a5
--- /dev/null
+++ b/tests/Neo.UnitTests/SmartContract/Manifest/TestFile/SampleEvent.manifest.json
@@ -0,0 +1 @@
+{"name":"SampleEvent","groups":[],"features":{},"supportedstandards":[],"abi":{"methods":[{"name":"main","parameters":[],"returntype":"Boolean","offset":0,"safe":false}],"events":[{"name":"new_event_name","parameters":[{"name":"arg1","type":"ByteArray"},{"name":"arg2","type":"String"},{"name":"arg3","type":"Integer"}]},{"name":"event2","parameters":[{"name":"arg1","type":"ByteArray"},{"name":"arg2","type":"Integer"}]}]},"permissions":[{"contract":"*","methods":"*"}],"trusts":[],"extra":{"Author":"code-dev","Description":"A sample contract that demonstrates how to use Events","Version":"0.0.1","Sourcecode":"https://github.com/neo-project/neo-devpack-dotnet/tree/master/examples/"}}
\ No newline at end of file
diff --git a/tests/Neo.UnitTests/SmartContract/Manifest/TestFile/SampleException.manifest.json b/tests/Neo.UnitTests/SmartContract/Manifest/TestFile/SampleException.manifest.json
new file mode 100644
index 0000000000..5d916af0f3
--- /dev/null
+++ b/tests/Neo.UnitTests/SmartContract/Manifest/TestFile/SampleException.manifest.json
@@ -0,0 +1 @@
+{"name":"SampleException","groups":[],"features":{},"supportedstandards":[],"abi":{"methods":[{"name":"try01","parameters":[],"returntype":"Any","offset":0,"safe":false},{"name":"try02","parameters":[],"returntype":"Any","offset":77,"safe":false},{"name":"try03","parameters":[],"returntype":"Any","offset":166,"safe":false},{"name":"tryNest","parameters":[],"returntype":"Any","offset":259,"safe":false},{"name":"tryFinally","parameters":[],"returntype":"Any","offset":404,"safe":false},{"name":"tryFinallyAndRethrow","parameters":[],"returntype":"Any","offset":474,"safe":false},{"name":"tryCatch","parameters":[],"returntype":"Any","offset":550,"safe":false},{"name":"tryWithTwoFinally","parameters":[],"returntype":"Any","offset":628,"safe":false},{"name":"tryecpointCast","parameters":[],"returntype":"Any","offset":920,"safe":false},{"name":"tryvalidByteString2Ecpoint","parameters":[],"returntype":"Any","offset":1010,"safe":false},{"name":"tryinvalidByteArray2UInt160","parameters":[],"returntype":"Any","offset":1100,"safe":false},{"name":"tryvalidByteArray2UInt160","parameters":[],"returntype":"Any","offset":1190,"safe":false},{"name":"tryinvalidByteArray2UInt256","parameters":[],"returntype":"Any","offset":1280,"safe":false},{"name":"tryvalidByteArray2UInt256","parameters":[],"returntype":"Any","offset":1370,"safe":false},{"name":"tryNULL2Ecpoint_1","parameters":[],"returntype":"Array","offset":1476,"safe":false},{"name":"tryNULL2Uint160_1","parameters":[],"returntype":"Array","offset":1652,"safe":false},{"name":"tryNULL2Uint256_1","parameters":[],"returntype":"Array","offset":1828,"safe":false},{"name":"tryNULL2Bytestring_1","parameters":[],"returntype":"Array","offset":1990,"safe":false},{"name":"tryUncatchableException","parameters":[],"returntype":"Any","offset":2141,"safe":false},{"name":"_initialize","parameters":[],"returntype":"Void","offset":2219,"safe":false}],"events":[]},"permissions":[{"contract":"*","methods":"*"}],"trusts":[],"extra":{"Author":"core-dev","Description":"A sample contract to demonstrate how to handle exception","Version":"0.0.1","Sourcecode":"https://github.com/neo-project/neo-devpack-dotnet/tree/master/examples/"}}
\ No newline at end of file
diff --git a/tests/Neo.UnitTests/SmartContract/Manifest/TestFile/SampleHelloWorld.manifest.json b/tests/Neo.UnitTests/SmartContract/Manifest/TestFile/SampleHelloWorld.manifest.json
new file mode 100644
index 0000000000..4c7c4b9605
--- /dev/null
+++ b/tests/Neo.UnitTests/SmartContract/Manifest/TestFile/SampleHelloWorld.manifest.json
@@ -0,0 +1 @@
+{"name":"SampleHelloWorld","groups":[],"features":{},"supportedstandards":[],"abi":{"methods":[{"name":"sayHello","parameters":[],"returntype":"String","offset":0,"safe":true}],"events":[]},"permissions":[{"contract":"*","methods":"*"}],"trusts":[],"extra":{"Description":"A simple \u0060hello world\u0060 contract","E-mail":"dev@neo.org","Version":"0.0.1","Sourcecode":"https://github.com/neo-project/neo-devpack-dotnet/tree/master/examples/"}}
\ No newline at end of file
diff --git a/tests/Neo.UnitTests/SmartContract/Manifest/TestFile/SampleNep17Token.manifest.json b/tests/Neo.UnitTests/SmartContract/Manifest/TestFile/SampleNep17Token.manifest.json
new file mode 100644
index 0000000000..bb9cf1682f
--- /dev/null
+++ b/tests/Neo.UnitTests/SmartContract/Manifest/TestFile/SampleNep17Token.manifest.json
@@ -0,0 +1 @@
+{"name":"SampleNep17Token","groups":[],"features":{},"supportedstandards":["NEP-17"],"abi":{"methods":[{"name":"symbol","parameters":[],"returntype":"String","offset":1333,"safe":true},{"name":"decimals","parameters":[],"returntype":"Integer","offset":1348,"safe":true},{"name":"totalSupply","parameters":[],"returntype":"Integer","offset":52,"safe":true},{"name":"balanceOf","parameters":[{"name":"owner","type":"Hash160"}],"returntype":"Integer","offset":98,"safe":true},{"name":"transfer","parameters":[{"name":"from","type":"Hash160"},{"name":"to","type":"Hash160"},{"name":"amount","type":"Integer"},{"name":"data","type":"Any"}],"returntype":"Boolean","offset":362,"safe":false},{"name":"getOwner","parameters":[],"returntype":"Hash160","offset":808,"safe":true},{"name":"setOwner","parameters":[{"name":"newOwner","type":"Any"}],"returntype":"Void","offset":877,"safe":false},{"name":"getMinter","parameters":[],"returntype":"Hash160","offset":980,"safe":true},{"name":"setMinter","parameters":[{"name":"newMinter","type":"Hash160"}],"returntype":"Void","offset":1025,"safe":false},{"name":"mint","parameters":[{"name":"to","type":"Hash160"},{"name":"amount","type":"Integer"}],"returntype":"Void","offset":1103,"safe":false},{"name":"burn","parameters":[{"name":"account","type":"Hash160"},{"name":"amount","type":"Integer"}],"returntype":"Void","offset":1158,"safe":false},{"name":"verify","parameters":[],"returntype":"Boolean","offset":1216,"safe":true},{"name":"update","parameters":[{"name":"nefFile","type":"ByteArray"},{"name":"manifest","type":"String"}],"returntype":"Boolean","offset":1222,"safe":false},{"name":"_initialize","parameters":[],"returntype":"Void","offset":1271,"safe":false}],"events":[{"name":"Transfer","parameters":[{"name":"from","type":"Hash160"},{"name":"to","type":"Hash160"},{"name":"amount","type":"Integer"}]},{"name":"SetOwner","parameters":[{"name":"newOwner","type":"Hash160"}]},{"name":"SetMinter","parameters":[{"name":"newMinter","type":"Hash160"}]}]},"permissions":[{"contract":"*","methods":"*"}],"trusts":[],"extra":{"Author":"core-dev","Version":"0.0.1","Description":"A sample NEP-17 token","Sourcecode":"https://github.com/neo-project/neo-devpack-dotnet/tree/master/examples/"}}
\ No newline at end of file
diff --git a/tests/Neo.UnitTests/SmartContract/Manifest/TestFile/SampleOracle.manifest.json b/tests/Neo.UnitTests/SmartContract/Manifest/TestFile/SampleOracle.manifest.json
new file mode 100644
index 0000000000..8570ccb3fb
--- /dev/null
+++ b/tests/Neo.UnitTests/SmartContract/Manifest/TestFile/SampleOracle.manifest.json
@@ -0,0 +1 @@
+{"name":"SampleOracle","groups":[],"features":{},"supportedstandards":[],"abi":{"methods":[{"name":"getResponse","parameters":[],"returntype":"String","offset":0,"safe":true},{"name":"doRequest","parameters":[],"returntype":"Void","offset":35,"safe":false},{"name":"onOracleResponse","parameters":[{"name":"requestedUrl","type":"String"},{"name":"userData","type":"Any"},{"name":"oracleResponse","type":"Integer"},{"name":"jsonString","type":"String"}],"returntype":"Void","offset":333,"safe":false}],"events":[]},"permissions":[{"contract":"*","methods":"*"}],"trusts":[],"extra":{"Author":"code-dev","Description":"A sample contract to demonstrate how to use Example.SmartContract.Oracle Service","Version":"0.0.1","Sourcecode":"https://github.com/neo-project/neo-devpack-dotnet/tree/master/examples/"}}
\ No newline at end of file
diff --git a/tests/Neo.UnitTests/SmartContract/Manifest/UT_ContractPermissionDescriptor.cs b/tests/Neo.UnitTests/SmartContract/Manifest/UT_ContractPermissionDescriptor.cs
index 1ef2397d69..cfcd9baf1e 100644
--- a/tests/Neo.UnitTests/SmartContract/Manifest/UT_ContractPermissionDescriptor.cs
+++ b/tests/Neo.UnitTests/SmartContract/Manifest/UT_ContractPermissionDescriptor.cs
@@ -9,10 +9,13 @@
// Redistribution and use in source and binary forms with or without
// modifications are permitted.
+using FluentAssertions;
using Microsoft.VisualStudio.TestTools.UnitTesting;
+using Neo.Json;
using Neo.SmartContract.Manifest;
using Neo.SmartContract.Native;
using Neo.Wallets;
+using System;
using System.Security.Cryptography;
namespace Neo.UnitTests.SmartContract.Manifest
@@ -34,7 +37,7 @@ public void TestCreateByECPointAndIsWildcard()
}
[TestMethod]
- public void TestFromAndToJson()
+ public void TestContractPermissionDescriptorFromAndToJson()
{
byte[] privateKey = new byte[32];
RandomNumberGenerator rng = RandomNumberGenerator.Create();
@@ -44,6 +47,20 @@ public void TestFromAndToJson()
ContractPermissionDescriptor result = ContractPermissionDescriptor.FromJson(temp.ToJson());
Assert.AreEqual(null, result.Hash);
Assert.AreEqual(result.Group, result.Group);
+ Assert.ThrowsException(() => ContractPermissionDescriptor.FromJson(string.Empty));
+ }
+
+ [TestMethod]
+ public void TestContractManifestFromJson()
+ {
+ Assert.ThrowsException(() => ContractManifest.FromJson(new Json.JObject()));
+ var jsonFiles = System.IO.Directory.GetFiles(System.IO.Path.Combine("SmartContract", "Manifest", "TestFile"));
+ foreach (var item in jsonFiles)
+ {
+ var json = JObject.Parse(System.IO.File.ReadAllText(item)) as JObject;
+ var manifest = ContractManifest.FromJson(json);
+ manifest.ToJson().ToString().Should().Be(json.ToString());
+ }
}
[TestMethod]
diff --git a/tests/Neo.UnitTests/SmartContract/Native/UT_StdLib.cs b/tests/Neo.UnitTests/SmartContract/Native/UT_StdLib.cs
index f36fa2cfa4..b5c9c198ec 100644
--- a/tests/Neo.UnitTests/SmartContract/Native/UT_StdLib.cs
+++ b/tests/Neo.UnitTests/SmartContract/Native/UT_StdLib.cs
@@ -9,6 +9,7 @@
// Redistribution and use in source and binary forms with or without
// modifications are permitted.
+using FluentAssertions;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Neo.SmartContract;
using Neo.SmartContract.Native;
@@ -53,6 +54,9 @@ public void TestItoaAtoi()
Assert.ThrowsException(() => StdLib.Atoi("a", 10));
Assert.ThrowsException(() => StdLib.Atoi("g", 16));
Assert.ThrowsException(() => StdLib.Atoi("a", 11));
+
+ StdLib.Atoi(StdLib.Itoa(BigInteger.One, 10)).Should().Be(BigInteger.One);
+ StdLib.Atoi(StdLib.Itoa(BigInteger.MinusOne, 10)).Should().Be(BigInteger.MinusOne);
}
[TestMethod]
diff --git a/tests/Neo.UnitTests/SmartContract/UT_InteropService.cs b/tests/Neo.UnitTests/SmartContract/UT_InteropService.cs
index 06290922da..1edcfbd9ca 100644
--- a/tests/Neo.UnitTests/SmartContract/UT_InteropService.cs
+++ b/tests/Neo.UnitTests/SmartContract/UT_InteropService.cs
@@ -10,6 +10,7 @@
// modifications are permitted.
using Akka.TestKit.Xunit2;
+using Akka.Util.Internal;
using FluentAssertions;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Neo.Cryptography;
@@ -507,6 +508,41 @@ public void TestBlockchain_GetContract()
NativeContract.ContractManagement.GetContract(engine.Snapshot, state.Hash).Hash.Should().Be(state.Hash);
}
+ [TestMethod]
+ public void TestBlockchain_GetContractById()
+ {
+ var engine = GetEngine(true, true);
+ var contract = NativeContract.ContractManagement.GetContractById(engine.Snapshot, -1);
+ contract.Id.Should().Be(-1);
+ contract.Manifest.Name.Should().Be(nameof(ContractManagement));
+ }
+
+ [TestMethod]
+ public void TestBlockchain_HasMethod()
+ {
+ var engine = GetEngine(true, true);
+ NativeContract.ContractManagement.HasMethod(engine.Snapshot, NativeContract.NEO.Hash, "symbol", 0).Should().Be(true);
+ NativeContract.ContractManagement.HasMethod(engine.Snapshot, NativeContract.NEO.Hash, "transfer", 4).Should().Be(true);
+ }
+
+ [TestMethod]
+ public void TestBlockchain_ListContracts()
+ {
+ var engine = GetEngine(true, true);
+ var list = NativeContract.ContractManagement.ListContracts(engine.Snapshot);
+ list.ForEach(p => p.Id.Should().BeLessThan(0));
+
+ var snapshot = TestBlockchain.GetTestSnapshot();
+ var state = TestUtils.GetContract();
+ snapshot.AddContract(state.Hash, state);
+ engine = ApplicationEngine.Create(TriggerType.Application, null, snapshot);
+ engine.LoadScript(new byte[] { 0x01 });
+ NativeContract.ContractManagement.GetContract(engine.Snapshot, state.Hash).Hash.Should().Be(state.Hash);
+
+ var list2 = NativeContract.ContractManagement.ListContracts(engine.Snapshot);
+ list2.Count().Should().Be(list.Count() + 1);
+ }
+
[TestMethod]
public void TestStorage_GetContext()
{
@@ -739,5 +775,92 @@ private static ApplicationEngine GetEngine(bool hasContainer = false, bool hasSn
if (addScript) engine.LoadScript(new byte[] { 0x01 });
return engine;
}
+
+ [TestMethod]
+ public void TestVerifyWithECDsaV0()
+ {
+ var privateKey = new byte[32];
+ using var rng = System.Security.Cryptography.RandomNumberGenerator.Create();
+ rng.GetBytes(privateKey);
+ var publicKeyR1 = new KeyPair(privateKey).PublicKey.ToArray();
+ var publicKeyK1 = (Neo.Cryptography.ECC.ECCurve.Secp256k1.G * privateKey).ToArray();
+ var hexMessage = "Hello, world!"u8.ToArray();
+ var signatureR1 = Crypto.Sign(hexMessage, privateKey, Neo.Cryptography.ECC.ECCurve.Secp256r1);
+ var signatureK1 = Crypto.Sign(hexMessage, privateKey, Neo.Cryptography.ECC.ECCurve.Secp256k1);
+
+ var result = CryptoLib.VerifyWithECDsaV0(hexMessage, publicKeyR1, signatureR1, NamedCurveHash.secp256r1SHA256);
+ result.Should().BeTrue();
+ result = CryptoLib.VerifyWithECDsaV0(hexMessage, publicKeyK1, signatureK1, NamedCurveHash.secp256k1SHA256);
+ result.Should().BeTrue();
+ result = CryptoLib.VerifyWithECDsaV0(hexMessage, publicKeyK1, new byte[0], NamedCurveHash.secp256k1SHA256);
+ result.Should().BeFalse();
+ Assert.ThrowsException(() => CryptoLib.VerifyWithECDsaV0(hexMessage, publicKeyK1, new byte[64], NamedCurveHash.secp256r1Keccak256));
+ }
+
+ [TestMethod]
+ public void TestSha256()
+ {
+ var input = "Hello, world!"u8.ToArray();
+ var actualHash = CryptoLib.Sha256(input);
+ var expectedHash = "315f5bdb76d078c43b8ac0064e4a0164612b1fce77c869345bfc94c75894edd3";
+ actualHash.ToHexString().Should().Be(expectedHash);
+ }
+
+ [TestMethod]
+ public void TestRIPEMD160()
+ {
+ var input = "Hello, world!"u8.ToArray();
+ var actualHash = CryptoLib.RIPEMD160(input);
+ var expectedHash = "58262d1fbdbe4530d8865d3518c6d6e41002610f";
+ actualHash.ToHexString().Should().Be(expectedHash);
+ }
+
+ [TestMethod]
+ public void TestMurmur32()
+ {
+ var input = "Hello, world!"u8.ToArray();
+ var actualHash = CryptoLib.Murmur32(input, 0);
+ var expectedHash = "433e36c0";
+ actualHash.ToHexString().Should().Be(expectedHash);
+ }
+
+ [TestMethod]
+ public void TestGetBlockHash()
+ {
+ var snapshot = GetEngine(true, true).Snapshot;
+ var hash = LedgerContract.Ledger.GetBlockHash(snapshot, 0);
+ var hash2 = LedgerContract.Ledger.GetBlock(snapshot, 0).Hash;
+ var hash3 = LedgerContract.Ledger.GetHeader(snapshot, 0).Hash;
+ hash.ToString().Should().Be(hash2.ToString());
+ hash.ToString().Should().Be(hash3.ToString());
+ hash.ToString().Should().Be("0x1f4d1defa46faa5e7b9b8d3f79a06bec777d7c26c4aa5f6f5899a291daa87c15");
+ LedgerContract.Ledger.ContainsBlock(snapshot, hash).Should().BeTrue();
+ }
+
+ [TestMethod]
+ public void TestGetCandidateVote()
+ {
+ var snapshot = GetEngine(true, true).Snapshot;
+ var vote = LedgerContract.NEO.GetCandidateVote(snapshot, new ECPoint());
+ vote.Should().Be(-1);
+ }
+
+ [TestMethod]
+ public void TestContractPermissionDescriptorEquals()
+ {
+ var descriptor1 = ContractPermissionDescriptor.CreateWildcard();
+ descriptor1.Equals(null).Should().BeFalse();
+ descriptor1.Equals(null as object).Should().BeFalse();
+ var descriptor2 = ContractPermissionDescriptor.Create(LedgerContract.NEO.Hash);
+ var descriptor3 = ContractPermissionDescriptor.Create(hash: null);
+ descriptor1.Equals(descriptor3).Should().BeTrue();
+ descriptor1.Equals(descriptor3 as object).Should().BeTrue();
+ var descriptor4 = ContractPermissionDescriptor.Create(group: null);
+ var descriptor5 = ContractPermissionDescriptor.Create(group: new ECPoint());
+ descriptor1.Equals(descriptor4).Should().BeTrue();
+ descriptor2.Equals(descriptor3).Should().BeFalse();
+ descriptor5.Equals(descriptor3).Should().BeFalse();
+ descriptor5.Equals(descriptor5).Should().BeTrue();
+ }
}
}
diff --git a/tests/Neo.UnitTests/SmartContract/UT_Syscalls.cs b/tests/Neo.UnitTests/SmartContract/UT_Syscalls.cs
index 76448855d7..e027fa4d88 100644
--- a/tests/Neo.UnitTests/SmartContract/UT_Syscalls.cs
+++ b/tests/Neo.UnitTests/SmartContract/UT_Syscalls.cs
@@ -81,10 +81,11 @@ public void System_Blockchain_GetBlock()
const byte Prefix_Transaction = 11;
const byte Prefix_CurrentBlock = 12;
+ TestUtils.BlocksAdd(snapshot, block.Hash, block);
+
var height = snapshot[NativeContract.Ledger.CreateStorageKey(Prefix_CurrentBlock)].GetInteroperable();
height.Index = block.Index + TestProtocolSettings.Default.MaxTraceableBlocks;
- TestUtils.BlocksAdd(snapshot, block.Hash, block);
snapshot.Add(NativeContract.Ledger.CreateStorageKey(Prefix_Transaction, tx.Hash), new StorageItem(new TransactionState
{
BlockIndex = block.Index,
diff --git a/tests/Neo.UnitTests/TestProtocolSettings.cs b/tests/Neo.UnitTests/TestProtocolSettings.cs
index b12f5c9a85..3f89fdd5f9 100644
--- a/tests/Neo.UnitTests/TestProtocolSettings.cs
+++ b/tests/Neo.UnitTests/TestProtocolSettings.cs
@@ -15,12 +15,12 @@ namespace Neo.UnitTests
{
public static class TestProtocolSettings
{
- public static ProtocolSettings Default = new()
+ public static readonly ProtocolSettings Default = new()
{
Network = 0x334F454Eu,
AddressVersion = ProtocolSettings.Default.AddressVersion,
- StandbyCommittee = new[]
- {
+ StandbyCommittee =
+ [
//Validators
ECPoint.Parse("03b209fd4f53a7170ea4444e0cb0a6bb6a53c2bd016926989cf85f9b0fba17a70c", ECCurve.Secp256r1),
ECPoint.Parse("02df48f60e8f3e01c48ff40b9b7f1310d7a8b2a193188befe1c2e3df740e895093", ECCurve.Secp256r1),
@@ -44,16 +44,42 @@ public static class TestProtocolSettings
ECPoint.Parse("0226933336f1b75baa42d42b71d9091508b638046d19abd67f4e119bf64a7cfb4d", ECCurve.Secp256r1),
ECPoint.Parse("03cdcea66032b82f5c30450e381e5295cae85c5e6943af716cc6b646352a6067dc", ECCurve.Secp256r1),
ECPoint.Parse("02cd5a5547119e24feaa7c2a0f37b8c9366216bab7054de0065c9be42084003c8a", ECCurve.Secp256r1)
- },
+ ],
ValidatorsCount = 7,
- SeedList = new[]
- {
+ SeedList =
+ [
"seed1.neo.org:10333",
"seed2.neo.org:10333",
"seed3.neo.org:10333",
"seed4.neo.org:10333",
"seed5.neo.org:10333"
- },
+ ],
+ MillisecondsPerBlock = ProtocolSettings.Default.MillisecondsPerBlock,
+ MaxTransactionsPerBlock = ProtocolSettings.Default.MaxTransactionsPerBlock,
+ MemoryPoolMaxTransactions = ProtocolSettings.Default.MemoryPoolMaxTransactions,
+ MaxTraceableBlocks = ProtocolSettings.Default.MaxTraceableBlocks,
+ InitialGasDistribution = ProtocolSettings.Default.InitialGasDistribution,
+ Hardforks = ProtocolSettings.Default.Hardforks
+ };
+
+ public static readonly ProtocolSettings SoleNode = new()
+ {
+ Network = 0x334F454Eu,
+ AddressVersion = ProtocolSettings.Default.AddressVersion,
+ StandbyCommittee =
+ [
+ //Validators
+ ECPoint.Parse("0278ed78c917797b637a7ed6e7a9d94e8c408444c41ee4c0a0f310a256b9271eda", ECCurve.Secp256r1)
+ ],
+ ValidatorsCount = 1,
+ SeedList =
+ [
+ "seed1.neo.org:10333",
+ "seed2.neo.org:10333",
+ "seed3.neo.org:10333",
+ "seed4.neo.org:10333",
+ "seed5.neo.org:10333"
+ ],
MillisecondsPerBlock = ProtocolSettings.Default.MillisecondsPerBlock,
MaxTransactionsPerBlock = ProtocolSettings.Default.MaxTransactionsPerBlock,
MemoryPoolMaxTransactions = ProtocolSettings.Default.MemoryPoolMaxTransactions,
diff --git a/tests/Neo.UnitTests/TestUtils.Block.cs b/tests/Neo.UnitTests/TestUtils.Block.cs
index 4f663fec2d..bed85131e6 100644
--- a/tests/Neo.UnitTests/TestUtils.Block.cs
+++ b/tests/Neo.UnitTests/TestUtils.Block.cs
@@ -30,10 +30,12 @@ public partial class TestUtils
const byte Prefix_Block = 5;
const byte Prefix_BlockHash = 9;
const byte Prefix_Transaction = 11;
+ const byte Prefix_CurrentBlock = 12;
///
/// Test Util function SetupHeaderWithValues
///
+ /// The snapshot of the current storage provider. Can be null.
/// The header to be assigned
/// PrevHash
/// MerkleRoot
@@ -42,12 +44,15 @@ public partial class TestUtils
/// Index
/// Nonce
/// Witness
- public static void SetupHeaderWithValues(Header header, UInt256 val256, out UInt256 merkRootVal, out UInt160 val160, out ulong timestampVal, out ulong nonceVal, out uint indexVal, out Witness scriptVal)
+ public static void SetupHeaderWithValues(DataCache snapshot, Header header, UInt256 val256, out UInt256 merkRootVal, out UInt160 val160, out ulong timestampVal, out ulong nonceVal, out uint indexVal, out Witness scriptVal)
{
header.PrevHash = val256;
header.MerkleRoot = merkRootVal = UInt256.Parse("0x6226416a0e5aca42b5566f5a19ab467692688ba9d47986f6981a7f747bba2772");
- header.Timestamp = timestampVal = new DateTime(1980, 06, 01, 0, 0, 1, 001, DateTimeKind.Utc).ToTimestampMS(); // GMT: Sunday, June 1, 1980 12:00:01.001 AM
- header.Index = indexVal = 0;
+ header.Timestamp = timestampVal = new DateTime(2024, 06, 05, 0, 33, 1, 001, DateTimeKind.Utc).ToTimestampMS();
+ if (snapshot != null)
+ header.Index = indexVal = NativeContract.Ledger.CurrentIndex(snapshot) + 1;
+ else
+ header.Index = indexVal = 0;
header.Nonce = nonceVal = 0;
header.NextConsensus = val160 = UInt160.Zero;
header.Witness = scriptVal = new Witness
@@ -57,10 +62,10 @@ public static void SetupHeaderWithValues(Header header, UInt256 val256, out UInt
};
}
- public static void SetupBlockWithValues(Block block, UInt256 val256, out UInt256 merkRootVal, out UInt160 val160, out ulong timestampVal, out ulong nonceVal, out uint indexVal, out Witness scriptVal, out Transaction[] transactionsVal, int numberOfTransactions)
+ public static void SetupBlockWithValues(DataCache snapshot, Block block, UInt256 val256, out UInt256 merkRootVal, out UInt160 val160, out ulong timestampVal, out ulong nonceVal, out uint indexVal, out Witness scriptVal, out Transaction[] transactionsVal, int numberOfTransactions)
{
Header header = new Header();
- SetupHeaderWithValues(header, val256, out merkRootVal, out val160, out timestampVal, out nonceVal, out indexVal, out scriptVal);
+ SetupHeaderWithValues(snapshot, header, val256, out merkRootVal, out val160, out timestampVal, out nonceVal, out indexVal, out scriptVal);
transactionsVal = new Transaction[numberOfTransactions];
if (numberOfTransactions > 0)
@@ -79,21 +84,32 @@ public static void SetupBlockWithValues(Block block, UInt256 val256, out UInt256
public static Block CreateBlockWithValidTransactions(DataCache snapshot, NEP6Wallet wallet, WalletAccount account, int numberOfTransactions)
{
- var block = new Block();
-
var transactions = new List();
for (var i = 0; i < numberOfTransactions; i++)
{
transactions.Add(CreateValidTx(snapshot, wallet, account));
}
+ return CreateBlockWithValidTransactions(snapshot, account, transactions.ToArray());
+ }
+
+ public static Block CreateBlockWithValidTransactions(DataCache snapshot, WalletAccount account, Transaction[] transactions)
+ {
+ var block = new Block();
var header = new Header();
- SetupHeaderWithValues(header, RandomUInt256(), out _, out _, out _, out _, out _, out _);
+ var state = snapshot.TryGet(NativeContract.Ledger.CreateStorageKey(Prefix_CurrentBlock)).GetInteroperable();
+ SetupHeaderWithValues(snapshot, header, state.Hash, out _, out _, out _, out _, out _, out _);
block.Header = header;
- block.Transactions = transactions.ToArray();
+ block.Transactions = transactions;
header.MerkleRoot = MerkleTree.ComputeRoot(block.Transactions.Select(p => p.Hash).ToArray());
+ var contract = Contract.CreateMultiSigContract(1, TestProtocolSettings.SoleNode.StandbyCommittee);
+ var sc = new ContractParametersContext(snapshot, header, TestProtocolSettings.SoleNode.Network);
+ var signature = header.Sign(account.GetKey(), TestProtocolSettings.SoleNode.Network);
+ sc.AddSignature(contract, TestProtocolSettings.SoleNode.StandbyCommittee[0], signature.ToArray());
+ block.Header.Witness = sc.GetWitnesses()[0];
+
return block;
}
@@ -115,6 +131,10 @@ public static void BlocksAdd(DataCache snapshot, UInt256 hash, TrimmedBlock bloc
{
snapshot.Add(NativeContract.Ledger.CreateStorageKey(Prefix_BlockHash, block.Index), new StorageItem(hash.ToArray()));
snapshot.Add(NativeContract.Ledger.CreateStorageKey(Prefix_Block, hash), new StorageItem(block.ToArray()));
+
+ var state = snapshot.GetAndChange(NativeContract.Ledger.CreateStorageKey(Prefix_CurrentBlock), () => new StorageItem(new HashIndexState())).GetInteroperable();
+ state.Hash = hash;
+ state.Index = block.Index;
}
public static void BlocksAdd(DataCache snapshot, UInt256 hash, Block block)
@@ -129,8 +149,42 @@ public static void BlocksAdd(DataCache snapshot, UInt256 hash, Block block)
};
TransactionAdd(snapshot, state);
});
+
snapshot.Add(NativeContract.Ledger.CreateStorageKey(Prefix_BlockHash, block.Index), new StorageItem(hash.ToArray()));
snapshot.Add(NativeContract.Ledger.CreateStorageKey(Prefix_Block, hash), new StorageItem(block.ToTrimmedBlock().ToArray()));
+ var state = snapshot.GetAndChange(NativeContract.Ledger.CreateStorageKey(Prefix_CurrentBlock), () => new StorageItem(new HashIndexState())).GetInteroperable();
+ state.Hash = hash;
+ state.Index = block.Index;
+ }
+
+ public static string CreateInvalidBlockFormat()
+ {
+ // Create a valid block
+ var validBlock = new Block
+ {
+ Header = new Header
+ {
+ Version = 0,
+ PrevHash = UInt256.Zero,
+ MerkleRoot = UInt256.Zero,
+ Timestamp = 0,
+ Index = 0,
+ NextConsensus = UInt160.Zero,
+ Witness = new Witness { InvocationScript = Array.Empty(), VerificationScript = Array.Empty() }
+ },
+ Transactions = []
+ };
+
+ // Serialize the valid block
+ byte[] validBlockBytes = validBlock.ToArray();
+
+ // Corrupt the serialized data
+ // For example, we can truncate the data by removing the last few bytes
+ byte[] invalidBlockBytes = new byte[validBlockBytes.Length - 5];
+ Array.Copy(validBlockBytes, invalidBlockBytes, invalidBlockBytes.Length);
+
+ // Convert the corrupted data to a Base64 string
+ return Convert.ToBase64String(invalidBlockBytes);
}
public static TrimmedBlock ToTrimmedBlock(this Block block)
diff --git a/tests/Neo.UnitTests/TestUtils.Transaction.cs b/tests/Neo.UnitTests/TestUtils.Transaction.cs
new file mode 100644
index 0000000000..f96ac8ec74
--- /dev/null
+++ b/tests/Neo.UnitTests/TestUtils.Transaction.cs
@@ -0,0 +1,129 @@
+// Copyright (C) 2015-2024 The Neo Project.
+//
+// TestUtils.Transaction.cs file belongs to the neo project and is free
+// software distributed under the MIT software license, see the
+// accompanying file LICENSE in the main directory of the
+// repository or http://www.opensource.org/licenses/mit-license.php
+// for more details.
+//
+// Redistribution and use in source and binary forms with or without
+// modifications are permitted.
+
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using Neo.Cryptography;
+using Neo.IO;
+using Neo.Network.P2P.Payloads;
+using Neo.Persistence;
+using Neo.SmartContract;
+using Neo.SmartContract.Native;
+using Neo.VM;
+using Neo.Wallets;
+using Neo.Wallets.NEP6;
+using System;
+using System.IO;
+using System.Linq;
+
+namespace Neo.UnitTests;
+
+public partial class TestUtils
+{
+ public static Transaction CreateInvalidTransaction(DataCache snapshot, NEP6Wallet wallet, WalletAccount account, InvalidTransactionType type, UInt256 conflict = null)
+ {
+ var rand = new Random();
+ var sender = account.ScriptHash;
+
+ var tx = new Transaction
+ {
+ Version = 0,
+ Nonce = (uint)rand.Next(),
+ ValidUntilBlock = NativeContract.Ledger.CurrentIndex(snapshot) + wallet.ProtocolSettings.MaxValidUntilBlockIncrement,
+ Signers = [new Signer { Account = sender, Scopes = WitnessScope.CalledByEntry }],
+ Attributes = [],
+ Script = new[] { (byte)OpCode.RET }
+ };
+
+ switch (type)
+ {
+ case InvalidTransactionType.InsufficientBalance:
+ // Set an unrealistically high system fee
+ tx.SystemFee = long.MaxValue;
+ break;
+ case InvalidTransactionType.InvalidScript:
+ // Use an invalid script
+ tx.Script = new byte[] { 0xFF };
+ break;
+ case InvalidTransactionType.InvalidAttribute:
+ // Add an invalid attribute
+ tx.Attributes = [new InvalidAttribute()];
+ break;
+ case InvalidTransactionType.Oversized:
+ // Make the transaction oversized
+ tx.Script = new byte[Transaction.MaxTransactionSize];
+ break;
+ case InvalidTransactionType.Expired:
+ // Set an expired ValidUntilBlock
+ tx.ValidUntilBlock = NativeContract.Ledger.CurrentIndex(snapshot) - 1;
+ break;
+ case InvalidTransactionType.Conflicting:
+ // To create a conflicting transaction, we'd need another valid transaction.
+ // For simplicity, we'll just add a Conflicts attribute with a random hash.
+ tx.Attributes = [new Conflicts { Hash = conflict }];
+ break;
+ }
+
+ var data = new ContractParametersContext(snapshot, tx, TestProtocolSettings.Default.Network);
+ Assert.IsNull(data.GetSignatures(tx.Sender));
+ Assert.IsTrue(wallet.Sign(data));
+ Assert.IsTrue(data.Completed);
+ Assert.AreEqual(1, data.GetSignatures(tx.Sender).Count);
+ tx.Witnesses = data.GetWitnesses();
+ if (type == InvalidTransactionType.InvalidSignature)
+ {
+ tx.Witnesses[0] = new Witness
+ {
+ InvocationScript = new byte[] { (byte)OpCode.PUSHDATA1, 64 }.Concat(new byte[64]).ToArray(),
+ VerificationScript = data.GetWitnesses()[0].VerificationScript
+ };
+ }
+
+ return tx;
+ }
+
+ public enum InvalidTransactionType
+ {
+ InsufficientBalance,
+ InvalidSignature,
+ InvalidScript,
+ InvalidAttribute,
+ Oversized,
+ Expired,
+ Conflicting
+ }
+
+ class InvalidAttribute : TransactionAttribute
+ {
+ public override TransactionAttributeType Type => (TransactionAttributeType)0xFF;
+ public override bool AllowMultiple { get; }
+ protected override void DeserializeWithoutType(ref MemoryReader reader) { }
+ protected override void SerializeWithoutType(BinaryWriter writer) { }
+ }
+
+ public static void AddTransactionToBlockchain(DataCache snapshot, Transaction tx)
+ {
+ var block = new Block
+ {
+ Header = new Header
+ {
+ Index = NativeContract.Ledger.CurrentIndex(snapshot) + 1,
+ PrevHash = NativeContract.Ledger.CurrentHash(snapshot),
+ MerkleRoot = new UInt256(Crypto.Hash256(tx.Hash.ToArray())),
+ Timestamp = TimeProvider.Current.UtcNow.ToTimestampMS(),
+ NextConsensus = UInt160.Zero,
+ Witness = new Witness { InvocationScript = Array.Empty(), VerificationScript = Array.Empty() }
+ },
+ Transactions = [tx]
+ };
+
+ BlocksAdd(snapshot, block.Hash, block);
+ }
+}
diff --git a/tests/Neo.UnitTests/TestUtils.cs b/tests/Neo.UnitTests/TestUtils.cs
index 55492d882c..c1694347a7 100644
--- a/tests/Neo.UnitTests/TestUtils.cs
+++ b/tests/Neo.UnitTests/TestUtils.cs
@@ -24,6 +24,7 @@
using Neo.Wallets;
using Neo.Wallets.NEP6;
using System;
+using System.Collections.Generic;
using System.Linq;
using System.Numerics;
@@ -136,15 +137,14 @@ public static Transaction CreateValidTx(DataCache snapshot, NEP6Wallet wallet, W
public static Transaction CreateValidTx(DataCache snapshot, NEP6Wallet wallet, UInt160 account, uint nonce)
{
- var tx = wallet.MakeTransaction(snapshot, new TransferOutput[]
- {
- new TransferOutput()
+ var tx = wallet.MakeTransaction(snapshot, [
+ new TransferOutput
{
AssetId = NativeContract.GAS.Hash,
ScriptHash = account,
- Value = new BigDecimal(BigInteger.One,8)
+ Value = new BigDecimal(BigInteger.One, 8)
}
- },
+ ],
account);
tx.Nonce = nonce;
@@ -159,6 +159,28 @@ public static Transaction CreateValidTx(DataCache snapshot, NEP6Wallet wallet, U
return tx;
}
+ public static Transaction CreateValidTx(DataCache snapshot, NEP6Wallet wallet, UInt160 account, uint nonce, UInt256[] conflicts)
+ {
+ var tx = wallet.MakeTransaction(snapshot, [
+ new TransferOutput
+ {
+ AssetId = NativeContract.GAS.Hash,
+ ScriptHash = account,
+ Value = new BigDecimal(BigInteger.One, 8)
+ }
+ ],
+ account);
+ tx.Attributes = conflicts.Select(conflict => new Conflicts { Hash = conflict }).ToArray();
+ tx.Nonce = nonce;
+
+ var data = new ContractParametersContext(snapshot, tx, TestProtocolSettings.Default.Network);
+ Assert.IsNull(data.GetSignatures(tx.Sender));
+ Assert.IsTrue(wallet.Sign(data));
+ Assert.IsTrue(data.Completed);
+ Assert.AreEqual(1, data.GetSignatures(tx.Sender).Count);
+ tx.Witnesses = data.GetWitnesses();
+ return tx;
+ }
public static Transaction GetTransaction(UInt160 sender)
{
@@ -266,6 +288,15 @@ public static Transaction CreateRandomHashTransaction()
};
}
+ public static void FillMemoryPool(DataCache snapshot, NeoSystem system, NEP6Wallet wallet, WalletAccount account)
+ {
+ for (int i = 0; i < system.Settings.MemoryPoolMaxTransactions; i++)
+ {
+ var tx = CreateValidTx(snapshot, wallet, account);
+ system.MemPool.TryAdd(tx, snapshot);
+ }
+ }
+
public static T CopyMsgBySerialization(T serializableObj, T newObj) where T : ISerializable
{
MemoryReader reader = new(serializableObj.ToArray());