Join GitHub today
GitHub is home to over 28 million developers working together to host and review code, manage projects, and build software together.Sign up
A transaction that will normally fail to execute due to a uniqueness violation, if submitted as a deferred transaction will partially execute instead of failing entirely as expected #6214
When submitting a transaction that will cause a uniqueness constraint violation, it will fail immediately when submitting the transaction through cleos as expected. But submitting the exact same transaction as a deferred transaction causes some of the actions to succeed according to the history plugin and signals from the chain plugin while throwing the uniqueness constraint violation in nodeos:
Line 27 is an attempt to submit a duplicate transaction already done in line 19.
I haven't confirmed yet if any contract tables were actually changed or if it's just a bug in the history plugin where it shouldn't have recorded the second transaction attempt at line 27 due to it failing for uniqueness constraint violation.
Here is the nodeos output including some tags from the different signals in the chain plugin showing that the action trace was visible in accepted/applied transaction even though the transaction should have failed:
The transaction that was broadcasted had 3 actions in it as shown above (prepare, transfer, activate).
The transaction is designed such that if it would be submitted again as a duplicate then the activate action would try to insert a duplicate row and cause the entire transaction to fail. In the action log above i submitted the same transaction twice - it succeeded the first time as expected but the second time should have failed completely but actually one of the actions were applied according to anything listening on the applied transaction signal such as the history api and my plugin.
The transaction fails as expected when submitted as a normal transaction with nothing applied.
If it’s executed as a deferred transaction then the first action (prepare) emits an applied transaction signal and is saved in the history plugin while the other 2 actions are not applied as expected.
Analysis: the history plugin has a core assumption that it can blindly store traces without any status checking. The idea is that anything it stores will be rolled back by undo when there's a problem.
Problem: controller sometimes does the undo before sending
Potential fix: the history plugin will have to check for the existence of a transaction receipt. If it's absent or indicates failure then it shouldn't store the trace.
Caution for history plugin users: the history plugin is deprecated. It may have additional unnoticed border cases.
Caution for other plugin authors: even after this fix, the history plugin will still rely on undo, which greatly simplifies its logic. Plugins which store data outside of chainbase have a much higher burden. The history plugin is not suitable as a reference.
Absolutely. That's what the mongodb and state history plugins do, but only for deferred since those are part of consensus.
The deprecated history plugin won't after this fix.