-
Notifications
You must be signed in to change notification settings - Fork 1k
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
Fix Parallel verification issues (v1) #1417
Conversation
I will fix the UT when we decide if this is the right fix. Maybe we should move this check to |
src/neo/Ledger/MemoryPool.cs
Outdated
{ | ||
_unsortedTransactions.Remove(hash); | ||
return false; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this isn't the best way. And it's not enough when balance < SendersFeeMonitor.AddSenderFee(tx)
, more txs will be removed from memory pool.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since we already have UpdatePoolForBlockPersisted
, and this TryAdd
is called from a single thread (the Blockchain actor). We need to find the cause of this phenomenon.
neo/src/neo/Ledger/MemoryPool.cs
Lines 351 to 361 in fc1a64b
internal void UpdatePoolForBlockPersisted(Block block, StoreView snapshot) | |
{ | |
bool policyChanged = LoadPolicy(snapshot); | |
_txRwLock.EnterWriteLock(); | |
try | |
{ | |
// First remove the transactions verified in the block. | |
foreach (Transaction tx in block.Transactions) | |
{ | |
if (TryRemoveVerified(tx.Hash, out _)) continue; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This happend because it's not a single thread, Blockchain actor, but was send by RPC
So we can add a lock in OnNewTransaction
and check if it's solved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So we can add a lock in OnNewTransaction and check if it's solved
It doesn't work in my tests..
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I can still get the error with one single CN, and the sender
wallet with only one address.
[15:19:21.903] relay block: height=23 hash=0x35e977d9d7eeabc3e0e568cb9cc6590ebc378929d34fd283c32f19abb20e45c2 tx=0
[15:19:21.913] persist block: height=23 hash=0x35e977d9d7eeabc3e0e568cb9cc6590ebc378929d34fd283c32f19abb20e45c2 tx=0
[15:19:21.923] initialize: height=24 view=0 index=0 role=Primary
[15:19:36.922] timeout: height=24 view=0
[15:19:36.930] send prepare request: height=24 view=0
[15:19:36.954] send commit
[15:19:36.965] relay block: height=24 hash=0x85d722eecef7f7b1f8d0ac761e13f999ed27584f0abb1fc7336f9bc404cdd2ef tx=512
[ERROR][2020/1/16 7:19:37][Thread 0021][akka://NeoSystem/user/$a] Operation is not valid due to the current state of the object.
Cause: System.InvalidOperationException: Operation is not valid due to the current state of the object.
at Neo.Ledger.Blockchain.Persist(Block block) in D:\NEO\Github\neo\src\neo\Ledger\Blockchain.cs:line 501
at Neo.Ledger.Blockchain.OnNewBlock(Block block) in D:\NEO\Github\neo\src\neo\Ledger\Blockchain.cs:line 328
at Neo.Ledger.Blockchain.OnReceive(Object message) in D:\NEO\Github\neo\src\neo\Ledger\Blockchain.cs:line 465
at Akka.Actor.UntypedActor.Receive(Object message)
at Akka.Actor.ActorBase.AroundReceive(Receive receive, Object message)
at Akka.Actor.ActorCell.ReceiveMessage(Object message)
at Akka.Actor.ActorCell.Invoke(Envelope envelope)
[ERROR][2020/1/16 7:19:37][Thread 0021][akka://NeoSystem/user/$a] Error while creating actor instance of type Neo.Ledger.Blockchain with 2 args: (Neo.NeoSystem,Neo.Plugins.Storage.Store)
Cause: [akka://NeoSystem/user/$a#1090028194]: Akka.Actor.PostRestartException: Exception post restart (System.InvalidOperationException)
---> System.TypeLoadException: Error while creating actor instance of type Neo.Ledger.Blockchain with 2 args: (Neo.NeoSystem,Neo.Plugins.Storage.Store)
---> System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation.
---> System.InvalidOperationException: Operation is not valid due to the current state of the object.
at Neo.Ledger.Blockchain..ctor(NeoSystem system, IStore store) in D:\NEO\Github\neo\src\neo\Ledger\Blockchain.cs:line 111
--- End of inner exception stack trace ---
at System.RuntimeMethodHandle.InvokeMethod(Object target, Object[] arguments, Signature sig, Boolean constructor, Boolean wrapExceptions)
at System.Reflection.RuntimeConstructorInfo.Invoke(BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
at System.RuntimeType.CreateInstanceImpl(BindingFlags bindingAttr, Binder binder, Object[] args, CultureInfo culture)
at System.Activator.CreateInstance(Type type, BindingFlags bindingAttr, Binder binder, Object[] args, CultureInfo culture, Object[] activationAttributes)
at System.Activator.CreateInstance(Type type, Object[] args)
at Akka.Actor.Props.ActivatorProducer.Produce()
at Akka.Actor.Props.NewActor()
--- End of inner exception stack trace ---
at Akka.Actor.Props.NewActor()
at Akka.Actor.ActorCell.CreateNewActorInstance()
at Akka.Actor.ActorCell.<>c__DisplayClass109_0.<NewActor>b__0()
at Akka.Actor.ActorCell.UseThreadContext(Action action)
at Akka.Actor.ActorCell.NewActor()
at Akka.Actor.ActorCell.FinishRecreate(Exception cause, ActorBase failedActor)
--- End of inner exception stack trace ---
sender wallet with initial balance 100000 gas.
request:
{
"jsonrpc": "2.0",
"method": "sendtoaddress",
"params": ["0x8c23f196d8a1bfd103a9dcb1f9ccf0c611377d3b", "NcnELA9BMsxDCzatGmTT5Tbq5dFTEXMarN",0.00000001],
"id": 1
}
use jmeter to send 600 requests at one time.
I'll help investigate this problem |
@cloud8little thanks for your test, i spent half hour without issues and before the fix the issue was thrown in the first 4 blocks... I will review it more! |
@cloud8little if you try to replicate your issue with multiple threads, you will get another error produced by parallel verification |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good job, In this case the gas calculation error can be prevented.
try | ||
{ | ||
// Check balance | ||
BigInteger balance = NativeContract.GAS.BalanceOf(snapshot, tx.Sender); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In this sense, the key error was to not consider the current Balance of the sender, which is updated in parallel during OnPersist event?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think so.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we should move the "balance check" to BlockChain.OnParallelVerified
, which is right place to verify the transaction.
Test cases:
Test result: [PASS]
|
I have told you that it is very dangerous to use multithreading in actors. |
I think we can call |
We need to check if after this changes, parallel will be faster |
#1423 we can choose wich is the best one. |
Close #1420
Note: The issue doesn't happen without parallel verification.