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

Prioritize verification of higher fee TXs and do not starve RpcServer w/ Large mempool #356

54 changes: 50 additions & 4 deletions neo/Network/LocalNode.cs
Original file line number Diff line number Diff line change
Expand Up @@ -143,12 +143,56 @@ private void AddTransactionLoop()
{
new_tx_event.WaitOne();

bool shouldCoolDown = false;
MemPoolReadWriteLock.EnterReadLock();
if (mem_pool.Count > 1000 && temp_pool.Count > 1000) shouldCoolDown = true;
MemPoolReadWriteLock.ExitReadLock();
// Don't starve readers wanting to acquire the mem_pool lock
if (shouldCoolDown) Thread.Sleep(1000);

Transaction[] transactions;
lock (temp_pool)
{
if (temp_pool.Count == 0) continue;
transactions = temp_pool.ToArray();
temp_pool.Clear();
if (temp_pool.Count < 1000)
Copy link
Contributor Author

Choose a reason for hiding this comment

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

I should make the 1000 here a constant to make it more easily configurable

Copy link
Contributor Author

Choose a reason for hiding this comment

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

would be a bit more accurate actually if the condition were <= instead of <, but it doesn't make much of a difference just optimizes for the case that temp_pool.Count is exactly 1000.

{
transactions = temp_pool.ToArray();
temp_pool.Clear();
}
else
{
// Attempt verifying large fee transactions first.
transactions = temp_pool
.OrderByDescending(p =>
{
try
{
var fee = p.NetworkFee;
return fee / p.Size;
}
catch (Exception)
{
return Fixed8.Zero;
}
})
.ThenByDescending(p =>
{
try
{
return p.NetworkFee;
}
catch (Exception)
{
return Fixed8.Zero;
}
})
.ThenByDescending(p => new BigInteger(p.Hash.ToArray()))
.Take(1000)
.ToArray();

foreach (var tx in transactions)
temp_pool.Remove(tx);
}
}
ConcurrentBag<Transaction> verified = new ConcurrentBag<Transaction>();
lock (Blockchain.Default.PersistLock)
Expand Down Expand Up @@ -230,8 +274,10 @@ private void Blockchain_PersistCompleted(object sender, Block block)

remain = mem_pool.Values.ToArray();
mem_pool.Clear();

if (millisSinceLastBlock > 10000)

// Use normal AddTransactionLoop to verify if there is a large mem_pool to avoid
// starvation of RpcSerer with large mem_pool.
if (millisSinceLastBlock > 10000 && remain.Length < 1000)
Copy link
Contributor Author

Choose a reason for hiding this comment

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

I should probably make these numbers constants also.

{
ConcurrentBag<Transaction> verified = new ConcurrentBag<Transaction>();
// Reverify the remaining transactions in the mem_pool
Expand Down