From 4755824fece8c577874910fd69702e38ed777193 Mon Sep 17 00:00:00 2001 From: Erik Zhang Date: Tue, 24 Mar 2020 22:36:22 +0800 Subject: [PATCH] Send RelayResult to event stream (#1495) --- src/neo/Consensus/ConsensusService.cs | 2 +- src/neo/Ledger/Blockchain.cs | 76 ++++++++++--------- src/neo/Ledger/MemoryPool.cs | 2 +- .../{RelayResultReason.cs => VerifyResult.cs} | 2 +- src/neo/Network/P2P/LocalNode.cs | 2 - src/neo/Network/P2P/Payloads/Transaction.cs | 30 ++++---- tests/neo.UnitTests/Ledger/UT_Blockchain.cs | 6 +- tests/neo.UnitTests/Ledger/UT_MemoryPool.cs | 8 +- .../Ledger/UT_SendersFeeMonitor.cs | 4 +- .../Network/P2P/Payloads/UT_Transaction.cs | 2 +- 10 files changed, 70 insertions(+), 64 deletions(-) rename src/neo/Ledger/{RelayResultReason.cs => VerifyResult.cs} (84%) diff --git a/src/neo/Consensus/ConsensusService.cs b/src/neo/Consensus/ConsensusService.cs index 7276b9ea1b..9e59ba7283 100644 --- a/src/neo/Consensus/ConsensusService.cs +++ b/src/neo/Consensus/ConsensusService.cs @@ -61,7 +61,7 @@ internal ConsensusService(IActorRef localNode, IActorRef taskManager, ConsensusC private bool AddTransaction(Transaction tx, bool verify) { - if (verify && tx.Verify(context.Snapshot, context.SendersFeeMonitor.GetSenderFee(tx.Sender)) != RelayResultReason.Succeed) + if (verify && tx.Verify(context.Snapshot, context.SendersFeeMonitor.GetSenderFee(tx.Sender)) != VerifyResult.Succeed) { Log($"Invalid transaction: {tx.Hash}{Environment.NewLine}{tx.ToArray().ToHexString()}", LogLevel.Warning); RequestChangeView(ChangeViewReason.TxInvalid); diff --git a/src/neo/Ledger/Blockchain.cs b/src/neo/Ledger/Blockchain.cs index 65bba7bee0..f36784d89b 100644 --- a/src/neo/Ledger/Blockchain.cs +++ b/src/neo/Ledger/Blockchain.cs @@ -15,7 +15,6 @@ using System.Collections.Generic; using System.Linq; using System.Threading; -using System.Threading.Tasks; namespace Neo.Ledger { @@ -27,6 +26,7 @@ public class Import { public IEnumerable Blocks; public bool Verify = tru public class ImportCompleted { } public class FillMemoryPool { public IEnumerable Transactions; } public class FillCompleted { } + public class RelayResult { public IInventory Inventory; public VerifyResult Result; } public static readonly uint MillisecondsPerBlock = ProtocolSettings.Default.MillisecondsPerBlock; public const uint DecrementInterval = 2000000; @@ -279,7 +279,7 @@ private void OnFillMemoryPool(IEnumerable transactions) // 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)) != RelayResultReason.Succeed) + if (tx.Verify(currentSnapshot, MemPool.SendersFeeMonitor.GetSenderFee(tx.Sender)) != VerifyResult.Succeed) continue; // Add to the memory pool MemPool.TryAdd(tx.Hash, tx); @@ -289,26 +289,44 @@ private void OnFillMemoryPool(IEnumerable transactions) Sender.Tell(new FillCompleted()); } - private RelayResultReason OnNewBlock(Block block) + private void OnInventory(IInventory inventory, bool relay = true) + { + RelayResult rr = new RelayResult + { + Inventory = inventory, + Result = inventory switch + { + Block block => OnNewBlock(block), + Transaction transaction => OnNewTransaction(transaction), + ConsensusPayload payload => OnNewConsensus(payload), + _ => VerifyResult.Unknown + } + }; + if (relay && rr.Result == VerifyResult.Succeed) + system.LocalNode.Tell(new LocalNode.RelayDirectly { Inventory = inventory }); + Context.System.EventStream.Publish(rr); + } + + private VerifyResult OnNewBlock(Block block) { if (block.Index <= Height) - return RelayResultReason.AlreadyExists; + return VerifyResult.AlreadyExists; if (block_cache.ContainsKey(block.Hash)) - return RelayResultReason.AlreadyExists; + return VerifyResult.AlreadyExists; if (block.Index - 1 >= header_index.Count) { AddUnverifiedBlockToCache(block); - return RelayResultReason.UnableToVerify; + return VerifyResult.UnableToVerify; } if (block.Index == header_index.Count) { if (!block.Verify(currentSnapshot)) - return RelayResultReason.Invalid; + return VerifyResult.Invalid; } else { if (!block.Hash.Equals(header_index[(int)block.Index])) - return RelayResultReason.Invalid; + return VerifyResult.Invalid; } if (block.Index == Height + 1) { @@ -365,16 +383,15 @@ private RelayResultReason OnNewBlock(Block block) UpdateCurrentSnapshot(); } } - return RelayResultReason.Succeed; + return VerifyResult.Succeed; } - private RelayResultReason OnNewConsensus(ConsensusPayload payload) + private VerifyResult OnNewConsensus(ConsensusPayload payload) { - if (!payload.Verify(currentSnapshot)) return RelayResultReason.Invalid; + if (!payload.Verify(currentSnapshot)) return VerifyResult.Invalid; system.Consensus?.Tell(payload); ConsensusRelayCache.Add(payload); - system.LocalNode.Tell(new LocalNode.RelayDirectly { Inventory = payload }); - return RelayResultReason.Succeed; + return VerifyResult.Succeed; } private void OnNewHeaders(Header[] headers) @@ -398,25 +415,14 @@ private void OnNewHeaders(Header[] headers) system.TaskManager.Tell(new TaskManager.HeaderTaskCompleted(), Sender); } - private void OnNewTransaction(Transaction transaction, bool relay) + private VerifyResult OnNewTransaction(Transaction transaction) { - RelayResultReason reason; - if (ContainsTransaction(transaction.Hash)) - reason = RelayResultReason.AlreadyExists; - else if (!MemPool.CanTransactionFitInPool(transaction)) - reason = RelayResultReason.OutOfMemory; - else - reason = transaction.Verify(currentSnapshot, MemPool.SendersFeeMonitor.GetSenderFee(transaction.Sender)); - - if (reason == RelayResultReason.Succeed) - { - if (!MemPool.TryAdd(transaction.Hash, transaction)) - reason = RelayResultReason.OutOfMemory; - else if (relay) - system.LocalNode.Tell(new LocalNode.RelayDirectly { Inventory = transaction }); - } - - Sender.Tell(reason); + 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; } private void OnPersistCompleted(Block block) @@ -440,19 +446,19 @@ protected override void OnReceive(object message) OnNewHeaders(headers); break; case Block block: - Sender.Tell(OnNewBlock(block)); + OnInventory(block, false); break; case Transaction[] transactions: { // This message comes from a mempool's revalidation, already relayed - foreach (var tx in transactions) OnNewTransaction(tx, false); + foreach (var tx in transactions) OnInventory(tx, false); break; } case Transaction transaction: - OnNewTransaction(transaction, true); + OnInventory(transaction); break; case ConsensusPayload payload: - Sender.Tell(OnNewConsensus(payload)); + OnInventory(payload); break; case Idle _: if (MemPool.ReVerifyTopUnverifiedTransactionsIfNeeded(MaxTxToReverifyPerIdle, currentSnapshot)) diff --git a/src/neo/Ledger/MemoryPool.cs b/src/neo/Ledger/MemoryPool.cs index f0409b9e54..62466d65e8 100644 --- a/src/neo/Ledger/MemoryPool.cs +++ b/src/neo/Ledger/MemoryPool.cs @@ -416,7 +416,7 @@ private int ReverifyTransactions(SortedSet verifiedSortedTxPool, // Since unverifiedSortedTxPool is ordered in an ascending manner, we take from the end. foreach (PoolItem item in unverifiedSortedTxPool.Reverse().Take(count)) { - if (item.Tx.VerifyForEachBlock(snapshot, SendersFeeMonitor.GetSenderFee(item.Tx.Sender)) == RelayResultReason.Succeed) + if (item.Tx.VerifyForEachBlock(snapshot, SendersFeeMonitor.GetSenderFee(item.Tx.Sender)) == VerifyResult.Succeed) { reverifiedItems.Add(item); SendersFeeMonitor.AddSenderFee(item.Tx); diff --git a/src/neo/Ledger/RelayResultReason.cs b/src/neo/Ledger/VerifyResult.cs similarity index 84% rename from src/neo/Ledger/RelayResultReason.cs rename to src/neo/Ledger/VerifyResult.cs index 38ddfff73e..ab5c1f673e 100644 --- a/src/neo/Ledger/RelayResultReason.cs +++ b/src/neo/Ledger/VerifyResult.cs @@ -1,6 +1,6 @@ namespace Neo.Ledger { - public enum RelayResultReason : byte + public enum VerifyResult : byte { Succeed, AlreadyExists, diff --git a/src/neo/Network/P2P/LocalNode.cs b/src/neo/Network/P2P/LocalNode.cs index bdc4713bfe..ebdbca98fd 100644 --- a/src/neo/Network/P2P/LocalNode.cs +++ b/src/neo/Network/P2P/LocalNode.cs @@ -179,8 +179,6 @@ protected override void OnReceive(object message) case SendDirectly send: OnSendDirectly(send.Inventory); break; - case RelayResultReason _: - break; } } diff --git a/src/neo/Network/P2P/Payloads/Transaction.cs b/src/neo/Network/P2P/Payloads/Transaction.cs index 41bc126474..f5a17fbf11 100644 --- a/src/neo/Network/P2P/Payloads/Transaction.cs +++ b/src/neo/Network/P2P/Payloads/Transaction.cs @@ -263,38 +263,38 @@ public static Transaction FromJson(JObject json) bool IInventory.Verify(StoreView snapshot) { - return Verify(snapshot, BigInteger.Zero) == RelayResultReason.Succeed; + return Verify(snapshot, BigInteger.Zero) == VerifyResult.Succeed; } - public virtual RelayResultReason VerifyForEachBlock(StoreView snapshot, BigInteger totalSenderFeeFromPool) + public virtual VerifyResult VerifyForEachBlock(StoreView snapshot, BigInteger totalSenderFeeFromPool) { if (ValidUntilBlock <= snapshot.Height || ValidUntilBlock > snapshot.Height + MaxValidUntilBlockIncrement) - return RelayResultReason.Expired; + return VerifyResult.Expired; UInt160[] hashes = GetScriptHashesForVerifying(snapshot); if (NativeContract.Policy.GetBlockedAccounts(snapshot).Intersect(hashes).Any()) - return RelayResultReason.PolicyFail; + return VerifyResult.PolicyFail; BigInteger balance = NativeContract.GAS.BalanceOf(snapshot, Sender); BigInteger fee = SystemFee + NetworkFee + totalSenderFeeFromPool; - if (balance < fee) return RelayResultReason.InsufficientFunds; - if (hashes.Length != Witnesses.Length) return RelayResultReason.Invalid; + if (balance < fee) return VerifyResult.InsufficientFunds; + if (hashes.Length != Witnesses.Length) return VerifyResult.Invalid; for (int i = 0; i < hashes.Length; i++) { if (Witnesses[i].VerificationScript.Length > 0) continue; - if (snapshot.Contracts.TryGet(hashes[i]) is null) return RelayResultReason.Invalid; + if (snapshot.Contracts.TryGet(hashes[i]) is null) return VerifyResult.Invalid; } - return RelayResultReason.Succeed; + return VerifyResult.Succeed; } - public virtual RelayResultReason Verify(StoreView snapshot, BigInteger totalSenderFeeFromPool) + public virtual VerifyResult Verify(StoreView snapshot, BigInteger totalSenderFeeFromPool) { - RelayResultReason result = VerifyForEachBlock(snapshot, totalSenderFeeFromPool); - if (result != RelayResultReason.Succeed) return result; + VerifyResult result = VerifyForEachBlock(snapshot, totalSenderFeeFromPool); + if (result != VerifyResult.Succeed) return result; int size = Size; - if (size > MaxTransactionSize) return RelayResultReason.Invalid; + if (size > MaxTransactionSize) return VerifyResult.Invalid; long net_fee = NetworkFee - size * NativeContract.Policy.GetFeePerByte(snapshot); - if (net_fee < 0) return RelayResultReason.InsufficientFunds; - if (!this.VerifyWitnesses(snapshot, net_fee)) return RelayResultReason.Invalid; - return RelayResultReason.Succeed; + if (net_fee < 0) return VerifyResult.InsufficientFunds; + if (!this.VerifyWitnesses(snapshot, net_fee)) return VerifyResult.Invalid; + return VerifyResult.Succeed; } public StackItem ToStackItem(ReferenceCounter referenceCounter) diff --git a/tests/neo.UnitTests/Ledger/UT_Blockchain.cs b/tests/neo.UnitTests/Ledger/UT_Blockchain.cs index 622f156b16..822a9a70bb 100644 --- a/tests/neo.UnitTests/Ledger/UT_Blockchain.cs +++ b/tests/neo.UnitTests/Ledger/UT_Blockchain.cs @@ -134,11 +134,13 @@ public void TestValidTransaction() var tx = CreateValidTx(walletA, acc.ScriptHash, 0); + system.ActorSystem.EventStream.Subscribe(senderProbe, typeof(Blockchain.RelayResult)); + senderProbe.Send(system.Blockchain, tx); - senderProbe.ExpectMsg(RelayResultReason.Succeed); + senderProbe.ExpectMsg(p => p.Result == VerifyResult.Succeed); senderProbe.Send(system.Blockchain, tx); - senderProbe.ExpectMsg(RelayResultReason.AlreadyExists); + senderProbe.ExpectMsg(p => p.Result == VerifyResult.AlreadyExists); } } diff --git a/tests/neo.UnitTests/Ledger/UT_MemoryPool.cs b/tests/neo.UnitTests/Ledger/UT_MemoryPool.cs index 86ad694641..08d18ce58f 100644 --- a/tests/neo.UnitTests/Ledger/UT_MemoryPool.cs +++ b/tests/neo.UnitTests/Ledger/UT_MemoryPool.cs @@ -74,8 +74,8 @@ private Transaction CreateTransactionWithFee(long fee) var randomBytes = new byte[16]; random.NextBytes(randomBytes); Mock mock = new Mock(); - mock.Setup(p => p.VerifyForEachBlock(It.IsAny(), It.IsAny())).Returns(RelayResultReason.Succeed); - mock.Setup(p => p.Verify(It.IsAny(), It.IsAny())).Returns(RelayResultReason.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.Sender = UInt160.Zero; mock.Object.NetworkFee = fee; @@ -99,8 +99,8 @@ private Transaction CreateTransactionWithFeeAndBalanceVerify(long fee) random.NextBytes(randomBytes); Mock mock = new Mock(); UInt160 sender = UInt160.Zero; - mock.Setup(p => p.VerifyForEachBlock(It.IsAny(), It.IsAny())).Returns((StoreView snapshot, BigInteger amount) => NativeContract.GAS.BalanceOf(snapshot, sender) >= amount + fee ? RelayResultReason.Succeed : RelayResultReason.InsufficientFunds); - mock.Setup(p => p.Verify(It.IsAny(), It.IsAny())).Returns(RelayResultReason.Succeed); + mock.Setup(p => p.VerifyForEachBlock(It.IsAny(), It.IsAny())).Returns((StoreView snapshot, BigInteger amount) => NativeContract.GAS.BalanceOf(snapshot, sender) >= amount + fee ? VerifyResult.Succeed : VerifyResult.InsufficientFunds); + mock.Setup(p => p.Verify(It.IsAny(), It.IsAny())).Returns(VerifyResult.Succeed); mock.Object.Script = randomBytes; mock.Object.Sender = sender; mock.Object.NetworkFee = fee; diff --git a/tests/neo.UnitTests/Ledger/UT_SendersFeeMonitor.cs b/tests/neo.UnitTests/Ledger/UT_SendersFeeMonitor.cs index 6268fa0fde..2b0d7a349b 100644 --- a/tests/neo.UnitTests/Ledger/UT_SendersFeeMonitor.cs +++ b/tests/neo.UnitTests/Ledger/UT_SendersFeeMonitor.cs @@ -18,8 +18,8 @@ private Transaction CreateTransactionWithFee(long networkFee, long systemFee) var randomBytes = new byte[16]; random.NextBytes(randomBytes); Mock mock = new Mock(); - mock.Setup(p => p.VerifyForEachBlock(It.IsAny(), It.IsAny())).Returns(RelayResultReason.Succeed); - mock.Setup(p => p.Verify(It.IsAny(), It.IsAny())).Returns(RelayResultReason.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.Sender = UInt160.Zero; mock.Object.NetworkFee = networkFee; diff --git a/tests/neo.UnitTests/Network/P2P/Payloads/UT_Transaction.cs b/tests/neo.UnitTests/Network/P2P/Payloads/UT_Transaction.cs index 339df5605e..06ead63238 100644 --- a/tests/neo.UnitTests/Network/P2P/Payloads/UT_Transaction.cs +++ b/tests/neo.UnitTests/Network/P2P/Payloads/UT_Transaction.cs @@ -806,7 +806,7 @@ public void Transaction_Reverify_Hashes_Length_Unequal_To_Witnesses_Length() }; UInt160[] hashes = txSimple.GetScriptHashesForVerifying(snapshot); Assert.AreEqual(2, hashes.Length); - Assert.AreNotEqual(RelayResultReason.Succeed, txSimple.VerifyForEachBlock(snapshot, BigInteger.Zero)); + Assert.AreNotEqual(VerifyResult.Succeed, txSimple.VerifyForEachBlock(snapshot, BigInteger.Zero)); } [TestMethod]