From b14a589960c7bcb23ef99d9f54deaea08245f6de Mon Sep 17 00:00:00 2001 From: Jin Qiao Date: Fri, 20 Mar 2020 13:52:55 +0800 Subject: [PATCH 01/55] Relocate transaction verifcation --- src/neo/Ledger/Blockchain.cs | 7 ++----- src/neo/Network/P2P/ProtocolHandler.cs | 9 ++++++++- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/src/neo/Ledger/Blockchain.cs b/src/neo/Ledger/Blockchain.cs index 65bba7bee0..22192dba08 100644 --- a/src/neo/Ledger/Blockchain.cs +++ b/src/neo/Ledger/Blockchain.cs @@ -63,7 +63,7 @@ public class FillCompleted { } private readonly Dictionary block_cache = new Dictionary(); private readonly Dictionary> block_cache_unverified = new Dictionary>(); internal readonly RelayCache ConsensusRelayCache = new RelayCache(100); - private SnapshotView currentSnapshot; + public SnapshotView currentSnapshot; public IStore Store { get; } public ReadOnlyView View { get; } @@ -400,14 +400,11 @@ private void OnNewHeaders(Header[] headers) private void OnNewTransaction(Transaction transaction, bool relay) { - RelayResultReason reason; + RelayResultReason reason = RelayResultReason.Succeed; 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)) diff --git a/src/neo/Network/P2P/ProtocolHandler.cs b/src/neo/Network/P2P/ProtocolHandler.cs index a97cb46922..0a7972419f 100644 --- a/src/neo/Network/P2P/ProtocolHandler.cs +++ b/src/neo/Network/P2P/ProtocolHandler.cs @@ -135,7 +135,14 @@ private void OnMessage(Message msg) break; case MessageCommand.Transaction: if (msg.Payload.Size <= Transaction.MaxTransactionSize) - OnInventoryReceived((Transaction)msg.Payload); + { + Transaction tx = (Transaction)msg.Payload; + if (tx.Verify(Blockchain.Singleton.currentSnapshot, Blockchain.Singleton.MemPool.SendersFeeMonitor.GetSenderFee(tx.Sender)) != RelayResultReason.Succeed) + { + return; + } + OnInventoryReceived(tx); + } break; case MessageCommand.Verack: case MessageCommand.Version: From 9f2f7c6edc7eeb795d76b26bd45ab18c22fbba6b Mon Sep 17 00:00:00 2001 From: Jin Qiao Date: Wed, 25 Mar 2020 10:57:08 +0800 Subject: [PATCH 02/55] Code optimization --- src/neo/Network/P2P/ProtocolHandler.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/neo/Network/P2P/ProtocolHandler.cs b/src/neo/Network/P2P/ProtocolHandler.cs index 0a7972419f..72d1a4df49 100644 --- a/src/neo/Network/P2P/ProtocolHandler.cs +++ b/src/neo/Network/P2P/ProtocolHandler.cs @@ -137,7 +137,7 @@ private void OnMessage(Message msg) if (msg.Payload.Size <= Transaction.MaxTransactionSize) { Transaction tx = (Transaction)msg.Payload; - if (tx.Verify(Blockchain.Singleton.currentSnapshot, Blockchain.Singleton.MemPool.SendersFeeMonitor.GetSenderFee(tx.Sender)) != RelayResultReason.Succeed) + if (tx.Verify(Blockchain.Singleton.currentSnapshot, Blockchain.Singleton.MemPool.SendersFeeMonitor.GetSenderFee(tx.Sender)) != VerifyResult.Succeed) { return; } From fcaf7e4872b99ff0d601561ecfbadd3fb7ed103a Mon Sep 17 00:00:00 2001 From: Jin Qiao Date: Mon, 30 Mar 2020 14:54:41 +0800 Subject: [PATCH 03/55] Seperate sender fee check from transaction verification --- src/neo/Consensus/ConsensusService.cs | 3 ++- src/neo/Ledger/Blockchain.cs | 6 +++++- src/neo/Ledger/MemoryPool.cs | 3 ++- src/neo/Network/P2P/Payloads/Transaction.cs | 20 ++++++++++++------- src/neo/Network/P2P/ProtocolHandler.cs | 2 +- tests/neo.UnitTests/Ledger/UT_MemoryPool.cs | 10 ++++++---- .../Ledger/UT_SendersFeeMonitor.cs | 5 +++-- .../Network/P2P/Payloads/UT_Transaction.cs | 3 ++- 8 files changed, 34 insertions(+), 18 deletions(-) diff --git a/src/neo/Consensus/ConsensusService.cs b/src/neo/Consensus/ConsensusService.cs index 9e59ba7283..9083f80148 100644 --- a/src/neo/Consensus/ConsensusService.cs +++ b/src/neo/Consensus/ConsensusService.cs @@ -61,7 +61,8 @@ 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)) != VerifyResult.Succeed) + if (verify && tx.VerifySenderFeeFromPool(context.Snapshot, context.SendersFeeMonitor.GetSenderFee(tx.Sender)) != VerifyResult.Succeed + && tx.Verify(context.Snapshot) != 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 fa25b83753..c63c140e83 100644 --- a/src/neo/Ledger/Blockchain.cs +++ b/src/neo/Ledger/Blockchain.cs @@ -279,7 +279,9 @@ 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)) != VerifyResult.Succeed) + if (tx.VerifySenderFeeFromPool(currentSnapshot, MemPool.SendersFeeMonitor.GetSenderFee(tx.Sender)) != VerifyResult.Succeed) + continue; + if (tx.Verify(currentSnapshot) != VerifyResult.Succeed) continue; // Add to the memory pool MemPool.TryAdd(tx.Hash, tx); @@ -419,6 +421,8 @@ private VerifyResult OnNewTransaction(Transaction transaction) { if (ContainsTransaction(transaction.Hash)) return VerifyResult.AlreadyExists; if (!MemPool.CanTransactionFitInPool(transaction)) return VerifyResult.OutOfMemory; + VerifyResult reason = transaction.VerifySenderFeeFromPool(currentSnapshot, MemPool.SendersFeeMonitor.GetSenderFee(transaction.Sender)); + if (reason != VerifyResult.Succeed) return reason; if (!MemPool.TryAdd(transaction.Hash, transaction)) return VerifyResult.OutOfMemory; return VerifyResult.Succeed; } diff --git a/src/neo/Ledger/MemoryPool.cs b/src/neo/Ledger/MemoryPool.cs index 62466d65e8..3913bb9ac3 100644 --- a/src/neo/Ledger/MemoryPool.cs +++ b/src/neo/Ledger/MemoryPool.cs @@ -416,7 +416,8 @@ 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)) == VerifyResult.Succeed) + if (item.Tx.VerifySenderFeeFromPool(snapshot, SendersFeeMonitor.GetSenderFee(item.Tx.Sender)) == VerifyResult.Succeed + && item.Tx.VerifyForEachBlock(snapshot) == VerifyResult.Succeed) { reverifiedItems.Add(item); SendersFeeMonitor.AddSenderFee(item.Tx); diff --git a/src/neo/Network/P2P/Payloads/Transaction.cs b/src/neo/Network/P2P/Payloads/Transaction.cs index f5a17fbf11..799f255bfc 100644 --- a/src/neo/Network/P2P/Payloads/Transaction.cs +++ b/src/neo/Network/P2P/Payloads/Transaction.cs @@ -263,19 +263,25 @@ public static Transaction FromJson(JObject json) bool IInventory.Verify(StoreView snapshot) { - return Verify(snapshot, BigInteger.Zero) == VerifyResult.Succeed; + return VerifySenderFeeFromPool(snapshot, BigInteger.Zero) == VerifyResult.Succeed + && Verify(snapshot) == VerifyResult.Succeed; } - public virtual VerifyResult VerifyForEachBlock(StoreView snapshot, BigInteger totalSenderFeeFromPool) + public virtual VerifyResult VerifySenderFeeFromPool (StoreView snapshot, BigInteger totalSenderFeeFromPool) + { + BigInteger balance = NativeContract.GAS.BalanceOf(snapshot, Sender); + BigInteger fee = SystemFee + NetworkFee + totalSenderFeeFromPool; + if (balance < fee) return VerifyResult.InsufficientFunds; + else return VerifyResult.Succeed; + } + + public virtual VerifyResult VerifyForEachBlock(StoreView snapshot) { if (ValidUntilBlock <= snapshot.Height || ValidUntilBlock > snapshot.Height + MaxValidUntilBlockIncrement) return VerifyResult.Expired; UInt160[] hashes = GetScriptHashesForVerifying(snapshot); if (NativeContract.Policy.GetBlockedAccounts(snapshot).Intersect(hashes).Any()) return VerifyResult.PolicyFail; - BigInteger balance = NativeContract.GAS.BalanceOf(snapshot, Sender); - BigInteger fee = SystemFee + NetworkFee + totalSenderFeeFromPool; - if (balance < fee) return VerifyResult.InsufficientFunds; if (hashes.Length != Witnesses.Length) return VerifyResult.Invalid; for (int i = 0; i < hashes.Length; i++) { @@ -285,9 +291,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) { - VerifyResult result = VerifyForEachBlock(snapshot, totalSenderFeeFromPool); + VerifyResult result = VerifyForEachBlock(snapshot); if (result != VerifyResult.Succeed) return result; int size = Size; if (size > MaxTransactionSize) return VerifyResult.Invalid; diff --git a/src/neo/Network/P2P/ProtocolHandler.cs b/src/neo/Network/P2P/ProtocolHandler.cs index 72d1a4df49..96d294d52e 100644 --- a/src/neo/Network/P2P/ProtocolHandler.cs +++ b/src/neo/Network/P2P/ProtocolHandler.cs @@ -137,7 +137,7 @@ private void OnMessage(Message msg) if (msg.Payload.Size <= Transaction.MaxTransactionSize) { Transaction tx = (Transaction)msg.Payload; - if (tx.Verify(Blockchain.Singleton.currentSnapshot, Blockchain.Singleton.MemPool.SendersFeeMonitor.GetSenderFee(tx.Sender)) != VerifyResult.Succeed) + if (tx.Verify(Blockchain.Singleton.currentSnapshot) != VerifyResult.Succeed) { return; } diff --git a/tests/neo.UnitTests/Ledger/UT_MemoryPool.cs b/tests/neo.UnitTests/Ledger/UT_MemoryPool.cs index 08d18ce58f..eea2a37a86 100644 --- a/tests/neo.UnitTests/Ledger/UT_MemoryPool.cs +++ b/tests/neo.UnitTests/Ledger/UT_MemoryPool.cs @@ -74,8 +74,9 @@ 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(VerifyResult.Succeed); - mock.Setup(p => p.Verify(It.IsAny(), It.IsAny())).Returns(VerifyResult.Succeed); + mock.Setup(p => p.VerifySenderFeeFromPool(It.IsAny(), It.IsAny())).Returns(VerifyResult.Succeed); + mock.Setup(p => p.VerifyForEachBlock(It.IsAny())).Returns(VerifyResult.Succeed); + mock.Setup(p => p.Verify(It.IsAny())).Returns(VerifyResult.Succeed); mock.Object.Script = randomBytes; mock.Object.Sender = UInt160.Zero; mock.Object.NetworkFee = fee; @@ -99,8 +100,9 @@ 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 ? VerifyResult.Succeed : VerifyResult.InsufficientFunds); - mock.Setup(p => p.Verify(It.IsAny(), It.IsAny())).Returns(VerifyResult.Succeed); + mock.Setup(p => p.VerifySenderFeeFromPool(It.IsAny(), It.IsAny())).Returns((StoreView snapshot, BigInteger amount) => NativeContract.GAS.BalanceOf(snapshot, sender) >= amount + fee ? VerifyResult.Succeed : VerifyResult.InsufficientFunds); + mock.Setup(p => p.VerifyForEachBlock(It.IsAny())).Returns(VerifyResult.Succeed); + mock.Setup(p => p.Verify(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 2b0d7a349b..4927de8d99 100644 --- a/tests/neo.UnitTests/Ledger/UT_SendersFeeMonitor.cs +++ b/tests/neo.UnitTests/Ledger/UT_SendersFeeMonitor.cs @@ -18,8 +18,9 @@ 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(VerifyResult.Succeed); - mock.Setup(p => p.Verify(It.IsAny(), It.IsAny())).Returns(VerifyResult.Succeed); + mock.Setup(p => p.VerifySenderFeeFromPool(It.IsAny(), It.IsAny())).Returns(VerifyResult.Succeed); + mock.Setup(p => p.VerifyForEachBlock(It.IsAny())).Returns(VerifyResult.Succeed); + mock.Setup(p => p.Verify(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 06ead63238..3b41df5445 100644 --- a/tests/neo.UnitTests/Network/P2P/Payloads/UT_Transaction.cs +++ b/tests/neo.UnitTests/Network/P2P/Payloads/UT_Transaction.cs @@ -806,7 +806,8 @@ public void Transaction_Reverify_Hashes_Length_Unequal_To_Witnesses_Length() }; UInt160[] hashes = txSimple.GetScriptHashesForVerifying(snapshot); Assert.AreEqual(2, hashes.Length); - Assert.AreNotEqual(VerifyResult.Succeed, txSimple.VerifyForEachBlock(snapshot, BigInteger.Zero)); + Assert.AreNotEqual(VerifyResult.Succeed, txSimple.VerifySenderFeeFromPool(snapshot, BigInteger.Zero)); + Assert.AreNotEqual(VerifyResult.Succeed, txSimple.VerifyForEachBlock(snapshot)); } [TestMethod] From f7ba395e9b64fd74e6894cf1201436119c0e9a79 Mon Sep 17 00:00:00 2001 From: Jin Qiao Date: Mon, 30 Mar 2020 14:59:11 +0800 Subject: [PATCH 04/55] Format modification --- src/neo/Network/P2P/Payloads/Transaction.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/neo/Network/P2P/Payloads/Transaction.cs b/src/neo/Network/P2P/Payloads/Transaction.cs index 799f255bfc..8aa73350f9 100644 --- a/src/neo/Network/P2P/Payloads/Transaction.cs +++ b/src/neo/Network/P2P/Payloads/Transaction.cs @@ -267,7 +267,7 @@ bool IInventory.Verify(StoreView snapshot) && Verify(snapshot) == VerifyResult.Succeed; } - public virtual VerifyResult VerifySenderFeeFromPool (StoreView snapshot, BigInteger totalSenderFeeFromPool) + public virtual VerifyResult VerifySenderFeeFromPool(StoreView snapshot, BigInteger totalSenderFeeFromPool) { BigInteger balance = NativeContract.GAS.BalanceOf(snapshot, Sender); BigInteger fee = SystemFee + NetworkFee + totalSenderFeeFromPool; From e407aada8f1d0a78fef7ecb61d0b1bfd9fd3fe00 Mon Sep 17 00:00:00 2001 From: Jin Qiao Date: Fri, 3 Apr 2020 14:25:50 +0800 Subject: [PATCH 05/55] Function rename and add parallel strategy --- src/neo/Consensus/ConsensusService.cs | 4 ++-- src/neo/Ledger/Blockchain.cs | 6 +++--- src/neo/Ledger/MemoryPool.cs | 2 +- src/neo/Network/P2P/Payloads/Transaction.cs | 8 ++++---- src/neo/Network/P2P/ProtocolHandler.cs | 15 +++++++++------ tests/neo.UnitTests/Ledger/UT_MemoryPool.cs | 8 ++++---- .../neo.UnitTests/Ledger/UT_SendersFeeMonitor.cs | 4 ++-- .../Network/P2P/Payloads/UT_Transaction.cs | 2 +- 8 files changed, 26 insertions(+), 23 deletions(-) diff --git a/src/neo/Consensus/ConsensusService.cs b/src/neo/Consensus/ConsensusService.cs index 9083f80148..fc950a340b 100644 --- a/src/neo/Consensus/ConsensusService.cs +++ b/src/neo/Consensus/ConsensusService.cs @@ -61,8 +61,8 @@ internal ConsensusService(IActorRef localNode, IActorRef taskManager, ConsensusC private bool AddTransaction(Transaction tx, bool verify) { - if (verify && tx.VerifySenderFeeFromPool(context.Snapshot, context.SendersFeeMonitor.GetSenderFee(tx.Sender)) != VerifyResult.Succeed - && tx.Verify(context.Snapshot) != VerifyResult.Succeed) + if (verify && tx.VerifyStateDependent(context.Snapshot, context.SendersFeeMonitor.GetSenderFee(tx.Sender)) != VerifyResult.Succeed + && tx.VerifyStateIndependent(context.Snapshot) != 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 c63c140e83..53c554bbbb 100644 --- a/src/neo/Ledger/Blockchain.cs +++ b/src/neo/Ledger/Blockchain.cs @@ -279,9 +279,9 @@ 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.VerifySenderFeeFromPool(currentSnapshot, MemPool.SendersFeeMonitor.GetSenderFee(tx.Sender)) != VerifyResult.Succeed) + if (tx.VerifyStateDependent(currentSnapshot, MemPool.SendersFeeMonitor.GetSenderFee(tx.Sender)) != VerifyResult.Succeed) continue; - if (tx.Verify(currentSnapshot) != VerifyResult.Succeed) + if (tx.VerifyStateIndependent(currentSnapshot) != VerifyResult.Succeed) continue; // Add to the memory pool MemPool.TryAdd(tx.Hash, tx); @@ -421,7 +421,7 @@ private VerifyResult OnNewTransaction(Transaction transaction) { if (ContainsTransaction(transaction.Hash)) return VerifyResult.AlreadyExists; if (!MemPool.CanTransactionFitInPool(transaction)) return VerifyResult.OutOfMemory; - VerifyResult reason = transaction.VerifySenderFeeFromPool(currentSnapshot, MemPool.SendersFeeMonitor.GetSenderFee(transaction.Sender)); + VerifyResult reason = transaction.VerifyStateDependent(currentSnapshot, MemPool.SendersFeeMonitor.GetSenderFee(transaction.Sender)); if (reason != VerifyResult.Succeed) return reason; if (!MemPool.TryAdd(transaction.Hash, transaction)) return VerifyResult.OutOfMemory; return VerifyResult.Succeed; diff --git a/src/neo/Ledger/MemoryPool.cs b/src/neo/Ledger/MemoryPool.cs index 3913bb9ac3..d296e087ef 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.VerifySenderFeeFromPool(snapshot, SendersFeeMonitor.GetSenderFee(item.Tx.Sender)) == VerifyResult.Succeed + if (item.Tx.VerifyStateDependent(snapshot, SendersFeeMonitor.GetSenderFee(item.Tx.Sender)) == VerifyResult.Succeed && item.Tx.VerifyForEachBlock(snapshot) == VerifyResult.Succeed) { reverifiedItems.Add(item); diff --git a/src/neo/Network/P2P/Payloads/Transaction.cs b/src/neo/Network/P2P/Payloads/Transaction.cs index 8aa73350f9..754db9ab2c 100644 --- a/src/neo/Network/P2P/Payloads/Transaction.cs +++ b/src/neo/Network/P2P/Payloads/Transaction.cs @@ -263,11 +263,11 @@ public static Transaction FromJson(JObject json) bool IInventory.Verify(StoreView snapshot) { - return VerifySenderFeeFromPool(snapshot, BigInteger.Zero) == VerifyResult.Succeed - && Verify(snapshot) == VerifyResult.Succeed; + return VerifyStateDependent(snapshot, BigInteger.Zero) == VerifyResult.Succeed + && VerifyStateIndependent(snapshot) == VerifyResult.Succeed; } - public virtual VerifyResult VerifySenderFeeFromPool(StoreView snapshot, BigInteger totalSenderFeeFromPool) + public virtual VerifyResult VerifyStateDependent(StoreView snapshot, BigInteger totalSenderFeeFromPool) { BigInteger balance = NativeContract.GAS.BalanceOf(snapshot, Sender); BigInteger fee = SystemFee + NetworkFee + totalSenderFeeFromPool; @@ -291,7 +291,7 @@ public virtual VerifyResult VerifyForEachBlock(StoreView snapshot) return VerifyResult.Succeed; } - public virtual VerifyResult Verify(StoreView snapshot) + public virtual VerifyResult VerifyStateIndependent(StoreView snapshot) { VerifyResult result = VerifyForEachBlock(snapshot); if (result != VerifyResult.Succeed) return result; diff --git a/src/neo/Network/P2P/ProtocolHandler.cs b/src/neo/Network/P2P/ProtocolHandler.cs index 96d294d52e..028fe88052 100644 --- a/src/neo/Network/P2P/ProtocolHandler.cs +++ b/src/neo/Network/P2P/ProtocolHandler.cs @@ -14,6 +14,7 @@ using System.Collections.ObjectModel; using System.Linq; using System.Net; +using System.Threading.Tasks; namespace Neo.Network.P2P { @@ -134,15 +135,17 @@ private void OnMessage(Message msg) OnPongMessageReceived((PingPayload)msg.Payload); break; case MessageCommand.Transaction: - if (msg.Payload.Size <= Transaction.MaxTransactionSize) + Task.Run(() => { - Transaction tx = (Transaction)msg.Payload; - if (tx.Verify(Blockchain.Singleton.currentSnapshot) != VerifyResult.Succeed) + if (msg.Payload.Size <= Transaction.MaxTransactionSize) { - return; + Transaction tx = (Transaction)msg.Payload; + if (tx.VerifyStateIndependent(Blockchain.Singleton.currentSnapshot) == VerifyResult.Succeed) + { + OnInventoryReceived(tx); + } } - OnInventoryReceived(tx); - } + }); break; case MessageCommand.Verack: case MessageCommand.Version: diff --git a/tests/neo.UnitTests/Ledger/UT_MemoryPool.cs b/tests/neo.UnitTests/Ledger/UT_MemoryPool.cs index eea2a37a86..81181d6e3c 100644 --- a/tests/neo.UnitTests/Ledger/UT_MemoryPool.cs +++ b/tests/neo.UnitTests/Ledger/UT_MemoryPool.cs @@ -74,9 +74,9 @@ private Transaction CreateTransactionWithFee(long fee) var randomBytes = new byte[16]; random.NextBytes(randomBytes); Mock mock = new Mock(); - mock.Setup(p => p.VerifySenderFeeFromPool(It.IsAny(), It.IsAny())).Returns(VerifyResult.Succeed); + mock.Setup(p => p.VerifyStateDependent(It.IsAny(), It.IsAny())).Returns(VerifyResult.Succeed); mock.Setup(p => p.VerifyForEachBlock(It.IsAny())).Returns(VerifyResult.Succeed); - mock.Setup(p => p.Verify(It.IsAny())).Returns(VerifyResult.Succeed); + mock.Setup(p => p.VerifyStateIndependent(It.IsAny())).Returns(VerifyResult.Succeed); mock.Object.Script = randomBytes; mock.Object.Sender = UInt160.Zero; mock.Object.NetworkFee = fee; @@ -100,9 +100,9 @@ private Transaction CreateTransactionWithFeeAndBalanceVerify(long fee) random.NextBytes(randomBytes); Mock mock = new Mock(); UInt160 sender = UInt160.Zero; - mock.Setup(p => p.VerifySenderFeeFromPool(It.IsAny(), It.IsAny())).Returns((StoreView snapshot, BigInteger amount) => NativeContract.GAS.BalanceOf(snapshot, sender) >= amount + fee ? VerifyResult.Succeed : VerifyResult.InsufficientFunds); + mock.Setup(p => p.VerifyStateDependent(It.IsAny(), It.IsAny())).Returns((StoreView snapshot, BigInteger amount) => NativeContract.GAS.BalanceOf(snapshot, sender) >= amount + fee ? VerifyResult.Succeed : VerifyResult.InsufficientFunds); mock.Setup(p => p.VerifyForEachBlock(It.IsAny())).Returns(VerifyResult.Succeed); - mock.Setup(p => p.Verify(It.IsAny())).Returns(VerifyResult.Succeed); + mock.Setup(p => p.VerifyStateIndependent(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 4927de8d99..3dab859d09 100644 --- a/tests/neo.UnitTests/Ledger/UT_SendersFeeMonitor.cs +++ b/tests/neo.UnitTests/Ledger/UT_SendersFeeMonitor.cs @@ -18,9 +18,9 @@ private Transaction CreateTransactionWithFee(long networkFee, long systemFee) var randomBytes = new byte[16]; random.NextBytes(randomBytes); Mock mock = new Mock(); - mock.Setup(p => p.VerifySenderFeeFromPool(It.IsAny(), It.IsAny())).Returns(VerifyResult.Succeed); + mock.Setup(p => p.VerifyStateDependent(It.IsAny(), It.IsAny())).Returns(VerifyResult.Succeed); mock.Setup(p => p.VerifyForEachBlock(It.IsAny())).Returns(VerifyResult.Succeed); - mock.Setup(p => p.Verify(It.IsAny())).Returns(VerifyResult.Succeed); + mock.Setup(p => p.VerifyStateIndependent(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 3b41df5445..edae2ec0bd 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(VerifyResult.Succeed, txSimple.VerifySenderFeeFromPool(snapshot, BigInteger.Zero)); + Assert.AreNotEqual(VerifyResult.Succeed, txSimple.VerifyStateDependent(snapshot, BigInteger.Zero)); Assert.AreNotEqual(VerifyResult.Succeed, txSimple.VerifyForEachBlock(snapshot)); } From 6896500953f655945140dc12eef435e80dfeefb3 Mon Sep 17 00:00:00 2001 From: Jin Qiao Date: Mon, 6 Apr 2020 12:13:47 +0800 Subject: [PATCH 06/55] Code optimization --- src/neo/Consensus/ConsensusService.cs | 3 +- src/neo/Ledger/Blockchain.cs | 4 +-- src/neo/Ledger/MemoryPool.cs | 3 +- src/neo/Network/P2P/Payloads/Transaction.cs | 33 ++++++++++++++----- tests/neo.UnitTests/Ledger/UT_MemoryPool.cs | 8 +++-- .../Ledger/UT_SendersFeeMonitor.cs | 4 ++- .../Network/P2P/Payloads/UT_Transaction.cs | 3 +- 7 files changed, 37 insertions(+), 21 deletions(-) diff --git a/src/neo/Consensus/ConsensusService.cs b/src/neo/Consensus/ConsensusService.cs index fc950a340b..9e59ba7283 100644 --- a/src/neo/Consensus/ConsensusService.cs +++ b/src/neo/Consensus/ConsensusService.cs @@ -61,8 +61,7 @@ internal ConsensusService(IActorRef localNode, IActorRef taskManager, ConsensusC private bool AddTransaction(Transaction tx, bool verify) { - if (verify && tx.VerifyStateDependent(context.Snapshot, context.SendersFeeMonitor.GetSenderFee(tx.Sender)) != VerifyResult.Succeed - && tx.VerifyStateIndependent(context.Snapshot) != VerifyResult.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 53c554bbbb..f86bc93814 100644 --- a/src/neo/Ledger/Blockchain.cs +++ b/src/neo/Ledger/Blockchain.cs @@ -279,9 +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.VerifyStateDependent(currentSnapshot, MemPool.SendersFeeMonitor.GetSenderFee(tx.Sender)) != VerifyResult.Succeed) - continue; - if (tx.VerifyStateIndependent(currentSnapshot) != VerifyResult.Succeed) + if (tx.Verify(currentSnapshot, MemPool.SendersFeeMonitor.GetSenderFee(tx.Sender)) != VerifyResult.Succeed) continue; // Add to the memory pool MemPool.TryAdd(tx.Hash, tx); diff --git a/src/neo/Ledger/MemoryPool.cs b/src/neo/Ledger/MemoryPool.cs index d296e087ef..62466d65e8 100644 --- a/src/neo/Ledger/MemoryPool.cs +++ b/src/neo/Ledger/MemoryPool.cs @@ -416,8 +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.VerifyStateDependent(snapshot, SendersFeeMonitor.GetSenderFee(item.Tx.Sender)) == VerifyResult.Succeed - && item.Tx.VerifyForEachBlock(snapshot) == VerifyResult.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/Network/P2P/Payloads/Transaction.cs b/src/neo/Network/P2P/Payloads/Transaction.cs index 754db9ab2c..55a91602d5 100644 --- a/src/neo/Network/P2P/Payloads/Transaction.cs +++ b/src/neo/Network/P2P/Payloads/Transaction.cs @@ -263,19 +263,18 @@ public static Transaction FromJson(JObject json) bool IInventory.Verify(StoreView snapshot) { - return VerifyStateDependent(snapshot, BigInteger.Zero) == VerifyResult.Succeed - && VerifyStateIndependent(snapshot) == VerifyResult.Succeed; + return Verify(snapshot, BigInteger.Zero) == VerifyResult.Succeed; } - public virtual VerifyResult VerifyStateDependent(StoreView snapshot, BigInteger totalSenderFeeFromPool) + public virtual VerifyResult VerifyForEachBlock(StoreView snapshot, BigInteger totalSenderFeeFromPool) { - BigInteger balance = NativeContract.GAS.BalanceOf(snapshot, Sender); - BigInteger fee = SystemFee + NetworkFee + totalSenderFeeFromPool; - if (balance < fee) return VerifyResult.InsufficientFunds; - else return VerifyResult.Succeed; + VerifyResult result = VerifyStateDependent(snapshot, totalSenderFeeFromPool); + if (result != VerifyResult.Succeed) return result; + result = VerifyForEachBlockStateIndependent(snapshot); + return result; } - public virtual VerifyResult VerifyForEachBlock(StoreView snapshot) + public virtual VerifyResult VerifyForEachBlockStateIndependent(StoreView snapshot) { if (ValidUntilBlock <= snapshot.Height || ValidUntilBlock > snapshot.Height + MaxValidUntilBlockIncrement) return VerifyResult.Expired; @@ -291,9 +290,17 @@ public virtual VerifyResult VerifyForEachBlock(StoreView snapshot) return VerifyResult.Succeed; } + public virtual VerifyResult VerifyStateDependent(StoreView snapshot, BigInteger totalSenderFeeFromPool) + { + BigInteger balance = NativeContract.GAS.BalanceOf(snapshot, Sender); + BigInteger fee = SystemFee + NetworkFee + totalSenderFeeFromPool; + if (balance < fee) return VerifyResult.InsufficientFunds; + else return VerifyResult.Succeed; + } + public virtual VerifyResult VerifyStateIndependent(StoreView snapshot) { - VerifyResult result = VerifyForEachBlock(snapshot); + VerifyResult result = VerifyForEachBlockStateIndependent(snapshot); if (result != VerifyResult.Succeed) return result; int size = Size; if (size > MaxTransactionSize) return VerifyResult.Invalid; @@ -303,6 +310,14 @@ public virtual VerifyResult VerifyStateIndependent(StoreView snapshot) return VerifyResult.Succeed; } + public virtual VerifyResult Verify(StoreView snapshot, BigInteger totalSenderFeeFromPool) + { + VerifyResult result = VerifyStateDependent(snapshot, totalSenderFeeFromPool); + if (result != VerifyResult.Succeed) return result; + result = VerifyStateIndependent(snapshot); + return result; + } + public StackItem ToStackItem(ReferenceCounter referenceCounter) { return new Array(referenceCounter, new StackItem[] diff --git a/tests/neo.UnitTests/Ledger/UT_MemoryPool.cs b/tests/neo.UnitTests/Ledger/UT_MemoryPool.cs index 81181d6e3c..c7adf6b33c 100644 --- a/tests/neo.UnitTests/Ledger/UT_MemoryPool.cs +++ b/tests/neo.UnitTests/Ledger/UT_MemoryPool.cs @@ -74,8 +74,10 @@ 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(VerifyResult.Succeed); + mock.Setup(p => p.VerifyForEachBlockStateIndependent(It.IsAny())).Returns(VerifyResult.Succeed); + mock.Setup(p => p.Verify(It.IsAny(), It.IsAny())).Returns(VerifyResult.Succeed); mock.Setup(p => p.VerifyStateDependent(It.IsAny(), It.IsAny())).Returns(VerifyResult.Succeed); - mock.Setup(p => p.VerifyForEachBlock(It.IsAny())).Returns(VerifyResult.Succeed); mock.Setup(p => p.VerifyStateIndependent(It.IsAny())).Returns(VerifyResult.Succeed); mock.Object.Script = randomBytes; mock.Object.Sender = UInt160.Zero; @@ -100,8 +102,10 @@ 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(VerifyResult.Succeed); + mock.Setup(p => p.VerifyForEachBlockStateIndependent(It.IsAny())).Returns(VerifyResult.Succeed); + mock.Setup(p => p.Verify(It.IsAny(), It.IsAny())).Returns(VerifyResult.Succeed); mock.Setup(p => p.VerifyStateDependent(It.IsAny(), It.IsAny())).Returns((StoreView snapshot, BigInteger amount) => NativeContract.GAS.BalanceOf(snapshot, sender) >= amount + fee ? VerifyResult.Succeed : VerifyResult.InsufficientFunds); - mock.Setup(p => p.VerifyForEachBlock(It.IsAny())).Returns(VerifyResult.Succeed); mock.Setup(p => p.VerifyStateIndependent(It.IsAny())).Returns(VerifyResult.Succeed); mock.Object.Script = randomBytes; mock.Object.Sender = sender; diff --git a/tests/neo.UnitTests/Ledger/UT_SendersFeeMonitor.cs b/tests/neo.UnitTests/Ledger/UT_SendersFeeMonitor.cs index 3dab859d09..ba6a1b4c55 100644 --- a/tests/neo.UnitTests/Ledger/UT_SendersFeeMonitor.cs +++ b/tests/neo.UnitTests/Ledger/UT_SendersFeeMonitor.cs @@ -18,8 +18,10 @@ 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(VerifyResult.Succeed); + mock.Setup(p => p.VerifyForEachBlockStateIndependent(It.IsAny())).Returns(VerifyResult.Succeed); + mock.Setup(p => p.Verify(It.IsAny(), It.IsAny())).Returns(VerifyResult.Succeed); mock.Setup(p => p.VerifyStateDependent(It.IsAny(), It.IsAny())).Returns(VerifyResult.Succeed); - mock.Setup(p => p.VerifyForEachBlock(It.IsAny())).Returns(VerifyResult.Succeed); mock.Setup(p => p.VerifyStateIndependent(It.IsAny())).Returns(VerifyResult.Succeed); mock.Object.Script = randomBytes; mock.Object.Sender = UInt160.Zero; diff --git a/tests/neo.UnitTests/Network/P2P/Payloads/UT_Transaction.cs b/tests/neo.UnitTests/Network/P2P/Payloads/UT_Transaction.cs index edae2ec0bd..06ead63238 100644 --- a/tests/neo.UnitTests/Network/P2P/Payloads/UT_Transaction.cs +++ b/tests/neo.UnitTests/Network/P2P/Payloads/UT_Transaction.cs @@ -806,8 +806,7 @@ public void Transaction_Reverify_Hashes_Length_Unequal_To_Witnesses_Length() }; UInt160[] hashes = txSimple.GetScriptHashesForVerifying(snapshot); Assert.AreEqual(2, hashes.Length); - Assert.AreNotEqual(VerifyResult.Succeed, txSimple.VerifyStateDependent(snapshot, BigInteger.Zero)); - Assert.AreNotEqual(VerifyResult.Succeed, txSimple.VerifyForEachBlock(snapshot)); + Assert.AreNotEqual(VerifyResult.Succeed, txSimple.VerifyForEachBlock(snapshot, BigInteger.Zero)); } [TestMethod] From b3b8c257117b6ccee72f758e6cddf61ffc7380ea Mon Sep 17 00:00:00 2001 From: Jin Qiao Date: Tue, 7 Apr 2020 10:18:57 +0800 Subject: [PATCH 07/55] Code optimization --- tests/neo.UnitTests/Ledger/UT_MemoryPool.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/neo.UnitTests/Ledger/UT_MemoryPool.cs b/tests/neo.UnitTests/Ledger/UT_MemoryPool.cs index c7adf6b33c..71dd26cc70 100644 --- a/tests/neo.UnitTests/Ledger/UT_MemoryPool.cs +++ b/tests/neo.UnitTests/Ledger/UT_MemoryPool.cs @@ -102,7 +102,7 @@ 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(VerifyResult.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.VerifyForEachBlockStateIndependent(It.IsAny())).Returns(VerifyResult.Succeed); mock.Setup(p => p.Verify(It.IsAny(), It.IsAny())).Returns(VerifyResult.Succeed); mock.Setup(p => p.VerifyStateDependent(It.IsAny(), It.IsAny())).Returns((StoreView snapshot, BigInteger amount) => NativeContract.GAS.BalanceOf(snapshot, sender) >= amount + fee ? VerifyResult.Succeed : VerifyResult.InsufficientFunds); From 0173cd39b3e177b7ae79cc3fc1630d6cf45bf51d Mon Sep 17 00:00:00 2001 From: Jin Qiao Date: Wed, 8 Apr 2020 16:18:51 +0800 Subject: [PATCH 08/55] Code optimization --- src/neo/Ledger/Blockchain.cs | 3 ++- src/neo/Network/P2P/ProtocolHandler.cs | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/neo/Ledger/Blockchain.cs b/src/neo/Ledger/Blockchain.cs index f86bc93814..6681f588e7 100644 --- a/src/neo/Ledger/Blockchain.cs +++ b/src/neo/Ledger/Blockchain.cs @@ -63,7 +63,8 @@ public class RelayResult { public IInventory Inventory; public VerifyResult Resu private readonly Dictionary block_cache = new Dictionary(); private readonly Dictionary> block_cache_unverified = new Dictionary>(); internal readonly RelayCache ConsensusRelayCache = new RelayCache(100); - public SnapshotView currentSnapshot; + private SnapshotView currentSnapshot; + public SnapshotView GetCurrentSnapshot() {return currentSnapshot;} public IStore Store { get; } public ReadOnlyView View { get; } diff --git a/src/neo/Network/P2P/ProtocolHandler.cs b/src/neo/Network/P2P/ProtocolHandler.cs index 028fe88052..2862bcb3c6 100644 --- a/src/neo/Network/P2P/ProtocolHandler.cs +++ b/src/neo/Network/P2P/ProtocolHandler.cs @@ -140,7 +140,7 @@ private void OnMessage(Message msg) if (msg.Payload.Size <= Transaction.MaxTransactionSize) { Transaction tx = (Transaction)msg.Payload; - if (tx.VerifyStateIndependent(Blockchain.Singleton.currentSnapshot) == VerifyResult.Succeed) + if (tx.VerifyStateIndependent(Blockchain.Singleton.GetCurrentSnapshot()) == VerifyResult.Succeed) { OnInventoryReceived(tx); } From 78b304fb65cda0bb6156868d05b078b02e4a0eaf Mon Sep 17 00:00:00 2001 From: Jin Qiao Date: Wed, 8 Apr 2020 16:22:42 +0800 Subject: [PATCH 09/55] Format optimization --- src/neo/Ledger/Blockchain.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/neo/Ledger/Blockchain.cs b/src/neo/Ledger/Blockchain.cs index 6681f588e7..e8ab93a549 100644 --- a/src/neo/Ledger/Blockchain.cs +++ b/src/neo/Ledger/Blockchain.cs @@ -64,7 +64,10 @@ public class RelayResult { public IInventory Inventory; public VerifyResult Resu private readonly Dictionary> block_cache_unverified = new Dictionary>(); internal readonly RelayCache ConsensusRelayCache = new RelayCache(100); private SnapshotView currentSnapshot; - public SnapshotView GetCurrentSnapshot() {return currentSnapshot;} + public SnapshotView GetCurrentSnapshot() + { + return currentSnapshot; + } public IStore Store { get; } public ReadOnlyView View { get; } From eb6f41f689c95e9324e00ae4047903648d62b492 Mon Sep 17 00:00:00 2001 From: Jin Qiao Date: Wed, 8 Apr 2020 18:32:50 +0800 Subject: [PATCH 10/55] Code optimization --- src/neo/Ledger/Blockchain.cs | 7 +++++-- src/neo/Network/P2P/ProtocolHandler.cs | 2 +- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/neo/Ledger/Blockchain.cs b/src/neo/Ledger/Blockchain.cs index e8ab93a549..d1e966149e 100644 --- a/src/neo/Ledger/Blockchain.cs +++ b/src/neo/Ledger/Blockchain.cs @@ -64,9 +64,12 @@ public class RelayResult { public IInventory Inventory; public VerifyResult Resu private readonly Dictionary> block_cache_unverified = new Dictionary>(); internal readonly RelayCache ConsensusRelayCache = new RelayCache(100); private SnapshotView currentSnapshot; - public SnapshotView GetCurrentSnapshot() + public SnapshotView CurrentSnapshot { - return currentSnapshot; + get + { + return currentSnapshot; + } } public IStore Store { get; } diff --git a/src/neo/Network/P2P/ProtocolHandler.cs b/src/neo/Network/P2P/ProtocolHandler.cs index 2862bcb3c6..de02948a50 100644 --- a/src/neo/Network/P2P/ProtocolHandler.cs +++ b/src/neo/Network/P2P/ProtocolHandler.cs @@ -140,7 +140,7 @@ private void OnMessage(Message msg) if (msg.Payload.Size <= Transaction.MaxTransactionSize) { Transaction tx = (Transaction)msg.Payload; - if (tx.VerifyStateIndependent(Blockchain.Singleton.GetCurrentSnapshot()) == VerifyResult.Succeed) + if (tx.VerifyStateIndependent(Blockchain.Singleton.CurrentSnapshot) == VerifyResult.Succeed) { OnInventoryReceived(tx); } From 729d2ce3bcdd5ef9619612f6261f1cf04a4e5d17 Mon Sep 17 00:00:00 2001 From: Jin Qiao Date: Wed, 6 May 2020 18:45:56 +0800 Subject: [PATCH 11/55] Fix VerifyWitnesses --- src/neo/SmartContract/Helper.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/neo/SmartContract/Helper.cs b/src/neo/SmartContract/Helper.cs index 33c6b260cf..47428f67f3 100644 --- a/src/neo/SmartContract/Helper.cs +++ b/src/neo/SmartContract/Helper.cs @@ -167,6 +167,8 @@ internal static bool VerifyWitnesses(this IVerifiable verifiable, StoreView snap engine.LoadScript(verifiable.Witnesses[i].InvocationScript, CallFlags.None); if (engine.Execute() == VMState.FAULT) return false; if (!engine.ResultStack.TryPop(out StackItem result) || !result.ToBoolean()) return false; + gas -= engine.GasConsumed; + if (gas < 0) return false; } } return true; From fcc3c1227af9b644b9bb04a38bce0ab2c08602aa Mon Sep 17 00:00:00 2001 From: Jin Qiao Date: Wed, 6 May 2020 18:48:17 +0800 Subject: [PATCH 12/55] Revert "Fix VerifyWitnesses" This reverts commit 729d2ce3bcdd5ef9619612f6261f1cf04a4e5d17. --- src/neo/SmartContract/Helper.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/neo/SmartContract/Helper.cs b/src/neo/SmartContract/Helper.cs index 47428f67f3..33c6b260cf 100644 --- a/src/neo/SmartContract/Helper.cs +++ b/src/neo/SmartContract/Helper.cs @@ -167,8 +167,6 @@ internal static bool VerifyWitnesses(this IVerifiable verifiable, StoreView snap engine.LoadScript(verifiable.Witnesses[i].InvocationScript, CallFlags.None); if (engine.Execute() == VMState.FAULT) return false; if (!engine.ResultStack.TryPop(out StackItem result) || !result.ToBoolean()) return false; - gas -= engine.GasConsumed; - if (gas < 0) return false; } } return true; From e578754f5b189f29329b6d6e0fd6b61191ca340a Mon Sep 17 00:00:00 2001 From: Jin Qiao Date: Thu, 7 May 2020 17:59:32 +0800 Subject: [PATCH 13/55] Rewrite verify_witness and corresponding logic --- src/neo/Network/P2P/Payloads/Transaction.cs | 68 ++++++++++++++++--- src/neo/Network/P2P/Payloads/Witness.cs | 1 + .../Network/P2P/RemoteNode.ProtocolHandler.cs | 10 ++- src/neo/SmartContract/Helper.cs | 61 ++++++++++------- tests/neo.UnitTests/Ledger/UT_MemoryPool.cs | 8 +-- .../Ledger/UT_SendersFeeMonitor.cs | 4 +- 6 files changed, 110 insertions(+), 42 deletions(-) diff --git a/src/neo/Network/P2P/Payloads/Transaction.cs b/src/neo/Network/P2P/Payloads/Transaction.cs index baaf29f1df..36050d8d76 100644 --- a/src/neo/Network/P2P/Payloads/Transaction.cs +++ b/src/neo/Network/P2P/Payloads/Transaction.cs @@ -13,6 +13,7 @@ using System.IO; using System.Linq; using System.Numerics; +using System.Threading.Tasks; using Array = Neo.VM.Types.Array; namespace Neo.Network.P2P.Payloads @@ -258,11 +259,11 @@ public virtual VerifyResult VerifyForEachBlock(StoreView snapshot, BigInteger to { VerifyResult result = VerifyStateDependent(snapshot, totalSenderFeeFromPool); if (result != VerifyResult.Succeed) return result; - result = VerifyForEachBlockStateIndependent(snapshot); + result = VerifyForEachBlockStateDependent(snapshot); return result; } - public virtual VerifyResult VerifyForEachBlockStateIndependent(StoreView snapshot) + public virtual VerifyResult VerifyForEachBlockStateDependent(StoreView snapshot) { if (ValidUntilBlock <= snapshot.Height || ValidUntilBlock > snapshot.Height + MaxValidUntilBlockIncrement) return VerifyResult.Expired; @@ -280,21 +281,31 @@ public virtual VerifyResult VerifyForEachBlockStateIndependent(StoreView snapsho public virtual VerifyResult VerifyStateDependent(StoreView snapshot, BigInteger totalSenderFeeFromPool) { + VerifyResult result = VerifyForEachBlockStateDependent(snapshot); + if (result != VerifyResult.Succeed) return result; + long net_fee = NetworkFee - Size * NativeContract.Policy.GetFeePerByte(snapshot); + if (net_fee < 0) return VerifyResult.InsufficientFunds; BigInteger balance = NativeContract.GAS.BalanceOf(snapshot, Sender); BigInteger fee = SystemFee + NetworkFee + totalSenderFeeFromPool; if (balance < fee) return VerifyResult.InsufficientFunds; - else return VerifyResult.Succeed; + if (isStateDepedent) + { + if (!this.VerifyWitnesses(snapshot, net_fee)) return VerifyResult.Invalid; + } + else + { + long gasConsumed = 0; + foreach (Witness witness in witnesses) + gasConsumed += witness.GasConsumed; + if (gasConsumed > net_fee) return VerifyResult.Invalid; + } + return VerifyResult.Succeed; } - public virtual VerifyResult VerifyStateIndependent(StoreView snapshot) + public virtual VerifyResult VerifyStateIndependent(StoreView snapshot, bool checkWitness = true) { - VerifyResult result = VerifyForEachBlockStateIndependent(snapshot); - if (result != VerifyResult.Succeed) return result; - int size = Size; - if (size > MaxTransactionSize) return VerifyResult.Invalid; - long net_fee = NetworkFee - size * NativeContract.Policy.GetFeePerByte(snapshot); - if (net_fee < 0) return VerifyResult.InsufficientFunds; - if (!this.VerifyWitnesses(snapshot, net_fee)) return VerifyResult.Invalid; + if (Size > MaxTransactionSize) return VerifyResult.Invalid; + if (checkWitness && !this.VerifyWitnesses(snapshot, NetworkFee)) return VerifyResult.Invalid; return VerifyResult.Succeed; } @@ -323,5 +334,40 @@ public StackItem ToStackItem(ReferenceCounter referenceCounter) Script, }); } + + private int _stateDependent = -1; + + public bool isStateDepedent + { + get + { + switch (_stateDependent) + { + case 0: + return false; + case 1: + return true; + default: + bool isStateDependent = false; + Parallel.ForEach(witnesses, (witness, state) => + { + if (witness.VerificationScript.Length == 0 || !witness.VerificationScript.IsStandardContract()) + { + isStateDependent = true; + state.Stop(); + } + }); + if (isStateDependent) + { + _stateDependent = 1; + } + else + { + _stateDependent = 0; + } + return isStateDependent; + } + } + } } } diff --git a/src/neo/Network/P2P/Payloads/Witness.cs b/src/neo/Network/P2P/Payloads/Witness.cs index 34121a6a6a..601e9c3f8f 100644 --- a/src/neo/Network/P2P/Payloads/Witness.cs +++ b/src/neo/Network/P2P/Payloads/Witness.cs @@ -10,6 +10,7 @@ public class Witness : ISerializable { public byte[] InvocationScript; public byte[] VerificationScript; + public long GasConsumed; private UInt160 _scriptHash; public virtual UInt160 ScriptHash diff --git a/src/neo/Network/P2P/RemoteNode.ProtocolHandler.cs b/src/neo/Network/P2P/RemoteNode.ProtocolHandler.cs index f46c05573c..94dd2ec2d3 100644 --- a/src/neo/Network/P2P/RemoteNode.ProtocolHandler.cs +++ b/src/neo/Network/P2P/RemoteNode.ProtocolHandler.cs @@ -113,10 +113,16 @@ private void OnMessage(Message msg) if (msg.Payload.Size <= Transaction.MaxTransactionSize) { Transaction tx = (Transaction)msg.Payload; - if (tx.VerifyStateIndependent(Blockchain.Singleton.CurrentSnapshot) == VerifyResult.Succeed) + if (tx.isStateDepedent) { - OnInventoryReceived(tx); + if (tx.VerifyStateIndependent(null, false) != VerifyResult.Succeed) + return; } + else if (tx.VerifyStateIndependent(Blockchain.Singleton.CurrentSnapshot, true) != VerifyResult.Succeed) + { + return; + } + OnInventoryReceived(tx); } }); break; diff --git a/src/neo/SmartContract/Helper.cs b/src/neo/SmartContract/Helper.cs index 33c6b260cf..a06d05aaf0 100644 --- a/src/neo/SmartContract/Helper.cs +++ b/src/neo/SmartContract/Helper.cs @@ -145,29 +145,44 @@ internal static bool VerifyWitnesses(this IVerifiable verifiable, StoreView snap if (hashes.Length != verifiable.Witnesses.Length) return false; for (int i = 0; i < hashes.Length; i++) { - int offset; - byte[] verification = verifiable.Witnesses[i].VerificationScript; - if (verification.Length == 0) - { - ContractState cs = snapshot.Contracts.TryGet(hashes[i]); - if (cs is null) return false; - ContractMethodDescriptor md = cs.Manifest.Abi.GetMethod("verify"); - if (md is null) return false; - verification = cs.Script; - offset = md.Offset; - } - else - { - if (hashes[i] != verifiable.Witnesses[i].ScriptHash) return false; - offset = 0; - } - using (ApplicationEngine engine = new ApplicationEngine(TriggerType.Verification, verifiable, snapshot, gas)) - { - engine.LoadScript(verification, CallFlags.ReadOnly).InstructionPointer = offset; - engine.LoadScript(verifiable.Witnesses[i].InvocationScript, CallFlags.None); - if (engine.Execute() == VMState.FAULT) return false; - if (!engine.ResultStack.TryPop(out StackItem result) || !result.ToBoolean()) return false; - } + if (verifiable.Witnesses[i].VerificationScript.Length == 0 + && !verifiable.VerifyWitnessStateDependent(snapshot, gas, hashes[i], verifiable.Witnesses[i])) + return false; + else if (!verifiable.VerifyWitnessStateIndependent(snapshot, gas, hashes[i], verifiable.Witnesses[i])) + return false; + } + return true; + } + + internal static bool VerifyWitnessStateIndependent (this IVerifiable verifiable, StoreView snapshot, long gas, UInt160 hash, Witness witness) + { + if (hash != witness.ScriptHash) return false; + + using (ApplicationEngine engine = new ApplicationEngine(TriggerType.Verification, verifiable, snapshot, gas)) + { + engine.LoadScript(witness.VerificationScript, CallFlags.ReadOnly).InstructionPointer = 0; + engine.LoadScript(witness.InvocationScript, CallFlags.None); + if (engine.Execute() == VMState.FAULT) return false; + if (!engine.ResultStack.TryPop(out StackItem result) || !result.ToBoolean()) return false; + witness.GasConsumed = engine.GasConsumed; + } + return true; + } + + internal static bool VerifyWitnessStateDependent (this IVerifiable verifiable, StoreView snapshot, long gas, UInt160 hash, Witness witness) + { + ContractState cs = snapshot.Contracts.TryGet(hash); + if (cs is null) return false; + ContractMethodDescriptor md = cs.Manifest.Abi.GetMethod("verify"); + if (md is null) return false; + + using (ApplicationEngine engine = new ApplicationEngine(TriggerType.Verification, verifiable, snapshot, gas)) + { + engine.LoadScript(cs.Script, CallFlags.ReadOnly).InstructionPointer = md.Offset; + engine.LoadScript(witness.InvocationScript, CallFlags.None); + if (engine.Execute() == VMState.FAULT) return false; + if (!engine.ResultStack.TryPop(out StackItem result) || !result.ToBoolean()) return false; + witness.GasConsumed = engine.GasConsumed; } return true; } diff --git a/tests/neo.UnitTests/Ledger/UT_MemoryPool.cs b/tests/neo.UnitTests/Ledger/UT_MemoryPool.cs index 71dd26cc70..0e3f40bd09 100644 --- a/tests/neo.UnitTests/Ledger/UT_MemoryPool.cs +++ b/tests/neo.UnitTests/Ledger/UT_MemoryPool.cs @@ -75,10 +75,10 @@ private Transaction CreateTransactionWithFee(long fee) random.NextBytes(randomBytes); Mock mock = new Mock(); mock.Setup(p => p.VerifyForEachBlock(It.IsAny(), It.IsAny())).Returns(VerifyResult.Succeed); - mock.Setup(p => p.VerifyForEachBlockStateIndependent(It.IsAny())).Returns(VerifyResult.Succeed); + mock.Setup(p => p.VerifyForEachBlockStateDependent(It.IsAny())).Returns(VerifyResult.Succeed); mock.Setup(p => p.Verify(It.IsAny(), It.IsAny())).Returns(VerifyResult.Succeed); mock.Setup(p => p.VerifyStateDependent(It.IsAny(), It.IsAny())).Returns(VerifyResult.Succeed); - mock.Setup(p => p.VerifyStateIndependent(It.IsAny())).Returns(VerifyResult.Succeed); + mock.Setup(p => p.VerifyStateIndependent(It.IsAny(), It.IsAny())).Returns(VerifyResult.Succeed); mock.Object.Script = randomBytes; mock.Object.Sender = UInt160.Zero; mock.Object.NetworkFee = fee; @@ -103,10 +103,10 @@ private Transaction CreateTransactionWithFeeAndBalanceVerify(long fee) 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 ? VerifyResult.Succeed : VerifyResult.InsufficientFunds); - mock.Setup(p => p.VerifyForEachBlockStateIndependent(It.IsAny())).Returns(VerifyResult.Succeed); + mock.Setup(p => p.VerifyForEachBlockStateDependent(It.IsAny())).Returns(VerifyResult.Succeed); mock.Setup(p => p.Verify(It.IsAny(), It.IsAny())).Returns(VerifyResult.Succeed); mock.Setup(p => p.VerifyStateDependent(It.IsAny(), It.IsAny())).Returns((StoreView snapshot, BigInteger amount) => NativeContract.GAS.BalanceOf(snapshot, sender) >= amount + fee ? VerifyResult.Succeed : VerifyResult.InsufficientFunds); - mock.Setup(p => p.VerifyStateIndependent(It.IsAny())).Returns(VerifyResult.Succeed); + mock.Setup(p => p.VerifyStateIndependent(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 ba6a1b4c55..14252c38a8 100644 --- a/tests/neo.UnitTests/Ledger/UT_SendersFeeMonitor.cs +++ b/tests/neo.UnitTests/Ledger/UT_SendersFeeMonitor.cs @@ -19,10 +19,10 @@ private Transaction CreateTransactionWithFee(long networkFee, long systemFee) random.NextBytes(randomBytes); Mock mock = new Mock(); mock.Setup(p => p.VerifyForEachBlock(It.IsAny(), It.IsAny())).Returns(VerifyResult.Succeed); - mock.Setup(p => p.VerifyForEachBlockStateIndependent(It.IsAny())).Returns(VerifyResult.Succeed); + mock.Setup(p => p.VerifyForEachBlockStateDependent(It.IsAny())).Returns(VerifyResult.Succeed); mock.Setup(p => p.Verify(It.IsAny(), It.IsAny())).Returns(VerifyResult.Succeed); mock.Setup(p => p.VerifyStateDependent(It.IsAny(), It.IsAny())).Returns(VerifyResult.Succeed); - mock.Setup(p => p.VerifyStateIndependent(It.IsAny())).Returns(VerifyResult.Succeed); + mock.Setup(p => p.VerifyStateIndependent(It.IsAny(), It.IsAny())).Returns(VerifyResult.Succeed); mock.Object.Script = randomBytes; mock.Object.Sender = UInt160.Zero; mock.Object.NetworkFee = networkFee; From d228a512e61ac1027d127803280e66702f208b6a Mon Sep 17 00:00:00 2001 From: Jin Qiao Date: Thu, 7 May 2020 18:04:04 +0800 Subject: [PATCH 14/55] code format --- src/neo/SmartContract/Helper.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/neo/SmartContract/Helper.cs b/src/neo/SmartContract/Helper.cs index a06d05aaf0..a398526b6b 100644 --- a/src/neo/SmartContract/Helper.cs +++ b/src/neo/SmartContract/Helper.cs @@ -154,7 +154,7 @@ internal static bool VerifyWitnesses(this IVerifiable verifiable, StoreView snap return true; } - internal static bool VerifyWitnessStateIndependent (this IVerifiable verifiable, StoreView snapshot, long gas, UInt160 hash, Witness witness) + internal static bool VerifyWitnessStateIndependent(this IVerifiable verifiable, StoreView snapshot, long gas, UInt160 hash, Witness witness) { if (hash != witness.ScriptHash) return false; @@ -169,7 +169,7 @@ internal static bool VerifyWitnessStateIndependent (this IVerifiable verifiable, return true; } - internal static bool VerifyWitnessStateDependent (this IVerifiable verifiable, StoreView snapshot, long gas, UInt160 hash, Witness witness) + internal static bool VerifyWitnessStateDependent(this IVerifiable verifiable, StoreView snapshot, long gas, UInt160 hash, Witness witness) { ContractState cs = snapshot.Contracts.TryGet(hash); if (cs is null) return false; From 51e785cd05b57801b98dc1e4b91078c121512439 Mon Sep 17 00:00:00 2001 From: Jin Qiao Date: Sat, 9 May 2020 16:24:05 +0800 Subject: [PATCH 15/55] Add statedependent to witness --- src/neo/Network/P2P/Payloads/Transaction.cs | 58 +++---------------- src/neo/Network/P2P/Payloads/Witness.cs | 27 +++++++++ .../Network/P2P/RemoteNode.ProtocolHandler.cs | 12 +--- src/neo/SmartContract/Helper.cs | 17 ++++-- .../SmartContract/WitnessVerifyStrategy.cs | 9 +++ tests/neo.UnitTests/Ledger/UT_MemoryPool.cs | 4 +- .../Ledger/UT_SendersFeeMonitor.cs | 2 +- 7 files changed, 61 insertions(+), 68 deletions(-) create mode 100644 src/neo/SmartContract/WitnessVerifyStrategy.cs diff --git a/src/neo/Network/P2P/Payloads/Transaction.cs b/src/neo/Network/P2P/Payloads/Transaction.cs index 36050d8d76..020b3db009 100644 --- a/src/neo/Network/P2P/Payloads/Transaction.cs +++ b/src/neo/Network/P2P/Payloads/Transaction.cs @@ -13,7 +13,6 @@ using System.IO; using System.Linq; using System.Numerics; -using System.Threading.Tasks; using Array = Neo.VM.Types.Array; namespace Neo.Network.P2P.Payloads @@ -288,24 +287,20 @@ public virtual VerifyResult VerifyStateDependent(StoreView snapshot, BigInteger BigInteger balance = NativeContract.GAS.BalanceOf(snapshot, Sender); BigInteger fee = SystemFee + NetworkFee + totalSenderFeeFromPool; if (balance < fee) return VerifyResult.InsufficientFunds; - if (isStateDepedent) - { - if (!this.VerifyWitnesses(snapshot, net_fee)) return VerifyResult.Invalid; - } - else - { - long gasConsumed = 0; - foreach (Witness witness in witnesses) - gasConsumed += witness.GasConsumed; - if (gasConsumed > net_fee) return VerifyResult.Invalid; - } + if (!this.VerifyWitnesses(snapshot, net_fee, WitnessVerifyStrategy.OnlyStateDependent)) return VerifyResult.Invalid; + + //Check all gas consumed for state dependent and independent witnesses + long gasConsumed = 0; + foreach (Witness witness in witnesses) + gasConsumed += witness.GasConsumed; + if (gasConsumed > net_fee) return VerifyResult.Invalid; return VerifyResult.Succeed; } - public virtual VerifyResult VerifyStateIndependent(StoreView snapshot, bool checkWitness = true) + public virtual VerifyResult VerifyStateIndependent(StoreView snapshot) { if (Size > MaxTransactionSize) return VerifyResult.Invalid; - if (checkWitness && !this.VerifyWitnesses(snapshot, NetworkFee)) return VerifyResult.Invalid; + if (!this.VerifyWitnesses(snapshot, NetworkFee, WitnessVerifyStrategy.OnlyStateIndependent)) return VerifyResult.Invalid; return VerifyResult.Succeed; } @@ -334,40 +329,5 @@ public StackItem ToStackItem(ReferenceCounter referenceCounter) Script, }); } - - private int _stateDependent = -1; - - public bool isStateDepedent - { - get - { - switch (_stateDependent) - { - case 0: - return false; - case 1: - return true; - default: - bool isStateDependent = false; - Parallel.ForEach(witnesses, (witness, state) => - { - if (witness.VerificationScript.Length == 0 || !witness.VerificationScript.IsStandardContract()) - { - isStateDependent = true; - state.Stop(); - } - }); - if (isStateDependent) - { - _stateDependent = 1; - } - else - { - _stateDependent = 0; - } - return isStateDependent; - } - } - } } } diff --git a/src/neo/Network/P2P/Payloads/Witness.cs b/src/neo/Network/P2P/Payloads/Witness.cs index 601e9c3f8f..fe06290898 100644 --- a/src/neo/Network/P2P/Payloads/Witness.cs +++ b/src/neo/Network/P2P/Payloads/Witness.cs @@ -49,5 +49,32 @@ public JObject ToJson() json["verification"] = Convert.ToBase64String(VerificationScript); return json; } + + private int _stateDependent = -1; + + public bool IsStateDepedent + { + get + { + switch (_stateDependent) + { + case 0: + return false; + case 1: + return true; + default: + if (VerificationScript.Length == 0 || !VerificationScript.IsStandardContract()) + { + _stateDependent = 1; + return true; + } + else + { + _stateDependent = 0; + return false; + } + } + } + } } } diff --git a/src/neo/Network/P2P/RemoteNode.ProtocolHandler.cs b/src/neo/Network/P2P/RemoteNode.ProtocolHandler.cs index 94dd2ec2d3..2442dccc08 100644 --- a/src/neo/Network/P2P/RemoteNode.ProtocolHandler.cs +++ b/src/neo/Network/P2P/RemoteNode.ProtocolHandler.cs @@ -113,16 +113,8 @@ private void OnMessage(Message msg) if (msg.Payload.Size <= Transaction.MaxTransactionSize) { Transaction tx = (Transaction)msg.Payload; - if (tx.isStateDepedent) - { - if (tx.VerifyStateIndependent(null, false) != VerifyResult.Succeed) - return; - } - else if (tx.VerifyStateIndependent(Blockchain.Singleton.CurrentSnapshot, true) != VerifyResult.Succeed) - { - return; - } - OnInventoryReceived(tx); + if (tx.VerifyStateIndependent(Blockchain.Singleton.CurrentSnapshot) == VerifyResult.Succeed) + OnInventoryReceived(tx); } }); break; diff --git a/src/neo/SmartContract/Helper.cs b/src/neo/SmartContract/Helper.cs index a398526b6b..c57dd02103 100644 --- a/src/neo/SmartContract/Helper.cs +++ b/src/neo/SmartContract/Helper.cs @@ -129,7 +129,7 @@ public static UInt160 ToScriptHash(this ReadOnlySpan script) return new UInt160(Crypto.Hash160(script)); } - internal static bool VerifyWitnesses(this IVerifiable verifiable, StoreView snapshot, long gas) + internal static bool VerifyWitnesses(this IVerifiable verifiable, StoreView snapshot, long gas, WitnessVerifyStrategy strategy = WitnessVerifyStrategy.All) { if (gas < 0) return false; @@ -145,11 +145,16 @@ internal static bool VerifyWitnesses(this IVerifiable verifiable, StoreView snap if (hashes.Length != verifiable.Witnesses.Length) return false; for (int i = 0; i < hashes.Length; i++) { - if (verifiable.Witnesses[i].VerificationScript.Length == 0 - && !verifiable.VerifyWitnessStateDependent(snapshot, gas, hashes[i], verifiable.Witnesses[i])) - return false; - else if (!verifiable.VerifyWitnessStateIndependent(snapshot, gas, hashes[i], verifiable.Witnesses[i])) - return false; + if (verifiable.Witnesses[i].IsStateDepedent && strategy != WitnessVerifyStrategy.OnlyStateIndependent) + { + if (!verifiable.VerifyWitnessStateDependent(snapshot, gas, hashes[i], verifiable.Witnesses[i])) + return false; + } + else if (!verifiable.Witnesses[i].IsStateDepedent && strategy != WitnessVerifyStrategy.OnlyStateDependent) + { + if (!verifiable.VerifyWitnessStateIndependent(snapshot, gas, hashes[i], verifiable.Witnesses[i])) + return false; + } } return true; } diff --git a/src/neo/SmartContract/WitnessVerifyStrategy.cs b/src/neo/SmartContract/WitnessVerifyStrategy.cs new file mode 100644 index 0000000000..a5c3ffefa6 --- /dev/null +++ b/src/neo/SmartContract/WitnessVerifyStrategy.cs @@ -0,0 +1,9 @@ +namespace Neo.SmartContract +{ + public enum WitnessVerifyStrategy : byte + { + OnlyStateDependent = 0x1, + OnlyStateIndependent = 0x2, + All = 0x3 + } +} diff --git a/tests/neo.UnitTests/Ledger/UT_MemoryPool.cs b/tests/neo.UnitTests/Ledger/UT_MemoryPool.cs index 0e3f40bd09..9558e307f4 100644 --- a/tests/neo.UnitTests/Ledger/UT_MemoryPool.cs +++ b/tests/neo.UnitTests/Ledger/UT_MemoryPool.cs @@ -78,7 +78,7 @@ private Transaction CreateTransactionWithFee(long fee) mock.Setup(p => p.VerifyForEachBlockStateDependent(It.IsAny())).Returns(VerifyResult.Succeed); mock.Setup(p => p.Verify(It.IsAny(), It.IsAny())).Returns(VerifyResult.Succeed); mock.Setup(p => p.VerifyStateDependent(It.IsAny(), It.IsAny())).Returns(VerifyResult.Succeed); - mock.Setup(p => p.VerifyStateIndependent(It.IsAny(), It.IsAny())).Returns(VerifyResult.Succeed); + mock.Setup(p => p.VerifyStateIndependent(It.IsAny())).Returns(VerifyResult.Succeed); mock.Object.Script = randomBytes; mock.Object.Sender = UInt160.Zero; mock.Object.NetworkFee = fee; @@ -106,7 +106,7 @@ private Transaction CreateTransactionWithFeeAndBalanceVerify(long fee) mock.Setup(p => p.VerifyForEachBlockStateDependent(It.IsAny())).Returns(VerifyResult.Succeed); mock.Setup(p => p.Verify(It.IsAny(), It.IsAny())).Returns(VerifyResult.Succeed); mock.Setup(p => p.VerifyStateDependent(It.IsAny(), It.IsAny())).Returns((StoreView snapshot, BigInteger amount) => NativeContract.GAS.BalanceOf(snapshot, sender) >= amount + fee ? VerifyResult.Succeed : VerifyResult.InsufficientFunds); - mock.Setup(p => p.VerifyStateIndependent(It.IsAny(), It.IsAny())).Returns(VerifyResult.Succeed); + mock.Setup(p => p.VerifyStateIndependent(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 14252c38a8..d9dfe6f1bf 100644 --- a/tests/neo.UnitTests/Ledger/UT_SendersFeeMonitor.cs +++ b/tests/neo.UnitTests/Ledger/UT_SendersFeeMonitor.cs @@ -22,7 +22,7 @@ private Transaction CreateTransactionWithFee(long networkFee, long systemFee) mock.Setup(p => p.VerifyForEachBlockStateDependent(It.IsAny())).Returns(VerifyResult.Succeed); mock.Setup(p => p.Verify(It.IsAny(), It.IsAny())).Returns(VerifyResult.Succeed); mock.Setup(p => p.VerifyStateDependent(It.IsAny(), It.IsAny())).Returns(VerifyResult.Succeed); - mock.Setup(p => p.VerifyStateIndependent(It.IsAny(), It.IsAny())).Returns(VerifyResult.Succeed); + mock.Setup(p => p.VerifyStateIndependent(It.IsAny())).Returns(VerifyResult.Succeed); mock.Object.Script = randomBytes; mock.Object.Sender = UInt160.Zero; mock.Object.NetworkFee = networkFee; From 83ee355dccfce2f44d961c5d73d9a3ccfecaa526 Mon Sep 17 00:00:00 2001 From: Jin Qiao Date: Sat, 9 May 2020 16:45:32 +0800 Subject: [PATCH 16/55] Code optimization --- src/neo/SmartContract/Helper.cs | 62 ++++++++++++--------------------- 1 file changed, 23 insertions(+), 39 deletions(-) diff --git a/src/neo/SmartContract/Helper.cs b/src/neo/SmartContract/Helper.cs index c57dd02103..b1dfc1a1eb 100644 --- a/src/neo/SmartContract/Helper.cs +++ b/src/neo/SmartContract/Helper.cs @@ -145,49 +145,33 @@ internal static bool VerifyWitnesses(this IVerifiable verifiable, StoreView snap if (hashes.Length != verifiable.Witnesses.Length) return false; for (int i = 0; i < hashes.Length; i++) { - if (verifiable.Witnesses[i].IsStateDepedent && strategy != WitnessVerifyStrategy.OnlyStateIndependent) + int offset; + Witness witness = verifiable.Witnesses[i]; + byte[] verification = witness.VerificationScript; + if (witness.IsStateDepedent) { - if (!verifiable.VerifyWitnessStateDependent(snapshot, gas, hashes[i], verifiable.Witnesses[i])) - return false; + if (strategy == WitnessVerifyStrategy.OnlyStateIndependent) continue; + ContractState cs = snapshot.Contracts.TryGet(hashes[i]); + if (cs is null) return false; + ContractMethodDescriptor md = cs.Manifest.Abi.GetMethod("verify"); + if (md is null) return false; + verification = cs.Script; + offset = md.Offset; } - else if (!verifiable.Witnesses[i].IsStateDepedent && strategy != WitnessVerifyStrategy.OnlyStateDependent) + else { - if (!verifiable.VerifyWitnessStateIndependent(snapshot, gas, hashes[i], verifiable.Witnesses[i])) - return false; + if (strategy == WitnessVerifyStrategy.OnlyStateDependent) continue; + if (hashes[i] != verifiable.Witnesses[i].ScriptHash) return false; + offset = 0; + } + using (ApplicationEngine engine = new ApplicationEngine(TriggerType.Verification, verifiable, snapshot, gas)) + { + engine.LoadScript(verification, CallFlags.ReadOnly).InstructionPointer = offset; + engine.LoadScript(verifiable.Witnesses[i].InvocationScript, CallFlags.None); + if (engine.Execute() == VMState.FAULT) return false; + if (!engine.ResultStack.TryPop(out StackItem result) || !result.ToBoolean()) return false; + gas -= engine.GasConsumed; } - } - return true; - } - - internal static bool VerifyWitnessStateIndependent(this IVerifiable verifiable, StoreView snapshot, long gas, UInt160 hash, Witness witness) - { - if (hash != witness.ScriptHash) return false; - - using (ApplicationEngine engine = new ApplicationEngine(TriggerType.Verification, verifiable, snapshot, gas)) - { - engine.LoadScript(witness.VerificationScript, CallFlags.ReadOnly).InstructionPointer = 0; - engine.LoadScript(witness.InvocationScript, CallFlags.None); - if (engine.Execute() == VMState.FAULT) return false; - if (!engine.ResultStack.TryPop(out StackItem result) || !result.ToBoolean()) return false; - witness.GasConsumed = engine.GasConsumed; - } - return true; - } - - internal static bool VerifyWitnessStateDependent(this IVerifiable verifiable, StoreView snapshot, long gas, UInt160 hash, Witness witness) - { - ContractState cs = snapshot.Contracts.TryGet(hash); - if (cs is null) return false; - ContractMethodDescriptor md = cs.Manifest.Abi.GetMethod("verify"); - if (md is null) return false; - - using (ApplicationEngine engine = new ApplicationEngine(TriggerType.Verification, verifiable, snapshot, gas)) - { - engine.LoadScript(cs.Script, CallFlags.ReadOnly).InstructionPointer = md.Offset; - engine.LoadScript(witness.InvocationScript, CallFlags.None); - if (engine.Execute() == VMState.FAULT) return false; - if (!engine.ResultStack.TryPop(out StackItem result) || !result.ToBoolean()) return false; - witness.GasConsumed = engine.GasConsumed; } return true; } From 5c103262f37dd393be79be010867d4d7d89e9d9c Mon Sep 17 00:00:00 2001 From: Qiao Jin <43407364+Qiao-Jin@users.noreply.github.com> Date: Sat, 9 May 2020 17:05:29 +0800 Subject: [PATCH 17/55] Update src/neo/Network/P2P/Payloads/Witness.cs Co-authored-by: Luchuan --- src/neo/Network/P2P/Payloads/Witness.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/neo/Network/P2P/Payloads/Witness.cs b/src/neo/Network/P2P/Payloads/Witness.cs index fe06290898..f041b34b10 100644 --- a/src/neo/Network/P2P/Payloads/Witness.cs +++ b/src/neo/Network/P2P/Payloads/Witness.cs @@ -50,7 +50,7 @@ public JObject ToJson() return json; } - private int _stateDependent = -1; + private Boolean _IsStandardWitness; public bool IsStateDepedent { From f78503ed58296df00eb2dac1469e33532c5e4da3 Mon Sep 17 00:00:00 2001 From: Qiao Jin <43407364+Qiao-Jin@users.noreply.github.com> Date: Sat, 9 May 2020 17:05:45 +0800 Subject: [PATCH 18/55] Update src/neo/Network/P2P/Payloads/Witness.cs Co-authored-by: Luchuan --- src/neo/Network/P2P/Payloads/Witness.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/neo/Network/P2P/Payloads/Witness.cs b/src/neo/Network/P2P/Payloads/Witness.cs index f041b34b10..8cf4959052 100644 --- a/src/neo/Network/P2P/Payloads/Witness.cs +++ b/src/neo/Network/P2P/Payloads/Witness.cs @@ -52,7 +52,7 @@ public JObject ToJson() private Boolean _IsStandardWitness; - public bool IsStateDepedent + public bool IsStandardWitness { get { From 64d2a3f45e06e896f15033b2b6de52d53a95a73a Mon Sep 17 00:00:00 2001 From: Qiao Jin <43407364+Qiao-Jin@users.noreply.github.com> Date: Sat, 9 May 2020 17:08:47 +0800 Subject: [PATCH 19/55] Update src/neo/Network/P2P/Payloads/Witness.cs Co-authored-by: Luchuan --- src/neo/Network/P2P/Payloads/Witness.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/neo/Network/P2P/Payloads/Witness.cs b/src/neo/Network/P2P/Payloads/Witness.cs index 8cf4959052..b26d05d63e 100644 --- a/src/neo/Network/P2P/Payloads/Witness.cs +++ b/src/neo/Network/P2P/Payloads/Witness.cs @@ -56,7 +56,8 @@ public bool IsStandardWitness { get { - switch (_stateDependent) + _IsStandardWitness??= VerificationScript.IsStandardContract(); + return _IsStandardWitness; { case 0: return false; From 5bea75d48e607648f68445d39b3fa1dd6ea58708 Mon Sep 17 00:00:00 2001 From: Jin Qiao Date: Sat, 9 May 2020 17:20:53 +0800 Subject: [PATCH 20/55] Revert "Update src/neo/Network/P2P/Payloads/Witness.cs" This reverts commit 5c103262f37dd393be79be010867d4d7d89e9d9c. --- src/neo/Network/P2P/Payloads/Witness.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/neo/Network/P2P/Payloads/Witness.cs b/src/neo/Network/P2P/Payloads/Witness.cs index b26d05d63e..33f8f22b1b 100644 --- a/src/neo/Network/P2P/Payloads/Witness.cs +++ b/src/neo/Network/P2P/Payloads/Witness.cs @@ -50,7 +50,7 @@ public JObject ToJson() return json; } - private Boolean _IsStandardWitness; + private int _stateDependent = -1; public bool IsStandardWitness { From a4b38f0fb64ce054032cae23eea05dcd50e8a681 Mon Sep 17 00:00:00 2001 From: Jin Qiao Date: Sat, 9 May 2020 17:21:14 +0800 Subject: [PATCH 21/55] Revert "Update src/neo/Network/P2P/Payloads/Witness.cs" This reverts commit 64d2a3f45e06e896f15033b2b6de52d53a95a73a. --- src/neo/Network/P2P/Payloads/Witness.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/neo/Network/P2P/Payloads/Witness.cs b/src/neo/Network/P2P/Payloads/Witness.cs index 33f8f22b1b..a5319f48c9 100644 --- a/src/neo/Network/P2P/Payloads/Witness.cs +++ b/src/neo/Network/P2P/Payloads/Witness.cs @@ -56,8 +56,7 @@ public bool IsStandardWitness { get { - _IsStandardWitness??= VerificationScript.IsStandardContract(); - return _IsStandardWitness; + switch (_stateDependent) { case 0: return false; From f119e181a7c1889c44a9afc0c8d5aa77305275d4 Mon Sep 17 00:00:00 2001 From: Jin Qiao Date: Sat, 9 May 2020 17:21:48 +0800 Subject: [PATCH 22/55] Revert "Update src/neo/Network/P2P/Payloads/Witness.cs" This reverts commit f78503ed58296df00eb2dac1469e33532c5e4da3. --- src/neo/Network/P2P/Payloads/Witness.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/neo/Network/P2P/Payloads/Witness.cs b/src/neo/Network/P2P/Payloads/Witness.cs index a5319f48c9..fe06290898 100644 --- a/src/neo/Network/P2P/Payloads/Witness.cs +++ b/src/neo/Network/P2P/Payloads/Witness.cs @@ -52,7 +52,7 @@ public JObject ToJson() private int _stateDependent = -1; - public bool IsStandardWitness + public bool IsStateDepedent { get { From 47567ae06d00ba8ba3568d0ebbbed462f7d82174 Mon Sep 17 00:00:00 2001 From: Luchuan Date: Sat, 9 May 2020 22:10:58 +0800 Subject: [PATCH 23/55] optimize Witness --- src/neo/Network/P2P/Payloads/Witness.cs | 23 +++++------------------ 1 file changed, 5 insertions(+), 18 deletions(-) diff --git a/src/neo/Network/P2P/Payloads/Witness.cs b/src/neo/Network/P2P/Payloads/Witness.cs index fe06290898..dec02de105 100644 --- a/src/neo/Network/P2P/Payloads/Witness.cs +++ b/src/neo/Network/P2P/Payloads/Witness.cs @@ -50,30 +50,17 @@ public JObject ToJson() return json; } - private int _stateDependent = -1; + private int _isStandardWitness; - public bool IsStateDepedent + public bool IsStandardWitness { get { - switch (_stateDependent) + if (_isStandardWitness == 0) { - case 0: - return false; - case 1: - return true; - default: - if (VerificationScript.Length == 0 || !VerificationScript.IsStandardContract()) - { - _stateDependent = 1; - return true; - } - else - { - _stateDependent = 0; - return false; - } + _isStandardWitness = VerificationScript.IsStandardContract() ? 1 : -1; } + return _isStandardWitness == 1; } } } From e0a57522d6fa854f4393564a69d41d880817d353 Mon Sep 17 00:00:00 2001 From: Luchuan Date: Sat, 9 May 2020 23:46:44 +0800 Subject: [PATCH 24/55] optimize witness and IVerifiable.verifyWitness --- src/neo/Network/P2P/Payloads/Transaction.cs | 8 ++++---- src/neo/Network/P2P/Payloads/Witness.cs | 11 +++++------ src/neo/Network/P2P/RemoteNode.ProtocolHandler.cs | 2 +- src/neo/SmartContract/Helper.cs | 10 +++++----- src/neo/SmartContract/InteropService.Contract.cs | 2 +- src/neo/SmartContract/InteropService.Runtime.cs | 2 +- src/neo/SmartContract/WitnessFlag.cs | 15 +++++++++++++++ src/neo/SmartContract/WitnessVerifyStrategy.cs | 9 --------- tests/neo.UnitTests/Ledger/UT_MemoryPool.cs | 4 ++-- .../neo.UnitTests/Ledger/UT_SendersFeeMonitor.cs | 2 +- 10 files changed, 35 insertions(+), 30 deletions(-) create mode 100644 src/neo/SmartContract/WitnessFlag.cs delete mode 100644 src/neo/SmartContract/WitnessVerifyStrategy.cs diff --git a/src/neo/Network/P2P/Payloads/Transaction.cs b/src/neo/Network/P2P/Payloads/Transaction.cs index 06dedf0592..f61aa2c75f 100644 --- a/src/neo/Network/P2P/Payloads/Transaction.cs +++ b/src/neo/Network/P2P/Payloads/Transaction.cs @@ -277,7 +277,7 @@ public virtual VerifyResult VerifyStateDependent(StoreView snapshot, BigInteger BigInteger balance = NativeContract.GAS.BalanceOf(snapshot, Sender); BigInteger fee = SystemFee + NetworkFee + totalSenderFeeFromPool; if (balance < fee) return VerifyResult.InsufficientFunds; - if (!this.VerifyWitnesses(snapshot, net_fee, WitnessVerifyStrategy.OnlyStateDependent)) return VerifyResult.Invalid; + if (!this.VerifyWitnesses(snapshot, net_fee, WitnessFlag.NonStandardWitness)) return VerifyResult.Invalid; //Check all gas consumed for state dependent and independent witnesses long gasConsumed = 0; @@ -287,10 +287,10 @@ public virtual VerifyResult VerifyStateDependent(StoreView snapshot, BigInteger return VerifyResult.Succeed; } - public virtual VerifyResult VerifyStateIndependent(StoreView snapshot) + public virtual VerifyResult VerifyStateIndependent() { if (Size > MaxTransactionSize) return VerifyResult.Invalid; - if (!this.VerifyWitnesses(snapshot, NetworkFee, WitnessVerifyStrategy.OnlyStateIndependent)) return VerifyResult.Invalid; + if (!this.VerifyWitnesses(null, NetworkFee, WitnessFlag.StandardWitness)) return VerifyResult.Invalid; return VerifyResult.Succeed; } @@ -298,7 +298,7 @@ public virtual VerifyResult Verify(StoreView snapshot, BigInteger totalSenderFee { VerifyResult result = VerifyStateDependent(snapshot, totalSenderFeeFromPool); if (result != VerifyResult.Succeed) return result; - result = VerifyStateIndependent(snapshot); + result = VerifyStateIndependent(); return result; } diff --git a/src/neo/Network/P2P/Payloads/Witness.cs b/src/neo/Network/P2P/Payloads/Witness.cs index dec02de105..72bc8368bc 100644 --- a/src/neo/Network/P2P/Payloads/Witness.cs +++ b/src/neo/Network/P2P/Payloads/Witness.cs @@ -50,17 +50,16 @@ public JObject ToJson() return json; } - private int _isStandardWitness; - - public bool IsStandardWitness + private WitnessFlag _flag = WitnessFlag.None; + public WitnessFlag Flag { get { - if (_isStandardWitness == 0) + if (_flag == WitnessFlag.None) { - _isStandardWitness = VerificationScript.IsStandardContract() ? 1 : -1; + _flag = VerificationScript.IsStandardContract() ? WitnessFlag.StandardWitness : WitnessFlag.NonStandardWitness; } - return _isStandardWitness == 1; + return _flag; } } } diff --git a/src/neo/Network/P2P/RemoteNode.ProtocolHandler.cs b/src/neo/Network/P2P/RemoteNode.ProtocolHandler.cs index 2442dccc08..cde1ab35b8 100644 --- a/src/neo/Network/P2P/RemoteNode.ProtocolHandler.cs +++ b/src/neo/Network/P2P/RemoteNode.ProtocolHandler.cs @@ -113,7 +113,7 @@ private void OnMessage(Message msg) if (msg.Payload.Size <= Transaction.MaxTransactionSize) { Transaction tx = (Transaction)msg.Payload; - if (tx.VerifyStateIndependent(Blockchain.Singleton.CurrentSnapshot) == VerifyResult.Succeed) + if (tx.VerifyStateIndependent() == VerifyResult.Succeed) OnInventoryReceived(tx); } }); diff --git a/src/neo/SmartContract/Helper.cs b/src/neo/SmartContract/Helper.cs index b1dfc1a1eb..bf20c2d4cb 100644 --- a/src/neo/SmartContract/Helper.cs +++ b/src/neo/SmartContract/Helper.cs @@ -129,7 +129,7 @@ public static UInt160 ToScriptHash(this ReadOnlySpan script) return new UInt160(Crypto.Hash160(script)); } - internal static bool VerifyWitnesses(this IVerifiable verifiable, StoreView snapshot, long gas, WitnessVerifyStrategy strategy = WitnessVerifyStrategy.All) + internal static bool VerifyWitnesses(this IVerifiable verifiable, StoreView snapshot, long gas, WitnessFlag filter = WitnessFlag.All) { if (gas < 0) return false; @@ -145,12 +145,13 @@ internal static bool VerifyWitnesses(this IVerifiable verifiable, StoreView snap if (hashes.Length != verifiable.Witnesses.Length) return false; for (int i = 0; i < hashes.Length; i++) { - int offset; Witness witness = verifiable.Witnesses[i]; + if (!filter.HasFlag(witness.Flag)) continue; + + int offset; byte[] verification = witness.VerificationScript; - if (witness.IsStateDepedent) + if (verification.Length == 0) { - if (strategy == WitnessVerifyStrategy.OnlyStateIndependent) continue; ContractState cs = snapshot.Contracts.TryGet(hashes[i]); if (cs is null) return false; ContractMethodDescriptor md = cs.Manifest.Abi.GetMethod("verify"); @@ -160,7 +161,6 @@ internal static bool VerifyWitnesses(this IVerifiable verifiable, StoreView snap } else { - if (strategy == WitnessVerifyStrategy.OnlyStateDependent) continue; if (hashes[i] != verifiable.Witnesses[i].ScriptHash) return false; offset = 0; } diff --git a/src/neo/SmartContract/InteropService.Contract.cs b/src/neo/SmartContract/InteropService.Contract.cs index 36b3cad6ad..069af89d3f 100644 --- a/src/neo/SmartContract/InteropService.Contract.cs +++ b/src/neo/SmartContract/InteropService.Contract.cs @@ -23,7 +23,7 @@ public static class Contract public static readonly InteropDescriptor Destroy = Register("System.Contract.Destroy", Contract_Destroy, 0_01000000, TriggerType.Application, CallFlags.AllowModifyStates); public static readonly InteropDescriptor Call = Register("System.Contract.Call", Contract_Call, 0_01000000, TriggerType.System | TriggerType.Application, CallFlags.AllowCall); public static readonly InteropDescriptor CallEx = Register("System.Contract.CallEx", Contract_CallEx, 0_01000000, TriggerType.System | TriggerType.Application, CallFlags.AllowCall); - public static readonly InteropDescriptor IsStandard = Register("System.Contract.IsStandard", Contract_IsStandard, 0_00030000, TriggerType.All, CallFlags.None); + public static readonly InteropDescriptor IsStandard = Register("System.Contract.IsStandard", Contract_IsStandard, 0_00030000, TriggerType.System | TriggerType.Application, CallFlags.None); public static readonly InteropDescriptor GetCallFlags = Register("System.Contract.GetCallFlags", Contract_GetCallFlags, 0_00030000, TriggerType.All, CallFlags.None); /// diff --git a/src/neo/SmartContract/InteropService.Runtime.cs b/src/neo/SmartContract/InteropService.Runtime.cs index ff58e0a897..4b57c41197 100644 --- a/src/neo/SmartContract/InteropService.Runtime.cs +++ b/src/neo/SmartContract/InteropService.Runtime.cs @@ -24,7 +24,7 @@ public static class Runtime public static readonly InteropDescriptor GetExecutingScriptHash = Register("System.Runtime.GetExecutingScriptHash", Runtime_GetExecutingScriptHash, 0_00000400, TriggerType.All, CallFlags.None); public static readonly InteropDescriptor GetCallingScriptHash = Register("System.Runtime.GetCallingScriptHash", Runtime_GetCallingScriptHash, 0_00000400, TriggerType.All, CallFlags.None); public static readonly InteropDescriptor GetEntryScriptHash = Register("System.Runtime.GetEntryScriptHash", Runtime_GetEntryScriptHash, 0_00000400, TriggerType.All, CallFlags.None); - public static readonly InteropDescriptor CheckWitness = Register("System.Runtime.CheckWitness", Runtime_CheckWitness, 0_00030000, TriggerType.All, CallFlags.AllowStates); + public static readonly InteropDescriptor CheckWitness = Register("System.Runtime.CheckWitness", Runtime_CheckWitness, 0_00030000, TriggerType.System | TriggerType.Application, CallFlags.AllowStates); public static readonly InteropDescriptor GetInvocationCounter = Register("System.Runtime.GetInvocationCounter", Runtime_GetInvocationCounter, 0_00000400, TriggerType.All, CallFlags.None); public static readonly InteropDescriptor Log = Register("System.Runtime.Log", Runtime_Log, 0_01000000, TriggerType.All, CallFlags.AllowNotify); public static readonly InteropDescriptor Notify = Register("System.Runtime.Notify", Runtime_Notify, 0_01000000, TriggerType.All, CallFlags.AllowNotify); diff --git a/src/neo/SmartContract/WitnessFlag.cs b/src/neo/SmartContract/WitnessFlag.cs new file mode 100644 index 0000000000..964ddd3bb1 --- /dev/null +++ b/src/neo/SmartContract/WitnessFlag.cs @@ -0,0 +1,15 @@ +using System; + +namespace Neo.SmartContract +{ + [Flags] + public enum WitnessFlag : byte + { + None = 0, + + StandardWitness = 0b00000001, + NonStandardWitness = 0b00000010, + + All = StandardWitness | NonStandardWitness + } +} diff --git a/src/neo/SmartContract/WitnessVerifyStrategy.cs b/src/neo/SmartContract/WitnessVerifyStrategy.cs deleted file mode 100644 index a5c3ffefa6..0000000000 --- a/src/neo/SmartContract/WitnessVerifyStrategy.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace Neo.SmartContract -{ - public enum WitnessVerifyStrategy : byte - { - OnlyStateDependent = 0x1, - OnlyStateIndependent = 0x2, - All = 0x3 - } -} diff --git a/tests/neo.UnitTests/Ledger/UT_MemoryPool.cs b/tests/neo.UnitTests/Ledger/UT_MemoryPool.cs index 8ac0acc377..1b8e767615 100644 --- a/tests/neo.UnitTests/Ledger/UT_MemoryPool.cs +++ b/tests/neo.UnitTests/Ledger/UT_MemoryPool.cs @@ -78,7 +78,7 @@ private Transaction CreateTransactionWithFee(long fee) mock.Setup(p => p.VerifyForEachBlockStateDependent(It.IsAny())).Returns(VerifyResult.Succeed); mock.Setup(p => p.Verify(It.IsAny(), It.IsAny())).Returns(VerifyResult.Succeed); mock.Setup(p => p.VerifyStateDependent(It.IsAny(), It.IsAny())).Returns(VerifyResult.Succeed); - mock.Setup(p => p.VerifyStateIndependent(It.IsAny())).Returns(VerifyResult.Succeed); + mock.Setup(p => p.VerifyStateIndependent()).Returns(VerifyResult.Succeed); mock.Object.Script = randomBytes; mock.Object.Sender = UInt160.Zero; mock.Object.NetworkFee = fee; @@ -105,7 +105,7 @@ private Transaction CreateTransactionWithFeeAndBalanceVerify(long fee) mock.Setup(p => p.VerifyForEachBlockStateDependent(It.IsAny())).Returns(VerifyResult.Succeed); mock.Setup(p => p.Verify(It.IsAny(), It.IsAny())).Returns(VerifyResult.Succeed); mock.Setup(p => p.VerifyStateDependent(It.IsAny(), It.IsAny())).Returns((StoreView snapshot, BigInteger amount) => NativeContract.GAS.BalanceOf(snapshot, sender) >= amount + fee ? VerifyResult.Succeed : VerifyResult.InsufficientFunds); - mock.Setup(p => p.VerifyStateIndependent(It.IsAny())).Returns(VerifyResult.Succeed); + mock.Setup(p => p.VerifyStateIndependent()).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 54c4c024f5..d88941501f 100644 --- a/tests/neo.UnitTests/Ledger/UT_SendersFeeMonitor.cs +++ b/tests/neo.UnitTests/Ledger/UT_SendersFeeMonitor.cs @@ -22,7 +22,7 @@ private Transaction CreateTransactionWithFee(long networkFee, long systemFee) mock.Setup(p => p.VerifyForEachBlockStateDependent(It.IsAny())).Returns(VerifyResult.Succeed); mock.Setup(p => p.Verify(It.IsAny(), It.IsAny())).Returns(VerifyResult.Succeed); mock.Setup(p => p.VerifyStateDependent(It.IsAny(), It.IsAny())).Returns(VerifyResult.Succeed); - mock.Setup(p => p.VerifyStateIndependent(It.IsAny())).Returns(VerifyResult.Succeed); + mock.Setup(p => p.VerifyStateIndependent()).Returns(VerifyResult.Succeed); mock.Object.Script = randomBytes; mock.Object.Sender = UInt160.Zero; mock.Object.NetworkFee = networkFee; From 406e1d01d51bed6b4d775e05d05e7e3413988bfb Mon Sep 17 00:00:00 2001 From: Luchuan Date: Sat, 9 May 2020 23:49:28 +0800 Subject: [PATCH 25/55] fix tx.Verify --- src/neo/Network/P2P/Payloads/Transaction.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/neo/Network/P2P/Payloads/Transaction.cs b/src/neo/Network/P2P/Payloads/Transaction.cs index f61aa2c75f..fd694c9012 100644 --- a/src/neo/Network/P2P/Payloads/Transaction.cs +++ b/src/neo/Network/P2P/Payloads/Transaction.cs @@ -296,9 +296,9 @@ public virtual VerifyResult VerifyStateIndependent() public virtual VerifyResult Verify(StoreView snapshot, BigInteger totalSenderFeeFromPool) { - VerifyResult result = VerifyStateDependent(snapshot, totalSenderFeeFromPool); + VerifyResult result = VerifyStateIndependent(); if (result != VerifyResult.Succeed) return result; - result = VerifyStateIndependent(); + result = VerifyStateDependent(snapshot, totalSenderFeeFromPool); return result; } From 116b59a9b0568e8538f6b3af325ac1a5cee743d8 Mon Sep 17 00:00:00 2001 From: Luchuan Date: Sun, 10 May 2020 00:03:53 +0800 Subject: [PATCH 26/55] optimize code --- src/neo/Ledger/Blockchain.cs | 7 ------- src/neo/SmartContract/Helper.cs | 4 ++-- 2 files changed, 2 insertions(+), 9 deletions(-) diff --git a/src/neo/Ledger/Blockchain.cs b/src/neo/Ledger/Blockchain.cs index 6c3f04579e..cfc995fb2d 100644 --- a/src/neo/Ledger/Blockchain.cs +++ b/src/neo/Ledger/Blockchain.cs @@ -66,13 +66,6 @@ public class RelayResult { public IInventory Inventory; public VerifyResult Resu private readonly Dictionary> block_cache_unverified = new Dictionary>(); internal readonly RelayCache ConsensusRelayCache = new RelayCache(100); private SnapshotView currentSnapshot; - public SnapshotView CurrentSnapshot - { - get - { - return currentSnapshot; - } - } public IStore Store { get; } public ReadOnlyView View { get; } diff --git a/src/neo/SmartContract/Helper.cs b/src/neo/SmartContract/Helper.cs index bf20c2d4cb..bbdccbb2c5 100644 --- a/src/neo/SmartContract/Helper.cs +++ b/src/neo/SmartContract/Helper.cs @@ -161,13 +161,13 @@ internal static bool VerifyWitnesses(this IVerifiable verifiable, StoreView snap } else { - if (hashes[i] != verifiable.Witnesses[i].ScriptHash) return false; + if (hashes[i] != witness.ScriptHash) return false; offset = 0; } using (ApplicationEngine engine = new ApplicationEngine(TriggerType.Verification, verifiable, snapshot, gas)) { engine.LoadScript(verification, CallFlags.ReadOnly).InstructionPointer = offset; - engine.LoadScript(verifiable.Witnesses[i].InvocationScript, CallFlags.None); + engine.LoadScript(witness.InvocationScript, CallFlags.None); if (engine.Execute() == VMState.FAULT) return false; if (!engine.ResultStack.TryPop(out StackItem result) || !result.ToBoolean()) return false; gas -= engine.GasConsumed; From fb9853a0913dc5c3b448230fbaedc2be7d8c09ee Mon Sep 17 00:00:00 2001 From: Luchuan Date: Sun, 10 May 2020 00:13:18 +0800 Subject: [PATCH 27/55] optimize tx.GetScriptHashesForVerifying --- src/neo/Network/P2P/Payloads/Transaction.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/neo/Network/P2P/Payloads/Transaction.cs b/src/neo/Network/P2P/Payloads/Transaction.cs index fd694c9012..8a30f21a41 100644 --- a/src/neo/Network/P2P/Payloads/Transaction.cs +++ b/src/neo/Network/P2P/Payloads/Transaction.cs @@ -197,7 +197,7 @@ public override int GetHashCode() return Hash.GetHashCode(); } - public UInt160[] GetScriptHashesForVerifying(StoreView snapshot) + public UInt160[] GetScriptHashesForVerifying(StoreView snapshot = null) { var hashes = new HashSet { Sender }; hashes.UnionWith(Cosigners.Select(p => p.Account)); @@ -256,7 +256,7 @@ public virtual VerifyResult VerifyForEachBlockStateDependent(StoreView snapshot) { if (ValidUntilBlock <= snapshot.Height || ValidUntilBlock > snapshot.Height + MaxValidUntilBlockIncrement) return VerifyResult.Expired; - UInt160[] hashes = GetScriptHashesForVerifying(snapshot); + UInt160[] hashes = GetScriptHashesForVerifying(); if (NativeContract.Policy.GetBlockedAccounts(snapshot).Intersect(hashes).Any()) return VerifyResult.PolicyFail; if (hashes.Length != Witnesses.Length) return VerifyResult.Invalid; From b8c139e90f8b35ce2d61a23473f6f6fb1a5c412f Mon Sep 17 00:00:00 2001 From: Luchuan Date: Sun, 10 May 2020 00:27:59 +0800 Subject: [PATCH 28/55] Remove verifyForEachBlock --- src/neo/Ledger/MemoryPool.cs | 2 +- src/neo/Ledger/VerifyResult.cs | 1 + src/neo/Network/P2P/Payloads/Transaction.cs | 33 +++++-------------- tests/neo.UnitTests/Ledger/UT_MemoryPool.cs | 4 --- .../Ledger/UT_SendersFeeMonitor.cs | 2 -- .../Network/P2P/Payloads/UT_Transaction.cs | 2 +- 6 files changed, 11 insertions(+), 33 deletions(-) diff --git a/src/neo/Ledger/MemoryPool.cs b/src/neo/Ledger/MemoryPool.cs index 62466d65e8..6e2ac1fdf1 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)) == VerifyResult.Succeed) + if (item.Tx.VerifyStateDependent(snapshot, SendersFeeMonitor.GetSenderFee(item.Tx.Sender)) == VerifyResult.Succeed) { reverifiedItems.Add(item); SendersFeeMonitor.AddSenderFee(item.Tx); diff --git a/src/neo/Ledger/VerifyResult.cs b/src/neo/Ledger/VerifyResult.cs index ab5c1f673e..1c276099f5 100644 --- a/src/neo/Ledger/VerifyResult.cs +++ b/src/neo/Ledger/VerifyResult.cs @@ -9,6 +9,7 @@ public enum VerifyResult : byte Invalid, Expired, InsufficientFunds, + InsufficientFee, PolicyFail, Unknown } diff --git a/src/neo/Network/P2P/Payloads/Transaction.cs b/src/neo/Network/P2P/Payloads/Transaction.cs index 8a30f21a41..cef1e7b413 100644 --- a/src/neo/Network/P2P/Payloads/Transaction.cs +++ b/src/neo/Network/P2P/Payloads/Transaction.cs @@ -244,46 +244,29 @@ bool IInventory.Verify(StoreView snapshot) return Verify(snapshot, BigInteger.Zero) == VerifyResult.Succeed; } - public virtual VerifyResult VerifyForEachBlock(StoreView snapshot, BigInteger totalSenderFeeFromPool) - { - VerifyResult result = VerifyStateDependent(snapshot, totalSenderFeeFromPool); - if (result != VerifyResult.Succeed) return result; - result = VerifyForEachBlockStateDependent(snapshot); - return result; - } - - public virtual VerifyResult VerifyForEachBlockStateDependent(StoreView snapshot) + public virtual VerifyResult VerifyStateDependent(StoreView snapshot, BigInteger totalSenderFeeFromPool) { if (ValidUntilBlock <= snapshot.Height || ValidUntilBlock > snapshot.Height + MaxValidUntilBlockIncrement) return VerifyResult.Expired; UInt160[] hashes = GetScriptHashesForVerifying(); if (NativeContract.Policy.GetBlockedAccounts(snapshot).Intersect(hashes).Any()) return VerifyResult.PolicyFail; - 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 VerifyResult.Invalid; - } - return VerifyResult.Succeed; - } - - public virtual VerifyResult VerifyStateDependent(StoreView snapshot, BigInteger totalSenderFeeFromPool) - { - VerifyResult result = VerifyForEachBlockStateDependent(snapshot); - if (result != VerifyResult.Succeed) return result; long net_fee = NetworkFee - Size * NativeContract.Policy.GetFeePerByte(snapshot); - if (net_fee < 0) return VerifyResult.InsufficientFunds; + if (net_fee < 0) + return VerifyResult.InsufficientFunds; + BigInteger balance = NativeContract.GAS.BalanceOf(snapshot, Sender); BigInteger fee = SystemFee + NetworkFee + totalSenderFeeFromPool; if (balance < fee) return VerifyResult.InsufficientFunds; - if (!this.VerifyWitnesses(snapshot, net_fee, WitnessFlag.NonStandardWitness)) return VerifyResult.Invalid; + if (!this.VerifyWitnesses(snapshot, net_fee, WitnessFlag.NonStandardWitness)) + return VerifyResult.Invalid; //Check all gas consumed for state dependent and independent witnesses long gasConsumed = 0; foreach (Witness witness in witnesses) gasConsumed += witness.GasConsumed; - if (gasConsumed > net_fee) return VerifyResult.Invalid; + if (gasConsumed > net_fee) + return VerifyResult.InsufficientFee; return VerifyResult.Succeed; } diff --git a/tests/neo.UnitTests/Ledger/UT_MemoryPool.cs b/tests/neo.UnitTests/Ledger/UT_MemoryPool.cs index 1b8e767615..3771a3333e 100644 --- a/tests/neo.UnitTests/Ledger/UT_MemoryPool.cs +++ b/tests/neo.UnitTests/Ledger/UT_MemoryPool.cs @@ -74,8 +74,6 @@ 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(VerifyResult.Succeed); - mock.Setup(p => p.VerifyForEachBlockStateDependent(It.IsAny())).Returns(VerifyResult.Succeed); mock.Setup(p => p.Verify(It.IsAny(), It.IsAny())).Returns(VerifyResult.Succeed); mock.Setup(p => p.VerifyStateDependent(It.IsAny(), It.IsAny())).Returns(VerifyResult.Succeed); mock.Setup(p => p.VerifyStateIndependent()).Returns(VerifyResult.Succeed); @@ -101,8 +99,6 @@ 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 ? VerifyResult.Succeed : VerifyResult.InsufficientFunds); - mock.Setup(p => p.VerifyForEachBlockStateDependent(It.IsAny())).Returns(VerifyResult.Succeed); mock.Setup(p => p.Verify(It.IsAny(), It.IsAny())).Returns(VerifyResult.Succeed); mock.Setup(p => p.VerifyStateDependent(It.IsAny(), It.IsAny())).Returns((StoreView snapshot, BigInteger amount) => NativeContract.GAS.BalanceOf(snapshot, sender) >= amount + fee ? VerifyResult.Succeed : VerifyResult.InsufficientFunds); mock.Setup(p => p.VerifyStateIndependent()).Returns(VerifyResult.Succeed); diff --git a/tests/neo.UnitTests/Ledger/UT_SendersFeeMonitor.cs b/tests/neo.UnitTests/Ledger/UT_SendersFeeMonitor.cs index d88941501f..515dc42b7d 100644 --- a/tests/neo.UnitTests/Ledger/UT_SendersFeeMonitor.cs +++ b/tests/neo.UnitTests/Ledger/UT_SendersFeeMonitor.cs @@ -18,8 +18,6 @@ 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(VerifyResult.Succeed); - mock.Setup(p => p.VerifyForEachBlockStateDependent(It.IsAny())).Returns(VerifyResult.Succeed); mock.Setup(p => p.Verify(It.IsAny(), It.IsAny())).Returns(VerifyResult.Succeed); mock.Setup(p => p.VerifyStateDependent(It.IsAny(), It.IsAny())).Returns(VerifyResult.Succeed); mock.Setup(p => p.VerifyStateIndependent()).Returns(VerifyResult.Succeed); diff --git a/tests/neo.UnitTests/Network/P2P/Payloads/UT_Transaction.cs b/tests/neo.UnitTests/Network/P2P/Payloads/UT_Transaction.cs index 4267f8931e..5e2538a2ec 100644 --- a/tests/neo.UnitTests/Network/P2P/Payloads/UT_Transaction.cs +++ b/tests/neo.UnitTests/Network/P2P/Payloads/UT_Transaction.cs @@ -747,7 +747,7 @@ public void Transaction_Reverify_Hashes_Length_Unequal_To_Witnesses_Length() }; UInt160[] hashes = txSimple.GetScriptHashesForVerifying(snapshot); Assert.AreEqual(2, hashes.Length); - Assert.AreNotEqual(VerifyResult.Succeed, txSimple.VerifyForEachBlock(snapshot, BigInteger.Zero)); + Assert.AreNotEqual(VerifyResult.Succeed, txSimple.VerifyStateDependent(snapshot, BigInteger.Zero)); } [TestMethod] From 33a70fc452fcecfac3ccae038c1b06f916e6bca7 Mon Sep 17 00:00:00 2001 From: Luchuan Date: Sun, 10 May 2020 00:42:07 +0800 Subject: [PATCH 29/55] add VerifyResult.InvalidWitness --- src/neo/Ledger/VerifyResult.cs | 1 + src/neo/Network/P2P/Payloads/Transaction.cs | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/neo/Ledger/VerifyResult.cs b/src/neo/Ledger/VerifyResult.cs index 1c276099f5..3767a23d29 100644 --- a/src/neo/Ledger/VerifyResult.cs +++ b/src/neo/Ledger/VerifyResult.cs @@ -7,6 +7,7 @@ public enum VerifyResult : byte OutOfMemory, UnableToVerify, Invalid, + InvalidWitness, Expired, InsufficientFunds, InsufficientFee, diff --git a/src/neo/Network/P2P/Payloads/Transaction.cs b/src/neo/Network/P2P/Payloads/Transaction.cs index cef1e7b413..b2100228fa 100644 --- a/src/neo/Network/P2P/Payloads/Transaction.cs +++ b/src/neo/Network/P2P/Payloads/Transaction.cs @@ -259,7 +259,7 @@ public virtual VerifyResult VerifyStateDependent(StoreView snapshot, BigInteger BigInteger fee = SystemFee + NetworkFee + totalSenderFeeFromPool; if (balance < fee) return VerifyResult.InsufficientFunds; if (!this.VerifyWitnesses(snapshot, net_fee, WitnessFlag.NonStandardWitness)) - return VerifyResult.Invalid; + return VerifyResult.InvalidWitness; //Check all gas consumed for state dependent and independent witnesses long gasConsumed = 0; @@ -273,7 +273,7 @@ public virtual VerifyResult VerifyStateDependent(StoreView snapshot, BigInteger public virtual VerifyResult VerifyStateIndependent() { if (Size > MaxTransactionSize) return VerifyResult.Invalid; - if (!this.VerifyWitnesses(null, NetworkFee, WitnessFlag.StandardWitness)) return VerifyResult.Invalid; + if (!this.VerifyWitnesses(null, NetworkFee, WitnessFlag.StandardWitness)) return VerifyResult.InvalidWitness; return VerifyResult.Succeed; } From e263a0665459e983dc6ba405bd49de2faa16a57a Mon Sep 17 00:00:00 2001 From: Luchuan Date: Sun, 10 May 2020 00:46:43 +0800 Subject: [PATCH 30/55] Disallow witness.verificationScript to access the snapshot --- src/neo/SmartContract/Helper.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/neo/SmartContract/Helper.cs b/src/neo/SmartContract/Helper.cs index bbdccbb2c5..749de56515 100644 --- a/src/neo/SmartContract/Helper.cs +++ b/src/neo/SmartContract/Helper.cs @@ -164,7 +164,7 @@ internal static bool VerifyWitnesses(this IVerifiable verifiable, StoreView snap if (hashes[i] != witness.ScriptHash) return false; offset = 0; } - using (ApplicationEngine engine = new ApplicationEngine(TriggerType.Verification, verifiable, snapshot, gas)) + using (ApplicationEngine engine = new ApplicationEngine(TriggerType.Verification, verifiable, null, gas)) { engine.LoadScript(verification, CallFlags.ReadOnly).InstructionPointer = offset; engine.LoadScript(witness.InvocationScript, CallFlags.None); From 2016da99b3b4650484edd72986215f38393c7e35 Mon Sep 17 00:00:00 2001 From: Luchuan Date: Sun, 10 May 2020 00:56:31 +0800 Subject: [PATCH 31/55] Optimize tx.VerifyStateDependent and verifiable.VerifyWitness --- src/neo/Ledger/VerifyResult.cs | 2 -- src/neo/Network/P2P/Payloads/Transaction.cs | 28 ++++++++++----------- src/neo/SmartContract/Helper.cs | 6 ++++- 3 files changed, 19 insertions(+), 17 deletions(-) diff --git a/src/neo/Ledger/VerifyResult.cs b/src/neo/Ledger/VerifyResult.cs index 3767a23d29..ab5c1f673e 100644 --- a/src/neo/Ledger/VerifyResult.cs +++ b/src/neo/Ledger/VerifyResult.cs @@ -7,10 +7,8 @@ public enum VerifyResult : byte OutOfMemory, UnableToVerify, Invalid, - InvalidWitness, Expired, InsufficientFunds, - InsufficientFee, PolicyFail, Unknown } diff --git a/src/neo/Network/P2P/Payloads/Transaction.cs b/src/neo/Network/P2P/Payloads/Transaction.cs index b2100228fa..7eeb5022f8 100644 --- a/src/neo/Network/P2P/Payloads/Transaction.cs +++ b/src/neo/Network/P2P/Payloads/Transaction.cs @@ -248,32 +248,32 @@ public virtual VerifyResult VerifyStateDependent(StoreView snapshot, BigInteger { if (ValidUntilBlock <= snapshot.Height || ValidUntilBlock > snapshot.Height + MaxValidUntilBlockIncrement) return VerifyResult.Expired; + UInt160[] hashes = GetScriptHashesForVerifying(); if (NativeContract.Policy.GetBlockedAccounts(snapshot).Intersect(hashes).Any()) - return VerifyResult.PolicyFail; + return VerifyResult.PolicyFail; + + BigInteger balance = NativeContract.GAS.BalanceOf(snapshot, Sender); + BigInteger fee = SystemFee + NetworkFee + totalSenderFeeFromPool; + if (balance < fee) + return VerifyResult.InsufficientFunds; + long net_fee = NetworkFee - Size * NativeContract.Policy.GetFeePerByte(snapshot); if (net_fee < 0) return VerifyResult.InsufficientFunds; - BigInteger balance = NativeContract.GAS.BalanceOf(snapshot, Sender); - BigInteger fee = SystemFee + NetworkFee + totalSenderFeeFromPool; - if (balance < fee) return VerifyResult.InsufficientFunds; if (!this.VerifyWitnesses(snapshot, net_fee, WitnessFlag.NonStandardWitness)) - return VerifyResult.InvalidWitness; - - //Check all gas consumed for state dependent and independent witnesses - long gasConsumed = 0; - foreach (Witness witness in witnesses) - gasConsumed += witness.GasConsumed; - if (gasConsumed > net_fee) - return VerifyResult.InsufficientFee; + return VerifyResult.Invalid; + return VerifyResult.Succeed; } public virtual VerifyResult VerifyStateIndependent() { - if (Size > MaxTransactionSize) return VerifyResult.Invalid; - if (!this.VerifyWitnesses(null, NetworkFee, WitnessFlag.StandardWitness)) return VerifyResult.InvalidWitness; + if (Size > MaxTransactionSize) + return VerifyResult.Invalid; + if (!this.VerifyWitnesses(null, NetworkFee, WitnessFlag.StandardWitness)) + return VerifyResult.Invalid; return VerifyResult.Succeed; } diff --git a/src/neo/SmartContract/Helper.cs b/src/neo/SmartContract/Helper.cs index 749de56515..0e3b28ddc9 100644 --- a/src/neo/SmartContract/Helper.cs +++ b/src/neo/SmartContract/Helper.cs @@ -146,7 +146,11 @@ internal static bool VerifyWitnesses(this IVerifiable verifiable, StoreView snap for (int i = 0; i < hashes.Length; i++) { Witness witness = verifiable.Witnesses[i]; - if (!filter.HasFlag(witness.Flag)) continue; + if (!filter.HasFlag(witness.Flag)) + { + gas -= witness.GasConsumed; + continue; + } int offset; byte[] verification = witness.VerificationScript; From 0bd44798dd3547ab572c846c1604c4cfb7be577b Mon Sep 17 00:00:00 2001 From: Luchuan Date: Sun, 10 May 2020 01:02:03 +0800 Subject: [PATCH 32/55] format --- src/neo/Network/P2P/Payloads/Transaction.cs | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/src/neo/Network/P2P/Payloads/Transaction.cs b/src/neo/Network/P2P/Payloads/Transaction.cs index 7eeb5022f8..03fd5d6214 100644 --- a/src/neo/Network/P2P/Payloads/Transaction.cs +++ b/src/neo/Network/P2P/Payloads/Transaction.cs @@ -248,23 +248,18 @@ public virtual VerifyResult VerifyStateDependent(StoreView snapshot, BigInteger { if (ValidUntilBlock <= snapshot.Height || ValidUntilBlock > snapshot.Height + MaxValidUntilBlockIncrement) return VerifyResult.Expired; - UInt160[] hashes = GetScriptHashesForVerifying(); if (NativeContract.Policy.GetBlockedAccounts(snapshot).Intersect(hashes).Any()) - return VerifyResult.PolicyFail; - + return VerifyResult.PolicyFail; BigInteger balance = NativeContract.GAS.BalanceOf(snapshot, Sender); BigInteger fee = SystemFee + NetworkFee + totalSenderFeeFromPool; if (balance < fee) return VerifyResult.InsufficientFunds; - long net_fee = NetworkFee - Size * NativeContract.Policy.GetFeePerByte(snapshot); if (net_fee < 0) return VerifyResult.InsufficientFunds; - if (!this.VerifyWitnesses(snapshot, net_fee, WitnessFlag.NonStandardWitness)) return VerifyResult.Invalid; - return VerifyResult.Succeed; } From 866697658df3c595aa696524f1692f567c044a5e Mon Sep 17 00:00:00 2001 From: Luchuan Date: Sun, 10 May 2020 08:27:20 +0800 Subject: [PATCH 33/55] fix VerifyWitness --- src/neo/SmartContract/Helper.cs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/neo/SmartContract/Helper.cs b/src/neo/SmartContract/Helper.cs index 0e3b28ddc9..17fb2086c7 100644 --- a/src/neo/SmartContract/Helper.cs +++ b/src/neo/SmartContract/Helper.cs @@ -131,8 +131,6 @@ public static UInt160 ToScriptHash(this ReadOnlySpan script) internal static bool VerifyWitnesses(this IVerifiable verifiable, StoreView snapshot, long gas, WitnessFlag filter = WitnessFlag.All) { - if (gas < 0) return false; - UInt160[] hashes; try { @@ -146,9 +144,10 @@ internal static bool VerifyWitnesses(this IVerifiable verifiable, StoreView snap for (int i = 0; i < hashes.Length; i++) { Witness witness = verifiable.Witnesses[i]; - if (!filter.HasFlag(witness.Flag)) + if (filter != WitnessFlag.All && !filter.HasFlag(witness.Flag)) { gas -= witness.GasConsumed; + if (gas < 0) return false; continue; } From 4f832ba1446c5c76212d6aea9833b9e0f160a65c Mon Sep 17 00:00:00 2001 From: Luchuan Date: Sun, 10 May 2020 08:34:45 +0800 Subject: [PATCH 34/55] optimize tx.verify --- src/neo/Network/P2P/Payloads/Transaction.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/neo/Network/P2P/Payloads/Transaction.cs b/src/neo/Network/P2P/Payloads/Transaction.cs index 03fd5d6214..ab298bc642 100644 --- a/src/neo/Network/P2P/Payloads/Transaction.cs +++ b/src/neo/Network/P2P/Payloads/Transaction.cs @@ -256,8 +256,6 @@ public virtual VerifyResult VerifyStateDependent(StoreView snapshot, BigInteger if (balance < fee) return VerifyResult.InsufficientFunds; long net_fee = NetworkFee - Size * NativeContract.Policy.GetFeePerByte(snapshot); - if (net_fee < 0) - return VerifyResult.InsufficientFunds; if (!this.VerifyWitnesses(snapshot, net_fee, WitnessFlag.NonStandardWitness)) return VerifyResult.Invalid; return VerifyResult.Succeed; From 5d1a2180fb632e383632c90c6823db3aa0780dc1 Mon Sep 17 00:00:00 2001 From: Luchuan Date: Sun, 10 May 2020 19:09:29 +0800 Subject: [PATCH 35/55] optimize verifywitness --- src/neo/SmartContract/Helper.cs | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/src/neo/SmartContract/Helper.cs b/src/neo/SmartContract/Helper.cs index 17fb2086c7..b97db558c9 100644 --- a/src/neo/SmartContract/Helper.cs +++ b/src/neo/SmartContract/Helper.cs @@ -143,16 +143,11 @@ internal static bool VerifyWitnesses(this IVerifiable verifiable, StoreView snap if (hashes.Length != verifiable.Witnesses.Length) return false; for (int i = 0; i < hashes.Length; i++) { - Witness witness = verifiable.Witnesses[i]; - if (filter != WitnessFlag.All && !filter.HasFlag(witness.Flag)) - { - gas -= witness.GasConsumed; - if (gas < 0) return false; - continue; - } + if (i != 0) gas -= verifiable.Witnesses[i - 1].GasConsumed; + if (filter != WitnessFlag.All && !filter.HasFlag(verifiable.Witnesses[i].Flag)) continue; int offset; - byte[] verification = witness.VerificationScript; + byte[] verification = verifiable.Witnesses[i].VerificationScript; if (verification.Length == 0) { ContractState cs = snapshot.Contracts.TryGet(hashes[i]); @@ -164,16 +159,16 @@ internal static bool VerifyWitnesses(this IVerifiable verifiable, StoreView snap } else { - if (hashes[i] != witness.ScriptHash) return false; + if (hashes[i] != verifiable.Witnesses[i].ScriptHash) return false; offset = 0; } using (ApplicationEngine engine = new ApplicationEngine(TriggerType.Verification, verifiable, null, gas)) { engine.LoadScript(verification, CallFlags.ReadOnly).InstructionPointer = offset; - engine.LoadScript(witness.InvocationScript, CallFlags.None); + engine.LoadScript(verifiable.Witnesses[i].InvocationScript, CallFlags.None); if (engine.Execute() == VMState.FAULT) return false; if (!engine.ResultStack.TryPop(out StackItem result) || !result.ToBoolean()) return false; - gas -= engine.GasConsumed; + verifiable.Witnesses[i].GasConsumed = engine.GasConsumed; } } return true; From de81ddd753b7cfd5cfbf9531f73d48f11c6b6074 Mon Sep 17 00:00:00 2001 From: Tommo-L Date: Mon, 11 May 2020 10:23:51 +0800 Subject: [PATCH 36/55] reset InteropService --- src/neo/SmartContract/Helper.cs | 4 +++- src/neo/SmartContract/InteropService.Contract.cs | 2 +- src/neo/SmartContract/InteropService.Runtime.cs | 2 +- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/neo/SmartContract/Helper.cs b/src/neo/SmartContract/Helper.cs index b97db558c9..681782c28a 100644 --- a/src/neo/SmartContract/Helper.cs +++ b/src/neo/SmartContract/Helper.cs @@ -131,6 +131,8 @@ public static UInt160 ToScriptHash(this ReadOnlySpan script) internal static bool VerifyWitnesses(this IVerifiable verifiable, StoreView snapshot, long gas, WitnessFlag filter = WitnessFlag.All) { + if (gas < 0) return false; + UInt160[] hashes; try { @@ -162,7 +164,7 @@ internal static bool VerifyWitnesses(this IVerifiable verifiable, StoreView snap if (hashes[i] != verifiable.Witnesses[i].ScriptHash) return false; offset = 0; } - using (ApplicationEngine engine = new ApplicationEngine(TriggerType.Verification, verifiable, null, gas)) + using (ApplicationEngine engine = new ApplicationEngine(TriggerType.Verification, verifiable, snapshot, gas)) { engine.LoadScript(verification, CallFlags.ReadOnly).InstructionPointer = offset; engine.LoadScript(verifiable.Witnesses[i].InvocationScript, CallFlags.None); diff --git a/src/neo/SmartContract/InteropService.Contract.cs b/src/neo/SmartContract/InteropService.Contract.cs index 069af89d3f..36b3cad6ad 100644 --- a/src/neo/SmartContract/InteropService.Contract.cs +++ b/src/neo/SmartContract/InteropService.Contract.cs @@ -23,7 +23,7 @@ public static class Contract public static readonly InteropDescriptor Destroy = Register("System.Contract.Destroy", Contract_Destroy, 0_01000000, TriggerType.Application, CallFlags.AllowModifyStates); public static readonly InteropDescriptor Call = Register("System.Contract.Call", Contract_Call, 0_01000000, TriggerType.System | TriggerType.Application, CallFlags.AllowCall); public static readonly InteropDescriptor CallEx = Register("System.Contract.CallEx", Contract_CallEx, 0_01000000, TriggerType.System | TriggerType.Application, CallFlags.AllowCall); - public static readonly InteropDescriptor IsStandard = Register("System.Contract.IsStandard", Contract_IsStandard, 0_00030000, TriggerType.System | TriggerType.Application, CallFlags.None); + public static readonly InteropDescriptor IsStandard = Register("System.Contract.IsStandard", Contract_IsStandard, 0_00030000, TriggerType.All, CallFlags.None); public static readonly InteropDescriptor GetCallFlags = Register("System.Contract.GetCallFlags", Contract_GetCallFlags, 0_00030000, TriggerType.All, CallFlags.None); /// diff --git a/src/neo/SmartContract/InteropService.Runtime.cs b/src/neo/SmartContract/InteropService.Runtime.cs index 4b57c41197..ff58e0a897 100644 --- a/src/neo/SmartContract/InteropService.Runtime.cs +++ b/src/neo/SmartContract/InteropService.Runtime.cs @@ -24,7 +24,7 @@ public static class Runtime public static readonly InteropDescriptor GetExecutingScriptHash = Register("System.Runtime.GetExecutingScriptHash", Runtime_GetExecutingScriptHash, 0_00000400, TriggerType.All, CallFlags.None); public static readonly InteropDescriptor GetCallingScriptHash = Register("System.Runtime.GetCallingScriptHash", Runtime_GetCallingScriptHash, 0_00000400, TriggerType.All, CallFlags.None); public static readonly InteropDescriptor GetEntryScriptHash = Register("System.Runtime.GetEntryScriptHash", Runtime_GetEntryScriptHash, 0_00000400, TriggerType.All, CallFlags.None); - public static readonly InteropDescriptor CheckWitness = Register("System.Runtime.CheckWitness", Runtime_CheckWitness, 0_00030000, TriggerType.System | TriggerType.Application, CallFlags.AllowStates); + public static readonly InteropDescriptor CheckWitness = Register("System.Runtime.CheckWitness", Runtime_CheckWitness, 0_00030000, TriggerType.All, CallFlags.AllowStates); public static readonly InteropDescriptor GetInvocationCounter = Register("System.Runtime.GetInvocationCounter", Runtime_GetInvocationCounter, 0_00000400, TriggerType.All, CallFlags.None); public static readonly InteropDescriptor Log = Register("System.Runtime.Log", Runtime_Log, 0_01000000, TriggerType.All, CallFlags.AllowNotify); public static readonly InteropDescriptor Notify = Register("System.Runtime.Notify", Runtime_Notify, 0_01000000, TriggerType.All, CallFlags.AllowNotify); From 0638e0b8fa0e4c19e16b2cf5f38f6fabf37720e2 Mon Sep 17 00:00:00 2001 From: Jin Qiao Date: Mon, 11 May 2020 14:08:13 +0800 Subject: [PATCH 37/55] add UT --- .../Network/P2P/Payloads/UT_Transaction.cs | 213 ++++++++++++++++++ 1 file changed, 213 insertions(+) diff --git a/tests/neo.UnitTests/Network/P2P/Payloads/UT_Transaction.cs b/tests/neo.UnitTests/Network/P2P/Payloads/UT_Transaction.cs index 5e2538a2ec..383ad3b4f3 100644 --- a/tests/neo.UnitTests/Network/P2P/Payloads/UT_Transaction.cs +++ b/tests/neo.UnitTests/Network/P2P/Payloads/UT_Transaction.cs @@ -1034,5 +1034,218 @@ public void ToJson() jObj["script"].AsString().Should().Be("QiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA="); jObj["sys_fee"].AsString().Should().Be("4200000000"); } + + [TestMethod] + public void Test_VerifyStateIndependent() + { + var tx = new Transaction() + { + Attributes = Array.Empty(), + NetworkFee = 0, + Nonce = (uint)Environment.TickCount, + Script = new byte[Transaction.MaxTransactionSize], + Sender = UInt160.Zero, + SystemFee = 0, + ValidUntilBlock = 0, + Version = 0, + Witnesses = new Witness[0], + }; + tx.VerifyStateIndependent().Should().Be(VerifyResult.Invalid); + tx.Script = new byte[0]; + tx.VerifyStateIndependent().Should().Be(VerifyResult.Invalid); + + var walletA = TestUtils.GenerateTestWallet(); + var walletB = TestUtils.GenerateTestWallet(); + var snapshot = Blockchain.Singleton.GetSnapshot(); + + using (var unlockA = walletA.Unlock("123")) + using (var unlockB = walletB.Unlock("123")) + { + var a = walletA.CreateAccount(); + var b = walletB.CreateAccount(); + + var multiSignContract = Contract.CreateMultiSigContract(2, + new ECPoint[] + { + a.GetKey().PublicKey, + b.GetKey().PublicKey + }); + + walletA.CreateAccount(multiSignContract, a.GetKey()); + var acc = walletB.CreateAccount(multiSignContract, b.GetKey()); + + // Fake balance + + var key = NativeContract.GAS.CreateStorageKey(20, acc.ScriptHash); + var entry = snapshot.Storages.GetAndChange(key, () => new StorageItem(new Nep5AccountState())); + + entry.GetInteroperable().Balance = 10000 * NativeContract.GAS.Factor; + + snapshot.Commit(); + + // Make transaction + + tx = walletA.MakeTransaction(new TransferOutput[] + { + new TransferOutput() + { + AssetId = NativeContract.GAS.Hash, + ScriptHash = acc.ScriptHash, + Value = new BigDecimal(1,8) + } + }, acc.ScriptHash); + + // Sign + + var data = new ContractParametersContext(tx); + Assert.IsTrue(walletA.Sign(data)); + Assert.IsTrue(walletB.Sign(data)); + Assert.IsTrue(data.Completed); + + tx.Witnesses = data.GetWitnesses(); + tx.VerifyStateIndependent().Should().Be(VerifyResult.Succeed); + } + } + + [TestMethod] + public void Test_VerifyStateDependent() + { + var snapshot = Blockchain.Singleton.GetSnapshot(); + var tx = new Transaction() + { + Attributes = Array.Empty(), + NetworkFee = 0, + Nonce = (uint)Environment.TickCount, + Script = new byte[0], + Sender = UInt160.Zero, + SystemFee = 0, + ValidUntilBlock = snapshot.Height + 1, + Version = 0, + Witnesses = new Witness[0], + }; + tx.VerifyStateDependent(snapshot, 0).Should().Be(VerifyResult.Invalid); + tx.VerifyStateDependent(snapshot, 10).Should().Be(VerifyResult.InsufficientFunds); + + var walletA = TestUtils.GenerateTestWallet(); + var walletB = TestUtils.GenerateTestWallet(); + + using (var unlockA = walletA.Unlock("123")) + using (var unlockB = walletB.Unlock("123")) + { + var a = walletA.CreateAccount(); + var b = walletB.CreateAccount(); + + var multiSignContract = Contract.CreateMultiSigContract(2, + new ECPoint[] + { + a.GetKey().PublicKey, + b.GetKey().PublicKey + }); + + walletA.CreateAccount(multiSignContract, a.GetKey()); + var acc = walletB.CreateAccount(multiSignContract, b.GetKey()); + + // Fake balance + + var key = NativeContract.GAS.CreateStorageKey(20, acc.ScriptHash); + var entry = snapshot.Storages.GetAndChange(key, () => new StorageItem(new Nep5AccountState())); + + entry.GetInteroperable().Balance = 10000 * NativeContract.GAS.Factor; + + snapshot.Commit(); + + // Make transaction + + tx = walletA.MakeTransaction(new TransferOutput[] + { + new TransferOutput() + { + AssetId = NativeContract.GAS.Hash, + ScriptHash = acc.ScriptHash, + Value = new BigDecimal(1,8) + } + }, acc.ScriptHash); + + // Sign + + var data = new ContractParametersContext(tx); + Assert.IsTrue(walletA.Sign(data)); + Assert.IsTrue(walletB.Sign(data)); + Assert.IsTrue(data.Completed); + + tx.Witnesses = data.GetWitnesses(); + tx.VerifyStateDependent(snapshot, 0).Should().Be(VerifyResult.Succeed); + } + } + + [TestMethod] + public void Test_Verify() + { + var snapshot = Blockchain.Singleton.GetSnapshot(); + var tx = new Transaction() + { + Attributes = Array.Empty(), + NetworkFee = 0, + Nonce = (uint)Environment.TickCount, + Script = new byte[Transaction.MaxTransactionSize], + Sender = UInt160.Zero, + SystemFee = 0, + ValidUntilBlock = 0, + Version = 0, + Witnesses = new Witness[0], + }; + tx.Verify(snapshot, 0).Should().Be(VerifyResult.Invalid); + + var walletA = TestUtils.GenerateTestWallet(); + var walletB = TestUtils.GenerateTestWallet(); + + using (var unlockA = walletA.Unlock("123")) + using (var unlockB = walletB.Unlock("123")) + { + var a = walletA.CreateAccount(); + var b = walletB.CreateAccount(); + + var multiSignContract = Contract.CreateMultiSigContract(2, + new ECPoint[] + { + a.GetKey().PublicKey, + b.GetKey().PublicKey + }); + + walletA.CreateAccount(multiSignContract, a.GetKey()); + var acc = walletB.CreateAccount(multiSignContract, b.GetKey()); + + // Fake balance + + var key = NativeContract.GAS.CreateStorageKey(20, acc.ScriptHash); + var entry = snapshot.Storages.GetAndChange(key, () => new StorageItem(new Nep5AccountState())); + + entry.GetInteroperable().Balance = 10000 * NativeContract.GAS.Factor; + + snapshot.Commit(); + + // Make transaction + + tx = walletA.MakeTransaction(new TransferOutput[] + { + new TransferOutput() + { + AssetId = NativeContract.GAS.Hash, + ScriptHash = acc.ScriptHash, + Value = new BigDecimal(1,8) + } + }, acc.ScriptHash); + + // Sign + + var data = new ContractParametersContext(tx); + Assert.IsTrue(walletA.Sign(data)); + Assert.IsTrue(walletB.Sign(data)); + Assert.IsTrue(data.Completed); + + tx.Witnesses = data.GetWitnesses(); + tx.Verify(snapshot, 0).Should().Be(VerifyResult.Succeed); + } + } } } From c32f0fab025cbfaef6a53aea87bc14ae2f743a7f Mon Sep 17 00:00:00 2001 From: Jin Qiao Date: Fri, 15 May 2020 18:10:19 +0800 Subject: [PATCH 38/55] Split func OnInventoryReceived to avoid dirty write --- .../Network/P2P/RemoteNode.ProtocolHandler.cs | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/src/neo/Network/P2P/RemoteNode.ProtocolHandler.cs b/src/neo/Network/P2P/RemoteNode.ProtocolHandler.cs index cde1ab35b8..db50e84539 100644 --- a/src/neo/Network/P2P/RemoteNode.ProtocolHandler.cs +++ b/src/neo/Network/P2P/RemoteNode.ProtocolHandler.cs @@ -63,10 +63,14 @@ private void OnMessage(Message msg) OnAddrMessageReceived((AddrPayload)msg.Payload); break; case MessageCommand.Block: - OnInventoryReceived((Block)msg.Payload); + Block block = (Block)msg.Payload; + OnInventoryReceived(block); + RenewKnownHashes(block.Hash); break; case MessageCommand.Consensus: - OnInventoryReceived((ConsensusPayload)msg.Payload); + ConsensusPayload consensusPayload = (ConsensusPayload)msg.Payload; + OnInventoryReceived(consensusPayload); + RenewKnownHashes(consensusPayload.Hash); break; case MessageCommand.FilterAdd: OnFilterAddMessageReceived((FilterAddPayload)msg.Payload); @@ -108,11 +112,12 @@ private void OnMessage(Message msg) OnPongMessageReceived((PingPayload)msg.Payload); break; case MessageCommand.Transaction: + Transaction tx = (Transaction)msg.Payload; + RenewKnownHashes(tx.Hash); Task.Run(() => { if (msg.Payload.Size <= Transaction.MaxTransactionSize) { - Transaction tx = (Transaction)msg.Payload; if (tx.VerifyStateIndependent() == VerifyResult.Succeed) OnInventoryReceived(tx); } @@ -295,8 +300,12 @@ private void OnInventoryReceived(IInventory inventory) { system.TaskManager.Tell(new TaskManager.TaskCompleted { Hash = inventory.Hash }); system.LocalNode.Tell(new LocalNode.Relay { Inventory = inventory }); - pendingKnownHashes.Remove(inventory.Hash); - knownHashes.Add(inventory.Hash); + } + + private void RenewKnownHashes(UInt256 hash) + { + pendingKnownHashes.Remove(hash); + knownHashes.Add(hash); } private void OnInvMessageReceived(InvPayload payload) From 7ab56c30119d24642a3cfa8160c7d888bb295fd0 Mon Sep 17 00:00:00 2001 From: Jin Qiao Date: Wed, 27 May 2020 16:20:39 +0800 Subject: [PATCH 39/55] Renew UT --- .../Network/P2P/Payloads/UT_Transaction.cs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/tests/neo.UnitTests/Network/P2P/Payloads/UT_Transaction.cs b/tests/neo.UnitTests/Network/P2P/Payloads/UT_Transaction.cs index 71e782d40e..ef011b9086 100644 --- a/tests/neo.UnitTests/Network/P2P/Payloads/UT_Transaction.cs +++ b/tests/neo.UnitTests/Network/P2P/Payloads/UT_Transaction.cs @@ -1077,9 +1077,9 @@ public void Test_VerifyStateIndependent() // Fake balance var key = NativeContract.GAS.CreateStorageKey(20, acc.ScriptHash); - var entry = snapshot.Storages.GetAndChange(key, () => new StorageItem(new Nep5AccountState())); + var entry = snapshot.Storages.GetAndChange(key, () => new StorageItem(new AccountState())); - entry.GetInteroperable().Balance = 10000 * NativeContract.GAS.Factor; + entry.GetInteroperable().Balance = 10000 * NativeContract.GAS.Factor; snapshot.Commit(); @@ -1148,9 +1148,9 @@ public void Test_VerifyStateDependent() // Fake balance var key = NativeContract.GAS.CreateStorageKey(20, acc.ScriptHash); - var entry = snapshot.Storages.GetAndChange(key, () => new StorageItem(new Nep5AccountState())); + var entry = snapshot.Storages.GetAndChange(key, () => new StorageItem(new AccountState())); - entry.GetInteroperable().Balance = 10000 * NativeContract.GAS.Factor; + entry.GetInteroperable().Balance = 10000 * NativeContract.GAS.Factor; snapshot.Commit(); @@ -1218,9 +1218,9 @@ public void Test_Verify() // Fake balance var key = NativeContract.GAS.CreateStorageKey(20, acc.ScriptHash); - var entry = snapshot.Storages.GetAndChange(key, () => new StorageItem(new Nep5AccountState())); + var entry = snapshot.Storages.GetAndChange(key, () => new StorageItem(new AccountState())); - entry.GetInteroperable().Balance = 10000 * NativeContract.GAS.Factor; + entry.GetInteroperable().Balance = 10000 * NativeContract.GAS.Factor; snapshot.Commit(); From 9d81c5504fc2cb0b3ff80b751e082ae843b5b252 Mon Sep 17 00:00:00 2001 From: Jin Qiao Date: Fri, 7 Aug 2020 10:48:44 +0800 Subject: [PATCH 40/55] Check transaction size before creating task --- src/neo/Network/P2P/RemoteNode.ProtocolHandler.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/neo/Network/P2P/RemoteNode.ProtocolHandler.cs b/src/neo/Network/P2P/RemoteNode.ProtocolHandler.cs index 66e0a02012..856891b098 100644 --- a/src/neo/Network/P2P/RemoteNode.ProtocolHandler.cs +++ b/src/neo/Network/P2P/RemoteNode.ProtocolHandler.cs @@ -111,14 +111,14 @@ private void OnMessage(Message msg) case MessageCommand.Transaction: Transaction tx = (Transaction)msg.Payload; RenewKnownHashes(tx.Hash); - Task.Run(() => + if (msg.Payload.Size <= Transaction.MaxTransactionSize) { - if (msg.Payload.Size <= Transaction.MaxTransactionSize) + Task.Run(() => { if (tx.VerifyStateIndependent() == VerifyResult.Succeed) OnInventoryReceived(tx); - } - }); + }); + } break; case MessageCommand.Verack: case MessageCommand.Version: From 151dbacadcdc17460f35132ac44f2c597b0d4851 Mon Sep 17 00:00:00 2001 From: Jin Qiao Date: Fri, 7 Aug 2020 14:41:16 +0800 Subject: [PATCH 41/55] Add missing note --- src/neo/Ledger/MemoryPool.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/neo/Ledger/MemoryPool.cs b/src/neo/Ledger/MemoryPool.cs index ef5086e51f..2cf471a21e 100644 --- a/src/neo/Ledger/MemoryPool.cs +++ b/src/neo/Ledger/MemoryPool.cs @@ -422,6 +422,7 @@ private int ReverifyTransactions(SortedSet verifiedSortedTxPool, _txRwLock.EnterWriteLock(); try { + // Since unverifiedSortedTxPool is ordered in an ascending manner, we take from the end. foreach (PoolItem item in unverifiedSortedTxPool.Reverse().Take(count)) { if (item.Tx.VerifyStateDependent(snapshot, VerificationContext) == VerifyResult.Succeed) From 0ab3d71fa363f82665b4ed59e2d8c5af90b53840 Mon Sep 17 00:00:00 2001 From: Shargon Date: Fri, 7 Aug 2020 10:03:25 +0200 Subject: [PATCH 42/55] Fix gas --- src/neo/SmartContract/Helper.cs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/neo/SmartContract/Helper.cs b/src/neo/SmartContract/Helper.cs index 77821136f5..b0c60367aa 100644 --- a/src/neo/SmartContract/Helper.cs +++ b/src/neo/SmartContract/Helper.cs @@ -146,8 +146,12 @@ internal static bool VerifyWitnesses(this IVerifiable verifiable, StoreView snap if (hashes.Length != verifiable.Witnesses.Length) return false; for (int i = 0; i < hashes.Length; i++) { - if (i != 0) gas -= verifiable.Witnesses[i - 1].GasConsumed; - if (filter != WitnessFlag.All && !filter.HasFlag(verifiable.Witnesses[i].Flag)) continue; + if (filter != WitnessFlag.All && !filter.HasFlag(verifiable.Witnesses[i].Flag)) + { + gas -= verifiable.Witnesses[i].GasConsumed; + if (gas < 0) return false; + continue; + } int offset; ContractMethodDescriptor init = null; From c8be7658d4508e9c4f95247c96a130515c7b0c02 Mon Sep 17 00:00:00 2001 From: Shargon Date: Fri, 7 Aug 2020 10:06:47 +0200 Subject: [PATCH 43/55] Re-fix --- src/neo/SmartContract/Helper.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/neo/SmartContract/Helper.cs b/src/neo/SmartContract/Helper.cs index b0c60367aa..3062e7a083 100644 --- a/src/neo/SmartContract/Helper.cs +++ b/src/neo/SmartContract/Helper.cs @@ -178,6 +178,7 @@ internal static bool VerifyWitnesses(this IVerifiable verifiable, StoreView snap engine.LoadScript(verifiable.Witnesses[i].InvocationScript, CallFlags.None); if (engine.Execute() == VMState.FAULT) return false; if (engine.ResultStack.Count != 1 || !engine.ResultStack.Pop().GetBoolean()) return false; + gas -= engine.GasConsumed; verifiable.Witnesses[i].GasConsumed = engine.GasConsumed; } } From 868ff313effec1cc6f64bec1714ac11f47637dda Mon Sep 17 00:00:00 2001 From: Jin Qiao Date: Fri, 7 Aug 2020 16:36:25 +0800 Subject: [PATCH 44/55] Redefine WitnessFlag --- src/neo/Network/P2P/Payloads/Transaction.cs | 4 ++-- src/neo/Network/P2P/Payloads/Witness.cs | 2 +- src/neo/SmartContract/WitnessFlag.cs | 7 +++---- 3 files changed, 6 insertions(+), 7 deletions(-) diff --git a/src/neo/Network/P2P/Payloads/Transaction.cs b/src/neo/Network/P2P/Payloads/Transaction.cs index 43dc3827aa..bc7986f4a5 100644 --- a/src/neo/Network/P2P/Payloads/Transaction.cs +++ b/src/neo/Network/P2P/Payloads/Transaction.cs @@ -295,7 +295,7 @@ public virtual VerifyResult VerifyStateDependent(StoreView snapshot, Transaction if (!attribute.Verify(snapshot, this)) return VerifyResult.Invalid; long net_fee = NetworkFee - Size * NativeContract.Policy.GetFeePerByte(snapshot); - if (!this.VerifyWitnesses(snapshot, net_fee, WitnessFlag.NonStandardWitness)) + if (!this.VerifyWitnesses(snapshot, net_fee, WitnessFlag.StateDependentWitness)) return VerifyResult.Invalid; return VerifyResult.Succeed; } @@ -304,7 +304,7 @@ public virtual VerifyResult VerifyStateIndependent() { if (Size > MaxTransactionSize) return VerifyResult.Invalid; - if (!this.VerifyWitnesses(null, NetworkFee, WitnessFlag.StandardWitness)) + if (!this.VerifyWitnesses(null, NetworkFee, WitnessFlag.StateIndependentWitness)) return VerifyResult.Invalid; return VerifyResult.Succeed; } diff --git a/src/neo/Network/P2P/Payloads/Witness.cs b/src/neo/Network/P2P/Payloads/Witness.cs index 72bc8368bc..b7d7769b78 100644 --- a/src/neo/Network/P2P/Payloads/Witness.cs +++ b/src/neo/Network/P2P/Payloads/Witness.cs @@ -57,7 +57,7 @@ public WitnessFlag Flag { if (_flag == WitnessFlag.None) { - _flag = VerificationScript.IsStandardContract() ? WitnessFlag.StandardWitness : WitnessFlag.NonStandardWitness; + _flag = VerificationScript.Length == 0 ? WitnessFlag.StateDependentWitness : WitnessFlag.StateIndependentWitness; } return _flag; } diff --git a/src/neo/SmartContract/WitnessFlag.cs b/src/neo/SmartContract/WitnessFlag.cs index 964ddd3bb1..cc9618670f 100644 --- a/src/neo/SmartContract/WitnessFlag.cs +++ b/src/neo/SmartContract/WitnessFlag.cs @@ -6,10 +6,9 @@ namespace Neo.SmartContract public enum WitnessFlag : byte { None = 0, + StateIndependentWitness = 0b00000001, + StateDependentWitness = 0b00000010, - StandardWitness = 0b00000001, - NonStandardWitness = 0b00000010, - - All = StandardWitness | NonStandardWitness + All = StateIndependentWitness | StateDependentWitness } } From 5288f27e714885ed07e0c5ec941002ee188952ad Mon Sep 17 00:00:00 2001 From: Jin Qiao Date: Wed, 12 Aug 2020 15:51:43 +0800 Subject: [PATCH 45/55] Change multi task to actor pool --- .../Network/P2P/RemoteNode.ProtocolHandler.cs | 49 +++++++++++++------ src/neo/Network/P2P/RemoteNode.cs | 2 + 2 files changed, 36 insertions(+), 15 deletions(-) diff --git a/src/neo/Network/P2P/RemoteNode.ProtocolHandler.cs b/src/neo/Network/P2P/RemoteNode.ProtocolHandler.cs index 856891b098..4f9adb3fd1 100644 --- a/src/neo/Network/P2P/RemoteNode.ProtocolHandler.cs +++ b/src/neo/Network/P2P/RemoteNode.ProtocolHandler.cs @@ -18,6 +18,34 @@ namespace Neo.Network.P2P { partial class RemoteNode { + private class TransactionRouter : UntypedActor + { + private readonly NeoSystem system; + + public TransactionRouter (NeoSystem system) + { + this.system = system; + } + + protected override void OnReceive(object message) + { + switch (message) + { + case Transaction tx: + if (tx.VerifyStateIndependent() == VerifyResult.Succeed) + OnTransactionReceived(tx); + break; + } + } + + private void OnTransactionReceived(Transaction tx) + { + system.TaskManager.Tell(tx); + system.Consensus?.Tell(tx); + system.Blockchain.Tell(tx, ActorRefs.NoSender); + } + } + private class Timer { } private class PendingKnownHashesCollection : KeyedCollection { @@ -32,6 +60,7 @@ protected override UInt256 GetKeyForItem((UInt256, DateTime) item) private readonly HashSetCache sentHashes = new HashSetCache(Blockchain.Singleton.MemPool.Capacity * 2 / 5); private bool verack = false; private BloomFilter bloom_filter; + private IActorRef transactionRouter; private static readonly TimeSpan TimerInterval = TimeSpan.FromSeconds(30); private static readonly TimeSpan PendingTimeout = TimeSpan.FromMinutes(1); @@ -64,12 +93,14 @@ private void OnMessage(Message msg) break; case MessageCommand.Block: Block block = (Block)msg.Payload; - OnInventoryReceived(block); + system.TaskManager.Tell(block); + system.Blockchain.Tell(block, ActorRefs.NoSender); RenewKnownHashes(block.Hash); break; case MessageCommand.Consensus: ConsensusPayload consensusPayload = (ConsensusPayload)msg.Payload; - OnInventoryReceived(consensusPayload); + system.TaskManager.Tell(consensusPayload); + system.Blockchain.Tell(consensusPayload, ActorRefs.NoSender); RenewKnownHashes(consensusPayload.Hash); break; case MessageCommand.FilterAdd: @@ -113,11 +144,7 @@ private void OnMessage(Message msg) RenewKnownHashes(tx.Hash); if (msg.Payload.Size <= Transaction.MaxTransactionSize) { - Task.Run(() => - { - if (tx.VerifyStateIndependent() == VerifyResult.Succeed) - OnInventoryReceived(tx); - }); + transactionRouter.Tell(tx); } break; case MessageCommand.Verack: @@ -297,14 +324,6 @@ private void OnGetHeadersMessageReceived(GetBlockByIndexPayload payload) EnqueueMessage(Message.Create(MessageCommand.Headers, HeadersPayload.Create(headers.ToArray()))); } - private void OnInventoryReceived(IInventory inventory) - { - system.TaskManager.Tell(inventory); - if (inventory is Transaction transaction) - system.Consensus?.Tell(transaction); - system.Blockchain.Tell(inventory, ActorRefs.NoSender); - } - private void RenewKnownHashes(UInt256 hash) { pendingKnownHashes.Remove(hash); diff --git a/src/neo/Network/P2P/RemoteNode.cs b/src/neo/Network/P2P/RemoteNode.cs index b1457a8522..a27c245a43 100644 --- a/src/neo/Network/P2P/RemoteNode.cs +++ b/src/neo/Network/P2P/RemoteNode.cs @@ -1,6 +1,7 @@ using Akka.Actor; using Akka.Configuration; using Akka.IO; +using Akka.Routing; using Neo.Cryptography; using Neo.IO; using Neo.IO.Actors; @@ -36,6 +37,7 @@ public RemoteNode(NeoSystem system, object connection, IPEndPoint remote, IPEndP { this.system = system; LocalNode.Singleton.RemoteNodes.TryAdd(Self, this); + transactionRouter = Context.ActorOf(Akka.Actor.Props.Create(() => new TransactionRouter(system)).WithMailbox("remote-node-mailbox").WithRouter(new SmallestMailboxPool(20))); } /// From 8c6ce6874a459ceb58605a7d3cc642081e639eb2 Mon Sep 17 00:00:00 2001 From: Jin Qiao Date: Wed, 12 Aug 2020 16:21:37 +0800 Subject: [PATCH 46/55] Format correction --- src/neo/Network/P2P/RemoteNode.ProtocolHandler.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/neo/Network/P2P/RemoteNode.ProtocolHandler.cs b/src/neo/Network/P2P/RemoteNode.ProtocolHandler.cs index 4f9adb3fd1..dc0bb622ce 100644 --- a/src/neo/Network/P2P/RemoteNode.ProtocolHandler.cs +++ b/src/neo/Network/P2P/RemoteNode.ProtocolHandler.cs @@ -22,7 +22,7 @@ private class TransactionRouter : UntypedActor { private readonly NeoSystem system; - public TransactionRouter (NeoSystem system) + public TransactionRouter(NeoSystem system) { this.system = system; } From 16fb3dee59c05a6a04b41318f58ee2a8c226a2b6 Mon Sep 17 00:00:00 2001 From: erikzhang Date: Thu, 13 Aug 2020 13:26:03 +0800 Subject: [PATCH 47/55] Update Transaction.cs --- src/neo/Network/P2P/Payloads/Transaction.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/neo/Network/P2P/Payloads/Transaction.cs b/src/neo/Network/P2P/Payloads/Transaction.cs index bc7986f4a5..122c68840e 100644 --- a/src/neo/Network/P2P/Payloads/Transaction.cs +++ b/src/neo/Network/P2P/Payloads/Transaction.cs @@ -235,7 +235,7 @@ public override int GetHashCode() return Hash.GetHashCode(); } - public UInt160[] GetScriptHashesForVerifying(StoreView snapshot = null) + public UInt160[] GetScriptHashesForVerifying(StoreView snapshot) { return Signers.Select(p => p.Account).ToArray(); } @@ -285,7 +285,7 @@ public virtual VerifyResult VerifyStateDependent(StoreView snapshot, Transaction { if (ValidUntilBlock <= snapshot.Height || ValidUntilBlock > snapshot.Height + MaxValidUntilBlockIncrement) return VerifyResult.Expired; - UInt160[] hashes = GetScriptHashesForVerifying(); + UInt160[] hashes = GetScriptHashesForVerifying(snapshot); if (NativeContract.Policy.GetBlockedAccounts(snapshot).Intersect(hashes).Any()) return VerifyResult.PolicyFail; if (NativeContract.Policy.GetMaxBlockSystemFee(snapshot) < SystemFee) From d9c80eca5e1134c4ba258f67f114ca2a596c3689 Mon Sep 17 00:00:00 2001 From: erikzhang Date: Thu, 13 Aug 2020 15:01:57 +0800 Subject: [PATCH 48/55] Rename --- src/neo/Network/P2P/Payloads/Transaction.cs | 4 ++-- src/neo/Network/P2P/Payloads/Witness.cs | 2 +- src/neo/Network/P2P/Payloads/WitnessFlag.cs | 15 +++++++++++++++ src/neo/SmartContract/WitnessFlag.cs | 14 -------------- 4 files changed, 18 insertions(+), 17 deletions(-) create mode 100644 src/neo/Network/P2P/Payloads/WitnessFlag.cs delete mode 100644 src/neo/SmartContract/WitnessFlag.cs diff --git a/src/neo/Network/P2P/Payloads/Transaction.cs b/src/neo/Network/P2P/Payloads/Transaction.cs index 122c68840e..4b704ba0cd 100644 --- a/src/neo/Network/P2P/Payloads/Transaction.cs +++ b/src/neo/Network/P2P/Payloads/Transaction.cs @@ -295,7 +295,7 @@ public virtual VerifyResult VerifyStateDependent(StoreView snapshot, Transaction if (!attribute.Verify(snapshot, this)) return VerifyResult.Invalid; long net_fee = NetworkFee - Size * NativeContract.Policy.GetFeePerByte(snapshot); - if (!this.VerifyWitnesses(snapshot, net_fee, WitnessFlag.StateDependentWitness)) + if (!this.VerifyWitnesses(snapshot, net_fee, WitnessFlag.StateDependent)) return VerifyResult.Invalid; return VerifyResult.Succeed; } @@ -304,7 +304,7 @@ public virtual VerifyResult VerifyStateIndependent() { if (Size > MaxTransactionSize) return VerifyResult.Invalid; - if (!this.VerifyWitnesses(null, NetworkFee, WitnessFlag.StateIndependentWitness)) + if (!this.VerifyWitnesses(null, NetworkFee, WitnessFlag.StateIndependent)) return VerifyResult.Invalid; return VerifyResult.Succeed; } diff --git a/src/neo/Network/P2P/Payloads/Witness.cs b/src/neo/Network/P2P/Payloads/Witness.cs index b7d7769b78..ab8cdf24db 100644 --- a/src/neo/Network/P2P/Payloads/Witness.cs +++ b/src/neo/Network/P2P/Payloads/Witness.cs @@ -57,7 +57,7 @@ public WitnessFlag Flag { if (_flag == WitnessFlag.None) { - _flag = VerificationScript.Length == 0 ? WitnessFlag.StateDependentWitness : WitnessFlag.StateIndependentWitness; + _flag = VerificationScript.Length == 0 ? WitnessFlag.StateDependent : WitnessFlag.StateIndependent; } return _flag; } diff --git a/src/neo/Network/P2P/Payloads/WitnessFlag.cs b/src/neo/Network/P2P/Payloads/WitnessFlag.cs new file mode 100644 index 0000000000..6b31cdd55d --- /dev/null +++ b/src/neo/Network/P2P/Payloads/WitnessFlag.cs @@ -0,0 +1,15 @@ +using System; + +namespace Neo.SmartContract +{ + [Flags] + public enum WitnessFlag : byte + { + None = 0, + + StateIndependent = 0b00000001, + StateDependent = 0b00000010, + + All = StateIndependent | StateDependent + } +} diff --git a/src/neo/SmartContract/WitnessFlag.cs b/src/neo/SmartContract/WitnessFlag.cs deleted file mode 100644 index cc9618670f..0000000000 --- a/src/neo/SmartContract/WitnessFlag.cs +++ /dev/null @@ -1,14 +0,0 @@ -using System; - -namespace Neo.SmartContract -{ - [Flags] - public enum WitnessFlag : byte - { - None = 0, - StateIndependentWitness = 0b00000001, - StateDependentWitness = 0b00000010, - - All = StateIndependentWitness | StateDependentWitness - } -} From 90027d9e690527193252ca3a2e6f69288b68b80c Mon Sep 17 00:00:00 2001 From: erikzhang Date: Thu, 13 Aug 2020 15:26:40 +0800 Subject: [PATCH 49/55] Update Witness.cs --- src/neo/Network/P2P/Payloads/Witness.cs | 18 ++++-------------- 1 file changed, 4 insertions(+), 14 deletions(-) diff --git a/src/neo/Network/P2P/Payloads/Witness.cs b/src/neo/Network/P2P/Payloads/Witness.cs index ab8cdf24db..0c9faa13c0 100644 --- a/src/neo/Network/P2P/Payloads/Witness.cs +++ b/src/neo/Network/P2P/Payloads/Witness.cs @@ -10,7 +10,10 @@ public class Witness : ISerializable { public byte[] InvocationScript; public byte[] VerificationScript; - public long GasConsumed; + + public WitnessFlag Flag => VerificationScript.Length == 0 ? WitnessFlag.StateDependent : WitnessFlag.StateIndependent; + + internal long GasConsumed { get; set; } private UInt160 _scriptHash; public virtual UInt160 ScriptHash @@ -49,18 +52,5 @@ public JObject ToJson() json["verification"] = Convert.ToBase64String(VerificationScript); return json; } - - private WitnessFlag _flag = WitnessFlag.None; - public WitnessFlag Flag - { - get - { - if (_flag == WitnessFlag.None) - { - _flag = VerificationScript.Length == 0 ? WitnessFlag.StateDependent : WitnessFlag.StateIndependent; - } - return _flag; - } - } } } From f3b691a45cbaa2408ecc65f4052967e9499c694d Mon Sep 17 00:00:00 2001 From: Jin Qiao Date: Thu, 13 Aug 2020 17:09:18 +0800 Subject: [PATCH 50/55] Public transaction router --- src/neo/NeoSystem.cs | 2 + .../Network/P2P/RemoteNode.ProtocolHandler.cs | 32 +-------------- src/neo/Network/P2P/RemoteNode.cs | 2 - src/neo/Network/P2P/TransactionRouter.cs | 40 +++++++++++++++++++ 4 files changed, 43 insertions(+), 33 deletions(-) create mode 100644 src/neo/Network/P2P/TransactionRouter.cs diff --git a/src/neo/NeoSystem.cs b/src/neo/NeoSystem.cs index 88cc93ebcd..aefd8b89de 100644 --- a/src/neo/NeoSystem.cs +++ b/src/neo/NeoSystem.cs @@ -21,6 +21,7 @@ public class NeoSystem : IDisposable public IActorRef LocalNode { get; } internal IActorRef TaskManager { get; } public IActorRef Consensus { get; private set; } + public IActorRef TransactionRouter { get; } private readonly IStore store; private ChannelsConfig start_message = null; @@ -41,6 +42,7 @@ public NeoSystem(string storageEngine = null) this.Blockchain = ActorSystem.ActorOf(Ledger.Blockchain.Props(this, store)); this.LocalNode = ActorSystem.ActorOf(Network.P2P.LocalNode.Props(this)); this.TaskManager = ActorSystem.ActorOf(Network.P2P.TaskManager.Props(this)); + this.TransactionRouter = ActorSystem.ActorOf(Network.P2P.TransactionRouter.Props(this)); foreach (var plugin in Plugin.Plugins) plugin.OnPluginsLoaded(); } diff --git a/src/neo/Network/P2P/RemoteNode.ProtocolHandler.cs b/src/neo/Network/P2P/RemoteNode.ProtocolHandler.cs index 280f584ead..c1ae8464d4 100644 --- a/src/neo/Network/P2P/RemoteNode.ProtocolHandler.cs +++ b/src/neo/Network/P2P/RemoteNode.ProtocolHandler.cs @@ -12,40 +12,11 @@ using System.Collections.ObjectModel; using System.Linq; using System.Net; -using System.Threading.Tasks; namespace Neo.Network.P2P { partial class RemoteNode { - private class TransactionRouter : UntypedActor - { - private readonly NeoSystem system; - - public TransactionRouter(NeoSystem system) - { - this.system = system; - } - - protected override void OnReceive(object message) - { - switch (message) - { - case Transaction tx: - if (tx.VerifyStateIndependent() == VerifyResult.Succeed) - OnTransactionReceived(tx); - break; - } - } - - private void OnTransactionReceived(Transaction tx) - { - system.TaskManager.Tell(tx); - system.Consensus?.Tell(tx); - system.Blockchain.Tell(tx, ActorRefs.NoSender); - } - } - private class Timer { } private class PendingKnownHashesCollection : KeyedCollection { @@ -60,7 +31,6 @@ protected override UInt256 GetKeyForItem((UInt256, DateTime) item) private readonly HashSetCache sentHashes = new HashSetCache(Blockchain.Singleton.MemPool.Capacity * 2 / 5); private bool verack = false; private BloomFilter bloom_filter; - private IActorRef transactionRouter; private static readonly TimeSpan TimerInterval = TimeSpan.FromSeconds(30); private static readonly TimeSpan PendingTimeout = TimeSpan.FromMinutes(1); @@ -145,7 +115,7 @@ private void OnMessage(Message msg) RenewKnownHashes(tx.Hash); if (msg.Payload.Size <= Transaction.MaxTransactionSize) { - transactionRouter.Tell(tx); + system.TransactionRouter.Tell(tx); } break; case MessageCommand.Verack: diff --git a/src/neo/Network/P2P/RemoteNode.cs b/src/neo/Network/P2P/RemoteNode.cs index a27c245a43..b1457a8522 100644 --- a/src/neo/Network/P2P/RemoteNode.cs +++ b/src/neo/Network/P2P/RemoteNode.cs @@ -1,7 +1,6 @@ using Akka.Actor; using Akka.Configuration; using Akka.IO; -using Akka.Routing; using Neo.Cryptography; using Neo.IO; using Neo.IO.Actors; @@ -37,7 +36,6 @@ public RemoteNode(NeoSystem system, object connection, IPEndPoint remote, IPEndP { this.system = system; LocalNode.Singleton.RemoteNodes.TryAdd(Self, this); - transactionRouter = Context.ActorOf(Akka.Actor.Props.Create(() => new TransactionRouter(system)).WithMailbox("remote-node-mailbox").WithRouter(new SmallestMailboxPool(20))); } /// diff --git a/src/neo/Network/P2P/TransactionRouter.cs b/src/neo/Network/P2P/TransactionRouter.cs new file mode 100644 index 0000000000..94e481c8a0 --- /dev/null +++ b/src/neo/Network/P2P/TransactionRouter.cs @@ -0,0 +1,40 @@ +using Akka.Actor; +using Akka.Routing; +using Neo.Ledger; +using Neo.Network.P2P.Payloads; + +namespace Neo.Network.P2P +{ + public class TransactionRouter : UntypedActor + { + private readonly NeoSystem system; + + public TransactionRouter(NeoSystem system) + { + this.system = system; + } + + protected override void OnReceive(object message) + { + switch (message) + { + case Transaction tx: + if (tx.VerifyStateIndependent() == VerifyResult.Succeed) + OnTransactionReceived(tx); + break; + } + } + + private void OnTransactionReceived(Transaction tx) + { + system.TaskManager.Tell(tx); + system.Consensus?.Tell(tx); + system.Blockchain.Tell(tx, ActorRefs.NoSender); + } + + internal static Props Props(NeoSystem system) + { + return Akka.Actor.Props.Create(() => new TransactionRouter(system)).WithRouter(new SmallestMailboxPool(20)); + } + } +} From e6880d64bdd8db7ba8b66945d74bfcd69e88c0a3 Mon Sep 17 00:00:00 2001 From: erikzhang Date: Fri, 14 Aug 2020 19:32:51 +0800 Subject: [PATCH 51/55] Fix and optimize --- src/neo/Ledger/Blockchain.cs | 61 ++++++++++++++----- src/neo/NeoSystem.cs | 2 - .../Network/P2P/RemoteNode.ProtocolHandler.cs | 34 +++++------ src/neo/Network/P2P/TransactionRouter.cs | 30 ++++----- 4 files changed, 75 insertions(+), 52 deletions(-) diff --git a/src/neo/Ledger/Blockchain.cs b/src/neo/Ledger/Blockchain.cs index 2c9981f348..c7ce9a412a 100644 --- a/src/neo/Ledger/Blockchain.cs +++ b/src/neo/Ledger/Blockchain.cs @@ -26,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 { } + internal class PreverifyCompleted { public Transaction Transaction; public VerifyResult Result; public bool Relay; } public class RelayResult { public IInventory Inventory; public VerifyResult Result; } public static readonly uint MillisecondsPerBlock = ProtocolSettings.Default.MillisecondsPerBlock; @@ -58,6 +59,7 @@ public class RelayResult { public IInventory Inventory; public VerifyResult Resu private const int MaxTxToReverifyPerIdle = 10; private static readonly object lockObj = new object(); private readonly NeoSystem system; + private readonly IActorRef txrouter; private readonly List header_index = new List(); private uint stored_header_count = 0; private readonly Dictionary block_cache = new Dictionary(); @@ -103,6 +105,7 @@ static Blockchain() public Blockchain(NeoSystem system, IStore store) { this.system = system; + this.txrouter = Context.ActorOf(TransactionRouter.Props(system)); this.MemPool = new MemoryPool(system, ProtocolSettings.Default.MemoryPoolMaxTransactions); this.Store = store; this.View = new ReadOnlyView(store); @@ -302,20 +305,15 @@ private void OnFillMemoryPool(IEnumerable transactions) private void OnInventory(IInventory inventory, bool relay = true) { - RelayResult rr = new RelayResult + VerifyResult result = inventory switch { - Inventory = inventory, - Result = inventory switch - { - Block block => OnNewBlock(block), - Transaction transaction => OnNewTransaction(transaction), - _ => OnNewInventory(inventory) - } + Block block => OnNewBlock(block), + Transaction transaction => OnNewTransaction(transaction), + _ => OnNewInventory(inventory) }; - if (relay && rr.Result == VerifyResult.Succeed) + if (relay && result == VerifyResult.Succeed) system.LocalNode.Tell(new LocalNode.RelayDirectly { Inventory = inventory }); - Sender.Tell(rr); - Context.System.EventStream.Publish(rr); + SendRelayResult(inventory, result); } private VerifyResult OnNewBlock(Block block) @@ -360,6 +358,14 @@ private VerifyResult OnNewTransaction(Transaction transaction) return MemPool.TryAdd(transaction, currentSnapshot); } + private void OnPreverifyCompleted(PreverifyCompleted task) + { + if (task.Result == VerifyResult.Succeed) + OnInventory(task.Transaction, task.Relay); + else + SendRelayResult(task.Transaction, task.Result); + } + protected override void OnReceive(object message) { switch (message) @@ -373,15 +379,19 @@ protected override void OnReceive(object message) case Block block: OnInventory(block, false); break; + case Transaction tx: + OnTransaction(tx, true); + break; case Transaction[] transactions: - { - // This message comes from a mempool's revalidation, already relayed - foreach (var tx in transactions) OnInventory(tx, false); - break; - } + // This message comes from a mempool's revalidation, already relayed + foreach (var tx in transactions) OnTransaction(tx, false); + break; case IInventory inventory: OnInventory(inventory); break; + case PreverifyCompleted task: + OnPreverifyCompleted(task); + break; case Idle _: if (MemPool.ReVerifyTopUnverifiedTransactionsIfNeeded(MaxTxToReverifyPerIdle, currentSnapshot)) Self.Tell(Idle.Instance, ActorRefs.NoSender); @@ -389,6 +399,14 @@ protected override void OnReceive(object message) } } + private void OnTransaction(Transaction tx, bool relay) + { + if (ContainsTransaction(tx.Hash)) + SendRelayResult(tx, VerifyResult.AlreadyExists); + else + txrouter.Tell(new TransactionRouter.Task { Transaction = tx, Relay = relay }, Sender); + } + private void Persist(Block block) { using (SnapshotView snapshot = GetSnapshot()) @@ -507,6 +525,17 @@ private void SaveHeaderHashList(SnapshotView snapshot = null) } } + private void SendRelayResult(IInventory inventory, VerifyResult result) + { + RelayResult rr = new RelayResult + { + Inventory = inventory, + Result = result + }; + Sender.Tell(rr); + Context.System.EventStream.Publish(rr); + } + private void UpdateCurrentSnapshot() { Interlocked.Exchange(ref currentSnapshot, GetSnapshot())?.Dispose(); diff --git a/src/neo/NeoSystem.cs b/src/neo/NeoSystem.cs index aefd8b89de..88cc93ebcd 100644 --- a/src/neo/NeoSystem.cs +++ b/src/neo/NeoSystem.cs @@ -21,7 +21,6 @@ public class NeoSystem : IDisposable public IActorRef LocalNode { get; } internal IActorRef TaskManager { get; } public IActorRef Consensus { get; private set; } - public IActorRef TransactionRouter { get; } private readonly IStore store; private ChannelsConfig start_message = null; @@ -42,7 +41,6 @@ public NeoSystem(string storageEngine = null) this.Blockchain = ActorSystem.ActorOf(Ledger.Blockchain.Props(this, store)); this.LocalNode = ActorSystem.ActorOf(Network.P2P.LocalNode.Props(this)); this.TaskManager = ActorSystem.ActorOf(Network.P2P.TaskManager.Props(this)); - this.TransactionRouter = ActorSystem.ActorOf(Network.P2P.TransactionRouter.Props(this)); foreach (var plugin in Plugin.Plugins) plugin.OnPluginsLoaded(); } diff --git a/src/neo/Network/P2P/RemoteNode.ProtocolHandler.cs b/src/neo/Network/P2P/RemoteNode.ProtocolHandler.cs index c1ae8464d4..0cddbd49d7 100644 --- a/src/neo/Network/P2P/RemoteNode.ProtocolHandler.cs +++ b/src/neo/Network/P2P/RemoteNode.ProtocolHandler.cs @@ -62,17 +62,10 @@ private void OnMessage(Message msg) OnAddrMessageReceived((AddrPayload)msg.Payload); break; case MessageCommand.Block: - Block block = (Block)msg.Payload; - system.TaskManager.Tell(block); - system.Blockchain.Tell(block, ActorRefs.NoSender); - UpdateLastBlockIndex(block.Index, false); - RenewKnownHashes(block.Hash); + OnInventoryReceived((Block)msg.Payload); break; case MessageCommand.Consensus: - ConsensusPayload consensusPayload = (ConsensusPayload)msg.Payload; - system.TaskManager.Tell(consensusPayload); - system.Blockchain.Tell(consensusPayload, ActorRefs.NoSender); - RenewKnownHashes(consensusPayload.Hash); + OnInventoryReceived((ConsensusPayload)msg.Payload); break; case MessageCommand.FilterAdd: OnFilterAddMessageReceived((FilterAddPayload)msg.Payload); @@ -111,12 +104,8 @@ private void OnMessage(Message msg) OnPongMessageReceived((PingPayload)msg.Payload); break; case MessageCommand.Transaction: - Transaction tx = (Transaction)msg.Payload; - RenewKnownHashes(tx.Hash); if (msg.Payload.Size <= Transaction.MaxTransactionSize) - { - system.TransactionRouter.Tell(tx); - } + OnInventoryReceived((Transaction)msg.Payload); break; case MessageCommand.Verack: case MessageCommand.Version: @@ -295,10 +284,21 @@ private void OnGetHeadersMessageReceived(GetBlockByIndexPayload payload) EnqueueMessage(Message.Create(MessageCommand.Headers, HeadersPayload.Create(headers.ToArray()))); } - private void RenewKnownHashes(UInt256 hash) + private void OnInventoryReceived(IInventory inventory) { - pendingKnownHashes.Remove(hash); - knownHashes.Add(hash); + pendingKnownHashes.Remove(inventory.Hash); + knownHashes.Add(inventory.Hash); + system.TaskManager.Tell(inventory); + system.Blockchain.Tell(inventory, ActorRefs.NoSender); + switch (inventory) + { + case Transaction transaction: + system.Consensus?.Tell(transaction); + break; + case Block block: + UpdateLastBlockIndex(block.Index, false); + break; + } } private void OnInvMessageReceived(InvPayload payload) diff --git a/src/neo/Network/P2P/TransactionRouter.cs b/src/neo/Network/P2P/TransactionRouter.cs index 94e481c8a0..e187192b2b 100644 --- a/src/neo/Network/P2P/TransactionRouter.cs +++ b/src/neo/Network/P2P/TransactionRouter.cs @@ -2,39 +2,35 @@ using Akka.Routing; using Neo.Ledger; using Neo.Network.P2P.Payloads; +using System; namespace Neo.Network.P2P { - public class TransactionRouter : UntypedActor + internal class TransactionRouter : UntypedActor { - private readonly NeoSystem system; + public class Task { public Transaction Transaction; public bool Relay; } + + private readonly IActorRef blockchain; public TransactionRouter(NeoSystem system) { - this.system = system; + this.blockchain = system.Blockchain; } protected override void OnReceive(object message) { - switch (message) + if (!(message is Task task)) return; + blockchain.Tell(new Blockchain.PreverifyCompleted { - case Transaction tx: - if (tx.VerifyStateIndependent() == VerifyResult.Succeed) - OnTransactionReceived(tx); - break; - } - } - - private void OnTransactionReceived(Transaction tx) - { - system.TaskManager.Tell(tx); - system.Consensus?.Tell(tx); - system.Blockchain.Tell(tx, ActorRefs.NoSender); + Transaction = task.Transaction, + Result = task.Transaction.VerifyStateIndependent(), + Relay = task.Relay + }, Sender); } internal static Props Props(NeoSystem system) { - return Akka.Actor.Props.Create(() => new TransactionRouter(system)).WithRouter(new SmallestMailboxPool(20)); + return Akka.Actor.Props.Create(() => new TransactionRouter(system)).WithRouter(new SmallestMailboxPool(Environment.ProcessorCount)); } } } From c944e8676218c1ec9b700654b05a437d452942c7 Mon Sep 17 00:00:00 2001 From: erikzhang Date: Fri, 14 Aug 2020 19:35:03 +0800 Subject: [PATCH 52/55] Move namespace --- src/neo/{Network/P2P => Ledger}/TransactionRouter.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) rename src/neo/{Network/P2P => Ledger}/TransactionRouter.cs (95%) diff --git a/src/neo/Network/P2P/TransactionRouter.cs b/src/neo/Ledger/TransactionRouter.cs similarity index 95% rename from src/neo/Network/P2P/TransactionRouter.cs rename to src/neo/Ledger/TransactionRouter.cs index e187192b2b..8258c46751 100644 --- a/src/neo/Network/P2P/TransactionRouter.cs +++ b/src/neo/Ledger/TransactionRouter.cs @@ -1,10 +1,9 @@ using Akka.Actor; using Akka.Routing; -using Neo.Ledger; using Neo.Network.P2P.Payloads; using System; -namespace Neo.Network.P2P +namespace Neo.Ledger { internal class TransactionRouter : UntypedActor { From cd0cd4196cd1f8f70c10d0ea262ea95b66adca8e Mon Sep 17 00:00:00 2001 From: erikzhang Date: Fri, 14 Aug 2020 19:57:43 +0800 Subject: [PATCH 53/55] Move namespace --- src/neo/Network/P2P/Payloads/Witness.cs | 4 ++-- src/neo/SmartContract/Helper.cs | 3 ++- .../{Network/P2P/Payloads => SmartContract}/WitnessFlag.cs | 2 +- 3 files changed, 5 insertions(+), 4 deletions(-) rename src/neo/{Network/P2P/Payloads => SmartContract}/WitnessFlag.cs (85%) diff --git a/src/neo/Network/P2P/Payloads/Witness.cs b/src/neo/Network/P2P/Payloads/Witness.cs index 0c9faa13c0..d54158050d 100644 --- a/src/neo/Network/P2P/Payloads/Witness.cs +++ b/src/neo/Network/P2P/Payloads/Witness.cs @@ -11,8 +11,6 @@ public class Witness : ISerializable public byte[] InvocationScript; public byte[] VerificationScript; - public WitnessFlag Flag => VerificationScript.Length == 0 ? WitnessFlag.StateDependent : WitnessFlag.StateIndependent; - internal long GasConsumed { get; set; } private UInt160 _scriptHash; @@ -28,6 +26,8 @@ public virtual UInt160 ScriptHash } } + public bool StateDependent => VerificationScript.Length == 0; + public int Size => InvocationScript.GetVarSize() + VerificationScript.GetVarSize(); void ISerializable.Deserialize(BinaryReader reader) diff --git a/src/neo/SmartContract/Helper.cs b/src/neo/SmartContract/Helper.cs index 148a378209..ad36ef061e 100644 --- a/src/neo/SmartContract/Helper.cs +++ b/src/neo/SmartContract/Helper.cs @@ -146,7 +146,8 @@ internal static bool VerifyWitnesses(this IVerifiable verifiable, StoreView snap if (hashes.Length != verifiable.Witnesses.Length) return false; for (int i = 0; i < hashes.Length; i++) { - if (filter != WitnessFlag.All && !filter.HasFlag(verifiable.Witnesses[i].Flag)) + WitnessFlag flag = verifiable.Witnesses[i].StateDependent ? WitnessFlag.StateDependent : WitnessFlag.StateIndependent; + if (!filter.HasFlag(flag)) { gas -= verifiable.Witnesses[i].GasConsumed; if (gas < 0) return false; diff --git a/src/neo/Network/P2P/Payloads/WitnessFlag.cs b/src/neo/SmartContract/WitnessFlag.cs similarity index 85% rename from src/neo/Network/P2P/Payloads/WitnessFlag.cs rename to src/neo/SmartContract/WitnessFlag.cs index 6b31cdd55d..528562a70f 100644 --- a/src/neo/Network/P2P/Payloads/WitnessFlag.cs +++ b/src/neo/SmartContract/WitnessFlag.cs @@ -3,7 +3,7 @@ namespace Neo.SmartContract { [Flags] - public enum WitnessFlag : byte + internal enum WitnessFlag : byte { None = 0, From 3811cf6ea2e403022cd116d95264087c3bbe9a1f Mon Sep 17 00:00:00 2001 From: erikzhang Date: Fri, 14 Aug 2020 19:59:53 +0800 Subject: [PATCH 54/55] Optimize --- src/neo/SmartContract/Helper.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/neo/SmartContract/Helper.cs b/src/neo/SmartContract/Helper.cs index ad36ef061e..2ff56f8e5e 100644 --- a/src/neo/SmartContract/Helper.cs +++ b/src/neo/SmartContract/Helper.cs @@ -172,7 +172,7 @@ internal static bool VerifyWitnesses(this IVerifiable verifiable, StoreView snap if (hashes[i] != verifiable.Witnesses[i].ScriptHash) return false; offset = 0; } - using (ApplicationEngine engine = ApplicationEngine.Create(TriggerType.Verification, verifiable, snapshot != null ? snapshot.Clone() : snapshot, gas)) + using (ApplicationEngine engine = ApplicationEngine.Create(TriggerType.Verification, verifiable, snapshot?.Clone(), gas)) { ExecutionContext context = engine.LoadScript(verification, CallFlags.None, offset); if (init != null) engine.LoadContext(context.Clone(init.Offset), false); From f079a0fbd82bee0be46cdab81b9a493d6b26b47c Mon Sep 17 00:00:00 2001 From: erikzhang Date: Fri, 14 Aug 2020 20:04:53 +0800 Subject: [PATCH 55/55] Use the correct CallFlags --- src/neo/SmartContract/Helper.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/neo/SmartContract/Helper.cs b/src/neo/SmartContract/Helper.cs index 2ff56f8e5e..202cd862e3 100644 --- a/src/neo/SmartContract/Helper.cs +++ b/src/neo/SmartContract/Helper.cs @@ -174,7 +174,8 @@ internal static bool VerifyWitnesses(this IVerifiable verifiable, StoreView snap } using (ApplicationEngine engine = ApplicationEngine.Create(TriggerType.Verification, verifiable, snapshot?.Clone(), gas)) { - ExecutionContext context = engine.LoadScript(verification, CallFlags.None, offset); + CallFlags callFlags = verifiable.Witnesses[i].StateDependent ? CallFlags.AllowStates : CallFlags.None; + ExecutionContext context = engine.LoadScript(verification, callFlags, offset); if (init != null) engine.LoadContext(context.Clone(init.Offset), false); engine.LoadScript(verifiable.Witnesses[i].InvocationScript, CallFlags.None); if (engine.Execute() == VMState.FAULT) return false;