-
Notifications
You must be signed in to change notification settings - Fork 1k
[Neo Core Fix]Fix https://github.com/neo-project/neo/issues/2862 #3364
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
a037be6
ebc9377
6c27d09
9f13605
7d1afea
883bce9
977226a
3069a21
8893cd7
e397df8
004e5a1
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,184 @@ | ||
| // Copyright (C) 2015-2024 The Neo Project. | ||
| // | ||
| // SmartThrottler.cs file belongs to the neo project and is free | ||
| // software distributed under the MIT software license, see the | ||
| // accompanying file LICENSE in the main directory of the | ||
| // repository or http://www.opensource.org/licenses/mit-license.php | ||
| // for more details. | ||
| // | ||
| // Redistribution and use in source and binary forms with or without | ||
| // modifications are permitted. | ||
|
|
||
| #nullable enable | ||
|
|
||
| using Neo.Network.P2P.Payloads; | ||
| using System; | ||
| using System.Collections.Generic; | ||
| using System.Linq; | ||
|
|
||
| namespace Neo.Ledger; | ||
|
|
||
| /// <summary> | ||
| /// SmartThrottler: Protects Neo blockchain's memory pool from attacks and network congestion | ||
| /// </summary> | ||
| public class SmartThrottler | ||
| { | ||
| private readonly MemoryPool _memoryPool; | ||
| private readonly NeoSystem _system; | ||
| private uint _maxTransactionsPerSecond; | ||
| private int _transactionsThisSecond; | ||
| private DateTime _lastResetTime; | ||
| private long _averageFee; | ||
|
|
||
| // Fields for network load estimation | ||
| private readonly Queue<ulong> _recentBlockTimes = new(); | ||
| private const int BlockTimeWindowSize = 20; // Consider last 20 blocks | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Move to config |
||
| private ulong _lastBlockTimestamp; | ||
| private int _unconfirmedTxCount; | ||
|
|
||
| /// <summary> | ||
| /// Initializes a new instance of the SmartThrottler | ||
| /// </summary> | ||
| /// <param name="memoryPool">The memory pool this throttler is associated with</param> | ||
| /// <param name="system">The Neo system</param> | ||
| public SmartThrottler(MemoryPool memoryPool, NeoSystem system) | ||
| { | ||
| _memoryPool = memoryPool; | ||
| _system = system; | ||
| _maxTransactionsPerSecond = (uint)system.Settings.MemPoolSettings.MaxTransactionsPerSecond; | ||
| _lastResetTime = TimeProvider.Current.UtcNow; | ||
| _lastBlockTimestamp = _lastResetTime.ToTimestampMS(); | ||
| _averageFee = CalculateAverageFee(null); | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// Determines whether a new transaction should be accepted | ||
| /// </summary> | ||
| /// <param name="tx">The transaction to be evaluated</param> | ||
| /// <returns>True if the transaction should be accepted, false otherwise</returns> | ||
| public bool ShouldAcceptTransaction(Transaction tx) | ||
| { | ||
| var now = TimeProvider.Current.UtcNow; | ||
| if (now - _lastResetTime >= TimeSpan.FromSeconds(1)) | ||
| { | ||
| _transactionsThisSecond = 0; | ||
| _lastResetTime = now; | ||
| AdjustThrottling(null); | ||
| _averageFee = CalculateAverageFee(null); | ||
| } | ||
|
|
||
| // Check if we've hit the tx limit and it's not high priority | ||
| if ((_transactionsThisSecond >= _maxTransactionsPerSecond) && !IsHighPriorityTransaction(tx)) | ||
| return false; | ||
|
|
||
| _transactionsThisSecond++; | ||
| return true; | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// Updates the network state after a new block is added | ||
| /// </summary> | ||
| /// <param name="block">The newly added block</param> | ||
| public void UpdateNetworkState(Block block) | ||
| { | ||
| var currentTime = TimeProvider.Current.UtcNow.ToTimestampMS(); | ||
| var blockTime = currentTime - _lastBlockTimestamp; | ||
|
|
||
| _recentBlockTimes.Enqueue(blockTime); | ||
| if (_recentBlockTimes.Count > BlockTimeWindowSize) | ||
| _recentBlockTimes.Dequeue(); | ||
|
|
||
| _lastBlockTimestamp = currentTime; | ||
| _unconfirmedTxCount = _memoryPool.Count; | ||
| _averageFee = CalculateAverageFee(block); | ||
|
|
||
| AdjustThrottling(block); | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// Adjusts throttling parameters based on current network conditions | ||
| /// </summary> | ||
| private void AdjustThrottling(Block? block) | ||
| { | ||
| var memoryPoolUtilization = (double)_memoryPool.Count / _system.Settings.MemoryPoolMaxTransactions; | ||
| var networkLoad = EstimateNetworkLoad(block); | ||
|
|
||
| _maxTransactionsPerSecond = CalculateOptimalTps(memoryPoolUtilization, networkLoad, block); | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. _optimalMaxTransactionsPerSecond instead of _maxTransactionsPerSecond There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. no difference to the code. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nomenclature is bad like this, |
||
| } | ||
|
|
||
| /// <summary> | ||
| /// Estimates current network load | ||
| /// </summary> | ||
| /// <returns>An integer between 0 and 100 representing the estimated network load</returns> | ||
| private int EstimateNetworkLoad(Block? block) | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. move to double as well and base %, already divided by 100. The only use of it is aligned with memPool Use |
||
| { | ||
| var load = 0; | ||
|
|
||
| // 1. Memory pool utilization (30% weight) | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. These weights does not look like %, they are more than 100 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. how could it be more than 100? var memPoolUtilization = (double)_memoryPool.Count / _system.Settings.MemoryPoolMaxTransactions * 100;There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Check in the thread below |
||
| var memPoolUtilization = (double)_memoryPool.Count / _system.Settings.MemoryPoolMaxTransactions; | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. get this value from previous line before calling the method, it is called just once as it is right now |
||
| load += (int)(memPoolUtilization * 30); // Cap at 30 points | ||
|
|
||
| // 2. Recent block times (30% weight) | ||
| if (_recentBlockTimes.Count > 0) | ||
| { | ||
| var avgBlockTime = _recentBlockTimes.Average(t => (double)t); | ||
| load += (avgBlockTime < _system.Settings.MillisecondsPerBlock ? 1 : 0) * 30; // Cap at 30 points | ||
| } | ||
|
|
||
| // 3. Current block transaction count or unconfirmed transaction growth rate (40% weight) | ||
| if (block != null) // Cap at 40 points | ||
| { | ||
| var blockTxRatio = (double)block.Transactions.Length / _system.Settings.MaxTransactionsPerBlock; | ||
| load += (int)(Math.Min(blockTxRatio, 1) * 40); | ||
| } | ||
| else | ||
| { | ||
| var txGrowthRate = (double)_unconfirmedTxCount / _system.Settings.MaxTransactionsPerBlock; | ||
| load += (int)(Math.Min(txGrowthRate, 1) * 40); | ||
| } | ||
|
|
||
| return load; | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// Calculates optimal transactions per second | ||
| /// </summary> | ||
| private uint CalculateOptimalTps(double memoryPoolUtilization, int networkLoad, Block? block) | ||
| { | ||
| var baseTps = _system.Settings.MemPoolSettings.MaxTransactionsPerSecond; | ||
| var utilizationFactor = 1 - memoryPoolUtilization; | ||
| var loadFactor = 1 - (networkLoad / 100.0); | ||
|
|
||
| // Consider current block's transaction count if available | ||
| var blockFactor = 1.0; | ||
| if (block != null) | ||
| { | ||
| blockFactor = Math.Max(0.5, (double)block.Transactions.Length / _system.Settings.MaxTransactionsPerBlock); | ||
| } | ||
|
|
||
| var optimalTps = (uint)(baseTps * utilizationFactor * loadFactor * blockFactor); | ||
| return Math.Max(optimalTps, _system.Settings.MaxTransactionsPerBlock); // Ensure TPS isn't lower than max transactions per block | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// Determines if a transaction is high priority | ||
| /// </summary> | ||
| private bool IsHighPriorityTransaction(Transaction tx) | ||
| { | ||
| // High priority: fee > 3x average | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. committee address? |
||
| return tx.NetworkFee + tx.SystemFee > _averageFee * 3 || tx.GetAttribute<HighPriorityAttribute>() != null; | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// Calculates average fee of transactions in memory pool and new block (if provided) | ||
| /// </summary> | ||
| private long CalculateAverageFee(Block? block) | ||
| { | ||
| var transactions = _memoryPool.GetSortedVerifiedTransactions().ToList(); | ||
| if (block != null) | ||
| { | ||
| transactions.AddRange(block.Transactions); // Include transactions from the new block | ||
| } | ||
| return transactions.Count != 0 ? (long)transactions.Average(tx => tx.NetworkFee + tx.SystemFee) : 0; | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,73 @@ | ||
| # SmartThrottler | ||
|
|
||
| ## 1. Introduction | ||
|
|
||
| The SmartThrottler is designed to protect the blockchain from potential attacks and network congestion by intelligently controlling transaction flow. This document outlines its core features and implementation details. Issue ref. https://github.com/neo-project/neo/issues/2862. | ||
|
|
||
| ## 2. Key Features | ||
|
|
||
| - Dynamic adjustment of transaction acceptance rate | ||
| - Priority handling for high-fee transactions | ||
| - Multi-factor network load estimation | ||
| - Adaptive response to new block additions | ||
|
|
||
| ## 3. Core Components | ||
|
|
||
| ### 3.1 Transaction Acceptance Control | ||
|
|
||
| The `ShouldAcceptTransaction` method is the gatekeeper for new transactions. It resets the per-second transaction counter every second and checks against sender limits. High-fee transactions get preferential treatment. | ||
|
|
||
| ### 3.2 Network Load Estimation | ||
|
|
||
| Network load is calculated based on three factors: | ||
|
|
||
| 1. Memory Pool Usage (30% weight) | ||
| - Ratio of current transactions to pool capacity | ||
| - Indicates short-term transaction backlog | ||
|
|
||
| 2. Recent Block Times (30% weight) | ||
| - Average time for the last 20 blocks vs. expected time | ||
| - Reflects medium-term network performance | ||
|
|
||
| 3. Transaction Growth or Block Fullness (40% weight) | ||
| - Either current block transaction count or unconfirmed transaction growth | ||
| - Shows immediate transaction processing pressure | ||
|
|
||
| The final load score is capped at 100 to maintain consistency. | ||
|
|
||
| ### 3.3 Optimal TPS Calculation | ||
|
|
||
| The `CalculateOptimalTps` method determines the best transactions-per-second rate. It factors in memory pool usage, network load, and current block details to adapt to changing conditions. | ||
|
|
||
| ### 3.4 High-Priority Transaction Identification | ||
|
|
||
| Transactions with fees exceeding 3 times the average are flagged as high-priority. This allows important transactions to bypass normal throttling limits. | ||
|
|
||
| ### 3.5 Sender Limit Enforcement | ||
|
|
||
| Each sender is capped at 10 transactions in the memory pool. This prevents any single entity from flooding the network. | ||
|
|
||
| ## 4. Workflow | ||
|
|
||
| 1. Initialization: Set up initial parameters. | ||
| 2. Transaction Acceptance: | ||
| - Evaluate network conditions | ||
| - Apply throttling rules | ||
| - Update counters for accepted transactions | ||
| 3. Network State Updates: | ||
| - Recalculate average fees | ||
| - Adjust throttling parameters | ||
|
|
||
| ## 5. Key Algorithms | ||
|
|
||
| ### 5.1 Network Load Calculation | ||
|
|
||
| ``` | ||
| load = (pool_usage * 30) + (block_time_factor * 30) + (tx_growth_or_block_fullness * 40) | ||
| ``` | ||
|
|
||
| ### 5.2 Optimal TPS Calculation | ||
|
|
||
| ``` | ||
| optimal_tps = base_tps * (1 - pool_usage) * (1 - network_load/100) * block_factor | ||
| ``` |
Uh oh!
There was an error while loading. Please reload this page.