diff --git a/src/neo/Consensus/ConsensusContext.cs b/src/neo/Consensus/ConsensusContext.cs index 3d3a4fcb5d..7b1cc8b3d0 100644 --- a/src/neo/Consensus/ConsensusContext.cs +++ b/src/neo/Consensus/ConsensusContext.cs @@ -40,7 +40,7 @@ internal class ConsensusContext : IDisposable, ISerializable /// /// Store all verified unsorted transactions' senders' fee currently in the consensus context. /// - public SendersFeeMonitor SendersFeeMonitor = new SendersFeeMonitor(); + public TransactionVerificationContext VerificationContext = new TransactionVerificationContext(); public SnapshotView Snapshot { get; private set; } private KeyPair keyPair; @@ -116,11 +116,11 @@ public void Deserialize(BinaryReader reader) if (TransactionHashes.Length == 0 && !RequestSentOrReceived) TransactionHashes = null; Transactions = transactions.Length == 0 && !RequestSentOrReceived ? null : transactions.ToDictionary(p => p.Hash); - SendersFeeMonitor = new SendersFeeMonitor(); + VerificationContext = new TransactionVerificationContext(); if (Transactions != null) { foreach (Transaction tx in Transactions.Values) - SendersFeeMonitor.AddSenderFee(tx); + VerificationContext.AddTransaction(tx); } } @@ -266,7 +266,7 @@ internal void EnsureMaxBlockLimitation(IEnumerable txs) txs = txs.Take((int)maxTransactionsPerBlock); List hashes = new List(); Transactions = new Dictionary(); - SendersFeeMonitor = new SendersFeeMonitor(); + VerificationContext = new TransactionVerificationContext(); // Expected block size var blockSize = GetExpectedBlockSizeWithoutTransactions(txs.Count()); @@ -285,7 +285,7 @@ internal void EnsureMaxBlockLimitation(IEnumerable txs) hashes.Add(tx.Hash); Transactions.Add(tx.Hash, tx); - SendersFeeMonitor.AddSenderFee(tx); + VerificationContext.AddTransaction(tx); } TransactionHashes = hashes.ToArray(); diff --git a/src/neo/Consensus/ConsensusService.cs b/src/neo/Consensus/ConsensusService.cs index 26648c4429..9caca4b651 100644 --- a/src/neo/Consensus/ConsensusService.cs +++ b/src/neo/Consensus/ConsensusService.cs @@ -64,20 +64,24 @@ internal ConsensusService(IActorRef localNode, IActorRef taskManager, IActorRef private bool AddTransaction(Transaction tx, bool verify) { - if (verify && tx.Verify(context.Snapshot, context.SendersFeeMonitor.GetSenderFee(tx.Sender)) != VerifyResult.Succeed) + if (verify) { - Log($"Invalid transaction: {tx.Hash}{Environment.NewLine}{tx.ToArray().ToHexString()}", LogLevel.Warning); - RequestChangeView(ChangeViewReason.TxInvalid); - return false; - } - if (!NativeContract.Policy.CheckPolicy(tx, context.Snapshot)) - { - Log($"reject tx: {tx.Hash}{Environment.NewLine}{tx.ToArray().ToHexString()}", LogLevel.Warning); - RequestChangeView(ChangeViewReason.TxRejectedByPolicy); - return false; + VerifyResult result = tx.Verify(context.Snapshot, context.VerificationContext); + if (result == VerifyResult.PolicyFail) + { + Log($"reject tx: {tx.Hash}{Environment.NewLine}{tx.ToArray().ToHexString()}", LogLevel.Warning); + RequestChangeView(ChangeViewReason.TxRejectedByPolicy); + return false; + } + else if (result != VerifyResult.Succeed) + { + Log($"Invalid transaction: {tx.Hash}{Environment.NewLine}{tx.ToArray().ToHexString()}", LogLevel.Warning); + RequestChangeView(ChangeViewReason.TxInvalid); + return false; + } } context.Transactions[tx.Hash] = tx; - context.SendersFeeMonitor.AddSenderFee(tx); + context.VerificationContext.AddTransaction(tx); return CheckPrepareResponse(); } @@ -433,7 +437,7 @@ private void OnPrepareRequestReceived(ConsensusPayload payload, PrepareRequest m context.Block.ConsensusData.Nonce = message.Nonce; context.TransactionHashes = message.TransactionHashes; context.Transactions = new Dictionary(); - context.SendersFeeMonitor = new SendersFeeMonitor(); + context.VerificationContext = new TransactionVerificationContext(); for (int i = 0; i < context.PreparationPayloads.Length; i++) if (context.PreparationPayloads[i] != null) if (!context.PreparationPayloads[i].GetDeserializedMessage().PreparationHash.Equals(payload.Hash)) diff --git a/src/neo/Ledger/Blockchain.cs b/src/neo/Ledger/Blockchain.cs index 142180932a..f4f0c6879e 100644 --- a/src/neo/Ledger/Blockchain.cs +++ b/src/neo/Ledger/Blockchain.cs @@ -290,15 +290,10 @@ private void OnFillMemoryPool(IEnumerable transactions) { if (View.ContainsTransaction(tx.Hash)) continue; - if (!NativeContract.Policy.CheckPolicy(tx, currentSnapshot)) - continue; // First remove the tx if it is unverified in the pool. MemPool.TryRemoveUnVerified(tx.Hash, out _); - // Verify the the transaction - if (tx.Verify(currentSnapshot, MemPool.SendersFeeMonitor.GetSenderFee(tx.Sender)) != VerifyResult.Succeed) - continue; // Add to the memory pool - MemPool.TryAdd(tx.Hash, tx); + MemPool.TryAdd(tx, currentSnapshot); } // Transactions originally in the pool will automatically be reverified based on their priority. @@ -362,11 +357,7 @@ private VerifyResult OnNewInventory(IInventory inventory) private VerifyResult OnNewTransaction(Transaction transaction) { if (ContainsTransaction(transaction.Hash)) return VerifyResult.AlreadyExists; - if (!MemPool.CanTransactionFitInPool(transaction)) return VerifyResult.OutOfMemory; - VerifyResult reason = transaction.Verify(currentSnapshot, MemPool.SendersFeeMonitor.GetSenderFee(transaction.Sender)); - if (reason != VerifyResult.Succeed) return reason; - if (!MemPool.TryAdd(transaction.Hash, transaction)) return VerifyResult.OutOfMemory; - return VerifyResult.Succeed; + return MemPool.TryAdd(transaction, currentSnapshot); } protected override void OnReceive(object message) diff --git a/src/neo/Ledger/MemoryPool.cs b/src/neo/Ledger/MemoryPool.cs index 62466d65e8..9a8b42b6e6 100644 --- a/src/neo/Ledger/MemoryPool.cs +++ b/src/neo/Ledger/MemoryPool.cs @@ -71,7 +71,7 @@ public class MemoryPool : IReadOnlyCollection /// /// Store all verified unsorted transactions' senders' fee currently in the memory pool. /// - public SendersFeeMonitor SendersFeeMonitor = new SendersFeeMonitor(); + private TransactionVerificationContext VerificationContext = new TransactionVerificationContext(); /// /// Total count of transactions in the pool. @@ -261,18 +261,21 @@ internal bool CanTransactionFitInPool(Transaction tx) /// /// /// - internal bool TryAdd(UInt256 hash, Transaction tx) + internal VerifyResult TryAdd(Transaction tx, StoreView snapshot) { var poolItem = new PoolItem(tx); - if (_unsortedTransactions.ContainsKey(hash)) return false; + if (_unsortedTransactions.ContainsKey(tx.Hash)) return VerifyResult.AlreadyExists; List removedTransactions = null; _txRwLock.EnterWriteLock(); try { - _unsortedTransactions.Add(hash, poolItem); - SendersFeeMonitor.AddSenderFee(tx); + VerifyResult result = tx.Verify(snapshot, VerificationContext); + if (result != VerifyResult.Succeed) return result; + + _unsortedTransactions.Add(tx.Hash, poolItem); + VerificationContext.AddTransaction(tx); _sortedTransactions.Add(poolItem); if (Count > Capacity) @@ -290,7 +293,8 @@ internal bool TryAdd(UInt256 hash, Transaction tx) plugin.TransactionsRemoved(MemoryPoolTxRemovalReason.CapacityExceeded, removedTransactions); } - return _unsortedTransactions.ContainsKey(hash); + if (!_unsortedTransactions.ContainsKey(tx.Hash)) return VerifyResult.OutOfMemory; + return VerifyResult.Succeed; } private List RemoveOverCapacity() @@ -303,6 +307,9 @@ private List RemoveOverCapacity() unsortedPool.Remove(minItem.Tx.Hash); sortedPool.Remove(minItem); removedTransactions.Add(minItem.Tx); + + if (ReferenceEquals(sortedPool, _sortedTransactions)) + VerificationContext.RemoveTransaction(minItem.Tx); } while (Count > Capacity); return removedTransactions; @@ -315,7 +322,6 @@ private bool TryRemoveVerified(UInt256 hash, out PoolItem item) return false; _unsortedTransactions.Remove(hash); - SendersFeeMonitor.RemoveSenderFee(item.Tx); _sortedTransactions.Remove(item); return true; @@ -343,7 +349,7 @@ internal void InvalidateVerifiedTransactions() // Clear the verified transactions now, since they all must be reverified. _unsortedTransactions.Clear(); - SendersFeeMonitor = new SendersFeeMonitor(); + VerificationContext = new TransactionVerificationContext(); _sortedTransactions.Clear(); } @@ -413,23 +419,23 @@ private int ReverifyTransactions(SortedSet verifiedSortedTxPool, List reverifiedItems = new List(count); List invalidItems = new List(); - // Since unverifiedSortedTxPool is ordered in an ascending manner, we take from the end. - foreach (PoolItem item in unverifiedSortedTxPool.Reverse().Take(count)) + _txRwLock.EnterWriteLock(); + try { - if (item.Tx.VerifyForEachBlock(snapshot, SendersFeeMonitor.GetSenderFee(item.Tx.Sender)) == VerifyResult.Succeed) + // Since unverifiedSortedTxPool is ordered in an ascending manner, we take from the end. + foreach (PoolItem item in unverifiedSortedTxPool.Reverse().Take(count)) { - reverifiedItems.Add(item); - SendersFeeMonitor.AddSenderFee(item.Tx); - } - else // Transaction no longer valid -- it will be removed from unverifiedTxPool. - invalidItems.Add(item); + if (item.Tx.VerifyForEachBlock(snapshot, VerificationContext) == VerifyResult.Succeed) + { + reverifiedItems.Add(item); + VerificationContext.AddTransaction(item.Tx); + } + else // Transaction no longer valid -- it will be removed from unverifiedTxPool. + invalidItems.Add(item); - if (DateTime.UtcNow > reverifyCutOffTimeStamp) break; - } + if (DateTime.UtcNow > reverifyCutOffTimeStamp) break; + } - _txRwLock.EnterWriteLock(); - try - { int blocksTillRebroadcast = BlocksTillRebroadcast; // Increases, proportionally, blocksTillRebroadcast if mempool has more items than threshold bigger RebroadcastMultiplierThreshold if (Count > RebroadcastMultiplierThreshold) @@ -450,7 +456,7 @@ private int ReverifyTransactions(SortedSet verifiedSortedTxPool, } } else - SendersFeeMonitor.RemoveSenderFee(item.Tx); + VerificationContext.RemoveTransaction(item.Tx); _unverifiedTransactions.Remove(item.Tx.Hash); unverifiedSortedTxPool.Remove(item); diff --git a/src/neo/Ledger/SendersFeeMonitor.cs b/src/neo/Ledger/SendersFeeMonitor.cs deleted file mode 100644 index efe3ac6ebe..0000000000 --- a/src/neo/Ledger/SendersFeeMonitor.cs +++ /dev/null @@ -1,43 +0,0 @@ -using Neo.Network.P2P.Payloads; -using System.Collections.Generic; -using System.Numerics; -using System.Threading; - -namespace Neo.Ledger -{ - public class SendersFeeMonitor - { - private readonly ReaderWriterLockSlim _senderFeeRwLock = new ReaderWriterLockSlim(LockRecursionPolicy.SupportsRecursion); - - /// - /// Store all verified unsorted transactions' senders' fee currently in the memory pool. - /// - private readonly Dictionary _senderFee = new Dictionary(); - - public BigInteger GetSenderFee(UInt160 sender) - { - _senderFeeRwLock.EnterReadLock(); - if (!_senderFee.TryGetValue(sender, out var value)) - value = BigInteger.Zero; - _senderFeeRwLock.ExitReadLock(); - return value; - } - - public void AddSenderFee(Transaction tx) - { - _senderFeeRwLock.EnterWriteLock(); - if (_senderFee.TryGetValue(tx.Sender, out var value)) - _senderFee[tx.Sender] = value + tx.SystemFee + tx.NetworkFee; - else - _senderFee.Add(tx.Sender, tx.SystemFee + tx.NetworkFee); - _senderFeeRwLock.ExitWriteLock(); - } - - public void RemoveSenderFee(Transaction tx) - { - _senderFeeRwLock.EnterWriteLock(); - if ((_senderFee[tx.Sender] -= tx.SystemFee + tx.NetworkFee) == 0) _senderFee.Remove(tx.Sender); - _senderFeeRwLock.ExitWriteLock(); - } - } -} diff --git a/src/neo/Ledger/TransactionVerificationContext.cs b/src/neo/Ledger/TransactionVerificationContext.cs new file mode 100644 index 0000000000..a2bae45b0b --- /dev/null +++ b/src/neo/Ledger/TransactionVerificationContext.cs @@ -0,0 +1,37 @@ +using Neo.Network.P2P.Payloads; +using Neo.Persistence; +using Neo.SmartContract.Native; +using System.Collections.Generic; +using System.Numerics; + +namespace Neo.Ledger +{ + public class TransactionVerificationContext + { + /// + /// Store all verified unsorted transactions' senders' fee currently in the memory pool. + /// + private readonly Dictionary senderFee = new Dictionary(); + + public void AddTransaction(Transaction tx) + { + if (senderFee.TryGetValue(tx.Sender, out var value)) + senderFee[tx.Sender] = value + tx.SystemFee + tx.NetworkFee; + else + senderFee.Add(tx.Sender, tx.SystemFee + tx.NetworkFee); + } + + public bool CheckTransaction(Transaction tx, StoreView snapshot) + { + BigInteger balance = NativeContract.GAS.BalanceOf(snapshot, tx.Sender); + senderFee.TryGetValue(tx.Sender, out var totalSenderFeeFromPool); + BigInteger fee = tx.SystemFee + tx.NetworkFee + totalSenderFeeFromPool; + return balance >= fee; + } + + public void RemoveTransaction(Transaction tx) + { + if ((senderFee[tx.Sender] -= tx.SystemFee + tx.NetworkFee) == 0) senderFee.Remove(tx.Sender); + } + } +} diff --git a/src/neo/Network/P2P/Payloads/Transaction.cs b/src/neo/Network/P2P/Payloads/Transaction.cs index 5aab07af65..8c4071379c 100644 --- a/src/neo/Network/P2P/Payloads/Transaction.cs +++ b/src/neo/Network/P2P/Payloads/Transaction.cs @@ -12,7 +12,6 @@ using System.Collections.Generic; using System.IO; using System.Linq; -using System.Numerics; using Array = Neo.VM.Types.Array; namespace Neo.Network.P2P.Payloads @@ -268,10 +267,10 @@ public JObject ToJson() bool IInventory.Verify(StoreView snapshot) { - return Verify(snapshot, BigInteger.Zero) == VerifyResult.Succeed; + return Verify(snapshot, null) == VerifyResult.Succeed; } - public virtual VerifyResult VerifyForEachBlock(StoreView snapshot, BigInteger totalSenderFeeFromPool) + public virtual VerifyResult VerifyForEachBlock(StoreView snapshot, TransactionVerificationContext context) { if (ValidUntilBlock <= snapshot.Height || ValidUntilBlock > snapshot.Height + MaxValidUntilBlockIncrement) return VerifyResult.Expired; @@ -280,9 +279,7 @@ public virtual VerifyResult VerifyForEachBlock(StoreView snapshot, BigInteger to return VerifyResult.PolicyFail; if (NativeContract.Policy.GetMaxBlockSystemFee(snapshot) < SystemFee) return VerifyResult.PolicyFail; - BigInteger balance = NativeContract.GAS.BalanceOf(snapshot, Sender); - BigInteger fee = SystemFee + NetworkFee + totalSenderFeeFromPool; - if (balance < fee) return VerifyResult.InsufficientFunds; + if (!(context?.CheckTransaction(this, snapshot) ?? true)) return VerifyResult.InsufficientFunds; if (hashes.Length != Witnesses.Length) return VerifyResult.Invalid; for (int i = 0; i < hashes.Length; i++) { @@ -292,9 +289,9 @@ public virtual VerifyResult VerifyForEachBlock(StoreView snapshot, BigInteger to return VerifyResult.Succeed; } - public virtual VerifyResult Verify(StoreView snapshot, BigInteger totalSenderFeeFromPool) + public virtual VerifyResult Verify(StoreView snapshot, TransactionVerificationContext context) { - VerifyResult result = VerifyForEachBlock(snapshot, totalSenderFeeFromPool); + VerifyResult result = VerifyForEachBlock(snapshot, context); if (result != VerifyResult.Succeed) return result; int size = Size; if (size > MaxTransactionSize) return VerifyResult.Invalid; diff --git a/src/neo/SmartContract/Native/PolicyContract.cs b/src/neo/SmartContract/Native/PolicyContract.cs index 6fd173b409..65c690424e 100644 --- a/src/neo/SmartContract/Native/PolicyContract.cs +++ b/src/neo/SmartContract/Native/PolicyContract.cs @@ -2,12 +2,10 @@ using Neo.IO; using Neo.Ledger; -using Neo.Network.P2P.Payloads; using Neo.Persistence; using Neo.SmartContract.Manifest; using System; using System.Collections.Generic; -using System.Linq; namespace Neo.SmartContract.Native { @@ -27,14 +25,6 @@ public PolicyContract() Manifest.Features = ContractFeatures.HasStorage; } - internal bool CheckPolicy(Transaction tx, StoreView snapshot) - { - UInt160[] blockedAccounts = GetBlockedAccounts(snapshot); - if (blockedAccounts.Intersect(tx.GetScriptHashesForVerifying(snapshot)).Any()) - return false; - return true; - } - private bool CheckCommittees(ApplicationEngine engine) { UInt160 committeeMultiSigAddr = NEO.GetCommitteeAddress(engine.Snapshot); diff --git a/tests/neo.UnitTests/Ledger/UT_Blockchain.cs b/tests/neo.UnitTests/Ledger/UT_Blockchain.cs index a94bd98984..e4bf204d47 100644 --- a/tests/neo.UnitTests/Ledger/UT_Blockchain.cs +++ b/tests/neo.UnitTests/Ledger/UT_Blockchain.cs @@ -54,7 +54,7 @@ public class UT_Blockchain : TestKit public void Initialize() { system = TestBlockchain.TheNeoSystem; - Blockchain.Singleton.MemPool.TryAdd(txSample.Hash, txSample); + Blockchain.Singleton.MemPool.TryAdd(txSample, Blockchain.Singleton.GetSnapshot()); } [TestMethod] diff --git a/tests/neo.UnitTests/Ledger/UT_MemoryPool.cs b/tests/neo.UnitTests/Ledger/UT_MemoryPool.cs index e2bb92836e..106e60adc5 100644 --- a/tests/neo.UnitTests/Ledger/UT_MemoryPool.cs +++ b/tests/neo.UnitTests/Ledger/UT_MemoryPool.cs @@ -27,12 +27,20 @@ public void TransactionsRemoved(MemoryPoolTxRemovalReason reason, IEnumerable mock = new Mock(); - mock.Setup(p => p.VerifyForEachBlock(It.IsAny(), It.IsAny())).Returns(VerifyResult.Succeed); - mock.Setup(p => p.Verify(It.IsAny(), It.IsAny())).Returns(VerifyResult.Succeed); + mock.Setup(p => p.VerifyForEachBlock(It.IsAny(), It.IsAny())).Returns(VerifyResult.Succeed); + mock.Setup(p => p.Verify(It.IsAny(), It.IsAny())).Returns(VerifyResult.Succeed); mock.Object.Script = randomBytes; mock.Object.NetworkFee = fee; mock.Object.Attributes = Array.Empty(); @@ -97,9 +105,8 @@ private Transaction CreateTransactionWithFeeAndBalanceVerify(long fee) var randomBytes = new byte[16]; random.NextBytes(randomBytes); Mock mock = new Mock(); - mock.Setup(p => p.VerifyForEachBlock(It.IsAny(), It.IsAny())).Returns((StoreView snapshot, BigInteger amount) => - NativeContract.GAS.BalanceOf(snapshot, UInt160.Zero) >= amount + fee ? VerifyResult.Succeed : VerifyResult.InsufficientFunds); - mock.Setup(p => p.Verify(It.IsAny(), It.IsAny())).Returns(VerifyResult.Succeed); + mock.Setup(p => p.VerifyForEachBlock(It.IsAny(), It.IsAny())).Returns((StoreView snapshot, TransactionVerificationContext context) => context.CheckTransaction(mock.Object, snapshot) ? VerifyResult.Succeed : VerifyResult.InsufficientFunds); + mock.Setup(p => p.Verify(It.IsAny(), It.IsAny())).Returns(VerifyResult.Succeed); mock.Object.Script = randomBytes; mock.Object.NetworkFee = fee; mock.Object.Attributes = Array.Empty(); @@ -124,10 +131,11 @@ private Transaction CreateTransaction(long fee = -1) private void AddTransactions(int count) { + var snapshot = Blockchain.Singleton.GetSnapshot(); for (int i = 0; i < count; i++) { var txToAdd = CreateTransaction(); - _unit.TryAdd(txToAdd.Hash, txToAdd); + _unit.TryAdd(txToAdd, snapshot); } Console.WriteLine($"created {count} tx"); @@ -135,15 +143,17 @@ private void AddTransactions(int count) private void AddTransaction(Transaction txToAdd) { - _unit.TryAdd(txToAdd.Hash, txToAdd); + var snapshot = Blockchain.Singleton.GetSnapshot(); + _unit.TryAdd(txToAdd, snapshot); } private void AddTransactionsWithBalanceVerify(int count, long fee) { + var snapshot = Blockchain.Singleton.GetSnapshot(); for (int i = 0; i < count; i++) { var txToAdd = CreateTransactionWithFeeAndBalanceVerify(fee); - _unit.TryAdd(txToAdd.Hash, txToAdd); + _unit.TryAdd(txToAdd, snapshot); } Console.WriteLine($"created {count} tx"); @@ -355,10 +365,11 @@ public void TestInvalidateAll() [TestMethod] public void TestContainsKey() { + var snapshot = Blockchain.Singleton.GetSnapshot(); AddTransactions(10); var txToAdd = CreateTransaction(); - _unit.TryAdd(txToAdd.Hash, txToAdd); + _unit.TryAdd(txToAdd, snapshot); _unit.ContainsKey(txToAdd.Hash).Should().BeTrue(); _unit.InvalidateVerifiedTransactions(); _unit.ContainsKey(txToAdd.Hash).Should().BeTrue(); @@ -394,11 +405,12 @@ public void TestIEnumerableGetEnumerator() [TestMethod] public void TestGetVerifiedTransactions() { + var snapshot = Blockchain.Singleton.GetSnapshot(); var tx1 = CreateTransaction(); var tx2 = CreateTransaction(); - _unit.TryAdd(tx1.Hash, tx1); + _unit.TryAdd(tx1, snapshot); _unit.InvalidateVerifiedTransactions(); - _unit.TryAdd(tx2.Hash, tx2); + _unit.TryAdd(tx2, snapshot); IEnumerable enumerable = _unit.GetVerifiedTransactions(); enumerable.Count().Should().Be(1); var enumerator = enumerable.GetEnumerator(); @@ -445,17 +457,19 @@ public void TestReVerifyTopUnverifiedTransactionsIfNeeded() [TestMethod] public void TestTryAdd() { + var snapshot = Blockchain.Singleton.GetSnapshot(); var tx1 = CreateTransaction(); - _unit.TryAdd(tx1.Hash, tx1).Should().BeTrue(); - _unit.TryAdd(tx1.Hash, tx1).Should().BeFalse(); - _unit2.TryAdd(tx1.Hash, tx1).Should().BeFalse(); + _unit.TryAdd(tx1, snapshot).Should().Be(VerifyResult.Succeed); + _unit.TryAdd(tx1, snapshot).Should().NotBe(VerifyResult.Succeed); + _unit2.TryAdd(tx1, snapshot).Should().NotBe(VerifyResult.Succeed); } [TestMethod] public void TestTryGetValue() { + var snapshot = Blockchain.Singleton.GetSnapshot(); var tx1 = CreateTransaction(); - _unit.TryAdd(tx1.Hash, tx1); + _unit.TryAdd(tx1, snapshot); _unit.TryGetValue(tx1.Hash, out Transaction tx).Should().BeTrue(); tx.Should().BeEquivalentTo(tx1); @@ -491,7 +505,7 @@ public void TestUpdatePoolForBlockPersisted() var tx1 = CreateTransaction(); var tx2 = CreateTransaction(); Transaction[] transactions = { tx1, tx2 }; - _unit.TryAdd(tx1.Hash, tx1); + _unit.TryAdd(tx1, snapshot); var block = new Block { Transactions = transactions }; diff --git a/tests/neo.UnitTests/Ledger/UT_SendersFeeMonitor.cs b/tests/neo.UnitTests/Ledger/UT_SendersFeeMonitor.cs deleted file mode 100644 index 4c9e2fa333..0000000000 --- a/tests/neo.UnitTests/Ledger/UT_SendersFeeMonitor.cs +++ /dev/null @@ -1,55 +0,0 @@ -using FluentAssertions; -using Microsoft.VisualStudio.TestTools.UnitTesting; -using Moq; -using Neo.Ledger; -using Neo.Network.P2P.Payloads; -using Neo.Persistence; -using System; -using System.Numerics; - -namespace Neo.UnitTests.Ledger -{ - [TestClass] - public class UT_SendersFeeMonitor - { - private Transaction CreateTransactionWithFee(long networkFee, long systemFee) - { - Random random = new Random(); - var randomBytes = new byte[16]; - random.NextBytes(randomBytes); - Mock mock = new Mock(); - mock.Setup(p => p.VerifyForEachBlock(It.IsAny(), It.IsAny())).Returns(VerifyResult.Succeed); - mock.Setup(p => p.Verify(It.IsAny(), It.IsAny())).Returns(VerifyResult.Succeed); - mock.Object.Script = randomBytes; - mock.Object.NetworkFee = networkFee; - mock.Object.SystemFee = systemFee; - mock.Object.Attributes = Array.Empty(); - mock.Object.Signers = new Signer[] { new Signer() { Account = UInt160.Zero, Scopes = WitnessScope.FeeOnly } }; - mock.Object.Witnesses = new[] - { - new Witness - { - InvocationScript = new byte[0], - VerificationScript = new byte[0] - } - }; - return mock.Object; - } - - [TestMethod] - public void TestMemPoolSenderFee() - { - Transaction transaction = CreateTransactionWithFee(1, 2); - SendersFeeMonitor sendersFeeMonitor = new SendersFeeMonitor(); - sendersFeeMonitor.GetSenderFee(transaction.Sender).Should().Be(0); - sendersFeeMonitor.AddSenderFee(transaction); - sendersFeeMonitor.GetSenderFee(transaction.Sender).Should().Be(3); - sendersFeeMonitor.AddSenderFee(transaction); - sendersFeeMonitor.GetSenderFee(transaction.Sender).Should().Be(6); - sendersFeeMonitor.RemoveSenderFee(transaction); - sendersFeeMonitor.GetSenderFee(transaction.Sender).Should().Be(3); - sendersFeeMonitor.RemoveSenderFee(transaction); - sendersFeeMonitor.GetSenderFee(transaction.Sender).Should().Be(0); - } - } -} diff --git a/tests/neo.UnitTests/Ledger/UT_TransactionVerificationContext.cs b/tests/neo.UnitTests/Ledger/UT_TransactionVerificationContext.cs new file mode 100644 index 0000000000..a3636a4c91 --- /dev/null +++ b/tests/neo.UnitTests/Ledger/UT_TransactionVerificationContext.cs @@ -0,0 +1,71 @@ +using FluentAssertions; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Moq; +using Neo.Ledger; +using Neo.Network.P2P.Payloads; +using Neo.Persistence; +using Neo.SmartContract; +using Neo.SmartContract.Native; +using System; +using System.Numerics; + +namespace Neo.UnitTests.Ledger +{ + [TestClass] + public class UT_TransactionVerificationContext + { + private static NeoSystem testBlockchain; + + [ClassInitialize] + public static void TestSetup(TestContext ctx) + { + testBlockchain = TestBlockchain.TheNeoSystem; + } + + private Transaction CreateTransactionWithFee(long networkFee, long systemFee) + { + Random random = new Random(); + var randomBytes = new byte[16]; + random.NextBytes(randomBytes); + Mock mock = new Mock(); + mock.Setup(p => p.VerifyForEachBlock(It.IsAny(), It.IsAny())).Returns(VerifyResult.Succeed); + mock.Setup(p => p.Verify(It.IsAny(), It.IsAny())).Returns(VerifyResult.Succeed); + mock.Object.Script = randomBytes; + mock.Object.NetworkFee = networkFee; + mock.Object.SystemFee = systemFee; + mock.Object.Signers = new[] { new Signer { Account = UInt160.Zero } }; + mock.Object.Attributes = Array.Empty(); + mock.Object.Witnesses = new[] + { + new Witness + { + InvocationScript = new byte[0], + VerificationScript = new byte[0] + } + }; + return mock.Object; + } + + [TestMethod] + public void TestTransactionSenderFee() + { + var snapshot = Blockchain.Singleton.GetSnapshot(); + ApplicationEngine engine = ApplicationEngine.Create(TriggerType.Application, null, snapshot, long.MaxValue); + BigInteger balance = NativeContract.GAS.BalanceOf(snapshot, UInt160.Zero); + NativeContract.GAS.Burn(engine, UInt160.Zero, balance); + NativeContract.GAS.Mint(engine, UInt160.Zero, 8); + + TransactionVerificationContext verificationContext = new TransactionVerificationContext(); + var tx = CreateTransactionWithFee(1, 2); + verificationContext.CheckTransaction(tx, snapshot).Should().BeTrue(); + verificationContext.AddTransaction(tx); + verificationContext.CheckTransaction(tx, snapshot).Should().BeTrue(); + verificationContext.AddTransaction(tx); + verificationContext.CheckTransaction(tx, snapshot).Should().BeFalse(); + verificationContext.RemoveTransaction(tx); + verificationContext.CheckTransaction(tx, snapshot).Should().BeTrue(); + verificationContext.AddTransaction(tx); + verificationContext.CheckTransaction(tx, snapshot).Should().BeFalse(); + } + } +} diff --git a/tests/neo.UnitTests/Network/P2P/Payloads/UT_Transaction.cs b/tests/neo.UnitTests/Network/P2P/Payloads/UT_Transaction.cs index de5079a46d..e6f7c3414a 100644 --- a/tests/neo.UnitTests/Network/P2P/Payloads/UT_Transaction.cs +++ b/tests/neo.UnitTests/Network/P2P/Payloads/UT_Transaction.cs @@ -754,7 +754,7 @@ public void Transaction_Reverify_Hashes_Length_Unequal_To_Witnesses_Length() }; UInt160[] hashes = txSimple.GetScriptHashesForVerifying(snapshot); Assert.AreEqual(1, hashes.Length); - Assert.AreNotEqual(VerifyResult.Succeed, txSimple.VerifyForEachBlock(snapshot, BigInteger.Zero)); + Assert.AreNotEqual(VerifyResult.Succeed, txSimple.VerifyForEachBlock(snapshot, new TransactionVerificationContext())); } [TestMethod] diff --git a/tests/neo.UnitTests/SmartContract/Native/UT_PolicyContract.cs b/tests/neo.UnitTests/SmartContract/Native/UT_PolicyContract.cs index d464f45ea8..8eba15bf5c 100644 --- a/tests/neo.UnitTests/SmartContract/Native/UT_PolicyContract.cs +++ b/tests/neo.UnitTests/SmartContract/Native/UT_PolicyContract.cs @@ -276,28 +276,5 @@ public void Check_Block_UnblockAccount() ret.Should().BeOfType(); ((VM.Types.Array)ret).Count.Should().Be(0); } - - [TestMethod] - public void TestCheckPolicy() - { - Transaction tx = Blockchain.GenesisBlock.Transactions[0]; - var snapshot = Blockchain.Singleton.GetSnapshot(); - - StorageKey storageKey = new StorageKey - { - Id = NativeContract.Policy.Id, - Key = new byte[sizeof(byte)] - }; - storageKey.Key[0] = 15; - snapshot.Storages.Add(storageKey, new StorageItem - { - Value = new UInt160[] { tx.Sender }.ToByteArray(), - }); - - NativeContract.Policy.CheckPolicy(tx, snapshot).Should().BeFalse(); - - snapshot = Blockchain.Singleton.GetSnapshot(); - NativeContract.Policy.CheckPolicy(tx, snapshot).Should().BeTrue(); - } } }