-
Notifications
You must be signed in to change notification settings - Fork 989
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
Allow duplicate output commitments #3271
Comments
Implementation-wise it might be more efficient to have two separate indices from output commitment to output mmr index: the current one for unique outputs (UO) and a separate one for duplicate outputs (DO). DO requires more space per entry, but is expected to be much smaller in size. The downside is some more case analysis is required when adding or spending outputs. |
I'd like to revisit the assumption that we want to -
With cut-through in a block (or aggregated transaction) we implicitly spend newest first. This would maximize the age of unspent outputs (oldest would be spent last) in the UTXO set in the presence of duplicates. |
If I have multiple duplicate instances of an output in the current UTXO set it is not necessarily safe to only spend some of them. The remaining instances would be at risk of transaction "replay" in the simple case. So presumably we would want the ability to spend multiple or all duplicate instances in a single transaction. |
If we support duplicate outputs then we can have the following -
These are duplicate in the sense they have the same commitment, but different as the features differ. When we spend an output (via a transaction input) we actually specify both the commitment and the features. i.e. spending "coinbase, commitment C" is different to spending "plain, commitment C". This has always actually struck me a bit weird. Its another aspect that we need to think through in the context of duplicate outputs. We also need to consider how the precedence rules and different output features will interact. There are some potentially nasty edge cases to consider here. |
That's odd. I never realized that Input specifies features. |
grin/core/src/core/transaction.rs Lines 1447 to 1457 in 098d25e
I think this decision was originally made to allow us to hash the input and check it matches the hash in the output MMR (and you need the features to do this) so as to avoid actually looking the output itself up from the MMR. But this is a weak argument for doing this.
Basically this all lives in the txpool impl. |
I had also assumed that if we allow duplicates, then the spending order should be Last-In First-Out, |
I believe this will be a consensus rule that will not be verifiable prior to the fast sync horizon. This would appear to be similar to the coinbase maturity rule - historical validators are unable to validate these rules were followed for data pre-horizon. |
We must remind ourselves of the unusual consensus model of Grin. |
👍 |
Taking a step back and flipping this around - are there are benefits to maintaining the current restriction where we prevent duplicate unspent outputs? One tx can prevent another tx from being accepted if they share a common output - are there scenarios where this is beneficial? |
Certainly not in the case where the output in question is 1-of-1, since its owner can create and spend that output at will. So it would be some n-of-n, and the n parties pre-constructed two or more txs all spending to this same output. I still don't see any possible use of this... |
Linking these here for reference - https://gist.github.com/phyro/7d054c5431376c0fdaafc88a1d0e023a https://forum.grin.mw/t/payjoins-for-replay-protection/7544/8 "Payjoins for replay protection" relies on "anchor" outputs and assumes "duplicate outputs" are not allowed. |
Consensus here is we want to retain current behavior and disallow duplicate outputs. |
We currently have a consensus rule that disallows duplicate output commitments in the UTXO set.
We allow output commitments to be reused over time, but duplicates cannot exist concurrently.
We would like to consider relaxing this rule. This would be a consensus breaking change.
Rationale
One transaction can effectively invalidate another transaction if they both share an output commitment. This is not an issue for regular transactions but is an issue for multi-party transactions, for example closing an Elder (Lightning style) payment channel.
In this scenario a multiparty output is spent to two individual outputs, one for each channel participant. Each participant is then able to prevent the overall transaction by introducing a conflicting duplicate output, preventing the channel funds being distributed back to both parties.
There are workarounds to this, specifically introducing two independent close transactions to the channel, preventing either from impacting the other. But this comes at a cost of increased complexity and increased channel communication cost (more transactions to build).
The ideal solution here is to allow duplicate output commitments.
Proposal
Introduce consensus rules governing precedence of precisely which instance of a set of duplicates will be spent first.
It would appear reasonable to spend oldest first, given multiple outputs to choose from.
We would still want to cut-through within a transaction or within a block before applying this new rule.
We currently maintain an
output_pos
index in the database mapping output commitment to unique MMR pos, along with the associated block height.This index would be reworked to map output commitments to a list of MMR positions.
In the common case this list will only contain a single MMR pos.
This list will behave as a stack
In cases where duplicate commitments exist we need to handle the following situations -
We also need to take care to ensure this works in an adversarial environment. We may only normally see a few duplicate outputs and for these only a few duplicate instances. But we need to robustly handle a scenario where we have large numbers of duplicates, themselves with potentially large numbers of instances.
Simply storing duplicates naively as serialized vecs in the db will not be sufficient.
Proposal is to maintain a "doubly-linked list" in the database for each output commitment.
In the simple case the "head" and "tail" will simply be the single instance.
In the duplicate case the "head" will point to the most recent instance, with the "tail" pointing to the oldest instance. Each instance will have references to the "next" and "prev" instance, ordered by age (MMR insertion order).
Not exhaustive but a rough idea of what is involved to maintain this -
This should easily handle adversarial numbers of outputs as we only ever operate on the ends of the list structure.
Rollout
I propose we target
4.0.0
with the consensus breaking changes.We can implement the index and necessary data structures in advance of this - supporting a flexible index while still preventing duplicates at the consensus level.
We can then make the necessary consensus rule changes as required.
We would need to take care to ensure the current consensus rules are unchanged until then, rejecting transactions and blocks as necessary if duplicates outputs commitments are present.
The text was updated successfully, but these errors were encountered: