-
Notifications
You must be signed in to change notification settings - Fork 116
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
feat(rpc): Implement an RPC transaction queue #4015
Conversation
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 looks like a good design, I like the way you have separated the code out into different structs with clear roles. And it achieves the goals of the retry queue ticket.
Here are some alternative ways to achieve the same goals. And some things we need to be careful about. Let me know what you think!
Performance
I think we'll get better performance without the Mutex
.
Here is how we could get the transactions instead:
RpcImpl::send_raw_transaction()
->RpcImpl.transaction_sender
->- channel ->
Runner::run
receiver
To make that happen, we could do something like:
- Move the channel sender to
RpcImpl
- Move the channel receiver to
Runner
, and listen at the start of each run loop - Remove the
Listener
, its task, and theMutex
Denial of Service
We're getting transactions from users all over the internet. Some of them might send lots of transactions, so we need to handle that well.
Currently, there is no limit on the size of the Queue
.
And if the mpsc
channel is full, it will block the send_raw_transaction
RPC response until the next Runner
loop. (The blocking happens after the changes above. Without them, the mutex might cause deadlocks.)
It's ok to drop extra transactions, because we already sent them to the mempool once. (I like the way this PR does that separately.)
Here are some ways to drop extra transactions:
- Use a
broadcast
channel to automatically drop the oldest transactions when the channel is full - Add transactions to the front of the
Queue
, and remove them from the back if the queue gets full. You can use anIndexMap
as an orderedHashMap
.
This is similar to what the mempool does with its downloads and internal storage.
This comment was marked as resolved.
This comment was marked as resolved.
@oxarbitrage I can do a review if you'd like, did you want to do it on a video call? I think that will make it easier for me to understand some of the details. |
* Check for panics in the RPC transaction queue * Add missing pin! and abort in the start task * Check for transaction queue panics in tests
In PR #4046 I changed the return type of a method, and fixed up all the call sites. But I think it's now used in more tests on the main branch. I'll push a fix today. |
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.
It was a trivial fix in a new test on the main
branch, so I'm going to re-approve the PR with my fix.
This PR failed with a temporary authorisation error:
https://github.com/ZcashFoundation/zebra/runs/5865028642?check_suite_focus=true#step:9:2043 |
@Mergifyio refresh |
✅ Pull request refreshed |
The merge queue's sync past mandatory checkpoint step failed with:
|
@Mergifyio update |
✅ Branch has been successfully updated |
@Mergifyio requeue |
✅ The queue state of this pull request has been cleaned. It can be re-embarked automatically |
Motivation
When
send_raw_transaction
rpc method is called, transactions can fail to get into the mempool. We need a queue of transactions created by the rpc call that can resubmit this failed transactions at a later time (after a block gets added).Close #3654 if merged.
Solution
An rpc queue was implemented where retries are done.
Review
I think the code is pretty much complete now and have some decent test coverage. @jvff or @teor2345 will be good candidates for the review.
Reviewer Checklist