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

Retry adding send_raw_transaction to the mempool after missing UTXO failures #3654

Closed
conradoplg opened this issue Feb 25, 2022 · 8 comments · Fixed by #4015
Closed

Retry adding send_raw_transaction to the mempool after missing UTXO failures #3654

conradoplg opened this issue Feb 25, 2022 · 8 comments · Fixed by #4015
Assignees
Labels
C-enhancement Category: This is an improvement lightwalletd any work associated with lightwalletd

Comments

@conradoplg
Copy link
Collaborator

conradoplg commented Feb 25, 2022

Motivation

ZecWallet Lite creates transactions that spend transparent outputs from mempool transactions. But Zebra's mempool validation requires all UTXOs to be mined.

So we want send_raw_transaction to support transactions based on unmined UTXOs in the mempool.

We only need to support one level of unmined transaction dependencies, because that is what ZecWallet creates.

Designs

Do what Bitcoin does:

  • put transactions received via send_raw_transaction in a RPC-specific queue (we don't need to queue gossiped transactions)
  • re-submit failed transactions after receiving each new block
  • add a timeout of a few blocks, to clear transactions that will never succeed

Related Work

@conradoplg conradoplg added C-enhancement Category: This is an improvement S-needs-triage Status: A bug report needs triage P-Low ❄️ labels Feb 25, 2022
@ftm1000
Copy link

ftm1000 commented Feb 28, 2022

@ftm1000 ftm1000 added lightwalletd any work associated with lightwalletd and removed S-needs-triage Status: A bug report needs triage labels Mar 14, 2022
@oxarbitrage
Copy link
Contributor

How can we reproduce this problem in a test case and where it is happening exactly in the codebase ? If i understand this issue correctly the mempool will reject a transaction if it has utxos referencing another transaction inside the mempool. I can't find where is this is enforced.

I think the first step will be somehow reproduce and then proceed with the work on building the queue

@oxarbitrage
Copy link
Contributor

This ticket might be blocked on #3512

@conradoplg
Copy link
Collaborator Author

@oxarbitrage I think the idea is to:

  • Send a transaction A to the mempool using sendrawtransaction
  • Send a transaction B to the mempool, which spends an output from A, using sendrawtransaction, right after the previous (i.e. before the previous one is mined)

Since we don't actually have code for generating transactions, we would either need to mock this somehow (e.g. we can mock the transaction verifier to always return true, and thus we can create a transaction with dummy signatures), or do a integration test with a real wallet. Probably both, but the mock test seems to be a good start, if it's doable. I'm not sure how much work it will be, though.

You're correct that this is blocked on #3512 but that's just for testing. If we run out of stuff to implement than it's possible to implement this and leave testing for later.

@oxarbitrage
Copy link
Contributor

Thank you, that is pretty much what i had in mind.

The problem is right now if we do this from a unit/prop test, all transactions will be accepted because we don't verify them (mocked mempool). I think we are going to need a mempool in the tests that implement verification in order to be rejected.

Do you know where in the mempool verification the transactions are rejected by this issue?

@conradoplg
Copy link
Collaborator Author

Thank you, that is pretty much what i had in mind.

The problem is right now if we do this from a unit/prop test, all transactions will be accepted because we don't verify them (mocked mempool). I think we are going to need a mempool in the tests that implement verification in order to be rejected.

Do you know where in the mempool verification the transactions are rejected by this issue?

Good question. I think it will fail transaction validation, not the mempool itself. It will wait for the UTXO to appear in state and eventually timeout, and then be rejected by the mempool, i.e. it will pass through here:

storage.reject_if_needed(txid, e);

So we'd need to mock the tx verifier to make the first tx validate but return a TransactionDownloadVerifyError::DownloadFailed on the second.

@oxarbitrage
Copy link
Contributor

Ok cool, that is something to get started. Thank you very much for the input.

@teor2345
Copy link
Contributor

teor2345 commented Mar 21, 2022

Testing

The problem is right now if we do this from a unit/prop test, all transactions will be accepted because we don't verify them (mocked mempool).

When you use a MockService for the mempool service, you can return whatever mempool responses you like:

  1. Expect a request using expect_request or expect_request_that
  2. Send the response using the returned ResponseSender's respond method

Design

Currently, the mempool queues new transactions for verification internally. But it doesn't tell us the result of verification.

If we keep that design, we'd need to queue every transaction for retries.

Then there are 3 retry cases we need to handle:

  1. The transaction is in the state: remove it from the queue
  2. The transaction is in the mempool: remove it from the queue
  3. The transaction is not in the state or mempool: re-send the transaction to the mempool

After we've retried each transaction a few times, we should give up. If we give up using a timeout, it will handle high CPU/verification load better.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
C-enhancement Category: This is an improvement lightwalletd any work associated with lightwalletd
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants