From d1eab9ab83012e4458c2ab6da189c02025b428a1 Mon Sep 17 00:00:00 2001 From: Jimmy Date: Fri, 14 Jun 2024 06:32:32 +0300 Subject: [PATCH 01/20] try mock --- src/Plugins/RpcServer/RpcServer.Blockchain.cs | 2 +- .../UT_RpcServer.Blockchain.cs | 80 +++++++++++++++++++ .../UT_RpcServer.cs | 56 +++++++------ 3 files changed, 111 insertions(+), 27 deletions(-) create mode 100644 tests/Neo.Plugins.RpcServer.Tests/UT_RpcServer.Blockchain.cs diff --git a/src/Plugins/RpcServer/RpcServer.Blockchain.cs b/src/Plugins/RpcServer/RpcServer.Blockchain.cs index 1c8eecb99f..7d55d316d1 100644 --- a/src/Plugins/RpcServer/RpcServer.Blockchain.cs +++ b/src/Plugins/RpcServer/RpcServer.Blockchain.cs @@ -25,7 +25,7 @@ namespace Neo.Plugins.RpcServer partial class RpcServer { [RpcMethod] - protected virtual JToken GetBestBlockHash(JArray _params) + protected internal virtual JToken GetBestBlockHash(JArray _params) { return NativeContract.Ledger.CurrentHash(system.StoreView).ToString(); } diff --git a/tests/Neo.Plugins.RpcServer.Tests/UT_RpcServer.Blockchain.cs b/tests/Neo.Plugins.RpcServer.Tests/UT_RpcServer.Blockchain.cs new file mode 100644 index 0000000000..b7e3d4866a --- /dev/null +++ b/tests/Neo.Plugins.RpcServer.Tests/UT_RpcServer.Blockchain.cs @@ -0,0 +1,80 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// UT_RpcServer.Blockchain.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.AspNetCore.Http; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Moq; +using Neo.Ledger; +using Neo.Network.P2P.Payloads; +using Neo.Persistence; +using Neo.SmartContract.Native; +using Neo.VM.Types; +using System; +using System.Linq; +using System.Text; +using Neo.Json; + +namespace Neo.Plugins.RpcServer.Tests +{ + public partial class UT_RpcServer + { + + [TestMethod] + public void TestGetBestBlockHash() + { + // Arrange + var expectedHash = UInt256.Parse("0x0"); + + _iSnapshotMock.Setup(s => s.TryGet(new byte[]{0x00, 0x00, 0x00})).Returns([0x00]); + NativeContract.Ledger.CurrentHash(_neoSystem.StoreView); + + // Act + var result = _rpcServer.GetBestBlockHash(new JArray()); + + // Assert + Assert.AreEqual(expectedHash.ToString(), result.AsString()); + } + // + // [TestMethod] + // public void TestGetBlockByHash() + // { + // // Arrange + // var blockHash = UInt256.Parse("0x0"); + // var mockSnapshot = new Mock(); + // var block = new Block(); + // _systemMock.Setup(s => s.StoreView).Returns(mockSnapshot.Object); + // NativeContract.Ledger.GetBlock(mockSnapshot.Object, blockHash).Returns(block); + // + // var parameters = new JArray(blockHash.ToString(), true); + // + // // Act + // var result = _rpcServer.GetBlock(parameters); + // + // // Assert + // Assert.IsInstanceOfType(result, typeof(JObject)); + // } + // + // [TestMethod] + // public void TestGetBlockCount() + // { + // // Arrange + // var mockSnapshot = new Mock(); + // _systemMock.Setup(s => s.StoreView).Returns(mockSnapshot.Object); + // NativeContract.Ledger.CurrentIndex(mockSnapshot.Object).Returns(1234u); + // + // // Act + // var result = _rpcServer.GetBlockCount(new JArray()); + // + // // Assert + // Assert.AreEqual(1235u, result.AsNumber()); + // } + } +} diff --git a/tests/Neo.Plugins.RpcServer.Tests/UT_RpcServer.cs b/tests/Neo.Plugins.RpcServer.Tests/UT_RpcServer.cs index 7bca550b83..4be81374ea 100644 --- a/tests/Neo.Plugins.RpcServer.Tests/UT_RpcServer.cs +++ b/tests/Neo.Plugins.RpcServer.Tests/UT_RpcServer.cs @@ -1,20 +1,10 @@ -// Copyright (C) 2015-2024 The Neo Project. -// -// UT_RpcServer.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.AspNetCore.Http; using Microsoft.VisualStudio.TestTools.UnitTesting; using Moq; using Neo.Ledger; using Neo.Persistence; using System; +using System.Collections.Generic; using System.Text; namespace Neo.Plugins.RpcServer.Tests @@ -22,40 +12,54 @@ namespace Neo.Plugins.RpcServer.Tests [TestClass] public partial class UT_RpcServer { - private Mock _systemMock; - private SnapshotCache _snapshotCache; - private MemoryPool _memoryPool; - private RpcServerSettings _settings; + private NeoSystem _neoSystem; private RpcServer _rpcServer; + private Mock _iSnapshotMock; [TestInitialize] public void TestSetup() { - // Mock IReadOnlyStore - var mockStore = new Mock(); + // Mock IStore and ISnapshot + var mockStore = new Mock(); - // Initialize SnapshotCache with the mock IReadOnlyStore - _snapshotCache = new SnapshotCache(mockStore.Object); + // Setup mock behaviors for ISnapshot + _iSnapshotMock.Setup(snapshot => snapshot.TryGet(It.IsAny())) + .Returns((byte[] key) => null); // Return null or appropriate value + _iSnapshotMock.Setup(snapshot => snapshot.Seek(It.IsAny(), It.IsAny())) + .Returns(new List<(byte[], byte[])>()); // Return an empty list or appropriate values - // Initialize NeoSystem - var neoSystem = new NeoSystem(TestProtocolSettings.Default, new TestBlockchain.StoreProvider()); + // Setup mock behaviors for IStore + mockStore.Setup(store => store.GetSnapshot()).Returns(_iSnapshotMock.Object); + mockStore.Setup(store => store.Put(It.IsAny(), It.IsAny())); + mockStore.Setup(store => store.Delete(It.IsAny())); + mockStore.Setup(store => store.Contains(It.IsAny())).Returns(false); // Return appropriate value - // Initialize MemoryPool with the NeoSystem - _memoryPool = new MemoryPool(neoSystem); + // Mock IStoreProvider + var mockStoreProvider = new Mock(); + mockStoreProvider.Setup(provider => provider.GetStore(It.IsAny())).Returns(mockStore.Object); - // Set up the mock system with the correct constructor arguments - _systemMock = new Mock(_snapshotCache, _memoryPool); + // Initialize NeoSystem with the mocked store provider + var protocolSettings = TestProtocolSettings.Default; + var neoSystem = new NeoSystem(protocolSettings, mockStoreProvider.Object); - _rpcServer = new RpcServer(_systemMock.Object, RpcServerSettings.Default); + // Initialize RpcServer with the actual NeoSystem and default settings + _rpcServer = new RpcServer(neoSystem, RpcServerSettings.Default); } [TestMethod] public void TestCheckAuth_ValidCredentials_ReturnsTrue() { + // Arrange var context = new DefaultHttpContext(); context.Request.Headers["Authorization"] = "Basic " + Convert.ToBase64String(Encoding.UTF8.GetBytes("testuser:testpass")); + + // Act var result = _rpcServer.CheckAuth(context); + + // Assert Assert.IsTrue(result); } + + } } From dff3c79466e41beb07a6e96a333b010dd57eb318 Mon Sep 17 00:00:00 2001 From: Jimmy Date: Fri, 14 Jun 2024 17:09:37 +0800 Subject: [PATCH 02/20] not use mock --- src/Neo.IO/ByteArrayComparer.cs | 2 +- .../MockNeoSystem.cs | 34 ------------------ .../Neo.Plugins.RpcServer.Tests.csproj | 1 + .../TestMemoryStoreProvider.cs | 21 +++++++++++ .../UT_RpcServer.Blockchain.cs | 16 +++++---- .../UT_RpcServer.cs | 36 +++++++------------ 6 files changed, 44 insertions(+), 66 deletions(-) delete mode 100644 tests/Neo.Plugins.RpcServer.Tests/MockNeoSystem.cs create mode 100644 tests/Neo.Plugins.RpcServer.Tests/TestMemoryStoreProvider.cs diff --git a/src/Neo.IO/ByteArrayComparer.cs b/src/Neo.IO/ByteArrayComparer.cs index f9d44e24d6..6c375646cc 100644 --- a/src/Neo.IO/ByteArrayComparer.cs +++ b/src/Neo.IO/ByteArrayComparer.cs @@ -15,7 +15,7 @@ namespace Neo.IO { - internal class ByteArrayComparer : IComparer + public class ByteArrayComparer : IComparer { public static readonly ByteArrayComparer Default = new(1); public static readonly ByteArrayComparer Reverse = new(-1); diff --git a/tests/Neo.Plugins.RpcServer.Tests/MockNeoSystem.cs b/tests/Neo.Plugins.RpcServer.Tests/MockNeoSystem.cs deleted file mode 100644 index 0f45a63d98..0000000000 --- a/tests/Neo.Plugins.RpcServer.Tests/MockNeoSystem.cs +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright (C) 2015-2024 The Neo Project. -// -// MockNeoSystem.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.Ledger; -using Neo.Persistence; - -namespace Neo.Plugins.RpcServer.Tests -{ - public class MockNeoSystem : NeoSystem - { - public SnapshotCache SnapshotCache { get; } - public MemoryPool MemoryPool { get; } - - public MockNeoSystem(SnapshotCache snapshotCache, MemoryPool memoryPool) - : base(TestProtocolSettings.Default, new TestBlockchain.StoreProvider()) - { - SnapshotCache = snapshotCache; - MemoryPool = memoryPool; - } - - public SnapshotCache GetSnapshot() - { - return SnapshotCache; - } - } -} diff --git a/tests/Neo.Plugins.RpcServer.Tests/Neo.Plugins.RpcServer.Tests.csproj b/tests/Neo.Plugins.RpcServer.Tests/Neo.Plugins.RpcServer.Tests.csproj index 5b693c96b8..2ab06884fc 100644 --- a/tests/Neo.Plugins.RpcServer.Tests/Neo.Plugins.RpcServer.Tests.csproj +++ b/tests/Neo.Plugins.RpcServer.Tests/Neo.Plugins.RpcServer.Tests.csproj @@ -4,6 +4,7 @@ net8.0 Neo.Plugins.RpcServer.Tests Neo.Plugins.RpcServer.Tests + true diff --git a/tests/Neo.Plugins.RpcServer.Tests/TestMemoryStoreProvider.cs b/tests/Neo.Plugins.RpcServer.Tests/TestMemoryStoreProvider.cs new file mode 100644 index 0000000000..b39b4aeae5 --- /dev/null +++ b/tests/Neo.Plugins.RpcServer.Tests/TestMemoryStoreProvider.cs @@ -0,0 +1,21 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// TestMemoryStoreProvider.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.Persistence; + +namespace Neo.Plugins.RpcServer.Tests; + +public class TestMemoryStoreProvider(MemoryStore memoryStore) : IStoreProvider +{ + public MemoryStore MemoryStore { get; init; } = memoryStore; + public string Name => nameof(MemoryStore); + public IStore GetStore(string path) => MemoryStore; +} diff --git a/tests/Neo.Plugins.RpcServer.Tests/UT_RpcServer.Blockchain.cs b/tests/Neo.Plugins.RpcServer.Tests/UT_RpcServer.Blockchain.cs index b7e3d4866a..f6e14ba30d 100644 --- a/tests/Neo.Plugins.RpcServer.Tests/UT_RpcServer.Blockchain.cs +++ b/tests/Neo.Plugins.RpcServer.Tests/UT_RpcServer.Blockchain.cs @@ -12,15 +12,17 @@ using Microsoft.AspNetCore.Http; using Microsoft.VisualStudio.TestTools.UnitTesting; using Moq; +using Neo.IO; +using Neo.Json; using Neo.Ledger; using Neo.Network.P2P.Payloads; using Neo.Persistence; +using Neo.SmartContract; using Neo.SmartContract.Native; using Neo.VM.Types; using System; using System.Linq; using System.Text; -using Neo.Json; namespace Neo.Plugins.RpcServer.Tests { @@ -30,14 +32,14 @@ public partial class UT_RpcServer [TestMethod] public void TestGetBestBlockHash() { + var key = new KeyBuilder(5, 12); // Arrange - var expectedHash = UInt256.Parse("0x0"); - - _iSnapshotMock.Setup(s => s.TryGet(new byte[]{0x00, 0x00, 0x00})).Returns([0x00]); - NativeContract.Ledger.CurrentHash(_neoSystem.StoreView); + var expectedHash = UInt256.Zero; + var state = new HashIndexState { Hash = UInt256.Zero, Index = 100 }; + var item = new StorageItem(state); - // Act - var result = _rpcServer.GetBestBlockHash(new JArray()); + _neoSystem.StoreView.Add(key, item); + var result = _rpcServer.GetBestBlockHash([]); // Assert Assert.AreEqual(expectedHash.ToString(), result.AsString()); diff --git a/tests/Neo.Plugins.RpcServer.Tests/UT_RpcServer.cs b/tests/Neo.Plugins.RpcServer.Tests/UT_RpcServer.cs index 4be81374ea..ffc9a17581 100644 --- a/tests/Neo.Plugins.RpcServer.Tests/UT_RpcServer.cs +++ b/tests/Neo.Plugins.RpcServer.Tests/UT_RpcServer.cs @@ -14,38 +14,26 @@ public partial class UT_RpcServer { private NeoSystem _neoSystem; private RpcServer _rpcServer; - private Mock _iSnapshotMock; + private TestMemoryStoreProvider _memoryStoreProvider; + private MemoryStore _memoryStore; [TestInitialize] public void TestSetup() { - // Mock IStore and ISnapshot - var mockStore = new Mock(); - - // Setup mock behaviors for ISnapshot - _iSnapshotMock.Setup(snapshot => snapshot.TryGet(It.IsAny())) - .Returns((byte[] key) => null); // Return null or appropriate value - _iSnapshotMock.Setup(snapshot => snapshot.Seek(It.IsAny(), It.IsAny())) - .Returns(new List<(byte[], byte[])>()); // Return an empty list or appropriate values - - // Setup mock behaviors for IStore - mockStore.Setup(store => store.GetSnapshot()).Returns(_iSnapshotMock.Object); - mockStore.Setup(store => store.Put(It.IsAny(), It.IsAny())); - mockStore.Setup(store => store.Delete(It.IsAny())); - mockStore.Setup(store => store.Contains(It.IsAny())).Returns(false); // Return appropriate value - - // Mock IStoreProvider - var mockStoreProvider = new Mock(); - mockStoreProvider.Setup(provider => provider.GetStore(It.IsAny())).Returns(mockStore.Object); - - // Initialize NeoSystem with the mocked store provider + _memoryStore = new MemoryStore(); + _memoryStoreProvider = new TestMemoryStoreProvider(_memoryStore); var protocolSettings = TestProtocolSettings.Default; - var neoSystem = new NeoSystem(protocolSettings, mockStoreProvider.Object); - - // Initialize RpcServer with the actual NeoSystem and default settings + var neoSystem = new NeoSystem(protocolSettings, _memoryStoreProvider); _rpcServer = new RpcServer(neoSystem, RpcServerSettings.Default); } + [TestCleanup] + public void TestCleanup() + { + _memoryStore.GetSnapshot().Commit(); + _memoryStore.Reset(); + } + [TestMethod] public void TestCheckAuth_ValidCredentials_ReturnsTrue() { From cb5c8750b0f5e57e8d67e664d6b58998a1f5f869 Mon Sep 17 00:00:00 2001 From: Jimmy Date: Fri, 14 Jun 2024 19:17:19 +0800 Subject: [PATCH 03/20] test --- src/Neo/Persistence/SnapshotCache.cs | 12 ++++++++++++ .../UT_RpcServer.Blockchain.cs | 10 ++++++++-- tests/Neo.Plugins.RpcServer.Tests/UT_RpcServer.cs | 4 ++-- 3 files changed, 22 insertions(+), 4 deletions(-) diff --git a/src/Neo/Persistence/SnapshotCache.cs b/src/Neo/Persistence/SnapshotCache.cs index 6731e5342f..cf88cba9f0 100644 --- a/src/Neo/Persistence/SnapshotCache.cs +++ b/src/Neo/Persistence/SnapshotCache.cs @@ -37,11 +37,19 @@ public SnapshotCache(IReadOnlyStore store) protected override void AddInternal(StorageKey key, StorageItem value) { + if (store is MemoryStore memoryStore) + { + memoryStore.Put(key.ToArray(), value.ToArray()); + } snapshot?.Put(key.ToArray(), value.ToArray()); } protected override void DeleteInternal(StorageKey key) { + if (store is MemoryStore memoryStore) + { + memoryStore.Delete(key.ToArray()); + } snapshot?.Delete(key.ToArray()); } @@ -82,6 +90,10 @@ protected override StorageItem TryGetInternal(StorageKey key) protected override void UpdateInternal(StorageKey key, StorageItem value) { + if (store is MemoryStore memoryStore) + { + memoryStore.Put(key.ToArray(), value.ToArray()); + } snapshot?.Put(key.ToArray(), value.ToArray()); } } diff --git a/tests/Neo.Plugins.RpcServer.Tests/UT_RpcServer.Blockchain.cs b/tests/Neo.Plugins.RpcServer.Tests/UT_RpcServer.Blockchain.cs index f6e14ba30d..637d010605 100644 --- a/tests/Neo.Plugins.RpcServer.Tests/UT_RpcServer.Blockchain.cs +++ b/tests/Neo.Plugins.RpcServer.Tests/UT_RpcServer.Blockchain.cs @@ -32,13 +32,19 @@ public partial class UT_RpcServer [TestMethod] public void TestGetBestBlockHash() { - var key = new KeyBuilder(5, 12); + var key = new KeyBuilder(-4, 12); + var c = key.ToArray(); // Arrange var expectedHash = UInt256.Zero; var state = new HashIndexState { Hash = UInt256.Zero, Index = 100 }; var item = new StorageItem(state); - _neoSystem.StoreView.Add(key, item); + var v = _neoSystem.StoreView; + var b = v.GetAndChange(key, () => new StorageItem(new HashIndexState())).GetInteroperable(); + b.Hash = UInt256.Zero; + b.Index = 100; + v.Commit(); + b = v.GetAndChange(key, () => new StorageItem(new HashIndexState())).GetInteroperable(); var result = _rpcServer.GetBestBlockHash([]); // Assert diff --git a/tests/Neo.Plugins.RpcServer.Tests/UT_RpcServer.cs b/tests/Neo.Plugins.RpcServer.Tests/UT_RpcServer.cs index ffc9a17581..1a79853540 100644 --- a/tests/Neo.Plugins.RpcServer.Tests/UT_RpcServer.cs +++ b/tests/Neo.Plugins.RpcServer.Tests/UT_RpcServer.cs @@ -23,8 +23,8 @@ public void TestSetup() _memoryStore = new MemoryStore(); _memoryStoreProvider = new TestMemoryStoreProvider(_memoryStore); var protocolSettings = TestProtocolSettings.Default; - var neoSystem = new NeoSystem(protocolSettings, _memoryStoreProvider); - _rpcServer = new RpcServer(neoSystem, RpcServerSettings.Default); + _neoSystem = new NeoSystem(protocolSettings, _memoryStoreProvider); + _rpcServer = new RpcServer(_neoSystem, RpcServerSettings.Default); } [TestCleanup] From cccab7615851252d97de50e4e3906f96703be9fd Mon Sep 17 00:00:00 2001 From: Jimmy Date: Sat, 15 Jun 2024 19:37:22 +0800 Subject: [PATCH 04/20] fix test --- src/Plugins/RpcServer/RpcServer.Blockchain.cs | 98 +++++++++++++++ .../Neo.Plugins.RpcServer.Tests.csproj | 1 + .../UT_RpcServer.Blockchain.cs | 113 ++++++++++++------ 3 files changed, 178 insertions(+), 34 deletions(-) diff --git a/src/Plugins/RpcServer/RpcServer.Blockchain.cs b/src/Plugins/RpcServer/RpcServer.Blockchain.cs index 7d55d316d1..90a2f54969 100644 --- a/src/Plugins/RpcServer/RpcServer.Blockchain.cs +++ b/src/Plugins/RpcServer/RpcServer.Blockchain.cs @@ -24,12 +24,26 @@ namespace Neo.Plugins.RpcServer { partial class RpcServer { + + /// + /// Gets the hash of the best (most recent) block. + /// + /// An empty array; no parameters are required. + /// The hash of the best block as a JToken. [RpcMethod] protected internal virtual JToken GetBestBlockHash(JArray _params) { return NativeContract.Ledger.CurrentHash(system.StoreView).ToString(); } + /// + /// Gets a block by its hash or index. + /// + /// + /// An array containing the block hash or index as the first element, + /// and an optional boolean indicating whether to return verbose information. + /// + /// The block data as a JToken. [RpcMethod] protected virtual JToken GetBlock(JArray _params) { @@ -60,18 +74,33 @@ protected virtual JToken GetBlock(JArray _params) return Convert.ToBase64String(block.ToArray()); } + /// + /// Gets the number of block headers in the blockchain. + /// + /// An empty array; no parameters are required. + /// The count of block headers as a JToken. [RpcMethod] internal virtual JToken GetBlockHeaderCount(JArray _params) { return (system.HeaderCache.Last?.Index ?? NativeContract.Ledger.CurrentIndex(system.StoreView)) + 1; } + /// + /// Gets the number of blocks in the blockchain. + /// + /// An empty array; no parameters are required. + /// The count of blocks as a JToken. [RpcMethod] protected virtual JToken GetBlockCount(JArray _params) { return NativeContract.Ledger.CurrentIndex(system.StoreView) + 1; } + /// + /// Gets the hash of the block at the specified height. + /// + /// An array containing the block height as the first element. + /// The hash of the block at the specified height as a JToken. [RpcMethod] protected virtual JToken GetBlockHash(JArray _params) { @@ -84,6 +113,14 @@ protected virtual JToken GetBlockHash(JArray _params) throw new RpcException(RpcError.UnknownHeight); } + /// + /// Gets a block header by its hash or index. + /// + /// + /// An array containing the block header hash or index as the first element, + /// and an optional boolean indicating whether to return verbose information. + /// + /// The block header data as a JToken. [RpcMethod] protected virtual JToken GetBlockHeader(JArray _params) { @@ -114,6 +151,11 @@ protected virtual JToken GetBlockHeader(JArray _params) return Convert.ToBase64String(header.ToArray()); } + /// + /// Gets the state of a contract by its ID or script hash. + /// + /// An array containing the contract ID or script hash as the first element. + /// The contract state as a JToken. [RpcMethod] protected virtual JToken GetContractState(JArray _params) { @@ -128,6 +170,7 @@ protected virtual JToken GetContractState(JArray _params) return contract.NotNull_Or(RpcError.UnknownContract).ToJson(); } + private static UInt160 ToScriptHash(string keyword) { foreach (var native in NativeContract.Contracts) @@ -139,6 +182,11 @@ private static UInt160 ToScriptHash(string keyword) return UInt160.Parse(keyword); } + /// + /// Gets the current memory pool transactions. + /// + /// An array containing an optional boolean indicating whether to include unverified transactions. + /// The memory pool transactions as a JToken. [RpcMethod] protected virtual JToken GetRawMemPool(JArray _params) { @@ -156,6 +204,14 @@ protected virtual JToken GetRawMemPool(JArray _params) return json; } + /// + /// Gets a transaction by its hash. + /// + /// + /// An array containing the transaction hash as the first element, + /// and an optional boolean indicating whether to return verbose information. + /// + /// The transaction data as a JToken. [RpcMethod] protected virtual JToken GetRawTransaction(JArray _params) { @@ -179,6 +235,14 @@ protected virtual JToken GetRawTransaction(JArray _params) return json; } + /// + /// Gets the storage item by contract ID or script hash and key. + /// + /// + /// An array containing the contract ID or script hash as the first element, + /// and the storage key as the second element. + /// + /// The storage item as a JToken. [RpcMethod] protected virtual JToken GetStorage(JArray _params) { @@ -198,6 +262,15 @@ protected virtual JToken GetStorage(JArray _params) return Convert.ToBase64String(item.Value.Span); } + /// + /// Finds storage items by contract ID or script hash and prefix. + /// + /// + /// An array containing the contract ID or script hash as the first element, + /// the storage key prefix as the second element, + /// and an optional start index as the third element. + /// + /// The found storage items as a . [RpcMethod] protected virtual JToken FindStorage(JArray _params) { @@ -247,6 +320,11 @@ protected virtual JToken FindStorage(JArray _params) return json; } + /// + /// Gets the height of a transaction by its hash. + /// + /// An array containing the transaction hash as the first element. + /// The height of the transaction as a . [RpcMethod] protected virtual JToken GetTransactionHeight(JArray _params) { @@ -256,6 +334,11 @@ protected virtual JToken GetTransactionHeight(JArray _params) throw new RpcException(RpcError.UnknownTransaction); } + /// + /// Gets the next block validators. + /// + /// An empty array; no parameters are required. + /// The next block validators as a . [RpcMethod] protected virtual JToken GetNextBlockValidators(JArray _params) { @@ -270,6 +353,11 @@ protected virtual JToken GetNextBlockValidators(JArray _params) }).ToArray(); } + /// + /// Gets the list of candidates for the next block validators. + /// + /// An empty array; no parameters are required. + /// The candidates public key list as a JToken. [RpcMethod] protected virtual JToken GetCandidates(JArray _params) { @@ -322,12 +410,22 @@ protected virtual JToken GetCandidates(JArray _params) return json; } + /// + /// Gets the list of committee members. + /// + /// An empty array; no parameters are required. + /// The committee members publickeys as a . [RpcMethod] protected virtual JToken GetCommittee(JArray _params) { return new JArray(NativeContract.NEO.GetCommittee(system.StoreView).Select(p => (JToken)p.ToString())); } + /// + /// Gets the list of native contracts. + /// + /// An empty array; no parameters are required. + /// The native contract states as a . [RpcMethod] protected virtual JToken GetNativeContracts(JArray _params) { diff --git a/tests/Neo.Plugins.RpcServer.Tests/Neo.Plugins.RpcServer.Tests.csproj b/tests/Neo.Plugins.RpcServer.Tests/Neo.Plugins.RpcServer.Tests.csproj index 2ab06884fc..1586b9753d 100644 --- a/tests/Neo.Plugins.RpcServer.Tests/Neo.Plugins.RpcServer.Tests.csproj +++ b/tests/Neo.Plugins.RpcServer.Tests/Neo.Plugins.RpcServer.Tests.csproj @@ -17,6 +17,7 @@ + \ No newline at end of file diff --git a/tests/Neo.Plugins.RpcServer.Tests/UT_RpcServer.Blockchain.cs b/tests/Neo.Plugins.RpcServer.Tests/UT_RpcServer.Blockchain.cs index 637d010605..12c6a5a921 100644 --- a/tests/Neo.Plugins.RpcServer.Tests/UT_RpcServer.Blockchain.cs +++ b/tests/Neo.Plugins.RpcServer.Tests/UT_RpcServer.Blockchain.cs @@ -9,66 +9,111 @@ // Redistribution and use in source and binary forms with or without // modifications are permitted. -using Microsoft.AspNetCore.Http; +using FluentAssertions; using Microsoft.VisualStudio.TestTools.UnitTesting; using Moq; -using Neo.IO; using Neo.Json; -using Neo.Ledger; using Neo.Network.P2P.Payloads; using Neo.Persistence; using Neo.SmartContract; using Neo.SmartContract.Native; -using Neo.VM.Types; +using Neo.UnitTests; +using Neo.UnitTests.SmartContract; +using Neo.VM; using System; -using System.Linq; -using System.Text; namespace Neo.Plugins.RpcServer.Tests { public partial class UT_RpcServer { + public static TrimmedBlock GetTrimmedBlockWithNoTransaction() + { + return new TrimmedBlock + { + Header = new Header + { + MerkleRoot = UInt256.Parse("0xa400ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff02"), + PrevHash = UInt256.Parse("0xa400ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff01"), + Timestamp = new DateTime(1988, 06, 01, 0, 0, 0, DateTimeKind.Utc).ToTimestamp(), + Index = 1, + NextConsensus = UInt160.Parse("0xa400ff00ff00ff00ff00ff00ff00ff00ff00ff01"), + Witness = new Witness + { + InvocationScript = Array.Empty(), + VerificationScript = new[] { (byte)OpCode.PUSH1 } + }, + }, + Hashes = Array.Empty() + }; + } [TestMethod] public void TestGetBestBlockHash() { var key = new KeyBuilder(-4, 12); - var c = key.ToArray(); - // Arrange var expectedHash = UInt256.Zero; - var state = new HashIndexState { Hash = UInt256.Zero, Index = 100 }; - var item = new StorageItem(state); - var v = _neoSystem.StoreView; - var b = v.GetAndChange(key, () => new StorageItem(new HashIndexState())).GetInteroperable(); + var snapshot = _neoSystem.GetSnapshot(); + var b = snapshot.GetAndChange(key, () => new StorageItem(new HashIndexState())).GetInteroperable(); b.Hash = UInt256.Zero; b.Index = 100; - v.Commit(); - b = v.GetAndChange(key, () => new StorageItem(new HashIndexState())).GetInteroperable(); + snapshot.Commit(); var result = _rpcServer.GetBestBlockHash([]); - // Assert Assert.AreEqual(expectedHash.ToString(), result.AsString()); } - // - // [TestMethod] - // public void TestGetBlockByHash() - // { - // // Arrange - // var blockHash = UInt256.Parse("0x0"); - // var mockSnapshot = new Mock(); - // var block = new Block(); - // _systemMock.Setup(s => s.StoreView).Returns(mockSnapshot.Object); - // NativeContract.Ledger.GetBlock(mockSnapshot.Object, blockHash).Returns(block); - // - // var parameters = new JArray(blockHash.ToString(), true); - // - // // Act - // var result = _rpcServer.GetBlock(parameters); - // - // // Assert - // Assert.IsInstanceOfType(result, typeof(JObject)); - // } + + [TestMethod] + public void TestGetBlockByHash() + { + var snapshot = TestBlockchain.GetTestSnapshot(); + var tx1 = TestUtils.GetTransaction(UInt160.Zero); + tx1.Script = new byte[] { 0x01,0x01,0x01,0x01, + 0x01,0x01,0x01,0x01, + 0x01,0x01,0x01,0x01, + 0x01,0x01,0x01,0x01 }; + var state1 = new TransactionState + { + Transaction = tx1, + BlockIndex = 1 + }; + var tx2 = TestUtils.GetTransaction(UInt160.Zero); + tx2.Script = new byte[] { 0x01,0x01,0x01,0x01, + 0x01,0x01,0x01,0x01, + 0x01,0x01,0x01,0x01, + 0x01,0x01,0x01,0x02 }; + var state2 = new TransactionState + { + Transaction = tx2, + BlockIndex = 1 + }; + UT_SmartContractHelper.TransactionAdd(snapshot, state1, state2); + + TrimmedBlock tblock = GetTrimmedBlockWithNoTransaction(); + tblock.Hashes = new UInt256[] { tx1.Hash, tx2.Hash }; + UT_SmartContractHelper.BlocksAdd(snapshot, tblock.Hash, tblock); + + Block block = NativeContract.Ledger.GetBlock(snapshot, tblock.Hash); + + block.Index.Should().Be(1); + block.MerkleRoot.Should().Be(UInt256.Parse("0xa400ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff02")); + block.Transactions.Length.Should().Be(2); + block.Transactions[0].Hash.Should().Be(tx1.Hash); + block.Witness.InvocationScript.Span.ToHexString().Should().Be(tblock.Header.Witness.InvocationScript.Span.ToHexString()); + block.Witness.VerificationScript.Span.ToHexString().Should().Be(tblock.Header.Witness.VerificationScript.Span.ToHexString()); + + + NativeContract.Ledger.GetBlock(mockSnapshot.Object, blockHash).Returns(block); + + var parameters = new JArray(blockHash.ToString(), true); + + // Act + var result = _rpcServer.GetBlock(parameters); + + // Assert + Assert.IsInstanceOfType(result, typeof(JObject)); + } + // // [TestMethod] // public void TestGetBlockCount() From ef6b001f5633e56effdc57d55ea4b3f787562bc5 Mon Sep 17 00:00:00 2001 From: Jimmy Date: Sun, 16 Jun 2024 15:41:20 +0800 Subject: [PATCH 05/20] use neo testutils --- src/Plugins/RpcServer/RpcServer.Blockchain.cs | 2 +- .../UT_RpcServer.Blockchain.cs | 86 ++--------- .../UT_RpcServer.cs | 35 ++++- tests/Neo.UnitTests/Ledger/UT_Blockchain.cs | 32 +--- tests/Neo.UnitTests/Ledger/UT_TrimmedBlock.cs | 4 +- .../Network/P2P/Payloads/UT_Header.cs | 2 +- .../SmartContract/UT_InteropService.cs | 2 +- .../SmartContract/UT_SmartContractHelper.cs | 31 +--- .../SmartContract/UT_Syscalls.cs | 2 +- tests/Neo.UnitTests/TestUtils.Block.cs | 144 ++++++++++++++++++ tests/Neo.UnitTests/TestUtils.cs | 97 ++++++------ 11 files changed, 253 insertions(+), 184 deletions(-) create mode 100644 tests/Neo.UnitTests/TestUtils.Block.cs diff --git a/src/Plugins/RpcServer/RpcServer.Blockchain.cs b/src/Plugins/RpcServer/RpcServer.Blockchain.cs index 90a2f54969..ff873c0939 100644 --- a/src/Plugins/RpcServer/RpcServer.Blockchain.cs +++ b/src/Plugins/RpcServer/RpcServer.Blockchain.cs @@ -45,7 +45,7 @@ protected internal virtual JToken GetBestBlockHash(JArray _params) /// /// The block data as a JToken. [RpcMethod] - protected virtual JToken GetBlock(JArray _params) + protected internal virtual JToken GetBlock(JArray _params) { JToken key = Result.Ok_Or(() => _params[0], RpcError.InvalidParams.WithData($"Invalid Block Hash or Index: {_params[0]}")); bool verbose = _params.Count >= 2 && _params[1].AsBoolean(); diff --git a/tests/Neo.Plugins.RpcServer.Tests/UT_RpcServer.Blockchain.cs b/tests/Neo.Plugins.RpcServer.Tests/UT_RpcServer.Blockchain.cs index 12c6a5a921..93cef642fc 100644 --- a/tests/Neo.Plugins.RpcServer.Tests/UT_RpcServer.Blockchain.cs +++ b/tests/Neo.Plugins.RpcServer.Tests/UT_RpcServer.Blockchain.cs @@ -9,17 +9,15 @@ // Redistribution and use in source and binary forms with or without // modifications are permitted. -using FluentAssertions; +using Akka.Util.Internal; using Microsoft.VisualStudio.TestTools.UnitTesting; -using Moq; +using Neo.IO; using Neo.Json; +using Neo.Ledger; using Neo.Network.P2P.Payloads; -using Neo.Persistence; using Neo.SmartContract; using Neo.SmartContract.Native; using Neo.UnitTests; -using Neo.UnitTests.SmartContract; -using Neo.VM; using System; namespace Neo.Plugins.RpcServer.Tests @@ -27,30 +25,10 @@ namespace Neo.Plugins.RpcServer.Tests public partial class UT_RpcServer { - public static TrimmedBlock GetTrimmedBlockWithNoTransaction() - { - return new TrimmedBlock - { - Header = new Header - { - MerkleRoot = UInt256.Parse("0xa400ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff02"), - PrevHash = UInt256.Parse("0xa400ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff01"), - Timestamp = new DateTime(1988, 06, 01, 0, 0, 0, DateTimeKind.Utc).ToTimestamp(), - Index = 1, - NextConsensus = UInt160.Parse("0xa400ff00ff00ff00ff00ff00ff00ff00ff00ff01"), - Witness = new Witness - { - InvocationScript = Array.Empty(), - VerificationScript = new[] { (byte)OpCode.PUSH1 } - }, - }, - Hashes = Array.Empty() - }; - } [TestMethod] public void TestGetBestBlockHash() { - var key = new KeyBuilder(-4, 12); + var key = NativeContract.Ledger.CreateStorageKey(12); var expectedHash = UInt256.Zero; var snapshot = _neoSystem.GetSnapshot(); @@ -58,6 +36,7 @@ public void TestGetBestBlockHash() b.Hash = UInt256.Zero; b.Index = 100; snapshot.Commit(); + var result = _rpcServer.GetBestBlockHash([]); // Assert Assert.AreEqual(expectedHash.ToString(), result.AsString()); @@ -66,52 +45,19 @@ public void TestGetBestBlockHash() [TestMethod] public void TestGetBlockByHash() { - var snapshot = TestBlockchain.GetTestSnapshot(); - var tx1 = TestUtils.GetTransaction(UInt160.Zero); - tx1.Script = new byte[] { 0x01,0x01,0x01,0x01, - 0x01,0x01,0x01,0x01, - 0x01,0x01,0x01,0x01, - 0x01,0x01,0x01,0x01 }; - var state1 = new TransactionState - { - Transaction = tx1, - BlockIndex = 1 - }; - var tx2 = TestUtils.GetTransaction(UInt160.Zero); - tx2.Script = new byte[] { 0x01,0x01,0x01,0x01, - 0x01,0x01,0x01,0x01, - 0x01,0x01,0x01,0x01, - 0x01,0x01,0x01,0x02 }; - var state2 = new TransactionState - { - Transaction = tx2, - BlockIndex = 1 - }; - UT_SmartContractHelper.TransactionAdd(snapshot, state1, state2); - - TrimmedBlock tblock = GetTrimmedBlockWithNoTransaction(); - tblock.Hashes = new UInt256[] { tx1.Hash, tx2.Hash }; - UT_SmartContractHelper.BlocksAdd(snapshot, tblock.Hash, tblock); - - Block block = NativeContract.Ledger.GetBlock(snapshot, tblock.Hash); - - block.Index.Should().Be(1); - block.MerkleRoot.Should().Be(UInt256.Parse("0xa400ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff02")); - block.Transactions.Length.Should().Be(2); - block.Transactions[0].Hash.Should().Be(tx1.Hash); - block.Witness.InvocationScript.Span.ToHexString().Should().Be(tblock.Header.Witness.InvocationScript.Span.ToHexString()); - block.Witness.VerificationScript.Span.ToHexString().Should().Be(tblock.Header.Witness.VerificationScript.Span.ToHexString()); - - - NativeContract.Ledger.GetBlock(mockSnapshot.Object, blockHash).Returns(block); - - var parameters = new JArray(blockHash.ToString(), true); + var snapshot = _neoSystem.GetSnapshot(); + var block = TestUtils.CreateBlockWithValidTransactions(snapshot, _wallet, _walletAccount, 3); + TestUtils.BlocksAdd(snapshot, block.Hash, block); + snapshot.Commit(); - // Act + var parameters = new JArray(block.Hash.ToString(), false); var result = _rpcServer.GetBlock(parameters); - - // Assert - Assert.IsInstanceOfType(result, typeof(JObject)); + var blockArr = Convert.FromBase64String(result.AsString()); + var block2 = blockArr.AsSerializable(); + block2.Transactions.ForEach(tx => + { + Assert.AreEqual(VerifyResult.Succeed, tx.VerifyStateIndependent(UnitTests.TestProtocolSettings.Default)); + }); } // diff --git a/tests/Neo.Plugins.RpcServer.Tests/UT_RpcServer.cs b/tests/Neo.Plugins.RpcServer.Tests/UT_RpcServer.cs index 1a79853540..1442458dd5 100644 --- a/tests/Neo.Plugins.RpcServer.Tests/UT_RpcServer.cs +++ b/tests/Neo.Plugins.RpcServer.Tests/UT_RpcServer.cs @@ -1,10 +1,23 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// UT_RpcServer.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.AspNetCore.Http; using Microsoft.VisualStudio.TestTools.UnitTesting; -using Moq; -using Neo.Ledger; using Neo.Persistence; +using Neo.SmartContract; +using Neo.SmartContract.Native; +using Neo.UnitTests; +using Neo.Wallets; +using Neo.Wallets.NEP6; using System; -using System.Collections.Generic; using System.Text; namespace Neo.Plugins.RpcServer.Tests @@ -16,6 +29,8 @@ public partial class UT_RpcServer private RpcServer _rpcServer; private TestMemoryStoreProvider _memoryStoreProvider; private MemoryStore _memoryStore; + private readonly NEP6Wallet _wallet = TestUtils.GenerateTestWallet("123"); + private WalletAccount _walletAccount; [TestInitialize] public void TestSetup() @@ -25,13 +40,23 @@ public void TestSetup() var protocolSettings = TestProtocolSettings.Default; _neoSystem = new NeoSystem(protocolSettings, _memoryStoreProvider); _rpcServer = new RpcServer(_neoSystem, RpcServerSettings.Default); + _walletAccount = _wallet.CreateAccount(); + var key = new KeyBuilder(NativeContract.GAS.Id, 20).Add(_walletAccount.ScriptHash); + var snapshot = _neoSystem.GetSnapshot(); + var entry = snapshot.GetAndChange(key, () => new StorageItem(new AccountState())); + entry.GetInteroperable().Balance = 100_000_000 * NativeContract.GAS.Factor; + snapshot.Commit(); } [TestCleanup] public void TestCleanup() { - _memoryStore.GetSnapshot().Commit(); _memoryStore.Reset(); + var snapshot = _neoSystem.GetSnapshot(); + var key = new KeyBuilder(NativeContract.GAS.Id, 20).Add(_walletAccount.ScriptHash); + var entry = snapshot.GetAndChange(key, () => new StorageItem(new AccountState())); + entry.GetInteroperable().Balance = 100_000_000 * NativeContract.GAS.Factor; + snapshot.Commit(); } [TestMethod] @@ -40,10 +65,8 @@ public void TestCheckAuth_ValidCredentials_ReturnsTrue() // Arrange var context = new DefaultHttpContext(); context.Request.Headers["Authorization"] = "Basic " + Convert.ToBase64String(Encoding.UTF8.GetBytes("testuser:testpass")); - // Act var result = _rpcServer.CheckAuth(context); - // Assert Assert.IsTrue(result); } diff --git a/tests/Neo.UnitTests/Ledger/UT_Blockchain.cs b/tests/Neo.UnitTests/Ledger/UT_Blockchain.cs index 491b4fe21e..cedc68bb4d 100644 --- a/tests/Neo.UnitTests/Ledger/UT_Blockchain.cs +++ b/tests/Neo.UnitTests/Ledger/UT_Blockchain.cs @@ -70,7 +70,7 @@ public void TestValidTransaction() // Make transaction - var tx = CreateValidTx(snapshot, walletA, acc.ScriptHash, 0); + var tx = TestUtils.CreateValidTx(snapshot, walletA, acc.ScriptHash, 0); senderProbe.Send(system.Blockchain, tx); senderProbe.ExpectMsg(p => p.Result == VerifyResult.Succeed); @@ -91,30 +91,6 @@ internal static StorageKey CreateStorageKey(byte prefix, byte[] key = null) }; } - private static Transaction CreateValidTx(DataCache snapshot, NEP6Wallet wallet, UInt160 account, uint nonce) - { - var tx = wallet.MakeTransaction(snapshot, new TransferOutput[] - { - new TransferOutput() - { - AssetId = NativeContract.GAS.Hash, - ScriptHash = account, - Value = new BigDecimal(BigInteger.One,8) - } - }, - account); - - 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; - } [TestMethod] public void TestMaliciousOnChainConflict() @@ -141,9 +117,9 @@ public void TestMaliciousOnChainConflict() // Create transactions: // tx1 conflicts with tx2 and has the same sender (thus, it's a valid conflict and must prevent tx2 from entering the chain); // tx2 conflicts with tx3 and has different sender (thus, this conflict is invalid and must not prevent tx3 from entering the chain). - var tx1 = CreateValidTx(snapshot, walletA, accA.ScriptHash, 0); - var tx2 = CreateValidTx(snapshot, walletA, accA.ScriptHash, 1); - var tx3 = CreateValidTx(snapshot, walletB, accB.ScriptHash, 2); + var tx1 = TestUtils.CreateValidTx(snapshot, walletA, accA.ScriptHash, 0); + var tx2 = TestUtils.CreateValidTx(snapshot, walletA, accA.ScriptHash, 1); + var tx3 = TestUtils.CreateValidTx(snapshot, walletB, accB.ScriptHash, 2); tx1.Attributes = new TransactionAttribute[] { new Conflicts() { Hash = tx2.Hash }, new Conflicts() { Hash = tx3.Hash } }; diff --git a/tests/Neo.UnitTests/Ledger/UT_TrimmedBlock.cs b/tests/Neo.UnitTests/Ledger/UT_TrimmedBlock.cs index 7942847f94..ea797f8be3 100644 --- a/tests/Neo.UnitTests/Ledger/UT_TrimmedBlock.cs +++ b/tests/Neo.UnitTests/Ledger/UT_TrimmedBlock.cs @@ -69,11 +69,11 @@ public void TestGetBlock() Transaction = tx2, BlockIndex = 1 }; - UT_SmartContractHelper.TransactionAdd(snapshot, state1, state2); + TestUtils.TransactionAdd(snapshot, state1, state2); TrimmedBlock tblock = GetTrimmedBlockWithNoTransaction(); tblock.Hashes = new UInt256[] { tx1.Hash, tx2.Hash }; - UT_SmartContractHelper.BlocksAdd(snapshot, tblock.Hash, tblock); + TestUtils.BlocksAdd(snapshot, tblock.Hash, tblock); Block block = NativeContract.Ledger.GetBlock(snapshot, tblock.Hash); diff --git a/tests/Neo.UnitTests/Network/P2P/Payloads/UT_Header.cs b/tests/Neo.UnitTests/Network/P2P/Payloads/UT_Header.cs index df33505965..a597c88cb6 100644 --- a/tests/Neo.UnitTests/Network/P2P/Payloads/UT_Header.cs +++ b/tests/Neo.UnitTests/Network/P2P/Payloads/UT_Header.cs @@ -56,7 +56,7 @@ public void TrimTest() TestUtils.SetupHeaderWithValues(uut, val256, out _, out _, out _, out _, out _, out _); uut.Witness = new Witness() { InvocationScript = Array.Empty(), VerificationScript = Array.Empty() }; - UT_SmartContractHelper.BlocksAdd(snapshot, uut.Hash, new TrimmedBlock() + TestUtils.BlocksAdd(snapshot, uut.Hash, new TrimmedBlock() { Header = new Header { diff --git a/tests/Neo.UnitTests/SmartContract/UT_InteropService.cs b/tests/Neo.UnitTests/SmartContract/UT_InteropService.cs index 51f26d22eb..06290922da 100644 --- a/tests/Neo.UnitTests/SmartContract/UT_InteropService.cs +++ b/tests/Neo.UnitTests/SmartContract/UT_InteropService.cs @@ -476,7 +476,7 @@ public void TestBlockchain_GetTransactionHeight() BlockIndex = 0, Transaction = TestUtils.CreateRandomHashTransaction() }; - UT_SmartContractHelper.TransactionAdd(engine.Snapshot, state); + TestUtils.TransactionAdd(engine.Snapshot, state); using var script = new ScriptBuilder(); script.EmitDynamicCall(NativeContract.Ledger.Hash, "getTransactionHeight", state.Transaction.Hash); diff --git a/tests/Neo.UnitTests/SmartContract/UT_SmartContractHelper.cs b/tests/Neo.UnitTests/SmartContract/UT_SmartContractHelper.cs index c14b15c241..c1161213ce 100644 --- a/tests/Neo.UnitTests/SmartContract/UT_SmartContractHelper.cs +++ b/tests/Neo.UnitTests/SmartContract/UT_SmartContractHelper.cs @@ -27,9 +27,6 @@ namespace Neo.UnitTests.SmartContract [TestClass] public class UT_SmartContractHelper { - const byte Prefix_Block = 5; - const byte Prefix_BlockHash = 9; - const byte Prefix_Transaction = 11; [TestMethod] public void TestIsMultiSigContract() @@ -129,7 +126,7 @@ public void TestVerifyWitnesses() { var snapshot1 = TestBlockchain.GetTestSnapshot().CreateSnapshot(); UInt256 index1 = UInt256.Parse("0xa400ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff01"); - BlocksAdd(snapshot1, index1, new TrimmedBlock() + TestUtils.BlocksAdd(snapshot1, index1, new TrimmedBlock() { Header = new Header { @@ -141,7 +138,7 @@ public void TestVerifyWitnesses() }, Hashes = new UInt256[1] { UInt256.Zero }, }); - BlocksDelete(snapshot1, index1); + TestUtils.BlocksDelete(snapshot1, index1); Assert.AreEqual(false, Neo.SmartContract.Helper.VerifyWitnesses(new Header() { PrevHash = index1 }, TestProtocolSettings.Default, snapshot1, 100)); var snapshot2 = TestBlockchain.GetTestSnapshot(); @@ -158,7 +155,7 @@ public void TestVerifyWitnesses() }, Hashes = new UInt256[1] { UInt256.Zero }, }; - BlocksAdd(snapshot2, index2, block2); + TestUtils.BlocksAdd(snapshot2, index2, block2); Header header2 = new() { PrevHash = index2, Witness = new Witness { InvocationScript = Array.Empty(), VerificationScript = Array.Empty() } }; snapshot2.AddContract(UInt160.Zero, new ContractState()); @@ -179,7 +176,7 @@ public void TestVerifyWitnesses() }, Hashes = new UInt256[1] { UInt256.Zero }, }; - BlocksAdd(snapshot3, index3, block3); + TestUtils.BlocksAdd(snapshot3, index3, block3); Header header3 = new() { PrevHash = index3, @@ -213,25 +210,5 @@ public void TestVerifyWitnesses() Assert.AreEqual(true, Neo.SmartContract.Helper.VerifyWitnesses(tx, TestProtocolSettings.Default, snapshot3, 1000)); } - - private static void BlocksDelete(DataCache snapshot, UInt256 hash) - { - snapshot.Delete(NativeContract.Ledger.CreateStorageKey(Prefix_BlockHash, hash)); - snapshot.Delete(NativeContract.Ledger.CreateStorageKey(Prefix_Block, hash)); - } - - public static void TransactionAdd(DataCache snapshot, params TransactionState[] txs) - { - foreach (TransactionState tx in txs) - { - snapshot.Add(NativeContract.Ledger.CreateStorageKey(Prefix_Transaction, tx.Transaction.Hash), new StorageItem(tx)); - } - } - - public static void BlocksAdd(DataCache snapshot, UInt256 hash, TrimmedBlock block) - { - 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())); - } } } diff --git a/tests/Neo.UnitTests/SmartContract/UT_Syscalls.cs b/tests/Neo.UnitTests/SmartContract/UT_Syscalls.cs index 7791b8acef..76448855d7 100644 --- a/tests/Neo.UnitTests/SmartContract/UT_Syscalls.cs +++ b/tests/Neo.UnitTests/SmartContract/UT_Syscalls.cs @@ -84,7 +84,7 @@ public void System_Blockchain_GetBlock() var height = snapshot[NativeContract.Ledger.CreateStorageKey(Prefix_CurrentBlock)].GetInteroperable(); height.Index = block.Index + TestProtocolSettings.Default.MaxTraceableBlocks; - UT_SmartContractHelper.BlocksAdd(snapshot, block.Hash, block); + 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/TestUtils.Block.cs b/tests/Neo.UnitTests/TestUtils.Block.cs new file mode 100644 index 0000000000..4f663fec2d --- /dev/null +++ b/tests/Neo.UnitTests/TestUtils.Block.cs @@ -0,0 +1,144 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// TestUtils.Block.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 Akka.Util.Internal; +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.Collections.Generic; +using System.Linq; + +namespace Neo.UnitTests; + +public partial class TestUtils +{ + const byte Prefix_Block = 5; + const byte Prefix_BlockHash = 9; + const byte Prefix_Transaction = 11; + + /// + /// Test Util function SetupHeaderWithValues + /// + /// The header to be assigned + /// PrevHash + /// MerkleRoot + /// NextConsensus + /// Timestamp + /// 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) + { + 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.Nonce = nonceVal = 0; + header.NextConsensus = val160 = UInt160.Zero; + header.Witness = scriptVal = new Witness + { + InvocationScript = Array.Empty(), + VerificationScript = new[] { (byte)OpCode.PUSH1 } + }; + } + + 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) + { + Header header = new Header(); + SetupHeaderWithValues(header, val256, out merkRootVal, out val160, out timestampVal, out nonceVal, out indexVal, out scriptVal); + + transactionsVal = new Transaction[numberOfTransactions]; + if (numberOfTransactions > 0) + { + for (int i = 0; i < numberOfTransactions; i++) + { + transactionsVal[i] = GetTransaction(UInt160.Zero); + } + } + + block.Header = header; + block.Transactions = transactionsVal; + + header.MerkleRoot = merkRootVal = MerkleTree.ComputeRoot(block.Transactions.Select(p => p.Hash).ToArray()); + } + + 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)); + } + + var header = new Header(); + SetupHeaderWithValues(header, RandomUInt256(), out _, out _, out _, out _, out _, out _); + + block.Header = header; + block.Transactions = transactions.ToArray(); + + header.MerkleRoot = MerkleTree.ComputeRoot(block.Transactions.Select(p => p.Hash).ToArray()); + return block; + } + + public static void BlocksDelete(DataCache snapshot, UInt256 hash) + { + snapshot.Delete(NativeContract.Ledger.CreateStorageKey(Prefix_BlockHash, hash)); + snapshot.Delete(NativeContract.Ledger.CreateStorageKey(Prefix_Block, hash)); + } + + public static void TransactionAdd(DataCache snapshot, params TransactionState[] txs) + { + foreach (var tx in txs) + { + snapshot.Add(NativeContract.Ledger.CreateStorageKey(Prefix_Transaction, tx.Transaction.Hash), new StorageItem(tx)); + } + } + + public static void BlocksAdd(DataCache snapshot, UInt256 hash, TrimmedBlock block) + { + 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())); + } + + public static void BlocksAdd(DataCache snapshot, UInt256 hash, Block block) + { + + block.Transactions.ForEach(tx => + { + var state = new TransactionState + { + BlockIndex = block.Index, + Transaction = tx + }; + 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())); + } + + public static TrimmedBlock ToTrimmedBlock(this Block block) + { + return new TrimmedBlock + { + Header = block.Header, + Hashes = block.Transactions.Select(p => p.Hash).ToArray() + }; + } +} diff --git a/tests/Neo.UnitTests/TestUtils.cs b/tests/Neo.UnitTests/TestUtils.cs index f8f63de53a..869cff897c 100644 --- a/tests/Neo.UnitTests/TestUtils.cs +++ b/tests/Neo.UnitTests/TestUtils.cs @@ -10,25 +10,43 @@ // modifications are permitted. using FluentAssertions; +using Microsoft.VisualStudio.TestTools.UnitTesting; using Neo.Cryptography; using Neo.Cryptography.ECC; using Neo.IO; using Neo.Json; using Neo.Network.P2P.Payloads; +using Neo.Persistence; using Neo.SmartContract; using Neo.SmartContract.Manifest; using Neo.SmartContract.Native; using Neo.VM; +using Neo.Wallets; using Neo.Wallets.NEP6; using System; using System.Linq; +using System.Numerics; namespace Neo.UnitTests { - public static class TestUtils + public static partial class TestUtils { public static readonly Random TestRandom = new Random(1337); // use fixed seed for guaranteed determinism + public static UInt256 RandomUInt256() + { + byte[] data = new byte[32]; + TestRandom.NextBytes(data); + return new UInt256(data); + } + + public static UInt160 RandomUInt160() + { + byte[] data = new byte[20]; + TestRandom.NextBytes(data); + return new UInt160(data); + } + public static ContractManifest CreateDefaultManifest() { return new ContractManifest() @@ -111,6 +129,37 @@ public static NEP6Wallet GenerateTestWallet(string password) return new NEP6Wallet(null, password, TestProtocolSettings.Default, wallet); } + public static Transaction CreateValidTx(DataCache snapshot, NEP6Wallet wallet, WalletAccount account) + { + return CreateValidTx(snapshot, wallet, account.ScriptHash, (uint)new Random().Next()); + } + + public static Transaction CreateValidTx(DataCache snapshot, NEP6Wallet wallet, UInt160 account, uint nonce) + { + var tx = wallet.MakeTransaction(snapshot, new TransferOutput[] + { + new TransferOutput() + { + AssetId = NativeContract.GAS.Hash, + ScriptHash = account, + Value = new BigDecimal(BigInteger.One,8) + } + }, + account); + + 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) { return new Transaction @@ -188,52 +237,6 @@ internal static StorageKey GetStorageKey(int id, byte[] keyValue) }; } - /// - /// Test Util function SetupHeaderWithValues - /// - /// The header to be assigned - /// PrevHash - /// MerkleRoot - /// NextConsensus - /// Timestamp - /// 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) - { - 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.Nonce = nonceVal = 0; - header.NextConsensus = val160 = UInt160.Zero; - header.Witness = scriptVal = new Witness - { - InvocationScript = new byte[0], - VerificationScript = new[] { (byte)OpCode.PUSH1 } - }; - } - - 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) - { - Header header = new Header(); - SetupHeaderWithValues(header, val256, out merkRootVal, out val160, out timestampVal, out nonceVal, out indexVal, out scriptVal); - - transactionsVal = new Transaction[numberOfTransactions]; - if (numberOfTransactions > 0) - { - for (int i = 0; i < numberOfTransactions; i++) - { - transactionsVal[i] = GetTransaction(UInt160.Zero); - } - } - - block.Header = header; - block.Transactions = transactionsVal; - - header.MerkleRoot = merkRootVal = MerkleTree.ComputeRoot(block.Transactions.Select(p => p.Hash).ToArray()); - } - public static Transaction CreateRandomHashTransaction() { var randomBytes = new byte[16]; From 3c43399c0791ce6c3f4370924cac4c776c3a65d7 Mon Sep 17 00:00:00 2001 From: Jimmy Date: Sun, 16 Jun 2024 18:07:50 +0800 Subject: [PATCH 06/20] complete rpcserver blockchain tests. --- src/Neo/SmartContract/Native/NeoToken.cs | 2 +- src/Plugins/RpcServer/RpcServer.Blockchain.cs | 26 +- .../UT_RpcServer.Blockchain.cs | 396 +++++++++++++++++- tests/Neo.UnitTests/TestUtils.cs | 11 +- 4 files changed, 405 insertions(+), 30 deletions(-) diff --git a/src/Neo/SmartContract/Native/NeoToken.cs b/src/Neo/SmartContract/Native/NeoToken.cs index 99ecd41e29..f43a0d6079 100644 --- a/src/Neo/SmartContract/Native/NeoToken.cs +++ b/src/Neo/SmartContract/Native/NeoToken.cs @@ -421,7 +421,7 @@ private async ContractTask Vote(ApplicationEngine engine, UInt160 account, /// The snapshot used to read data. /// All the registered candidates. [ContractMethod(CpuFee = 1 << 22, RequiredCallFlags = CallFlags.ReadStates)] - private (ECPoint PublicKey, BigInteger Votes)[] GetCandidates(DataCache snapshot) + internal (ECPoint PublicKey, BigInteger Votes)[] GetCandidates(DataCache snapshot) { return GetCandidatesInternal(snapshot) .Select(p => (p.PublicKey, p.State.Votes)) diff --git a/src/Plugins/RpcServer/RpcServer.Blockchain.cs b/src/Plugins/RpcServer/RpcServer.Blockchain.cs index ff873c0939..d1314dabe3 100644 --- a/src/Plugins/RpcServer/RpcServer.Blockchain.cs +++ b/src/Plugins/RpcServer/RpcServer.Blockchain.cs @@ -91,7 +91,7 @@ internal virtual JToken GetBlockHeaderCount(JArray _params) /// An empty array; no parameters are required. /// The count of blocks as a JToken. [RpcMethod] - protected virtual JToken GetBlockCount(JArray _params) + protected internal virtual JToken GetBlockCount(JArray _params) { return NativeContract.Ledger.CurrentIndex(system.StoreView) + 1; } @@ -102,7 +102,7 @@ protected virtual JToken GetBlockCount(JArray _params) /// An array containing the block height as the first element. /// The hash of the block at the specified height as a JToken. [RpcMethod] - protected virtual JToken GetBlockHash(JArray _params) + protected internal virtual JToken GetBlockHash(JArray _params) { uint height = Result.Ok_Or(() => uint.Parse(_params[0].AsString()), RpcError.InvalidParams.WithData($"Invalid Height: {_params[0]}")); var snapshot = system.StoreView; @@ -122,7 +122,7 @@ protected virtual JToken GetBlockHash(JArray _params) /// /// The block header data as a JToken. [RpcMethod] - protected virtual JToken GetBlockHeader(JArray _params) + protected internal virtual JToken GetBlockHeader(JArray _params) { JToken key = _params[0]; bool verbose = _params.Count >= 2 && _params[1].AsBoolean(); @@ -157,7 +157,7 @@ protected virtual JToken GetBlockHeader(JArray _params) /// An array containing the contract ID or script hash as the first element. /// The contract state as a JToken. [RpcMethod] - protected virtual JToken GetContractState(JArray _params) + protected internal virtual JToken GetContractState(JArray _params) { if (int.TryParse(_params[0].AsString(), out int contractId)) { @@ -188,7 +188,7 @@ private static UInt160 ToScriptHash(string keyword) /// An array containing an optional boolean indicating whether to include unverified transactions. /// The memory pool transactions as a JToken. [RpcMethod] - protected virtual JToken GetRawMemPool(JArray _params) + protected internal virtual JToken GetRawMemPool(JArray _params) { bool shouldGetUnverified = _params.Count >= 1 && _params[0].AsBoolean(); if (!shouldGetUnverified) @@ -213,7 +213,7 @@ protected virtual JToken GetRawMemPool(JArray _params) /// /// The transaction data as a JToken. [RpcMethod] - protected virtual JToken GetRawTransaction(JArray _params) + protected internal virtual JToken GetRawTransaction(JArray _params) { UInt256 hash = Result.Ok_Or(() => UInt256.Parse(_params[0].AsString()), RpcError.InvalidParams.WithData($"Invalid Transaction Hash: {_params[0]}")); bool verbose = _params.Count >= 2 && _params[1].AsBoolean(); @@ -244,7 +244,7 @@ protected virtual JToken GetRawTransaction(JArray _params) /// /// The storage item as a JToken. [RpcMethod] - protected virtual JToken GetStorage(JArray _params) + protected internal virtual JToken GetStorage(JArray _params) { using var snapshot = system.GetSnapshot(); if (!int.TryParse(_params[0].AsString(), out int id)) @@ -272,7 +272,7 @@ protected virtual JToken GetStorage(JArray _params) /// /// The found storage items as a . [RpcMethod] - protected virtual JToken FindStorage(JArray _params) + protected internal virtual JToken FindStorage(JArray _params) { using var snapshot = system.GetSnapshot(); if (!int.TryParse(_params[0].AsString(), out int id)) @@ -326,7 +326,7 @@ protected virtual JToken FindStorage(JArray _params) /// An array containing the transaction hash as the first element. /// The height of the transaction as a . [RpcMethod] - protected virtual JToken GetTransactionHeight(JArray _params) + protected internal virtual JToken GetTransactionHeight(JArray _params) { UInt256 hash = Result.Ok_Or(() => UInt256.Parse(_params[0].AsString()), RpcError.InvalidParams.WithData($"Invalid Transaction Hash: {_params[0]}")); uint? height = NativeContract.Ledger.GetTransactionState(system.StoreView, hash)?.BlockIndex; @@ -340,7 +340,7 @@ protected virtual JToken GetTransactionHeight(JArray _params) /// An empty array; no parameters are required. /// The next block validators as a . [RpcMethod] - protected virtual JToken GetNextBlockValidators(JArray _params) + protected internal virtual JToken GetNextBlockValidators(JArray _params) { using var snapshot = system.GetSnapshot(); var validators = NativeContract.NEO.GetNextBlockValidators(snapshot, system.Settings.ValidatorsCount); @@ -359,7 +359,7 @@ protected virtual JToken GetNextBlockValidators(JArray _params) /// An empty array; no parameters are required. /// The candidates public key list as a JToken. [RpcMethod] - protected virtual JToken GetCandidates(JArray _params) + protected internal virtual JToken GetCandidates(JArray _params) { using var snapshot = system.GetSnapshot(); byte[] script; @@ -416,7 +416,7 @@ protected virtual JToken GetCandidates(JArray _params) /// An empty array; no parameters are required. /// The committee members publickeys as a . [RpcMethod] - protected virtual JToken GetCommittee(JArray _params) + protected internal virtual JToken GetCommittee(JArray _params) { return new JArray(NativeContract.NEO.GetCommittee(system.StoreView).Select(p => (JToken)p.ToString())); } @@ -427,7 +427,7 @@ protected virtual JToken GetCommittee(JArray _params) /// An empty array; no parameters are required. /// The native contract states as a . [RpcMethod] - protected virtual JToken GetNativeContracts(JArray _params) + protected internal virtual JToken GetNativeContracts(JArray _params) { return new JArray(NativeContract.Contracts.Select(p => NativeContract.ContractManagement.GetContract(system.StoreView, p.Hash).ToJson())); } diff --git a/tests/Neo.Plugins.RpcServer.Tests/UT_RpcServer.Blockchain.cs b/tests/Neo.Plugins.RpcServer.Tests/UT_RpcServer.Blockchain.cs index 93cef642fc..e5e50c2da7 100644 --- a/tests/Neo.Plugins.RpcServer.Tests/UT_RpcServer.Blockchain.cs +++ b/tests/Neo.Plugins.RpcServer.Tests/UT_RpcServer.Blockchain.cs @@ -18,7 +18,9 @@ using Neo.SmartContract; using Neo.SmartContract.Native; using Neo.UnitTests; +using Neo.UnitTests.Extensions; using System; +using System.Linq; namespace Neo.Plugins.RpcServer.Tests { @@ -60,20 +62,384 @@ public void TestGetBlockByHash() }); } - // - // [TestMethod] - // public void TestGetBlockCount() - // { - // // Arrange - // var mockSnapshot = new Mock(); - // _systemMock.Setup(s => s.StoreView).Returns(mockSnapshot.Object); - // NativeContract.Ledger.CurrentIndex(mockSnapshot.Object).Returns(1234u); - // - // // Act - // var result = _rpcServer.GetBlockCount(new JArray()); - // - // // Assert - // Assert.AreEqual(1235u, result.AsNumber()); - // } + [TestMethod] + public void TestGetBlockByIndex() + { + var snapshot = _neoSystem.GetSnapshot(); + var block = TestUtils.CreateBlockWithValidTransactions(snapshot, _wallet, _walletAccount, 3); + TestUtils.BlocksAdd(snapshot, block.Hash, block); + snapshot.Commit(); + + var parameters = new JArray(block.Index, false); + var result = _rpcServer.GetBlock(parameters); + var blockArr = Convert.FromBase64String(result.AsString()); + var block2 = blockArr.AsSerializable(); + block2.Transactions.ForEach(tx => + { + Assert.AreEqual(VerifyResult.Succeed, tx.VerifyStateIndependent(UnitTests.TestProtocolSettings.Default)); + }); + } + + [TestMethod] + public void TestGetBlockByUnKnownIndex() + { + var snapshot = _neoSystem.GetSnapshot(); + var block = TestUtils.CreateBlockWithValidTransactions(snapshot, _wallet, _walletAccount, 3); + TestUtils.BlocksAdd(snapshot, block.Hash, block); + snapshot.Commit(); + + var parameters = new JArray(int.MaxValue, false); + try + { + _rpcServer.GetBlock(parameters); + Assert.Fail("Expected RpcException was not thrown."); + } + catch (RpcException ex) + { + Assert.AreEqual(RpcError.UnknownBlock.Code, ex.HResult); + } + } + + [TestMethod] + public void TestGetBlockByUnKnownHash() + { + var snapshot = _neoSystem.GetSnapshot(); + var block = TestUtils.CreateBlockWithValidTransactions(snapshot, _wallet, _walletAccount, 3); + TestUtils.BlocksAdd(snapshot, block.Hash, block); + snapshot.Commit(); + + var parameters = new JArray(TestUtils.RandomUInt256().ToString(), false); + try + { + _rpcServer.GetBlock(parameters); + Assert.Fail("Expected RpcException was not thrown."); + } + catch (RpcException ex) + { + Assert.AreEqual(RpcError.UnknownBlock.Code, ex.HResult); + } + } + + [TestMethod] + public void TestGetBlockCount() + { + var expectedCount = 1; + var result = _rpcServer.GetBlockCount(new JArray()); + Assert.AreEqual(expectedCount, result.AsNumber()); + } + + [TestMethod] + public void TestGetBlockHeaderCount() + { + var expectedCount = 1; + var result = _rpcServer.GetBlockHeaderCount(new JArray()); + Assert.AreEqual(expectedCount, result.AsNumber()); + } + + [TestMethod] + public void TestGetBlockHash() + { + var snapshot = _neoSystem.GetSnapshot(); + var block = TestUtils.CreateBlockWithValidTransactions(snapshot, _wallet, _walletAccount, 3); + TestUtils.BlocksAdd(snapshot, block.Hash, block); + snapshot.Commit(); + var expectedHash = block.Hash.ToString(); + var result = _rpcServer.GetBlockHash(new JArray(block.Index)); + Assert.AreEqual(expectedHash, result.AsString()); + } + + [TestMethod] + public void TestGetBlockHashInvalidIndex() + { + var snapshot = _neoSystem.GetSnapshot(); + var block = TestUtils.CreateBlockWithValidTransactions(snapshot, _wallet, _walletAccount, 3); + TestUtils.BlocksAdd(snapshot, block.Hash, block); + snapshot.Commit(); + Assert.ThrowsException(() => _rpcServer.GetBlockHash(new JArray(block.Index + 1))); + } + + [TestMethod] + public void TestGetBlockHeader() + { + var snapshot = _neoSystem.GetSnapshot(); + var block = TestUtils.CreateBlockWithValidTransactions(snapshot, _wallet, _walletAccount, 3); + TestUtils.BlocksAdd(snapshot, block.Hash, block); + snapshot.Commit(); + var parameters = new JArray(block.Hash.ToString(), true); + var result = _rpcServer.GetBlockHeader(parameters); + var header = block.Header.ToJson(_neoSystem.Settings); + header["confirmations"] = NativeContract.Ledger.CurrentIndex(snapshot) - block.Index + 1; + Assert.AreEqual(header.ToString(), result.ToString()); + } + + [TestMethod] + public void TestGetContractState() + { + var snapshot = _neoSystem.GetSnapshot(); + var contractState = TestUtils.GetContract(); + snapshot.AddContract(contractState.Hash, contractState); + snapshot.Commit(); + var result = _rpcServer.GetContractState(new JArray(contractState.Hash.ToString())); + + Assert.AreEqual(contractState.ToJson().ToString(), result.ToString()); + } + + [TestMethod] + public void TestGetRawMemPool() + { + var snapshot = _neoSystem.GetSnapshot(); + var tx = TestUtils.CreateValidTx(snapshot, _wallet, _walletAccount); + snapshot.Commit(); + _neoSystem.MemPool.TryAdd(tx, snapshot); + + var result = _rpcServer.GetRawMemPool(new JArray()); + + Assert.IsTrue(((JArray)result).Any(p => p.AsString() == tx.Hash.ToString())); + } + + [TestMethod] + public void TestGetRawTransaction() + { + var snapshot = _neoSystem.GetSnapshot(); + var tx = TestUtils.CreateValidTx(snapshot, _wallet, _walletAccount); + _neoSystem.MemPool.TryAdd(tx, snapshot); + var parameters = new JArray(tx.Hash.ToString(), true); + snapshot.Commit(); + var result = _rpcServer.GetRawTransaction(parameters); + + var json = Utility.TransactionToJson(tx, _neoSystem.Settings); + Assert.AreEqual(json.ToString(), result.ToString()); + } + + [TestMethod] + public void TestGetStorage() + { + var snapshot = _neoSystem.GetSnapshot(); + var contractState = TestUtils.GetContract(); + snapshot.AddContract(contractState.Hash, contractState); + var key = new byte[] { 0x01 }; + var value = new byte[] { 0x02 }; + TestUtils.StorageItemAdd(snapshot, contractState.Id, key, value); + snapshot.Commit(); + + var result = _rpcServer.GetStorage(new JArray(contractState.Hash.ToString(), Convert.ToBase64String(key))); + Assert.AreEqual(Convert.ToBase64String(value), result.AsString()); + } + + [TestMethod] + public void TestFindStorage() + { + var snapshot = _neoSystem.GetSnapshot(); + var contractState = TestUtils.GetContract(); + snapshot.AddContract(contractState.Hash, contractState); + var key = new byte[] { 0x01 }; + var value = new byte[] { 0x02 }; + TestUtils.StorageItemAdd(snapshot, contractState.Id, key, value); + snapshot.Commit(); + var result = _rpcServer.FindStorage(new JArray(contractState.Hash.ToString(), Convert.ToBase64String(key), 0)); + + var json = new JObject(); + var jarr = new JArray(); + var j = new JObject(); + j["key"] = Convert.ToBase64String(key); + j["value"] = Convert.ToBase64String(value); + jarr.Add(j); + json["truncated"] = false; + json["next"] = 1; + json["results"] = jarr; + Assert.AreEqual(json.ToString(), result.ToString()); + } + + [TestMethod] + public void TestGetTransactionHeight() + { + var snapshot = _neoSystem.GetSnapshot(); + var block = TestUtils.CreateBlockWithValidTransactions(snapshot, _wallet, _walletAccount, 1); + TestUtils.BlocksAdd(snapshot, block.Hash, block); + snapshot.Commit(); + var tx = block.Transactions[0]; + var result = _rpcServer.GetTransactionHeight(new JArray(tx.Hash.ToString())); + Assert.AreEqual(block.Index, result.AsNumber()); + } + + [TestMethod] + public void TestGetNextBlockValidators() + { + var snapshot = _neoSystem.GetSnapshot(); + var result = _rpcServer.GetNextBlockValidators(new JArray()); + + var validators = NativeContract.NEO.GetNextBlockValidators(snapshot, _neoSystem.Settings.ValidatorsCount); + var expected = validators.Select(p => + { + var validator = new JObject(); + validator["publickey"] = p.ToString(); + validator["votes"] = (int)NativeContract.NEO.GetCandidateVote(snapshot, p); + return validator; + }).ToArray(); + Assert.AreEqual(new JArray(expected).ToString(), result.ToString()); + } + + [TestMethod] + public void TestGetCandidates() + { + var snapshot = _neoSystem.GetSnapshot(); + var result = _rpcServer.GetCandidates(new JArray()); + var json = new JArray(); + var validators = NativeContract.NEO.GetNextBlockValidators(snapshot, _neoSystem.Settings.ValidatorsCount); + snapshot.Commit(); + var candidates = NativeContract.NEO.GetCandidates(_neoSystem.GetSnapshot()); + + foreach (var candidate in candidates) + { + var item = new JObject(); + item["publickey"] = candidate.PublicKey.ToString(); + item["votes"] = candidate.Votes.ToString(); + item["active"] = validators.Contains(candidate.PublicKey); + json.Add(item); + } + Assert.AreEqual(json.ToString(), result.ToString()); + } + + [TestMethod] + public void TestGetCommittee() + { + var snapshot = _neoSystem.GetSnapshot(); + var result = _rpcServer.GetCommittee(new JArray()); + var committee = NativeContract.NEO.GetCommittee(snapshot); + var expected = new JArray(committee.Select(p => (JToken)p.ToString())); + Assert.AreEqual(expected.ToString(), result.ToString()); + } + + [TestMethod] + public void TestGetNativeContracts() + { + var result = _rpcServer.GetNativeContracts(new JArray()); + var contracts = new JArray(NativeContract.Contracts.Select(p => NativeContract.ContractManagement.GetContract(_neoSystem.GetSnapshot(), p.Hash).ToJson())); + Assert.AreEqual(contracts.ToString(), result.ToString()); + } + + [TestMethod] + public void TestGetBlockByUnknownIndex() + { + var snapshot = _neoSystem.GetSnapshot(); + var block = TestUtils.CreateBlockWithValidTransactions(snapshot, _wallet, _walletAccount, 3); + TestUtils.BlocksAdd(snapshot, block.Hash, block); + snapshot.Commit(); + + var parameters = new JArray(int.MaxValue, false); + try + { + _rpcServer.GetBlock(parameters); + Assert.Fail("Expected RpcException was not thrown."); + } + catch (RpcException ex) + { + Assert.AreEqual(RpcError.UnknownBlock.Code, ex.HResult); + } + } + + [TestMethod] + public void TestGetBlockByUnknownHash() + { + var snapshot = _neoSystem.GetSnapshot(); + var block = TestUtils.CreateBlockWithValidTransactions(snapshot, _wallet, _walletAccount, 3); + TestUtils.BlocksAdd(snapshot, block.Hash, block); + snapshot.Commit(); + + var parameters = new JArray(TestUtils.RandomUInt256().ToString(), false); + try + { + _rpcServer.GetBlock(parameters); + Assert.Fail("Expected RpcException was not thrown."); + } + catch (RpcException ex) + { + Assert.AreEqual(RpcError.UnknownBlock.Code, ex.HResult); + } + } + + [TestMethod] + public void TestGetContractStateUnknownContract() + { + var snapshot = _neoSystem.GetSnapshot(); + var randomHash = TestUtils.RandomUInt160(); + try + { + _rpcServer.GetContractState(new JArray(randomHash.ToString())); + Assert.Fail("Expected RpcException was not thrown."); + } + catch (RpcException ex) + { + Assert.AreEqual(RpcError.UnknownContract.Code, ex.HResult); + } + } + + [TestMethod] + public void TestGetStorageUnknownContract() + { + var snapshot = _neoSystem.GetSnapshot(); + var randomHash = TestUtils.RandomUInt160(); + var key = new byte[] { 0x01 }; + try + { + _rpcServer.GetStorage(new JArray(randomHash.ToString(), Convert.ToBase64String(key))); + Assert.Fail("Expected RpcException was not thrown."); + } + catch (RpcException ex) + { + Assert.AreEqual(RpcError.UnknownContract.Code, ex.HResult); + } + } + + [TestMethod] + public void TestGetStorageUnknownStorageItem() + { + var snapshot = _neoSystem.GetSnapshot(); + var contractState = TestUtils.GetContract(); + snapshot.AddContract(contractState.Hash, contractState); + snapshot.Commit(); + + var key = new byte[] { 0x01 }; + try + { + _rpcServer.GetStorage(new JArray(contractState.Hash.ToString(), Convert.ToBase64String(key))); + Assert.Fail("Expected RpcException was not thrown."); + } + catch (RpcException ex) + { + Assert.AreEqual(RpcError.UnknownStorageItem.Code, ex.HResult); + } + } + + [TestMethod] + public void TestGetTransactionHeightUnknownTransaction() + { + var randomHash = TestUtils.RandomUInt256(); + try + { + _rpcServer.GetTransactionHeight(new JArray(randomHash.ToString())); + Assert.Fail("Expected RpcException was not thrown."); + } + catch (RpcException ex) + { + Assert.AreEqual(RpcError.UnknownTransaction.Code, ex.HResult); + } + } + + [TestMethod] + public void TestGetRawTransactionUnknownTransaction() + { + var randomHash = TestUtils.RandomUInt256(); + try + { + _rpcServer.GetRawTransaction(new JArray(randomHash.ToString(), true)); + Assert.Fail("Expected RpcException was not thrown."); + } + catch (RpcException ex) + { + Assert.AreEqual(RpcError.UnknownTransaction.Code, ex.HResult); + } + } + } } diff --git a/tests/Neo.UnitTests/TestUtils.cs b/tests/Neo.UnitTests/TestUtils.cs index 869cff897c..55492d882c 100644 --- a/tests/Neo.UnitTests/TestUtils.cs +++ b/tests/Neo.UnitTests/TestUtils.cs @@ -182,7 +182,7 @@ public static Transaction GetTransaction(UInt160 sender) }; } - internal static ContractState GetContract(string method = "test", int parametersCount = 0) + public static ContractState GetContract(string method = "test", int parametersCount = 0) { NefFile nef = new() { @@ -237,6 +237,15 @@ internal static StorageKey GetStorageKey(int id, byte[] keyValue) }; } + public static void StorageItemAdd(DataCache snapshot, int id, byte[] keyValue, byte[] value) + { + snapshot.Add(new StorageKey + { + Id = id, + Key = keyValue + }, new StorageItem(value)); + } + public static Transaction CreateRandomHashTransaction() { var randomBytes = new byte[16]; From 0c90df1ddec88244f3006a7f90ce6bffde20bc04 Mon Sep 17 00:00:00 2001 From: Jimmy Date: Sun, 16 Jun 2024 18:13:48 +0800 Subject: [PATCH 07/20] revert change to ByteArrayComparer --- src/Neo.IO/ByteArrayComparer.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Neo.IO/ByteArrayComparer.cs b/src/Neo.IO/ByteArrayComparer.cs index 6c375646cc..f9d44e24d6 100644 --- a/src/Neo.IO/ByteArrayComparer.cs +++ b/src/Neo.IO/ByteArrayComparer.cs @@ -15,7 +15,7 @@ namespace Neo.IO { - public class ByteArrayComparer : IComparer + internal class ByteArrayComparer : IComparer { public static readonly ByteArrayComparer Default = new(1); public static readonly ByteArrayComparer Reverse = new(-1); From bee3102eecf95ba76d65c2d112fc2322b1e50188 Mon Sep 17 00:00:00 2001 From: Jimmy Date: Sun, 16 Jun 2024 18:14:46 +0800 Subject: [PATCH 08/20] revert cache change --- src/Neo/Persistence/SnapshotCache.cs | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/src/Neo/Persistence/SnapshotCache.cs b/src/Neo/Persistence/SnapshotCache.cs index cf88cba9f0..6731e5342f 100644 --- a/src/Neo/Persistence/SnapshotCache.cs +++ b/src/Neo/Persistence/SnapshotCache.cs @@ -37,19 +37,11 @@ public SnapshotCache(IReadOnlyStore store) protected override void AddInternal(StorageKey key, StorageItem value) { - if (store is MemoryStore memoryStore) - { - memoryStore.Put(key.ToArray(), value.ToArray()); - } snapshot?.Put(key.ToArray(), value.ToArray()); } protected override void DeleteInternal(StorageKey key) { - if (store is MemoryStore memoryStore) - { - memoryStore.Delete(key.ToArray()); - } snapshot?.Delete(key.ToArray()); } @@ -90,10 +82,6 @@ protected override StorageItem TryGetInternal(StorageKey key) protected override void UpdateInternal(StorageKey key, StorageItem value) { - if (store is MemoryStore memoryStore) - { - memoryStore.Put(key.ToArray(), value.ToArray()); - } snapshot?.Put(key.ToArray(), value.ToArray()); } } From a674ec7e7bfef139cc08c92f80e2f18b2dfe5dbd Mon Sep 17 00:00:00 2001 From: Jimmy Date: Sun, 16 Jun 2024 18:43:03 +0800 Subject: [PATCH 09/20] add more detail to comments --- src/Plugins/RpcServer/RpcServer.Blockchain.cs | 21 ++++++++++--------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/src/Plugins/RpcServer/RpcServer.Blockchain.cs b/src/Plugins/RpcServer/RpcServer.Blockchain.cs index d1314dabe3..cf9d0b26d9 100644 --- a/src/Plugins/RpcServer/RpcServer.Blockchain.cs +++ b/src/Plugins/RpcServer/RpcServer.Blockchain.cs @@ -29,7 +29,7 @@ partial class RpcServer /// Gets the hash of the best (most recent) block. /// /// An empty array; no parameters are required. - /// The hash of the best block as a JToken. + /// The hash of the best block as a . [RpcMethod] protected internal virtual JToken GetBestBlockHash(JArray _params) { @@ -43,7 +43,8 @@ protected internal virtual JToken GetBestBlockHash(JArray _params) /// An array containing the block hash or index as the first element, /// and an optional boolean indicating whether to return verbose information. /// - /// The block data as a JToken. + /// The block data as a . If the second item of is true, then + /// block data is json format, otherwise, the return type is byte array. [RpcMethod] protected internal virtual JToken GetBlock(JArray _params) { @@ -78,7 +79,7 @@ protected internal virtual JToken GetBlock(JArray _params) /// Gets the number of block headers in the blockchain. /// /// An empty array; no parameters are required. - /// The count of block headers as a JToken. + /// The count of block headers as a . [RpcMethod] internal virtual JToken GetBlockHeaderCount(JArray _params) { @@ -89,7 +90,7 @@ internal virtual JToken GetBlockHeaderCount(JArray _params) /// Gets the number of blocks in the blockchain. /// /// An empty array; no parameters are required. - /// The count of blocks as a JToken. + /// The count of blocks as a . [RpcMethod] protected internal virtual JToken GetBlockCount(JArray _params) { @@ -100,7 +101,7 @@ protected internal virtual JToken GetBlockCount(JArray _params) /// Gets the hash of the block at the specified height. /// /// An array containing the block height as the first element. - /// The hash of the block at the specified height as a JToken. + /// The hash of the block at the specified height as a . [RpcMethod] protected internal virtual JToken GetBlockHash(JArray _params) { @@ -120,7 +121,7 @@ protected internal virtual JToken GetBlockHash(JArray _params) /// An array containing the block header hash or index as the first element, /// and an optional boolean indicating whether to return verbose information. /// - /// The block header data as a JToken. + /// The block header data as a . In json format if the second item of is true, otherwise base64string. [RpcMethod] protected internal virtual JToken GetBlockHeader(JArray _params) { @@ -155,7 +156,7 @@ protected internal virtual JToken GetBlockHeader(JArray _params) /// Gets the state of a contract by its ID or script hash. /// /// An array containing the contract ID or script hash as the first element. - /// The contract state as a JToken. + /// The contract state in json format as a . [RpcMethod] protected internal virtual JToken GetContractState(JArray _params) { @@ -186,7 +187,7 @@ private static UInt160 ToScriptHash(string keyword) /// Gets the current memory pool transactions. /// /// An array containing an optional boolean indicating whether to include unverified transactions. - /// The memory pool transactions as a JToken. + /// The memory pool transactions in json format as a . [RpcMethod] protected internal virtual JToken GetRawMemPool(JArray _params) { @@ -211,7 +212,7 @@ protected internal virtual JToken GetRawMemPool(JArray _params) /// An array containing the transaction hash as the first element, /// and an optional boolean indicating whether to return verbose information. /// - /// The transaction data as a JToken. + /// The transaction data as a . In json format if the second item of is true, otherwise base64string. [RpcMethod] protected internal virtual JToken GetRawTransaction(JArray _params) { @@ -242,7 +243,7 @@ protected internal virtual JToken GetRawTransaction(JArray _params) /// An array containing the contract ID or script hash as the first element, /// and the storage key as the second element. /// - /// The storage item as a JToken. + /// The storage item as a . [RpcMethod] protected internal virtual JToken GetStorage(JArray _params) { From cdc2b41f6a59637cf3dfe7025b461076f3d1dde2 Mon Sep 17 00:00:00 2001 From: Jimmy Date: Sun, 16 Jun 2024 19:10:57 +0800 Subject: [PATCH 10/20] add more exception test cases --- src/Plugins/RpcServer/RpcServer.Blockchain.cs | 10 + .../UT_RpcServer.Blockchain.cs | 275 ++++++++++++++---- 2 files changed, 235 insertions(+), 50 deletions(-) diff --git a/src/Plugins/RpcServer/RpcServer.Blockchain.cs b/src/Plugins/RpcServer/RpcServer.Blockchain.cs index cf9d0b26d9..203d2513e2 100644 --- a/src/Plugins/RpcServer/RpcServer.Blockchain.cs +++ b/src/Plugins/RpcServer/RpcServer.Blockchain.cs @@ -59,6 +59,8 @@ protected internal virtual JToken GetBlock(JArray _params) } else { + // TODO: check for the format of the parameter + // FormatException => RpcError.InvalidParams UInt256 hash = UInt256.Parse(key.AsString()); block = NativeContract.Ledger.GetBlock(snapshot, hash); } @@ -160,6 +162,8 @@ protected internal virtual JToken GetBlockHeader(JArray _params) [RpcMethod] protected internal virtual JToken GetContractState(JArray _params) { + // TODO: need check the format of the parameter + // FormatException from int.TryParse => RpcError.InvalidParams if (int.TryParse(_params[0].AsString(), out int contractId)) { var contractState = NativeContract.ContractManagement.GetContractById(system.StoreView, contractId); @@ -248,6 +252,8 @@ protected internal virtual JToken GetRawTransaction(JArray _params) protected internal virtual JToken GetStorage(JArray _params) { using var snapshot = system.GetSnapshot(); + // TODO: check for the format of the parameter + // FormatException => RpcError.InvalidParams if (!int.TryParse(_params[0].AsString(), out int id)) { UInt160 hash = UInt160.Parse(_params[0].AsString()); @@ -276,8 +282,12 @@ protected internal virtual JToken GetStorage(JArray _params) protected internal virtual JToken FindStorage(JArray _params) { using var snapshot = system.GetSnapshot(); + // TODO: check for the format of the parameter + // FormatException => RpcError.InvalidParams if (!int.TryParse(_params[0].AsString(), out int id)) { + // TODO: check for the format of the parameter + // FormatException => RpcError.InvalidParams UInt160 hash = UInt160.Parse(_params[0].AsString()); ContractState contract = NativeContract.ContractManagement.GetContract(snapshot, hash).NotNull_Or(RpcError.UnknownContract); id = contract.Id; diff --git a/tests/Neo.Plugins.RpcServer.Tests/UT_RpcServer.Blockchain.cs b/tests/Neo.Plugins.RpcServer.Tests/UT_RpcServer.Blockchain.cs index e5e50c2da7..5fd37b2bc3 100644 --- a/tests/Neo.Plugins.RpcServer.Tests/UT_RpcServer.Blockchain.cs +++ b/tests/Neo.Plugins.RpcServer.Tests/UT_RpcServer.Blockchain.cs @@ -80,46 +80,6 @@ public void TestGetBlockByIndex() }); } - [TestMethod] - public void TestGetBlockByUnKnownIndex() - { - var snapshot = _neoSystem.GetSnapshot(); - var block = TestUtils.CreateBlockWithValidTransactions(snapshot, _wallet, _walletAccount, 3); - TestUtils.BlocksAdd(snapshot, block.Hash, block); - snapshot.Commit(); - - var parameters = new JArray(int.MaxValue, false); - try - { - _rpcServer.GetBlock(parameters); - Assert.Fail("Expected RpcException was not thrown."); - } - catch (RpcException ex) - { - Assert.AreEqual(RpcError.UnknownBlock.Code, ex.HResult); - } - } - - [TestMethod] - public void TestGetBlockByUnKnownHash() - { - var snapshot = _neoSystem.GetSnapshot(); - var block = TestUtils.CreateBlockWithValidTransactions(snapshot, _wallet, _walletAccount, 3); - TestUtils.BlocksAdd(snapshot, block.Hash, block); - snapshot.Commit(); - - var parameters = new JArray(TestUtils.RandomUInt256().ToString(), false); - try - { - _rpcServer.GetBlock(parameters); - Assert.Fail("Expected RpcException was not thrown."); - } - catch (RpcException ex) - { - Assert.AreEqual(RpcError.UnknownBlock.Code, ex.HResult); - } - } - [TestMethod] public void TestGetBlockCount() { @@ -148,16 +108,6 @@ public void TestGetBlockHash() Assert.AreEqual(expectedHash, result.AsString()); } - [TestMethod] - public void TestGetBlockHashInvalidIndex() - { - var snapshot = _neoSystem.GetSnapshot(); - var block = TestUtils.CreateBlockWithValidTransactions(snapshot, _wallet, _walletAccount, 3); - TestUtils.BlocksAdd(snapshot, block.Hash, block); - snapshot.Commit(); - Assert.ThrowsException(() => _rpcServer.GetBlockHash(new JArray(block.Index + 1))); - } - [TestMethod] public void TestGetBlockHeader() { @@ -358,6 +308,56 @@ public void TestGetBlockByUnknownHash() } } + [TestMethod] + public void TestGetBlockByUnKnownIndex() + { + var snapshot = _neoSystem.GetSnapshot(); + var block = TestUtils.CreateBlockWithValidTransactions(snapshot, _wallet, _walletAccount, 3); + TestUtils.BlocksAdd(snapshot, block.Hash, block); + snapshot.Commit(); + + var parameters = new JArray(int.MaxValue, false); + try + { + _rpcServer.GetBlock(parameters); + Assert.Fail("Expected RpcException was not thrown."); + } + catch (RpcException ex) + { + Assert.AreEqual(RpcError.UnknownBlock.Code, ex.HResult); + } + } + + [TestMethod] + public void TestGetBlockByUnKnownHash() + { + var snapshot = _neoSystem.GetSnapshot(); + var block = TestUtils.CreateBlockWithValidTransactions(snapshot, _wallet, _walletAccount, 3); + TestUtils.BlocksAdd(snapshot, block.Hash, block); + snapshot.Commit(); + + var parameters = new JArray(TestUtils.RandomUInt256().ToString(), false); + try + { + _rpcServer.GetBlock(parameters); + Assert.Fail("Expected RpcException was not thrown."); + } + catch (RpcException ex) + { + Assert.AreEqual(RpcError.UnknownBlock.Code, ex.HResult); + } + } + + [TestMethod] + public void TestGetBlockHashInvalidIndex() + { + var snapshot = _neoSystem.GetSnapshot(); + var block = TestUtils.CreateBlockWithValidTransactions(snapshot, _wallet, _walletAccount, 3); + TestUtils.BlocksAdd(snapshot, block.Hash, block); + snapshot.Commit(); + Assert.ThrowsException(() => _rpcServer.GetBlockHash(new JArray(block.Index + 1))); + } + [TestMethod] public void TestGetContractStateUnknownContract() { @@ -441,5 +441,180 @@ public void TestGetRawTransactionUnknownTransaction() } } + [TestMethod] + public void TestGetBlockInvalidParams() + { + try + { + _rpcServer.GetBlock(new JArray("invalid_hash", false)); + Assert.Fail("Expected RpcException was not thrown."); + } + catch (RpcException ex) + { + Assert.AreEqual(RpcError.InvalidParams.Code, ex.HResult); + } + catch (FormatException) + { + } + catch + { + Assert.Fail("Unexpected exception"); + } + } + + [TestMethod] + public void TestGetBlockHashInvalidParams() + { + try + { + _rpcServer.GetBlockHash(new JArray("invalid_index")); + Assert.Fail("Expected RpcException was not thrown."); + } + catch (RpcException ex) + { + Assert.AreEqual(RpcError.InvalidParams.Code, ex.HResult); + } + } + + [TestMethod] + public void TestGetBlockHeaderInvalidParams() + { + try + { + _rpcServer.GetBlockHeader(new JArray("invalid_hash", true)); + Assert.Fail("Expected RpcException was not thrown."); + } + catch (RpcException ex) + { + Assert.AreEqual(RpcError.InvalidParams.Code, ex.HResult); + } + catch (FormatException) + { + } + catch + { + Assert.Fail("Unexpected exception"); + } + } + + [TestMethod] + public void TestGetContractStateInvalidParams() + { + try + { + _rpcServer.GetContractState(new JArray("invalid_hash")); + Assert.Fail("Expected RpcException was not thrown."); + } + catch (RpcException ex) + { + Assert.AreEqual(RpcError.InvalidParams.Code, ex.HResult); + } + catch (FormatException) + { + } + catch + { + Assert.Fail("Unexpected exception"); + } + } + + [TestMethod] + public void TestGetStorageInvalidParams() + { + try + { + _rpcServer.GetStorage(new JArray("invalid_hash", "invalid_key")); + Assert.Fail("Expected RpcException was not thrown."); + } + catch (RpcException ex) + { + Assert.AreEqual(RpcError.InvalidParams.Code, ex.HResult); + } + catch (FormatException) + { + } + catch + { + Assert.Fail("Unexpected exception"); + } + } + + [TestMethod] + public void TestFindStorageInvalidParams() + { + try + { + _rpcServer.FindStorage(new JArray("invalid_hash", "invalid_prefix", "invalid_start")); + Assert.Fail("Expected RpcException was not thrown."); + } + catch (RpcException ex) + { + Assert.AreEqual(RpcError.InvalidParams.Code, ex.HResult); + } + catch (FormatException) + { + } + catch + { + Assert.Fail("Unexpected exception"); + } + } + + [TestMethod] + public void TestGetTransactionHeightInvalidParams() + { + try + { + _rpcServer.GetTransactionHeight(new JArray("invalid_hash")); + Assert.Fail("Expected RpcException was not thrown."); + } + catch (RpcException ex) + { + Assert.AreEqual(RpcError.InvalidParams.Code, ex.HResult); + } + } + + [TestMethod] + public void TestGetRawTransactionInvalidParams() + { + try + { + _rpcServer.GetRawTransaction(new JArray("invalid_hash", true)); + Assert.Fail("Expected RpcException was not thrown."); + } + catch (RpcException ex) + { + Assert.AreEqual(RpcError.InvalidParams.Code, ex.HResult); + } + } + + [TestMethod] + public void TestInternalServerError() + { + _memoryStore.Reset(); + try + { + _rpcServer.GetCandidates(new JArray()); + Assert.Fail("Expected RpcException was not thrown."); + } + catch (RpcException ex) + { + Assert.AreEqual(RpcError.InternalServerError.Code, ex.HResult); + } + } + + [TestMethod] + public void TestUnknownHeight() + { + try + { + _rpcServer.GetBlockHash(new JArray(int.MaxValue)); + Assert.Fail("Expected RpcException was not thrown."); + } + catch (RpcException ex) + { + Assert.AreEqual(RpcError.UnknownHeight.Code, ex.HResult); + } + } } } From a58e05fdaa8437b1cca287399b5926ab3b5cc0ef Mon Sep 17 00:00:00 2001 From: Jimmy Date: Sun, 16 Jun 2024 19:31:31 +0800 Subject: [PATCH 11/20] fix warning --- src/Plugins/RpcServer/RpcServer.Blockchain.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Plugins/RpcServer/RpcServer.Blockchain.cs b/src/Plugins/RpcServer/RpcServer.Blockchain.cs index 203d2513e2..fc411da71a 100644 --- a/src/Plugins/RpcServer/RpcServer.Blockchain.cs +++ b/src/Plugins/RpcServer/RpcServer.Blockchain.cs @@ -43,7 +43,7 @@ protected internal virtual JToken GetBestBlockHash(JArray _params) /// An array containing the block hash or index as the first element, /// and an optional boolean indicating whether to return verbose information. /// - /// The block data as a . If the second item of is true, then + /// The block data as a . If the second item of _params is true, then /// block data is json format, otherwise, the return type is byte array. [RpcMethod] protected internal virtual JToken GetBlock(JArray _params) @@ -123,7 +123,7 @@ protected internal virtual JToken GetBlockHash(JArray _params) /// An array containing the block header hash or index as the first element, /// and an optional boolean indicating whether to return verbose information. /// - /// The block header data as a . In json format if the second item of is true, otherwise base64string. + /// The block header data as a . In json format if the second item of _params is true, otherwise base64string. [RpcMethod] protected internal virtual JToken GetBlockHeader(JArray _params) { @@ -216,7 +216,7 @@ protected internal virtual JToken GetRawMemPool(JArray _params) /// An array containing the transaction hash as the first element, /// and an optional boolean indicating whether to return verbose information. /// - /// The transaction data as a . In json format if the second item of is true, otherwise base64string. + /// The transaction data as a . In json format if the second item of _params is true, otherwise base64string. [RpcMethod] protected internal virtual JToken GetRawTransaction(JArray _params) { From 02f3264ca2c2a3b468cb6d3b000f66e6664c66dc Mon Sep 17 00:00:00 2001 From: Shargon Date: Sun, 16 Jun 2024 14:08:33 +0200 Subject: [PATCH 12/20] Apply suggestions from code review --- src/Plugins/RpcServer/RpcServer.Blockchain.cs | 2 -- tests/Neo.Plugins.RpcServer.Tests/UT_RpcServer.cs | 2 -- 2 files changed, 4 deletions(-) diff --git a/src/Plugins/RpcServer/RpcServer.Blockchain.cs b/src/Plugins/RpcServer/RpcServer.Blockchain.cs index fc411da71a..b9ac6c2ad9 100644 --- a/src/Plugins/RpcServer/RpcServer.Blockchain.cs +++ b/src/Plugins/RpcServer/RpcServer.Blockchain.cs @@ -24,7 +24,6 @@ namespace Neo.Plugins.RpcServer { partial class RpcServer { - /// /// Gets the hash of the best (most recent) block. /// @@ -175,7 +174,6 @@ protected internal virtual JToken GetContractState(JArray _params) return contract.NotNull_Or(RpcError.UnknownContract).ToJson(); } - private static UInt160 ToScriptHash(string keyword) { foreach (var native in NativeContract.Contracts) diff --git a/tests/Neo.Plugins.RpcServer.Tests/UT_RpcServer.cs b/tests/Neo.Plugins.RpcServer.Tests/UT_RpcServer.cs index 1442458dd5..4ba95b7798 100644 --- a/tests/Neo.Plugins.RpcServer.Tests/UT_RpcServer.cs +++ b/tests/Neo.Plugins.RpcServer.Tests/UT_RpcServer.cs @@ -70,7 +70,5 @@ public void TestCheckAuth_ValidCredentials_ReturnsTrue() // Assert Assert.IsTrue(result); } - - } } From d8b67b31a3d5e3cdfd6e4e64f0a68c345d5f5e3a Mon Sep 17 00:00:00 2001 From: Jimmy Date: Sun, 16 Jun 2024 20:24:48 +0800 Subject: [PATCH 13/20] update TODO mark --- src/Plugins/RpcServer/RpcServer.Blockchain.cs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/Plugins/RpcServer/RpcServer.Blockchain.cs b/src/Plugins/RpcServer/RpcServer.Blockchain.cs index fc411da71a..8757502bfe 100644 --- a/src/Plugins/RpcServer/RpcServer.Blockchain.cs +++ b/src/Plugins/RpcServer/RpcServer.Blockchain.cs @@ -138,6 +138,8 @@ protected internal virtual JToken GetBlockHeader(JArray _params) } else { + // TODO: check for the format of the parameter + // UInt256.Parse FormatException => RpcError.InvalidParams UInt256 hash = UInt256.Parse(key.AsString()); header = NativeContract.Ledger.GetHeader(snapshot, hash).NotNull_Or(RpcError.UnknownBlock); } @@ -162,14 +164,14 @@ protected internal virtual JToken GetBlockHeader(JArray _params) [RpcMethod] protected internal virtual JToken GetContractState(JArray _params) { - // TODO: need check the format of the parameter - // FormatException from int.TryParse => RpcError.InvalidParams if (int.TryParse(_params[0].AsString(), out int contractId)) { var contractState = NativeContract.ContractManagement.GetContractById(system.StoreView, contractId); return contractState.NotNull_Or(RpcError.UnknownContract).ToJson(); } + // TODO: need check the format of the parameter + // FormatException from ToScriptHash => RpcError.InvalidParams var scriptHash = ToScriptHash(_params[0].AsString()); var contract = NativeContract.ContractManagement.GetContract(system.StoreView, scriptHash); return contract.NotNull_Or(RpcError.UnknownContract).ToJson(); @@ -252,10 +254,10 @@ protected internal virtual JToken GetRawTransaction(JArray _params) protected internal virtual JToken GetStorage(JArray _params) { using var snapshot = system.GetSnapshot(); - // TODO: check for the format of the parameter - // FormatException => RpcError.InvalidParams if (!int.TryParse(_params[0].AsString(), out int id)) { + // TODO: check for the format of the parameter + // UInt160.Parse FormatException => RpcError.InvalidParams UInt160 hash = UInt160.Parse(_params[0].AsString()); ContractState contract = NativeContract.ContractManagement.GetContract(snapshot, hash).NotNull_Or(RpcError.UnknownContract); id = contract.Id; @@ -282,8 +284,6 @@ protected internal virtual JToken GetStorage(JArray _params) protected internal virtual JToken FindStorage(JArray _params) { using var snapshot = system.GetSnapshot(); - // TODO: check for the format of the parameter - // FormatException => RpcError.InvalidParams if (!int.TryParse(_params[0].AsString(), out int id)) { // TODO: check for the format of the parameter From a4c763825debbfc96e6c7e0aa017c4dbfe20928e Mon Sep 17 00:00:00 2001 From: Jimmy Date: Mon, 24 Jun 2024 10:00:30 +1000 Subject: [PATCH 14/20] add node rpc tests --- src/Neo/Ledger/MemoryPool.cs | 21 ++ .../TestBlockchain.cs | 49 --- .../TestProtocolSettings.cs | 65 ---- .../UT_RpcServer.Blockchain.cs | 6 +- .../UT_RpcServer.Node.cs | 303 ++++++++++++++++++ .../UT_RpcServer.cs | 8 +- .../Network/P2P/Payloads/UT_Block.cs | 22 +- .../Network/P2P/Payloads/UT_Header.cs | 14 +- .../Network/P2P/Payloads/UT_HeadersPayload.cs | 4 +- tests/Neo.UnitTests/TestProtocolSettings.cs | 26 ++ tests/Neo.UnitTests/TestUtils.Block.cs | 72 ++++- tests/Neo.UnitTests/TestUtils.Transaction.cs | 130 ++++++++ tests/Neo.UnitTests/TestUtils.cs | 42 ++- 13 files changed, 609 insertions(+), 153 deletions(-) delete mode 100644 tests/Neo.Plugins.RpcServer.Tests/TestBlockchain.cs delete mode 100644 tests/Neo.Plugins.RpcServer.Tests/TestProtocolSettings.cs create mode 100644 tests/Neo.Plugins.RpcServer.Tests/UT_RpcServer.Node.cs create mode 100644 tests/Neo.UnitTests/TestUtils.Transaction.cs diff --git a/src/Neo/Ledger/MemoryPool.cs b/src/Neo/Ledger/MemoryPool.cs index 23eb711e87..babdda1d8c 100644 --- a/src/Neo/Ledger/MemoryPool.cs +++ b/src/Neo/Ledger/MemoryPool.cs @@ -653,5 +653,26 @@ internal bool ReVerifyTopUnverifiedTransactionsIfNeeded(int maxToVerify, DataCac return _unverifiedTransactions.Count > 0; } + +#if DEBUG + // This method is only for test purpose + // Do not remove it from the DEBUG build + internal void Clear() + { + _txRwLock.EnterReadLock(); + try + { + _unsortedTransactions.Clear(); + _conflicts.Clear(); + _sortedTransactions.Clear(); + _unverifiedTransactions.Clear(); + _unverifiedSortedTransactions.Clear(); + } + finally + { + _txRwLock.ExitReadLock(); + } + } +#endif } } diff --git a/tests/Neo.Plugins.RpcServer.Tests/TestBlockchain.cs b/tests/Neo.Plugins.RpcServer.Tests/TestBlockchain.cs deleted file mode 100644 index f6e35cf695..0000000000 --- a/tests/Neo.Plugins.RpcServer.Tests/TestBlockchain.cs +++ /dev/null @@ -1,49 +0,0 @@ -// Copyright (C) 2015-2024 The Neo Project. -// -// TestBlockchain.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 Akka.Actor; -using Neo.Ledger; -using Neo.Persistence; -using System; - -namespace Neo.Plugins.RpcServer.Tests -{ - public static class TestBlockchain - { - public static readonly NeoSystem TheNeoSystem; - public static readonly UInt160[] DefaultExtensibleWitnessWhiteList; - private static readonly MemoryStore Store = new(); - - internal class StoreProvider : IStoreProvider - { - public string Name => "TestProvider"; - - public IStore GetStore(string path) => Store; - } - - static TestBlockchain() - { - Console.WriteLine("initialize NeoSystem"); - TheNeoSystem = new NeoSystem(TestProtocolSettings.Default, new StoreProvider()); - } - - internal static void ResetStore() - { - Store.Reset(); - TheNeoSystem.Blockchain.Ask(new Blockchain.Initialize()).Wait(); - } - - internal static DataCache GetTestSnapshot() - { - return TheNeoSystem.GetSnapshot().CreateSnapshot(); - } - } -} 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 5fd37b2bc3..f62c4258ab 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.GetSnapshot(); 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..9d0d9587e4 --- /dev/null +++ b/tests/Neo.Plugins.RpcServer.Tests/UT_RpcServer.Node.cs @@ -0,0 +1,303 @@ +// 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.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); + } + + [TestMethod] + public void TestSendRawTransaction_MemoryPoolFull() + { + var snapshot = _neoSystem.GetSnapshot(); + TestUtils.FillMemoryPool(_neoSystem, _wallet, _walletAccount); + var tx = TestUtils.CreateValidTx(snapshot, _wallet, _walletAccount); + var txString = Convert.ToBase64String(tx.ToArray()); + + var exception = Assert.ThrowsException(() => + _rpcServer.SendRawTransaction(new JArray(txString)), + "Should throw RpcException when memory pool is full"); + Assert.AreEqual(RpcError.MempoolCapReached.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); + var blockString = Convert.ToBase64String(block.ToArray()); + + var exception = Assert.ThrowsException(() => + _rpcServer.SubmitBlock(new JArray(blockString)), + "Should throw RpcException for invalid block"); + Assert.AreEqual(RpcError.InvalidParams.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 4ba95b7798..b9a508671f 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; @@ -31,16 +32,16 @@ public partial class UT_RpcServer private MemoryStore _memoryStore; private readonly NEP6Wallet _wallet = TestUtils.GenerateTestWallet("123"); private WalletAccount _walletAccount; + private MemoryPool _memoryPool; [TestInitialize] 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.GetSnapshot(); var entry = snapshot.GetAndChange(key, () => new StorageItem(new AccountState())); @@ -51,6 +52,7 @@ public void TestSetup() [TestCleanup] public void TestCleanup() { + _neoSystem.MemPool.Clear(); _memoryStore.Reset(); var snapshot = _neoSystem.GetSnapshot(); var key = new KeyBuilder(NativeContract.GAS.Id, 20).Add(_walletAccount.ScriptHash); diff --git a/tests/Neo.UnitTests/Network/P2P/Payloads/UT_Block.cs b/tests/Neo.UnitTests/Network/P2P/Payloads/UT_Block.cs index 2021e5a187..0f25936665 100644 --- a/tests/Neo.UnitTests/Network/P2P/Payloads/UT_Block.cs +++ b/tests/Neo.UnitTests/Network/P2P/Payloads/UT_Block.cs @@ -38,7 +38,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 +53,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 +63,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 +77,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,7 +93,7 @@ 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"; uut.ToArray().ToHexString().Should().Be(hex); @@ -103,7 +103,7 @@ 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"; @@ -144,8 +144,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 +161,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,7 +171,7 @@ 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(); diff --git a/tests/Neo.UnitTests/Network/P2P/Payloads/UT_Header.cs b/tests/Neo.UnitTests/Network/P2P/Payloads/UT_Header.cs index a597c88cb6..1995d876b0 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()); } @@ -53,7 +53,7 @@ public void TrimTest() { UInt256 val256 = UInt256.Zero; var snapshot = TestBlockchain.GetTestSnapshot().CreateSnapshot(); - TestUtils.SetupHeaderWithValues(uut, val256, out _, out _, out _, out _, out _, out _); + 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,7 +87,7 @@ 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 @@ -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,7 +146,7 @@ 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"; 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/TestProtocolSettings.cs b/tests/Neo.UnitTests/TestProtocolSettings.cs index b12f5c9a85..d60dcc123d 100644 --- a/tests/Neo.UnitTests/TestProtocolSettings.cs +++ b/tests/Neo.UnitTests/TestProtocolSettings.cs @@ -61,5 +61,31 @@ public static class TestProtocolSettings 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, + MaxTraceableBlocks = ProtocolSettings.Default.MaxTraceableBlocks, + InitialGasDistribution = ProtocolSettings.Default.InitialGasDistribution, + Hardforks = ProtocolSettings.Default.Hardforks + }; } } diff --git a/tests/Neo.UnitTests/TestUtils.Block.cs b/tests/Neo.UnitTests/TestUtils.Block.cs index 4f663fec2d..f90aa72ff8 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 = TimeProvider.Current.UtcNow.ToTimestampMS();// new DateTime(1980, 06, 01, 0, 0, 1, 001, DateTimeKind.Utc).ToTimestampMS(); // GMT: Sunday, June 1, 1980 12:00:01.001 AM + 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..0f85d6ee72 --- /dev/null +++ b/tests/Neo.UnitTests/TestUtils.Transaction.cs @@ -0,0 +1,130 @@ +// 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..9f426d5ff1 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,16 @@ public static Transaction CreateRandomHashTransaction() }; } + public static void FillMemoryPool(NeoSystem system, NEP6Wallet wallet, WalletAccount account) + { + var snapshot = system.GetSnapshot(); + 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()); From 92858b2dde7c9fdb45bd4b7064692337d210fcc7 Mon Sep 17 00:00:00 2001 From: Jimmy Date: Wed, 26 Jun 2024 18:35:26 +1000 Subject: [PATCH 15/20] fix build error --- src/Plugins/RpcServer/RpcServer.Node.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) 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; From d39b9dc006d684918dc351ca070f3641b4e63864 Mon Sep 17 00:00:00 2001 From: Jimmy Date: Wed, 26 Jun 2024 18:59:59 +1000 Subject: [PATCH 16/20] set the mempool to 5. --- .../UT_RpcServer.Node.cs | 6 ++++-- .../UT_RpcServer.cs | 1 - tests/Neo.UnitTests/TestProtocolSettings.cs | 18 +++++++++--------- tests/Neo.UnitTests/TestUtils.cs | 3 +-- 4 files changed, 14 insertions(+), 14 deletions(-) diff --git a/tests/Neo.Plugins.RpcServer.Tests/UT_RpcServer.Node.cs b/tests/Neo.Plugins.RpcServer.Tests/UT_RpcServer.Node.cs index 9d0d9587e4..2995cfa2a0 100644 --- a/tests/Neo.Plugins.RpcServer.Tests/UT_RpcServer.Node.cs +++ b/tests/Neo.Plugins.RpcServer.Tests/UT_RpcServer.Node.cs @@ -12,6 +12,7 @@ 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; @@ -191,7 +192,7 @@ public void TestSendRawTransaction_AlreadyInBlockchain() public void TestSendRawTransaction_MemoryPoolFull() { var snapshot = _neoSystem.GetSnapshot(); - TestUtils.FillMemoryPool(_neoSystem, _wallet, _walletAccount); + TestUtils.FillMemoryPool(snapshot, _neoSystem, _wallet, _walletAccount); var tx = TestUtils.CreateValidTx(snapshot, _wallet, _walletAccount); var txString = Convert.ToBase64String(tx.ToArray()); @@ -250,12 +251,13 @@ 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.InvalidParams.Code, exception.HResult); + Assert.AreEqual(RpcError.VerificationFailed.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 b9a508671f..de4a56e380 100644 --- a/tests/Neo.Plugins.RpcServer.Tests/UT_RpcServer.cs +++ b/tests/Neo.Plugins.RpcServer.Tests/UT_RpcServer.cs @@ -32,7 +32,6 @@ public partial class UT_RpcServer private MemoryStore _memoryStore; private readonly NEP6Wallet _wallet = TestUtils.GenerateTestWallet("123"); private WalletAccount _walletAccount; - private MemoryPool _memoryPool; [TestInitialize] public void TestSetup() diff --git a/tests/Neo.UnitTests/TestProtocolSettings.cs b/tests/Neo.UnitTests/TestProtocolSettings.cs index d60dcc123d..42c4d3059a 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,16 @@ 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, @@ -81,8 +81,8 @@ public static class TestProtocolSettings "seed5.neo.org:10333" ], MillisecondsPerBlock = ProtocolSettings.Default.MillisecondsPerBlock, - MaxTransactionsPerBlock = ProtocolSettings.Default.MaxTransactionsPerBlock, - MemoryPoolMaxTransactions = ProtocolSettings.Default.MemoryPoolMaxTransactions, + MaxTransactionsPerBlock = ProtocolSettings.Default.MaxTransactionsPerBlock / 100, + MemoryPoolMaxTransactions = ProtocolSettings.Default.MemoryPoolMaxTransactions / 10_000, MaxTraceableBlocks = ProtocolSettings.Default.MaxTraceableBlocks, InitialGasDistribution = ProtocolSettings.Default.InitialGasDistribution, Hardforks = ProtocolSettings.Default.Hardforks diff --git a/tests/Neo.UnitTests/TestUtils.cs b/tests/Neo.UnitTests/TestUtils.cs index 9f426d5ff1..c1694347a7 100644 --- a/tests/Neo.UnitTests/TestUtils.cs +++ b/tests/Neo.UnitTests/TestUtils.cs @@ -288,9 +288,8 @@ public static Transaction CreateRandomHashTransaction() }; } - public static void FillMemoryPool(NeoSystem system, NEP6Wallet wallet, WalletAccount account) + public static void FillMemoryPool(DataCache snapshot, NeoSystem system, NEP6Wallet wallet, WalletAccount account) { - var snapshot = system.GetSnapshot(); for (int i = 0; i < system.Settings.MemoryPoolMaxTransactions; i++) { var tx = CreateValidTx(snapshot, wallet, account); From 3e91a32a23714e10ef666e4395534b6fca6e6f44 Mon Sep 17 00:00:00 2001 From: Jimmy Date: Wed, 26 Jun 2024 19:38:20 +1000 Subject: [PATCH 17/20] remove memory pool test. --- .../UT_RpcServer.Node.cs | 14 -------------- tests/Neo.UnitTests/TestProtocolSettings.cs | 4 ++-- 2 files changed, 2 insertions(+), 16 deletions(-) diff --git a/tests/Neo.Plugins.RpcServer.Tests/UT_RpcServer.Node.cs b/tests/Neo.Plugins.RpcServer.Tests/UT_RpcServer.Node.cs index 2995cfa2a0..b75706e001 100644 --- a/tests/Neo.Plugins.RpcServer.Tests/UT_RpcServer.Node.cs +++ b/tests/Neo.Plugins.RpcServer.Tests/UT_RpcServer.Node.cs @@ -188,20 +188,6 @@ public void TestSendRawTransaction_AlreadyInBlockchain() Assert.AreEqual(RpcError.AlreadyExists.Code, exception.HResult); } - [TestMethod] - public void TestSendRawTransaction_MemoryPoolFull() - { - var snapshot = _neoSystem.GetSnapshot(); - TestUtils.FillMemoryPool(snapshot, _neoSystem, _wallet, _walletAccount); - var tx = TestUtils.CreateValidTx(snapshot, _wallet, _walletAccount); - var txString = Convert.ToBase64String(tx.ToArray()); - - var exception = Assert.ThrowsException(() => - _rpcServer.SendRawTransaction(new JArray(txString)), - "Should throw RpcException when memory pool is full"); - Assert.AreEqual(RpcError.MempoolCapReached.Code, exception.HResult); - } - #endregion #region SubmitBlock Tests diff --git a/tests/Neo.UnitTests/TestProtocolSettings.cs b/tests/Neo.UnitTests/TestProtocolSettings.cs index 42c4d3059a..3f89fdd5f9 100644 --- a/tests/Neo.UnitTests/TestProtocolSettings.cs +++ b/tests/Neo.UnitTests/TestProtocolSettings.cs @@ -81,8 +81,8 @@ public static class TestProtocolSettings "seed5.neo.org:10333" ], MillisecondsPerBlock = ProtocolSettings.Default.MillisecondsPerBlock, - MaxTransactionsPerBlock = ProtocolSettings.Default.MaxTransactionsPerBlock / 100, - MemoryPoolMaxTransactions = ProtocolSettings.Default.MemoryPoolMaxTransactions / 10_000, + MaxTransactionsPerBlock = ProtocolSettings.Default.MaxTransactionsPerBlock, + MemoryPoolMaxTransactions = ProtocolSettings.Default.MemoryPoolMaxTransactions, MaxTraceableBlocks = ProtocolSettings.Default.MaxTraceableBlocks, InitialGasDistribution = ProtocolSettings.Default.InitialGasDistribution, Hardforks = ProtocolSettings.Default.Hardforks From 46c0216c4d82b74dd7187e1957fefb52d7c2a8d1 Mon Sep 17 00:00:00 2001 From: Jimmy Date: Fri, 5 Jul 2024 00:53:18 +0800 Subject: [PATCH 18/20] fix tests --- tests/Neo.Plugins.RpcServer.Tests/UT_RpcServer.cs | 1 + tests/Neo.UnitTests/TestUtils.Block.cs | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/Neo.Plugins.RpcServer.Tests/UT_RpcServer.cs b/tests/Neo.Plugins.RpcServer.Tests/UT_RpcServer.cs index de4a56e380..96de838ba8 100644 --- a/tests/Neo.Plugins.RpcServer.Tests/UT_RpcServer.cs +++ b/tests/Neo.Plugins.RpcServer.Tests/UT_RpcServer.cs @@ -51,6 +51,7 @@ public void TestSetup() [TestCleanup] public void TestCleanup() { + // Please build and test in debug mode _neoSystem.MemPool.Clear(); _memoryStore.Reset(); var snapshot = _neoSystem.GetSnapshot(); diff --git a/tests/Neo.UnitTests/TestUtils.Block.cs b/tests/Neo.UnitTests/TestUtils.Block.cs index f90aa72ff8..bed85131e6 100644 --- a/tests/Neo.UnitTests/TestUtils.Block.cs +++ b/tests/Neo.UnitTests/TestUtils.Block.cs @@ -48,7 +48,7 @@ public static void SetupHeaderWithValues(DataCache snapshot, Header header, UInt { header.PrevHash = val256; header.MerkleRoot = merkRootVal = UInt256.Parse("0x6226416a0e5aca42b5566f5a19ab467692688ba9d47986f6981a7f747bba2772"); - header.Timestamp = timestampVal = TimeProvider.Current.UtcNow.ToTimestampMS();// new DateTime(1980, 06, 01, 0, 0, 1, 001, DateTimeKind.Utc).ToTimestampMS(); // GMT: Sunday, June 1, 1980 12:00:01.001 AM + 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 From d8bc36a46b671c37bfaf2d27991a417fa577a147 Mon Sep 17 00:00:00 2001 From: Jimmy Date: Fri, 5 Jul 2024 08:18:27 +0800 Subject: [PATCH 19/20] fix test issue --- tests/Neo.UnitTests/Network/P2P/Payloads/UT_Block.cs | 6 +++--- tests/Neo.UnitTests/Network/P2P/Payloads/UT_Header.cs | 4 ++-- tests/Neo.UnitTests/SmartContract/UT_Syscalls.cs | 3 ++- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/tests/Neo.UnitTests/Network/P2P/Payloads/UT_Block.cs b/tests/Neo.UnitTests/Network/P2P/Payloads/UT_Block.cs index 0f25936665..1134e1e6de 100644 --- a/tests/Neo.UnitTests/Network/P2P/Payloads/UT_Block.cs +++ b/tests/Neo.UnitTests/Network/P2P/Payloads/UT_Block.cs @@ -95,7 +95,7 @@ public void Serialize() UInt256 val256 = UInt256.Zero; 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); } @@ -105,7 +105,7 @@ public void Deserialize() UInt256 val256 = UInt256.Zero; 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); @@ -175,7 +175,7 @@ public void ToJson() 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 1995d876b0..17e0cb894f 100644 --- a/tests/Neo.UnitTests/Network/P2P/Payloads/UT_Header.cs +++ b/tests/Neo.UnitTests/Network/P2P/Payloads/UT_Header.cs @@ -91,7 +91,7 @@ public void Deserialize() 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); @@ -148,7 +148,7 @@ public void Serialize() UInt256 val256 = UInt256.Zero; 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/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, From 4841d193a507281a62db061cc8f860fbcc1ecf8f Mon Sep 17 00:00:00 2001 From: Shargon Date: Fri, 5 Jul 2024 00:27:26 -0700 Subject: [PATCH 20/20] Update tests/Neo.UnitTests/TestUtils.Transaction.cs --- tests/Neo.UnitTests/TestUtils.Transaction.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/Neo.UnitTests/TestUtils.Transaction.cs b/tests/Neo.UnitTests/TestUtils.Transaction.cs index 0f85d6ee72..f96ac8ec74 100644 --- a/tests/Neo.UnitTests/TestUtils.Transaction.cs +++ b/tests/Neo.UnitTests/TestUtils.Transaction.cs @@ -27,7 +27,6 @@ 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();