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

Reject UTXO double spends #2511

Merged
merged 20 commits into from
Jul 22, 2021
Merged

Reject UTXO double spends #2511

merged 20 commits into from
Jul 22, 2021

Conversation

teor2345
Copy link
Contributor

@teor2345 teor2345 commented Jul 20, 2021

Motivation

We don't want users to be able to create new coins by spending transparent outputs more than once.

Specifications

Validation state associated with transparent inputs and outputs, such as the UTXO (Unspent Transaction Output) set, is not described in this document; it is used in essentially the same way as in Bitcoin.

https://zips.z.cash/protocol/protocol.pdf#transactions

each output of a particular transaction can only be used as an input once in the block chain.
Any subsequent reference is a forbidden double spend - an attempt to spend the same satoshis twice.

https://developer.bitcoin.org/devguide/block_chain.html#introduction

Any input within this block can spend an output which also appears in this block (assuming the spend is otherwise valid).
However, the TXID corresponding to the output must be placed at some point before the TXID corresponding to the input.
This ensures that any program parsing block chain transactions linearly will encounter each output before it is used as an input.

https://developer.bitcoin.org/reference/block_chain.html#merkle-trees

Designs

https://github.com/ZcashFoundation/zebra/blob/main/book/src/dev/rfcs/0005-state-updates.md#pub-fn-pushmut-self-block-arcblock

Solution

  • In the non-finalized state, check transparent spends against previous transactions in the block, the relevant non-finalized chain, and the finalized state
  • Add errors for each of these cases
  • Add useful methods to existing types

Closes #2231.

Testing

  • Test that duplicate transparent UTXOs are rejected by the non-finalized state
    • later transactions in this block
    • not in the non-finalized state or the finalized state
    • previously spent and never created
  • Fix other tests that fail these new checks
  • Add test-only methods to existing types
  • Move existing test functions so they can be used by multiple tests

Review

I'd like a review from @jvff.

This PR will conflict with a bunch of other recent/upcoming state PRs, but the conflicts should be easy enough to resolve.

Reviewer Checklist

  • Code implements Specs and Designs
  • Tests for Expected Behaviour
  • Tests for Errors

@teor2345 teor2345 added A-consensus Area: Consensus rule updates NU Sprout Network Upgrade: Sprout specific tasks (before Overwinter) A-rust Area: Updates to Rust code C-enhancement Category: This is an improvement P-Medium labels Jul 20, 2021
@teor2345 teor2345 requested a review from jvff July 20, 2021 04:51
@teor2345 teor2345 self-assigned this Jul 20, 2021
Copy link
Contributor

@jvff jvff left a comment

Choose a reason for hiding this comment

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

Looks good so far. There's only one optional suggestion that I'm not sure if it's valid, but if so it might affect the API of the function in the check module.

zebra-state/src/service/check/utxo.rs Outdated Show resolved Hide resolved
Base automatically changed from rename-nullifier-tests to main July 20, 2021 23:25
@teor2345 teor2345 force-pushed the reject-transparent-double-spends branch from 3859a5a to 76fbce1 Compare July 20, 2021 23:26
teor2345 and others added 10 commits July 21, 2021 10:58
Check that transparent spends use unspent outputs from:
* earlier transaction in the same block,
* earlier blocks in the parent non-finalized chain, or
* the finalized state.
Co-authored-by: Janito Vaqueiro Ferreira Filho <janito.vff@gmail.com>
- split each error case into a separate check
- combine `contains` and `insert`
- add a missing check against the non-finalized unspent UTXOs
- rename arguments and edit error strings for clarity
@teor2345 teor2345 force-pushed the reject-transparent-double-spends branch from 385211c to 8a411d2 Compare July 21, 2021 00:58
teor2345 added 3 commits July 21, 2021 15:31
- accept output and spend in the same block
- accept output and spend in a later block
- reject output and double-spend all in the same block
- reject output then double-spend in a later block
- reject output, spend, then double-spend all in different blocks
Copy link
Contributor

@jvff jvff left a comment

Choose a reason for hiding this comment

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

I still haven't finished reviewing the tests, I apologize for that :/

zebra-state/src/service/check/tests/utxo.rs Outdated Show resolved Hide resolved
zebra-state/src/service/check/tests/utxo.rs Outdated Show resolved Hide resolved
@teor2345 teor2345 marked this pull request as ready for review July 22, 2021 01:50
@teor2345 teor2345 force-pushed the reject-transparent-double-spends branch from 19fac23 to c44c17e Compare July 22, 2021 02:15
@teor2345 teor2345 changed the title WIP: Reject UTXO double spends Reject UTXO double spends Jul 22, 2021
Copy link
Contributor

@jvff jvff left a comment

Choose a reason for hiding this comment

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

Looks good. I just added some optional comments.

That was a lot of tests. If we end up having to write more tests like these, it might make sense to look into writing some more abstractions 🤔

zebra-state/src/service/check/tests/utxo.rs Show resolved Hide resolved
zebra-state/src/service/check/tests/utxo.rs Show resolved Hide resolved
zebra-state/src/service/check/tests/utxo.rs Show resolved Hide resolved
@teor2345
Copy link
Contributor Author

That was a lot of tests. If we end up having to write more tests like these, it might make sense to look into writing some more abstractions 🤔

Honestly I tried, there's already a lot of abstractions in there.

@teor2345
Copy link
Contributor Author

That was a lot of tests. If we end up having to write more tests like these, it might make sense to look into writing some more abstractions 🤔

Honestly I tried, there's already a lot of abstractions in there.

Thinking about this a bit more, we could use something like the contains_(shielded)_nullifier and best_contains_(shielded)_nullifier methods for UTXOs.

But I think the tests are good enough for now.

@teor2345 teor2345 enabled auto-merge (squash) July 22, 2021 23:22
@teor2345 teor2345 merged commit e6e0324 into main Jul 22, 2021
@teor2345 teor2345 deleted the reject-transparent-double-spends branch July 22, 2021 23:40
mpguerra added a commit that referenced this pull request May 19, 2023
mergify bot pushed a commit that referenced this pull request May 23, 2023
* ZIPs were updated to remove ambiguity, this was tracked in #1267.

* #2105 was fixed by #3039 and #2379 was closed by #3069

* #2230 was a duplicate of #2231 which was closed by #2511

* #3235 was obsoleted by #2156 which was fixed by #3505

* #1850 was fixed by #2944, #1851 was fixed by #2961 and #2902 was fixed by #2969

* We migrated to Rust 2021 edition in Jan 2022 with #3332

* #1631 was closed as not needed

* #338 was fixed by #3040 and #1162 was fixed by #3067

* #2079 was fixed by #2445

* #4794 was fixed by #6122

* #1678 stopped being an issue

* #3151 was fixed by #3934

* #3204 was closed as not needed

* #1213 was fixed by #4586

* #1774 was closed as not needed

* #4633 was closed as not needed

* Clarify behaviour of difficulty spacing

Co-authored-by: teor <teor@riseup.net>

* Update comment to reflect implemented behaviour

Co-authored-by: teor <teor@riseup.net>

* Update comment to reflect implemented behaviour when retrying block downloads

Co-authored-by: teor <teor@riseup.net>

* Update `TODO` to remove closed issue and clarify when we might want to fix

Co-authored-by: teor <teor@riseup.net>

* Update `TODO` to remove closed issue and clarify what we might want to change in future

Co-authored-by: teor <teor@riseup.net>

* Clarify benefits of how we do block verification

Co-authored-by: teor <teor@riseup.net>

* Fix rustfmt errors

---------

Co-authored-by: teor <teor@riseup.net>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-consensus Area: Consensus rule updates A-rust Area: Updates to Rust code C-enhancement Category: This is an improvement NU Sprout Network Upgrade: Sprout specific tasks (before Overwinter)
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Stop double-spends by checking nullifiers and UTXO spends in each non-finalized chain
2 participants