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

Added skipping of invalid transactions during block production #746

Merged
merged 11 commits into from
Nov 3, 2022

Conversation

xgreenx
Copy link
Collaborator

@xgreenx xgreenx commented Nov 2, 2022

Added skipping of invalid transactions during block production with unit tests.

Close #738

@xgreenx xgreenx self-assigned this Nov 2, 2022
@xgreenx xgreenx requested a review from a team November 2, 2022 20:24
fuel-core/src/executor.rs Outdated Show resolved Hide resolved
Co-authored-by: Brandon Kite <brandonkite92@gmail.com>

// Execute each transaction.
for (idx, tx) in tx_iter {
Copy link
Member

@Voxelot Voxelot Nov 2, 2022

Choose a reason for hiding this comment

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

why do we need to change this to a while loop with manually managed index incrementing? Is it just for skipping the first tx?

I'd prefer the iterator based approach to ensure we don't infinitely loop, or open the possibility of future refactoring bugs where the index isn't managed properly.

Copy link
Collaborator Author

@xgreenx xgreenx Nov 3, 2022

Choose a reason for hiding this comment

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

It was done to be able to use swap_remove below
image

With an iterator, it is not possible. Alternative to the while loop, I can transform transactions into into_iterator, filter them, and after collect them into vector and set to the block. Or Vec::retain

Copy link
Contributor

Choose a reason for hiding this comment

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

You could use retain_mut

Copy link
Member

@Voxelot Voxelot Nov 3, 2022

Choose a reason for hiding this comment

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

Hmm I don't think we'd want to swap_remove, as wouldn't that change the sorted order of the transactions and potentially impact the validity of the block?

For example, let's say you have 3 transactions (tx1, tx2, tx3):

  • let tx3 depend on the output of tx2
  • let tx1 be a faulty tx that needs to be skipped

If tx1 is swap_removed, the vec of transactions will now be [tx3, tx2]. When another node tries to sync this block, it will be invalid as tx3 depends on utxos that won't be in the state set yet. Worse, tx3 wont even be processed at all.

I made a simple playground to demonstrate how this can lead to pretty severely incorrect results on a larger set of txs where half of the txs are invalid: https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=50c1cc2edb68d931ebd99aa3e2ce58bc

I'd rather the focus of the code be on correctness and clarity, vs optimizing array access and modification.

As a remedy, I'd prefer to lean more heavily on iterator style operations like FilterMap as opposed to imperatively mucking with the memory. Generally speaking, modifying lists in place while iterating over them is a recipe for bugs.

Copy link
Member

Choose a reason for hiding this comment

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

Rust is also specially tuned to speed up iterators vs loops. It allows the compiler to do more inlining and other optimizations that aren't possible with side-effectful imperative looping styles: https://doc.rust-lang.org/book/ch13-04-performance.html

Copy link
Member

@Voxelot Voxelot Nov 3, 2022

Choose a reason for hiding this comment

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

Also, I don't think we'd want to increment the index if the tx was skipped. As the index is used for txpointers and other indexes where we want to record the total location of a tx within a block. If there are skipped txs and we increment the idx anyways, these indexes will point to incorrect locations in the block.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

In while we don't increment it for skipped transacitons=)

Copy link
Member

Choose a reason for hiding this comment

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

ah right - the continue

Copy link
Member

Choose a reason for hiding this comment

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

The changes look better, although since the original bug wasn't caught in the original unit tests I think we should add new cases to cover the issue I uncovered above.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Done

fuel-core/src/executor.rs Outdated Show resolved Hide resolved
Co-authored-by: Brandon Kite <brandonkite92@gmail.com>
Copy link
Contributor

@freesig freesig left a comment

Choose a reason for hiding this comment

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

It would be good to see this done without indices. Even if you get it correct it will be very easy for someone else to get it wrong in a refactor


// Execute each transaction.
for (idx, tx) in tx_iter {
Copy link
Contributor

Choose a reason for hiding this comment

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

You could use retain_mut

@xgreenx xgreenx requested review from Voxelot and freesig November 3, 2022 01:16
fuel-core/src/executor.rs Show resolved Hide resolved
@xgreenx xgreenx requested a review from freesig November 3, 2022 02:47
Copy link
Contributor

@freesig freesig left a comment

Choose a reason for hiding this comment

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

Nice one!

@xgreenx xgreenx merged commit 6b986d5 into master Nov 3, 2022
@xgreenx xgreenx deleted the bugfix/skip-invalid-transactions branch November 3, 2022 21:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

The proper handling of invalid transactions during block execution
3 participants