From cee078e6098502c445b047322d2d668da898b884 Mon Sep 17 00:00:00 2001 From: Charis Zhao Date: Mon, 23 Sep 2019 21:20:09 +0800 Subject: [PATCH] Unit test For Legder module (#1038) * update test ledger * format * Add enter between classes * fix ut suggestion * Update UT_PoolItem.cs * Update UT_MemoryPool.cs * Reduce usings * Reduce changes * More details on TestReVerifyTopUnverifiedTransactionsIfNeeded and fixed comment on ReVerifyTopUnverifiedTransactionsIfNeeded * Minor fix on generic transaction generation fee * Applying dotnet format * Enhance functions in TestDataCache * dotnet format * Cast refactor * comment tx3 for mempool * Removing TODO comment --- neo.UnitTests/Ledger/UT_Blockchain.cs | 102 ++++++++ neo.UnitTests/Ledger/UT_ContractState.cs | 99 ++++++++ neo.UnitTests/Ledger/UT_HashIndexState.cs | 63 +++++ neo.UnitTests/Ledger/UT_HeaderHashList.cs | 59 +++++ neo.UnitTests/Ledger/UT_MemoryPool.cs | 252 +++++++++++++++++++- neo.UnitTests/Ledger/UT_PoolItem.cs | 1 - neo.UnitTests/Ledger/UT_StorageItem.cs | 10 + neo.UnitTests/Ledger/UT_StorageKey.cs | 26 ++ neo.UnitTests/Ledger/UT_TransactionState.cs | 67 ++++++ neo.UnitTests/Ledger/UT_TrimmedBlock.cs | 138 +++++++++++ neo.UnitTests/TestBlockchain.cs | 13 +- neo.UnitTests/TestDataCache.cs | 22 +- neo.UnitTests/Wallets/NEP6/UT_NEP6Wallet.cs | 11 +- neo/Ledger/MemoryPool.cs | 3 +- 14 files changed, 837 insertions(+), 29 deletions(-) create mode 100644 neo.UnitTests/Ledger/UT_Blockchain.cs create mode 100644 neo.UnitTests/Ledger/UT_ContractState.cs create mode 100644 neo.UnitTests/Ledger/UT_HashIndexState.cs create mode 100644 neo.UnitTests/Ledger/UT_HeaderHashList.cs create mode 100644 neo.UnitTests/Ledger/UT_TransactionState.cs create mode 100644 neo.UnitTests/Ledger/UT_TrimmedBlock.cs diff --git a/neo.UnitTests/Ledger/UT_Blockchain.cs b/neo.UnitTests/Ledger/UT_Blockchain.cs new file mode 100644 index 0000000000..eb17e71c62 --- /dev/null +++ b/neo.UnitTests/Ledger/UT_Blockchain.cs @@ -0,0 +1,102 @@ +using FluentAssertions; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Neo.IO; +using Neo.Ledger; +using Neo.Network.P2P.Payloads; +using Neo.Persistence; + +namespace Neo.UnitTests.Ledger +{ + internal class TestBlock : Block + { + public override bool Verify(Snapshot snapshot) + { + return true; + } + + public static TestBlock Cast(Block input) + { + return input.ToArray().AsSerializable(); + } + } + + internal class TestHeader : Header + { + public override bool Verify(Snapshot snapshot) + { + return true; + } + + public static TestHeader Cast(Header input) + { + return input.ToArray().AsSerializable(); + } + } + + [TestClass] + public class UT_Blockchain + { + private NeoSystem system; + private Store store; + Transaction txSample = Blockchain.GenesisBlock.Transactions[0]; + + [TestInitialize] + public void Initialize() + { + system = TestBlockchain.InitializeMockNeoSystem(); + store = TestBlockchain.GetStore(); + Blockchain.Singleton.MemPool.TryAdd(txSample.Hash, txSample); + } + + [TestMethod] + public void TestConstructor() + { + system.ActorSystem.ActorOf(Blockchain.Props(system, store)).Should().NotBeSameAs(system.Blockchain); + } + + [TestMethod] + public void TestContainsBlock() + { + Blockchain.Singleton.ContainsBlock(UInt256.Zero).Should().BeFalse(); + } + + [TestMethod] + public void TestContainsTransaction() + { + Blockchain.Singleton.ContainsTransaction(UInt256.Zero).Should().BeFalse(); + Blockchain.Singleton.ContainsTransaction(txSample.Hash).Should().BeTrue(); + } + + [TestMethod] + public void TestGetCurrentBlockHash() + { + Blockchain.Singleton.CurrentBlockHash.Should().Be(UInt256.Parse("5662a113d8fa9532ea9c52046a463e2e3fcfcdd6192d99cad805b376fb643ceb")); + } + + [TestMethod] + public void TestGetCurrentHeaderHash() + { + Blockchain.Singleton.CurrentHeaderHash.Should().Be(UInt256.Parse("5662a113d8fa9532ea9c52046a463e2e3fcfcdd6192d99cad805b376fb643ceb")); + } + + [TestMethod] + public void TestGetBlock() + { + Blockchain.Singleton.GetBlock(UInt256.Zero).Should().BeNull(); + } + + [TestMethod] + public void TestGetBlockHash() + { + Blockchain.Singleton.GetBlockHash(0).Should().Be(UInt256.Parse("5662a113d8fa9532ea9c52046a463e2e3fcfcdd6192d99cad805b376fb643ceb")); + Blockchain.Singleton.GetBlockHash(10).Should().BeNull(); + } + + [TestMethod] + public void TestGetTransaction() + { + Blockchain.Singleton.GetTransaction(UInt256.Zero).Should().BeNull(); + Blockchain.Singleton.GetTransaction(txSample.Hash).Should().NotBeNull(); + } + } +} diff --git a/neo.UnitTests/Ledger/UT_ContractState.cs b/neo.UnitTests/Ledger/UT_ContractState.cs new file mode 100644 index 0000000000..87f1d7ac88 --- /dev/null +++ b/neo.UnitTests/Ledger/UT_ContractState.cs @@ -0,0 +1,99 @@ +using FluentAssertions; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Neo.IO; +using Neo.IO.Json; +using Neo.Ledger; +using Neo.SmartContract; +using Neo.SmartContract.Manifest; +using System.IO; + +namespace Neo.UnitTests.Ledger +{ + [TestClass] + public class UT_ContractState + { + ContractState contract; + byte[] script = { 0x01 }; + ContractManifest manifest; + + [TestInitialize] + public void TestSetup() + { + manifest = ContractManifest.CreateDefault(UInt160.Parse("0xa400ff00ff00ff00ff00ff00ff00ff00ff00ff01")); + contract = new ContractState + { + Script = script, + Manifest = manifest + }; + } + + [TestMethod] + public void TestGetHasStorage() + { + contract.HasStorage.Should().BeFalse(); + } + + [TestMethod] + public void TestGetPayable() + { + contract.Payable.Should().BeFalse(); + } + + [TestMethod] + public void TestGetScriptHash() + { + // _scriptHash == null + contract.ScriptHash.Should().Be(script.ToScriptHash()); + // _scriptHash != null + contract.ScriptHash.Should().Be(script.ToScriptHash()); + } + + [TestMethod] + public void TestClone() + { + ICloneable cloneable = contract; + ContractState clone = cloneable.Clone(); + clone.ToJson().ToString().Should().Be(contract.ToJson().ToString()); + } + + [TestMethod] + public void TestFromReplica() + { + ICloneable cloneable = new ContractState(); + cloneable.FromReplica(contract); + ((ContractState)cloneable).ToJson().ToString().Should().Be(contract.ToJson().ToString()); + } + + [TestMethod] + public void TestDeserialize() + { + ISerializable newContract = new ContractState(); + using (MemoryStream ms = new MemoryStream(1024)) + using (BinaryWriter writer = new BinaryWriter(ms)) + using (BinaryReader reader = new BinaryReader(ms)) + { + ((ISerializable)contract).Serialize(writer); + ms.Seek(0, SeekOrigin.Begin); + newContract.Deserialize(reader); + } + ((ContractState)newContract).Manifest.ToJson().ToString().Should().Be(contract.Manifest.ToJson().ToString()); + ((ContractState)newContract).Script.Should().BeEquivalentTo(contract.Script); + } + + [TestMethod] + public void TestGetSize() + { + ISerializable newContract = contract; + newContract.Size.Should().Be(355); + } + + [TestMethod] + public void TestToJson() + { + JObject json = contract.ToJson(); + json["hash"].AsString().Should().Be("0x820944cfdc70976602d71b0091445eedbc661bc5"); + json["script"].AsString().Should().Be("01"); + json["manifest"].AsString().Should().Be(manifest.ToJson().AsString()); + } + } +} diff --git a/neo.UnitTests/Ledger/UT_HashIndexState.cs b/neo.UnitTests/Ledger/UT_HashIndexState.cs new file mode 100644 index 0000000000..bfc85479dd --- /dev/null +++ b/neo.UnitTests/Ledger/UT_HashIndexState.cs @@ -0,0 +1,63 @@ +using FluentAssertions; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Neo.IO; +using Neo.Ledger; +using System.IO; + +namespace Neo.UnitTests.Ledger +{ + [TestClass] + public class UT_HashIndexState + { + HashIndexState origin; + + [TestInitialize] + public void Initialize() + { + origin = new HashIndexState + { + Hash = UInt256.Zero, + Index = 10 + }; + } + + [TestMethod] + public void TestClone() + { + HashIndexState dest = ((ICloneable)origin).Clone(); + dest.Hash.Should().Be(origin.Hash); + dest.Index.Should().Be(origin.Index); + } + + [TestMethod] + public void TestFromReplica() + { + HashIndexState dest = new HashIndexState(); + ((ICloneable)dest).FromReplica(origin); + dest.Hash.Should().Be(origin.Hash); + dest.Index.Should().Be(origin.Index); + } + + [TestMethod] + public void TestGetSize() + { + ((ISerializable)origin).Size.Should().Be(36); + } + + [TestMethod] + public void TestDeserialize() + { + using (MemoryStream ms = new MemoryStream(1024)) + using (BinaryWriter writer = new BinaryWriter(ms)) + using (BinaryReader reader = new BinaryReader(ms)) + { + ((ISerializable)origin).Serialize(writer); + ms.Seek(0, SeekOrigin.Begin); + HashIndexState dest = new HashIndexState(); + ((ISerializable)dest).Deserialize(reader); + dest.Hash.Should().Be(origin.Hash); + dest.Index.Should().Be(origin.Index); + } + } + } +} diff --git a/neo.UnitTests/Ledger/UT_HeaderHashList.cs b/neo.UnitTests/Ledger/UT_HeaderHashList.cs new file mode 100644 index 0000000000..2f198f4c6c --- /dev/null +++ b/neo.UnitTests/Ledger/UT_HeaderHashList.cs @@ -0,0 +1,59 @@ +using FluentAssertions; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Neo.IO; +using Neo.Ledger; +using System.IO; + +namespace Neo.UnitTests.Ledger +{ + [TestClass] + public class UT_HeaderHashList + { + HeaderHashList origin; + + [TestInitialize] + public void Initialize() + { + origin = new HeaderHashList + { + Hashes = new UInt256[] { UInt256.Zero } + }; + } + + [TestMethod] + public void TestClone() + { + HeaderHashList dest = ((ICloneable)origin).Clone(); + dest.Hashes.Should().BeEquivalentTo(origin.Hashes); + } + + [TestMethod] + public void TestFromReplica() + { + HeaderHashList dest = new HeaderHashList(); + ((ICloneable)dest).FromReplica(origin); + dest.Hashes.Should().BeEquivalentTo(origin.Hashes); + } + + [TestMethod] + public void TestDeserialize() + { + using (MemoryStream ms = new MemoryStream(1024)) + using (BinaryWriter writer = new BinaryWriter(ms)) + using (BinaryReader reader = new BinaryReader(ms)) + { + ((ISerializable)origin).Serialize(writer); + ms.Seek(0, SeekOrigin.Begin); + HeaderHashList dest = new HeaderHashList(); + ((ISerializable)dest).Deserialize(reader); + dest.Hashes.Should().BeEquivalentTo(origin.Hashes); + } + } + + [TestMethod] + public void TestGetSize() + { + ((ISerializable)origin).Size.Should().Be(33); + } + } +} diff --git a/neo.UnitTests/Ledger/UT_MemoryPool.cs b/neo.UnitTests/Ledger/UT_MemoryPool.cs index ea797d7c03..e9a451952c 100644 --- a/neo.UnitTests/Ledger/UT_MemoryPool.cs +++ b/neo.UnitTests/Ledger/UT_MemoryPool.cs @@ -1,19 +1,36 @@ using FluentAssertions; using Microsoft.VisualStudio.TestTools.UnitTesting; using Moq; +using Neo.Cryptography; +using Neo.IO; +using Neo.IO.Caching; using Neo.Ledger; using Neo.Network.P2P.Payloads; using Neo.Persistence; +using Neo.Plugins; +using Neo.SmartContract.Native; using System; +using System.Collections; using System.Collections.Generic; using System.Linq; namespace Neo.UnitTests.Ledger { + internal class TestIMemoryPoolTxObserverPlugin : Plugin, IMemoryPoolTxObserverPlugin + { + public override void Configure() { } + public void TransactionAdded(Transaction tx) { } + public void TransactionsRemoved(MemoryPoolTxRemovalReason reason, IEnumerable transactions) { } + } + [TestClass] public class UT_MemoryPool { + private const byte Prefix_MaxTransactionsPerBlock = 23; + private const byte Prefix_FeePerByte = 10; private MemoryPool _unit; + private MemoryPool _unit2; + private TestIMemoryPoolTxObserverPlugin plugin; [TestInitialize] public void TestSetup() @@ -33,6 +50,14 @@ public void TestSetup() _unit.VerifiedCount.ShouldBeEquivalentTo(0); _unit.UnVerifiedCount.ShouldBeEquivalentTo(0); _unit.Count.ShouldBeEquivalentTo(0); + _unit2 = new MemoryPool(TheNeoSystem, 0); + plugin = new TestIMemoryPoolTxObserverPlugin(); + } + + [TestCleanup] + public void CleanUp() + { + Plugin.TxObserverPlugins.Remove(plugin); } long LongRandom(long min, long max, Random rand) @@ -66,8 +91,10 @@ private Transaction CreateTransactionWithFee(long fee) return mock.Object; } - private Transaction CreateTransaction() + private Transaction CreateTransaction(long fee = -1) { + if (fee != -1) + return CreateTransactionWithFee(fee); return CreateTransactionWithFee(LongRandom(100000, 100000000, TestUtils.TestRandom)); } @@ -82,6 +109,10 @@ private void AddTransactions(int count) Console.WriteLine($"created {count} tx"); } + private void AddTransaction(Transaction txToAdd) + { + _unit.TryAdd(txToAdd.Hash, txToAdd); + } [TestMethod] public void CapacityTest() @@ -139,7 +170,7 @@ public void BlockPersistMovesTxToUnverifiedAndReverification() _unit.UnverifiedSortedTxCount.ShouldBeEquivalentTo(0); } - private void verifyTransactionsSortedDescending(IEnumerable transactions) + private void VerifyTransactionsSortedDescending(IEnumerable transactions) { Transaction lastTransaction = null; foreach (var tx in transactions) @@ -170,7 +201,7 @@ public void VerifySortOrderAndThatHighetFeeTransactionsAreReverifiedFirst() var sortedVerifiedTxs = _unit.GetSortedVerifiedTransactions().ToList(); // verify all 100 transactions are returned in sorted order sortedVerifiedTxs.Count.ShouldBeEquivalentTo(100); - verifyTransactionsSortedDescending(sortedVerifiedTxs); + VerifyTransactionsSortedDescending(sortedVerifiedTxs); // move all to unverified var block = new Block { Transactions = new Transaction[0] }; @@ -185,7 +216,7 @@ public void VerifySortOrderAndThatHighetFeeTransactionsAreReverifiedFirst() _unit.GetVerifiedAndUnverifiedTransactions(out var sortedVerifiedTransactions, out var sortedUnverifiedTransactions); sortedVerifiedTransactions.Count().ShouldBeEquivalentTo(0); var sortedUnverifiedArray = sortedUnverifiedTransactions.ToArray(); - verifyTransactionsSortedDescending(sortedUnverifiedArray); + VerifyTransactionsSortedDescending(sortedUnverifiedArray); var maxTransaction = sortedUnverifiedArray.First(); var minTransaction = sortedUnverifiedArray.Last(); @@ -253,5 +284,218 @@ public void TestInvalidateAll() _unit.UnverifiedSortedTxCount.ShouldBeEquivalentTo(30); _unit.SortedTxCount.ShouldBeEquivalentTo(0); } + + [TestMethod] + public void TestContainsKey() + { + AddTransactions(10); + + var txToAdd = CreateTransaction(); + _unit.TryAdd(txToAdd.Hash, txToAdd); + _unit.ContainsKey(txToAdd.Hash).Should().BeTrue(); + _unit.InvalidateVerifiedTransactions(); + _unit.ContainsKey(txToAdd.Hash).Should().BeTrue(); + } + + [TestMethod] + public void TestGetEnumerator() + { + AddTransactions(10); + _unit.InvalidateVerifiedTransactions(); + IEnumerator enumerator = _unit.GetEnumerator(); + foreach (Transaction tx in _unit) + { + enumerator.MoveNext(); + enumerator.Current.Should().BeSameAs(tx); + } + } + + [TestMethod] + public void TestIEnumerableGetEnumerator() + { + AddTransactions(10); + _unit.InvalidateVerifiedTransactions(); + IEnumerable enumerable = _unit; + var enumerator = enumerable.GetEnumerator(); + foreach (Transaction tx in _unit) + { + enumerator.MoveNext(); + enumerator.Current.Should().BeSameAs(tx); + } + } + + [TestMethod] + public void TestGetVerifiedTransactions() + { + var tx1 = CreateTransaction(); + var tx2 = CreateTransaction(); + _unit.TryAdd(tx1.Hash, tx1); + _unit.InvalidateVerifiedTransactions(); + _unit.TryAdd(tx2.Hash, tx2); + IEnumerable enumerable = _unit.GetVerifiedTransactions(); + enumerable.Count().Should().Be(1); + var enumerator = enumerable.GetEnumerator(); + enumerator.MoveNext(); + enumerator.Current.Should().BeSameAs(tx2); + } + + [TestMethod] + public void TestReVerifyTopUnverifiedTransactionsIfNeeded() + { + NeoSystem TheNeoSystem = TestBlockchain.InitializeMockNeoSystem(); + var s = Blockchain.Singleton.Height; + _unit = new MemoryPool(TheNeoSystem, 600); + _unit.LoadPolicy(TestBlockchain.GetStore().GetSnapshot()); + AddTransaction(CreateTransaction(100000001)); + AddTransaction(CreateTransaction(100000001)); + AddTransaction(CreateTransaction(100000001)); + AddTransaction(CreateTransaction(1)); + _unit.VerifiedCount.Should().Be(4); + _unit.UnVerifiedCount.Should().Be(0); + + _unit.InvalidateVerifiedTransactions(); + _unit.VerifiedCount.Should().Be(0); + _unit.UnVerifiedCount.Should().Be(4); + + AddTransactions(511); // Max per block currently is 512 + _unit.VerifiedCount.Should().Be(511); + _unit.UnVerifiedCount.Should().Be(4); + + var result = _unit.ReVerifyTopUnverifiedTransactionsIfNeeded(1, Blockchain.Singleton.GetSnapshot()); + result.Should().BeTrue(); + _unit.VerifiedCount.Should().Be(512); + _unit.UnVerifiedCount.Should().Be(3); + + result = _unit.ReVerifyTopUnverifiedTransactionsIfNeeded(2, Blockchain.Singleton.GetSnapshot()); + result.Should().BeTrue(); + _unit.VerifiedCount.Should().Be(514); + _unit.UnVerifiedCount.Should().Be(1); + + result = _unit.ReVerifyTopUnverifiedTransactionsIfNeeded(3, Blockchain.Singleton.GetSnapshot()); + result.Should().BeFalse(); + _unit.VerifiedCount.Should().Be(515); + _unit.UnVerifiedCount.Should().Be(0); + } + + [TestMethod] + public void TestTryAdd() + { + var tx1 = CreateTransaction(); + _unit.TryAdd(tx1.Hash, tx1).Should().BeTrue(); + _unit.TryAdd(tx1.Hash, tx1).Should().BeFalse(); + _unit2.TryAdd(tx1.Hash, tx1).Should().BeFalse(); + } + + [TestMethod] + public void TestTryGetValue() + { + var tx1 = CreateTransaction(); + _unit.TryAdd(tx1.Hash, tx1); + _unit.TryGetValue(tx1.Hash, out Transaction tx).Should().BeTrue(); + tx.ShouldBeEquivalentTo(tx1); + + _unit.InvalidateVerifiedTransactions(); + _unit.TryGetValue(tx1.Hash, out tx).Should().BeTrue(); + tx.ShouldBeEquivalentTo(tx1); + + var tx2 = CreateTransaction(); + _unit.TryGetValue(tx2.Hash, out tx).Should().BeFalse(); + } + + [TestMethod] + public void TestUpdatePoolForBlockPersisted() + { + var mockSnapshot = new Mock(); + byte[] transactionsPerBlock = { 0x18, 0x00, 0x00, 0x00 }; // 24 + byte[] feePerByte = { 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00 }; // 1048576 + StorageItem item1 = new StorageItem + { + Value = transactionsPerBlock + }; + StorageItem item2 = new StorageItem + { + Value = feePerByte + }; + var myDataCache = new MyDataCache(); + var key1 = CreateStorageKey(Prefix_MaxTransactionsPerBlock); + var key2 = CreateStorageKey(Prefix_FeePerByte); + key1.ScriptHash = NativeContract.Policy.Hash; + key2.ScriptHash = NativeContract.Policy.Hash; + myDataCache.Add(key1, item1); + myDataCache.Add(key2, item2); + mockSnapshot.SetupGet(p => p.Storages).Returns(myDataCache); + + var tx1 = CreateTransaction(); + var tx2 = CreateTransaction(); + Transaction[] transactions = { tx1, tx2 }; + _unit.TryAdd(tx1.Hash, tx1); + + var block = new Block { Transactions = transactions }; + + _unit.UnVerifiedCount.Should().Be(0); + _unit.VerifiedCount.Should().Be(1); + + _unit.UpdatePoolForBlockPersisted(block, mockSnapshot.Object); + + _unit.UnVerifiedCount.Should().Be(0); + _unit.VerifiedCount.Should().Be(0); + } + + public StorageKey CreateStorageKey(byte prefix, byte[] key = null) + { + StorageKey storageKey = new StorageKey + { + ScriptHash = null, + Key = new byte[sizeof(byte) + (key?.Length ?? 0)] + }; + storageKey.Key[0] = prefix; + if (key != null) + Buffer.BlockCopy(key, 0, storageKey.Key, 1, key.Length); + return storageKey; + } + } + + public class MyDataCache : DataCache + where TKey : IEquatable, ISerializable + where TValue : class, ICloneable, ISerializable, new() + { + private readonly TValue _defaultValue; + + public MyDataCache() + { + _defaultValue = null; + } + + public MyDataCache(TValue defaultValue) + { + this._defaultValue = defaultValue; + } + public override void DeleteInternal(TKey key) + { + } + + protected override void AddInternal(TKey key, TValue value) + { + Add(key, value); + } + + protected override IEnumerable> FindInternal(byte[] key_prefix) + { + return Enumerable.Empty>(); + } + + protected override TValue GetInternal(TKey key) + { + return TryGet(key); + } + + protected override TValue TryGetInternal(TKey key) + { + return _defaultValue; + } + + protected override void UpdateInternal(TKey key, TValue value) + { + } } } diff --git a/neo.UnitTests/Ledger/UT_PoolItem.cs b/neo.UnitTests/Ledger/UT_PoolItem.cs index 10a57ecc90..d94cec8e4c 100644 --- a/neo.UnitTests/Ledger/UT_PoolItem.cs +++ b/neo.UnitTests/Ledger/UT_PoolItem.cs @@ -11,7 +11,6 @@ namespace Neo.UnitTests.Ledger [TestClass] public class UT_PoolItem { - //private PoolItem uut; private static readonly Random TestRandom = new Random(1337); // use fixed seed for guaranteed determinism [TestInitialize] diff --git a/neo.UnitTests/Ledger/UT_StorageItem.cs b/neo.UnitTests/Ledger/UT_StorageItem.cs index 9afab26372..5ed24b5858 100644 --- a/neo.UnitTests/Ledger/UT_StorageItem.cs +++ b/neo.UnitTests/Ledger/UT_StorageItem.cs @@ -106,5 +106,15 @@ public void Serialize() } } + [TestMethod] + public void TestFromReplica() + { + uut.Value = TestUtils.GetByteArray(10, 0x42); + uut.IsConstant = true; + StorageItem dest = new StorageItem(); + ((ICloneable)dest).FromReplica(uut); + dest.Value.Should().BeEquivalentTo(uut.Value); + dest.IsConstant.Should().Be(uut.IsConstant); + } } } diff --git a/neo.UnitTests/Ledger/UT_StorageKey.cs b/neo.UnitTests/Ledger/UT_StorageKey.cs index 6e2223cdcb..1941cbc0cc 100644 --- a/neo.UnitTests/Ledger/UT_StorageKey.cs +++ b/neo.UnitTests/Ledger/UT_StorageKey.cs @@ -2,6 +2,7 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; using Neo.IO; using Neo.Ledger; +using System.IO; namespace Neo.UnitTests.Ledger { @@ -127,5 +128,30 @@ public void GetHashCode_Get() uut.Key = TestUtils.GetByteArray(10, 0x42); uut.GetHashCode().Should().Be(806209853); } + + [TestMethod] + public void Equals_Obj() + { + uut.Equals(1u).Should().BeFalse(); + uut.Equals((object)uut).Should().BeTrue(); + } + + [TestMethod] + public void TestDeserialize() + { + using (MemoryStream ms = new MemoryStream(1024)) + using (BinaryWriter writer = new BinaryWriter(ms)) + using (BinaryReader reader = new BinaryReader(ms)) + { + uut.ScriptHash = new UInt160(TestUtils.GetByteArray(20, 0x42)); + uut.Key = TestUtils.GetByteArray(10, 0x42); + ((ISerializable)uut).Serialize(writer); + ms.Seek(0, SeekOrigin.Begin); + StorageKey dest = new StorageKey(); + ((ISerializable)dest).Deserialize(reader); + dest.ScriptHash.Should().Be(uut.ScriptHash); + dest.Key.Should().BeEquivalentTo(uut.Key); + } + } } } diff --git a/neo.UnitTests/Ledger/UT_TransactionState.cs b/neo.UnitTests/Ledger/UT_TransactionState.cs new file mode 100644 index 0000000000..7abf431849 --- /dev/null +++ b/neo.UnitTests/Ledger/UT_TransactionState.cs @@ -0,0 +1,67 @@ +using FluentAssertions; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Neo.IO; +using Neo.Ledger; +using System.IO; + +namespace Neo.UnitTests.Ledger +{ + [TestClass] + public class UT_TransactionState + { + TransactionState origin; + + [TestInitialize] + public void Initialize() + { + origin = new TransactionState + { + BlockIndex = 1, + VMState = VM.VMState.NONE, + Transaction = Blockchain.GenesisBlock.Transactions[0] + }; + } + + [TestMethod] + public void TestClone() + { + TransactionState dest = ((ICloneable)origin).Clone(); + dest.BlockIndex.Should().Be(origin.BlockIndex); + dest.VMState.Should().Be(origin.VMState); + dest.Transaction.Should().Be(origin.Transaction); + } + + [TestMethod] + public void TestFromReplica() + { + TransactionState dest = new TransactionState(); + ((ICloneable)dest).FromReplica(origin); + dest.BlockIndex.Should().Be(origin.BlockIndex); + dest.VMState.Should().Be(origin.VMState); + dest.Transaction.Should().Be(origin.Transaction); + } + + [TestMethod] + public void TestDeserialize() + { + using (MemoryStream ms = new MemoryStream(1024)) + using (BinaryWriter writer = new BinaryWriter(ms)) + using (BinaryReader reader = new BinaryReader(ms)) + { + ((ISerializable)origin).Serialize(writer); + ms.Seek(0, SeekOrigin.Begin); + TransactionState dest = new TransactionState(); + ((ISerializable)dest).Deserialize(reader); + dest.BlockIndex.Should().Be(origin.BlockIndex); + dest.VMState.Should().Be(origin.VMState); + dest.Transaction.Should().Be(origin.Transaction); + } + } + + [TestMethod] + public void TestGetSize() + { + ((ISerializable)origin).Size.Should().Be(62); + } + } +} diff --git a/neo.UnitTests/Ledger/UT_TrimmedBlock.cs b/neo.UnitTests/Ledger/UT_TrimmedBlock.cs new file mode 100644 index 0000000000..3704279701 --- /dev/null +++ b/neo.UnitTests/Ledger/UT_TrimmedBlock.cs @@ -0,0 +1,138 @@ +using FluentAssertions; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Neo.IO; +using Neo.Ledger; +using Neo.Network.P2P.Payloads; +using Neo.VM; +using System; +using System.IO; + +namespace Neo.UnitTests.Ledger +{ + [TestClass] + public class UT_TrimmedBlock + { + public static TrimmedBlock GetTrimmedBlockWithNoTransaction() + { + return new TrimmedBlock + { + ConsensusData = new ConsensusData(), + 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 = new byte[0], + VerificationScript = new[] { (byte)OpCode.PUSHT } + }, + Hashes = new UInt256[0] + }; + } + + [TestMethod] + public void TestGetIsBlock() + { + TrimmedBlock block = GetTrimmedBlockWithNoTransaction(); + block.Hashes = new UInt256[] { TestUtils.GetTransaction().Hash }; + block.IsBlock.Should().BeTrue(); + } + + [TestMethod] + public void TestGetBlock() + { + var cache = new TestDataCache(); + var tx1 = TestUtils.GetTransaction(); + 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(); + 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 + }; + cache.Add(tx1.Hash, state1); + cache.Add(tx2.Hash, state2); + + TrimmedBlock tblock = GetTrimmedBlockWithNoTransaction(); + tblock.Hashes = new UInt256[] { tx1.Hash, tx2.Hash }; + Block block = tblock.GetBlock(cache); + + block.Index.Should().Be(1); + block.MerkleRoot.Should().Be(UInt256.Parse("0xa400ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff02")); + block.Transactions.Length.Should().Be(1); + block.Transactions[0].Hash.Should().Be(tx2.Hash); + } + + [TestMethod] + public void TestGetHeader() + { + TrimmedBlock tblock = GetTrimmedBlockWithNoTransaction(); + Header header = tblock.Header; + header.PrevHash.Should().Be(UInt256.Parse("0xa400ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff01")); + header.MerkleRoot.Should().Be(UInt256.Parse("0xa400ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff02")); + } + + [TestMethod] + public void TestGetSize() + { + TrimmedBlock tblock = GetTrimmedBlockWithNoTransaction(); + tblock.Hashes = new UInt256[] { TestUtils.GetTransaction().Hash }; + tblock.Size.Should().Be(146); + } + + [TestMethod] + public void TestDeserialize() + { + TrimmedBlock tblock = GetTrimmedBlockWithNoTransaction(); + tblock.Hashes = new UInt256[] { TestUtils.GetTransaction().Hash }; + var newBlock = new TrimmedBlock(); + using (MemoryStream ms = new MemoryStream(1024)) + using (BinaryWriter writer = new BinaryWriter(ms)) + using (BinaryReader reader = new BinaryReader(ms)) + { + tblock.Serialize(writer); + ms.Seek(0, SeekOrigin.Begin); + newBlock.Deserialize(reader); + } + tblock.MerkleRoot.Should().Be(newBlock.MerkleRoot); + tblock.PrevHash.Should().Be(newBlock.PrevHash); + tblock.Timestamp.Should().Be(newBlock.Timestamp); + tblock.Hashes.Length.Should().Be(newBlock.Hashes.Length); + tblock.Witness.ScriptHash.Should().Be(newBlock.Witness.ScriptHash); + tblock.ToJson().ToString().Should().Be(newBlock.ToJson().ToString()); + } + + [TestMethod] + public void TestClone() + { + TrimmedBlock tblock = GetTrimmedBlockWithNoTransaction(); + tblock.Hashes = new UInt256[] { TestUtils.GetTransaction().Hash }; + ICloneable cloneable = tblock; + var clonedBlock = cloneable.Clone(); + clonedBlock.ToJson().ToString().Should().Be(tblock.ToJson().ToString()); + } + + [TestMethod] + public void TestFromReplica() + { + TrimmedBlock tblock = GetTrimmedBlockWithNoTransaction(); + tblock.Hashes = new UInt256[] { TestUtils.GetTransaction().Hash }; + ICloneable cloneable = new TrimmedBlock(); + cloneable.FromReplica(tblock); + ((TrimmedBlock)cloneable).ToJson().ToString().Should().Be(tblock.ToJson().ToString()); + } + } +} diff --git a/neo.UnitTests/TestBlockchain.cs b/neo.UnitTests/TestBlockchain.cs index 5276dc2e4c..290e054d10 100644 --- a/neo.UnitTests/TestBlockchain.cs +++ b/neo.UnitTests/TestBlockchain.cs @@ -33,14 +33,13 @@ public static NeoSystem InitializeMockNeoSystem() _Store = new Mock(); var defaultTx = TestUtils.CreateRandomHashTransaction(); + var txState = new TransactionState + { + BlockIndex = 1, + Transaction = defaultTx + }; _Store.Setup(p => p.GetBlocks()).Returns(new TestDataCache()); - _Store.Setup(p => p.GetTransactions()).Returns(new TestDataCache( - new TransactionState - { - BlockIndex = 1, - Transaction = defaultTx - })); - + _Store.Setup(p => p.GetTransactions()).Returns(new TestDataCache(defaultTx.Hash, txState)); _Store.Setup(p => p.GetContracts()).Returns(new TestDataCache()); _Store.Setup(p => p.GetStorages()).Returns(new TestDataCache()); _Store.Setup(p => p.GetHeaderHashList()).Returns(new TestDataCache()); diff --git a/neo.UnitTests/TestDataCache.cs b/neo.UnitTests/TestDataCache.cs index 44d86141b5..b468e09e4c 100644 --- a/neo.UnitTests/TestDataCache.cs +++ b/neo.UnitTests/TestDataCache.cs @@ -10,43 +10,43 @@ public class TestDataCache : DataCache where TKey : IEquatable, ISerializable where TValue : class, ICloneable, ISerializable, new() { - private readonly TValue _defaultValue; + private readonly Dictionary dic = new Dictionary(); - public TestDataCache() - { - _defaultValue = null; - } + public TestDataCache() { } - public TestDataCache(TValue defaultValue) + public TestDataCache(TKey key, TValue value) { - this._defaultValue = defaultValue; + dic.Add(key, value); } public override void DeleteInternal(TKey key) { + dic.Remove(key); } protected override void AddInternal(TKey key, TValue value) { + dic.Add(key, value); } protected override IEnumerable> FindInternal(byte[] key_prefix) { - return Enumerable.Empty>(); + return dic.ToList(); } protected override TValue GetInternal(TKey key) { - if (_defaultValue == null) throw new NotImplementedException(); - return _defaultValue; + if (dic[key] == null) throw new NotImplementedException(); + return dic[key]; } protected override TValue TryGetInternal(TKey key) { - return _defaultValue; + return dic.TryGetValue(key, out TValue value) ? value : null; } protected override void UpdateInternal(TKey key, TValue value) { + dic[key] = value; } } } diff --git a/neo.UnitTests/Wallets/NEP6/UT_NEP6Wallet.cs b/neo.UnitTests/Wallets/NEP6/UT_NEP6Wallet.cs index 294afd91cd..6a8c16dbb6 100644 --- a/neo.UnitTests/Wallets/NEP6/UT_NEP6Wallet.cs +++ b/neo.UnitTests/Wallets/NEP6/UT_NEP6Wallet.cs @@ -17,10 +17,11 @@ namespace Neo.UnitTests.Wallets.NEP6 public class UT_NEP6Wallet { private NEP6Wallet uut; - private static string wPath; + private string wPath; private static KeyPair keyPair; private static string nep2key; private static UInt160 testScriptHash; + private string rootPath; public static string GetRandomPath() { @@ -48,9 +49,9 @@ private NEP6Wallet CreateWallet() private string CreateWalletFile() { - string path = GetRandomPath(); - if (!Directory.Exists(path)) Directory.CreateDirectory(path); - path = Path.Combine(path, "wallet.json"); + rootPath = GetRandomPath(); + if (!Directory.Exists(rootPath)) Directory.CreateDirectory(rootPath); + string path = Path.Combine(rootPath, "wallet.json"); File.WriteAllText(path, "{\"name\":\"name\",\"version\":\"0.0\",\"scrypt\":{\"n\":0,\"r\":0,\"p\":0},\"accounts\":[],\"extra\":{}}"); return path; } @@ -66,6 +67,7 @@ public void TestSetup() public void TestCleanUp() { if (File.Exists(wPath)) File.Delete(wPath); + if (Directory.Exists(rootPath)) Directory.Delete(rootPath); } [TestMethod] @@ -328,6 +330,7 @@ public void TestMigrate() NEP6Wallet nw = NEP6Wallet.Migrate(npath, path, "123"); bool result = nw.Contains(testScriptHash); Assert.AreEqual(true, result); + if (File.Exists(path)) File.Delete(path); } [TestMethod] diff --git a/neo/Ledger/MemoryPool.cs b/neo/Ledger/MemoryPool.cs index a6af9fc721..10ee5f9d0b 100644 --- a/neo/Ledger/MemoryPool.cs +++ b/neo/Ledger/MemoryPool.cs @@ -469,8 +469,7 @@ private int ReverifyTransactions(SortedSet verifiedSortedTxPool, /// /// Note: this must only be called from a single thread (the Blockchain actor) /// - /// Max transactions to reverify, the value passed should be >=2. If 1 is passed it - /// will still potentially use 2. + /// Max transactions to reverify, the value passed cam be >=1 /// The snapshot to use for verifying. /// true if more unsorted messages exist, otherwise false internal bool ReVerifyTopUnverifiedTransactionsIfNeeded(int maxToVerify, Snapshot snapshot)