Skip to content
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

[Neo Core Fix]Fix https://github.com/neo-project/neo/issues/2862 #3364

Closed
wants to merge 11 commits into from

Conversation

Jim8y
Copy link
Contributor

@Jim8y Jim8y commented Jun 27, 2024

Closes #2862

Description

There is an issue in the memorypool where attacker can dos the node by sending tons of transactions with ascending transaction fees.

Fixes # #2862

Type of change

  • Optimization (the change is only an optimization)
  • Style (the change is only a code style for better maintenance or standard purpose)
  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • This change requires a documentation update

How Has This Been Tested?

Test Configuration:

  • TestReVerifyTopUnverifiedTransactionsIfNeeded
  • TestReVerifyTopUnverifiedTransactionsWithSmartThrottler

Checklist:

  • My code follows the style guidelines of this project
  • I have performed a self-review of my code
  • I have commented my code, particularly in hard-to-understand areas
  • I have made corresponding changes to the documentation
  • My changes generate no new warnings
  • I have added tests that prove my fix is effective or that my feature works
  • New and existing unit tests pass locally with my changes
  • Any dependent changes have been merged and published in downstream modules

@Jim8y
Copy link
Contributor Author

Jim8y commented Jun 27, 2024

@superboyiii can you help to test it? I will fix the test if this pr is truly working. @dusmart can you take a look?

Copy link
Contributor

@roman-khimov roman-khimov left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not a solution to me.

src/Neo.CLI/config.fs.testnet.json Outdated Show resolved Hide resolved
Copy link
Member

@cschuchardt88 cschuchardt88 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why are all these markdown file in with the source? Should be in docs folder in the root of the repo.

@Jim8y
Copy link
Contributor Author

Jim8y commented Jun 28, 2024

Why are all these markdown file in with the source? Should be in docs folder in the root of the repo.

I know what you mean, but we don't have a doc folder.

@Jim8y
Copy link
Contributor Author

Jim8y commented Jun 28, 2024

Not a solution to me.

I need more specific reason.

Copy link
Member

@shargon shargon left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Partially review at Jim8y#1

/// </summary>
private bool IsHighPriorityTransaction(Transaction tx)
{
// High priority: fee > 3x average
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

committee address?


// Fields for network load estimation
private readonly Queue<ulong> _recentBlockTimes = new();
private const int BlockTimeWindowSize = 20; // Consider last 20 blocks
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Move to config

Copy link
Member

@vncoelho vncoelho left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I reviewed the PR, @Jim8y.
I see some hope in it right now.

This is currently not in milestone for 3.8.0, however, I will try to take a look more carefully soon.

var memoryPoolUtilization = (double)_memoryPool.Count / _system.Settings.MemoryPoolMaxTransactions;
var networkLoad = EstimateNetworkLoad(block);

_maxTransactionsPerSecond = CalculateOptimalTps(memoryPoolUtilization, networkLoad, block);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

_optimalMaxTransactionsPerSecond instead of _maxTransactionsPerSecond

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no difference to the code.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nomenclature is bad like this, maxTransactionPerSecond for something that is variable does not looks good to me.

/// Estimates current network load
/// </summary>
/// <returns>An integer between 0 and 100 representing the estimated network load</returns>
private int EstimateNetworkLoad(Block? block)
Copy link
Member

Choose a reason for hiding this comment

The 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)
var memPoolUtilization = (double)_memoryPool.Count / _system.Settings.MemoryPoolMaxTransactions;
Copy link
Member

Choose a reason for hiding this comment

The 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

{
var avgBlockTime = _recentBlockTimes.Average(t => (double)t);
var blockTimeRatio = avgBlockTime / _system.Settings.MillisecondsPerBlock;
load += (int)(Math.Min(blockTimeRatio, 2) * 30); // Cap at 60 points
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not sure.

avgBlockTime should usually not be lower than " _system.Settings.MillisecondsPerBlock".
So, usually blockTimeRatio is close to "1".

So, there is an average load from 30 - 60

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

its either 0 or 30 actually.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How?

(int)(Math.Min(blockTimeRatio, 2) * 30);

BlockTimeRatio will never/RARELY be less than 1.
So the range is 30 - 60 in this formula

{
var load = 0;

// 1. Memory pool utilization (30% weight)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These weights does not look like %, they are more than 100

Copy link
Contributor Author

Choose a reason for hiding this comment

The 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;

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Check in the thread below

load += (int)(Math.Min(txGrowthRate, 1) * 40);
}

return Math.Min(load, 100); // Ensure load doesn't exceed 100
Copy link
Member

@vncoelho vncoelho Jun 28, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is bad for any weight metric, insert some cut after weighting.

This part of the code needs enhanced.

If we decide move on with this solution I can later test and analyze.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated, now maximum load is 100.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

how could it be more than 100?

The same reason you have this Math.Min(load, 100); here

if (_recentBlockTimes.Count > 0)
{
var avgBlockTime = _recentBlockTimes.Average(t => (double)t);
load += (avgBlockTime < _system.Settings.MillisecondsPerBlock?1:0) * 30; // Cap at 30 points
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is bad formula as well, @Jim8y.
load += (avgBlockTime < _system.Settings.MillisecondsPerBlock?1:0) * 30; // Cap at 30 points is a degree function in control theory.

Copy link
Member

@vncoelho vncoelho Jun 28, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Previous formula was surely better, you just need to adjust the weights.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

could not understand, maybe you can provide one for me.

@shargon shargon mentioned this pull request Jun 28, 2024
15 tasks
Copy link
Member

@AnnaShaleva AnnaShaleva left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not a solution to me.

I need more specific reason.

I agree with Roman, and I don't quite like the idea of restricting the node in that way. I also agree with the #2862 (comment), it seems that this problem should be resolved on a consensus level rather than by restricting TPS at mempool level.

@dusmart
Copy link

dusmart commented Jul 2, 2024

It's great to have a feasible solution here.

My concern is that will this smart throttler can not defend us from other DoS vectors. A possible scene maybe the leader CN chooses a low priority tx somehow, then the other CNs may not get that low priority tx during a heavy network load. Then the consensus could not be reached. I've got to say. This is not the issue introduced by this PR. It's there already.

It would be better if this or some new PRs could prevent the above scene.

@Jim8y
Copy link
Contributor Author

Jim8y commented Jul 16, 2024

I agree with Roman, and I don't quite like the idea of restricting the node in that way. I also agree with the #2862 (comment), it seems that this problem should be resolved on a consensus level rather than by restricting TPS at mempool level.

@AnnaShaleva I dont care about how you agree with roman, i am sorry to say this anna, you and roman are in the same community and ofcourse you are with him all the time. What i care is what is your solution, you can always say this is not a perfect solution, I accept that, but where is your solution? leaving the network unprotected for months even years just waiting for a perfect solution is your solution? Previously i also asked @shargon not to sayI dont like or I dont think , cause it means nothing to me, as i dont care about how you feel, but I do respect and value your technical opinion. Propose your solution, work on it, that is what we need right now.

You are such a great reviewer and core contributer, I will always carefully consider your suggestions. As long as its not some feeling.

@Jim8y
Copy link
Contributor Author

Jim8y commented Dec 17, 2024

replaced with #3631

@Jim8y Jim8y closed this Dec 17, 2024
@Jim8y Jim8y deleted the fix-2862 branch December 17, 2024 13:07
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[suggestion] P2P module Enhancement
7 participants