Whether bundle equivocation fraud proof is necessary

We have equivocation proof for the consensus block which is critical to the consensus chain because without it if there 2 forks competing, the farmer is incentive to produce blocks to extend both forks to ensure its block will end up in the best fork and finalized so it can get the block reward, but the consensus chain uses longest chain fork choice rule, if all the farmers use this strategy we can never determine which fork is winning since they are keep growing in the same speed, as a result, a block is never finalized even beyond the confirmation_depth_k.

The situation is different for the domain because the domain chain is fully deterministically derived from the consensus chain, it follows the fork choice of the consensus chain, and the best domain fork is always the one derived from the best consensus fork. While the bundle is just a collection of domain transactions, it can’t affect the consensus of either the consensus chain or the domain chain.

If an operator produced 2 different bundles in the same slot, what we need to ensure is only one bundle is included in a specific consensus fork (so the operator won’t be rewarded twice), this can be done in the consensus runtime similar to the duplicated bundle check (since there are already some bundle info keep tracked in the consensus chain for the ER verification usage). If these 2 bundles are included in 2 different forks respectively it seems no harm, and it is just similar to a user signing 2 different tx with the same nonce and they are included in 2 different forks respectively.

1 Like

You are right! It is just like LazyLedger for which we can have duplicated or even conflicting transactions. This is absolutely OK because the execution is deterministic.

1 Like

Uncovered an old issue with similar concerns: Missing bundle equivocation checks allow malicious behavior by domain executors · Issue #1340 · subspace/subspace · GitHub

1 Like

From the consensus-chain point of view, a bundle is “just” a tx. Is this concern specific to bundles?
As with other transactions, one can broadcast multiple versions of the “same” tx by using the same nonce, hence spamming the p2 network by paying the fee only once. The way protocols defend against it is by not relaying the second appearance of the tx if it pays less fee than the previous version that the node already has. In Ethereum I think that it even must be (at least) 10% higher, otherwise nodes will reject it. So this kind of spamming has a cost.

1 Like

Is this concern specific to bundles?

Yeah, from my understanding, the only concern about bundle equivocation is an operator wins one slot but produces multiple bundles with this same slot and these bundles are included in the same consensus fork, as a result, the operator can get multiple rewards.

This can be defended by adding a check to the consensus node tx pool when receiving a bundle:

  • ensure the tx pool doesn’t contain other bundles with the same (domain_id, operator_id, slot)
  • ensure the bundle slot is larger than the highest slot of the bundle that was produced by the same operator and included in previous blocks.
1 Like

What rewards are we talking about? transaction fees?
If an operator submits multiple transactions to the consensus chain, first they have to pay for each transaction, secondly it is the domain operators, building the domain state, that should discard the second bundle, not the consensus farmers/nodes. So any execution receipt that includes the two bundles should be marked invalid and ignored by honest operators.

More generally, do farmers check that when a bundle is produced, the operator was eligible to produce it? These are checks that should be done on the domain level, farmers just get “blobs of data” and put them in blocks if they pay sufficient fee.

My question, that you replied to, was on the github issue (spamming the p2p network).

1 Like

Transaction fees, the fees of domain block n is distributed to the submitter of ER n and ER is submitted with bundle, the more times an operator submits the ER the more fees it gets.

If the check is delegated to the operator then a fraud proof will be required, which is what we try to avoid here, instead we want the farmer to perform the check to reject such bundle even before it enters the tx pool.

There are some basic checks done on the farmer side, including checking the ProofOfElection that proves the operator won a slot. In general, we prefer to keep these lightweight checks (which don’t involve domain chain state or domain runtime) on the farmer side, so an invalid bundle will be rejected before being included in the consensus chain (or even before entering the tx pool) and don’t need to involve fraud proof.

I can think of two alternative ways to address this.

On the consensus level: I don’t remember how exactly proof of election works for domain bundles, but since it is checked by nodes and assuming it explicitly states the slot, a block that contains 2 bundles with the same proof of election (in particular, for the same slot) should be considered invalid. Conceptually, it is not different than a block with 2 transactions from the same account with the same nonce.

On the domain level: as stated above, the second bundle (for some known order), or even both bundles, should be considered invalid by the domain operators, and not be part of the execution. If an operator executes it, and submits an ER for both bundles, it should be proven as incorrect by honest nodes. Conceptually, it is not different than any other incorrect execution of bundles.

:+1: I’m leaning toward the consensus level solution.

1 Like

To expand this further, We introduced bundle equivocation to penalize the bundle author to not re-use the same slot to submit multiple bundles. This is essentially spamming the network and they should ideally be dis-incentivised to do such a spamming.

Approach to watch the tx-pool to submit the Fraud proof if there is an equivocation slashes the operator and disincentivises them to do the same.

Moving this check to runtime where in the bundle simply rejected from inclusion because there is already an existing bundle from the slot seems to completely remove the slashing functionality and it does not give any information to consensus nodes if the they are doing it for every slot they win IIUC your proposal @Barak

Or are you suggesting to include the bundle and let the domain operator mark the bundle invalid ?
This approach would slash the operators sure but currently all the invalid bundles submitted through Execution receipt will be slashed after the ER is out of the challenged period, approximately one day. This will allow malicious operators to continue taking up the consensus block space until they are slashed.

I think the conclusion of the above discussion is that this is not something we need to penalize with fraud proof and slashing.

Consider an operator who doesn’t win the slot at all but still it constructs a bundle with an invalid ProofOfElection, and then broadcasts the bundle to the consensus network. This bundle when arriving at the honest farmer, will fail to pass the check and be rejected before adding to the tx pool, the operator node who gossips this bundle to the honest farmer its p2p network score will decrease as a penalty.

And the above is the same as the maximum harm an equivocate bundle can do after we add the check to the consensus runtime.

When considering network spamming, I think a user can do better spamming by sending a batch of System::remark tx with a big chunk of data and the same nonce but increasing tip like 1,2,3..., by sending these tx one by one and before any of them are included in the block, all of these tx will be consider as valid because tx with higher tip will replace the previous tx, as a result the user just pay one but can spam many tx to the network.

I think the conclusion of the above discussion is that this is not something we need to penalize with fraud proof and slashing

I’m not sure I agree TBH. IMHO, this is a malicious intent to get multiple bundles processed.

Consider an operator who doesn’t win the slot at all but still it constructs a bundle with an invalid ProofOfElection, and then broadcasts the bundle to the consensus network. This bundle when arriving at the honest farmer, will fail to pass the check and be rejected before adding to the tx pool, the operator node who gossips this bundle to the honest farmer its p2p network score will decrease as a penalty.

Well, this honest farmer is valid to reject the bundle because they did not win the slot. How is it comparable to operator who won the slot and decided to produce multiple bundles using the same slot ?

And the above is the same as the maximum harm an equivocate bundle can do after we add the check to the consensus runtime.

This is exactly I’m disagreeing about. While an operator who did not win the slot spams the network, then their P2P reputation decreases because they are not allowed to do it anyway. But If an operator who reuses the winning slot does not, IMO, fall under this same bucket.

When considering network spamming, I think a user can do better spamming by sending a batch of System::remark tx with a big chunk of data and the same nonce but increasing tip like 1,2,3... , by sending these tx one by one and before any of them are included in the block, all of these tx will be consider as valid because tx with higher tip will replace the previous tx, as a result the user just pay one but can spam many tx to the network.

Well this problem exists for any signed transaction and I believe this is not comparable to bundle equivocation.

@nazar-pc @dariolina do you have any thoughts here ?

Similar to transactions with the same nonce from the same address (where nodes replace the previous tx only if the new one pays higher fee), the proposal makes sure that at any given time the node’s mempool has at most one bundle (for a given proof of election). This means that the magnitude of spamming is restricted, and that this kind of dishonest behaviour has a cost.
Moreover, we can add a more strict rule that nodes don’t replace a bundle, even if the tx pays higher fees (but this may be incentive incompatible, and so we may end up with custom implementations removing this rule).

I don’t know if the p2p network treats these different types of transactions significantly different, but a dishonest operator, who wins a slot and wishes to spam the network, can start sending normal transactions with the same nonce and increasing fee – it will give the same result.

If we have a check in the consensus runtime to detect and reject equivocated bundle then the honest farmer will treat the equivocated bundle as the same as invalid bundle that didn’t win the slot.

If the question is how this check can be done I think adding the following rules will be enough:

  1. Use (operator_id, slot) as the tag of the bundle in the tx pool, since bundle doesn’t pay any tip, only the first bundle with the same tag will be accepted by the tx pool
  2. Keep track of the highest slot of the bundle that is submitted and included in chain by an operator, and reject any bundle produced by this operator and with a slot that is smaller than this.

My point is if the best harm an equivocated bundle can do is network spamming and any signed transaction can do better spamming than the equivocated bundle, is it still necessary to slash it with fraud proof?

One of the big reasons in addition to building forks on consensus side is indeed spamming of the network, which is also applicable to bundles.

The question here boils down to how cheap or expensive is it to verify the bundle validity once received.

I agree we can just stop propagation when we see conflicting bundles and not occupy space in transaction pool unnecessarily (though I’m not sure off top of my head that this is supported without custom transaction pool, maybe with the same “provides”). We just need to make sure bundle can be very cheaply checked for validity. If that is not the case, then it makes sense to have explicit equivocation to strongly disincentivizing operators from even attempting to do this.

Where to draw the line between “too cheap” and “too expensive” I do not yet know.

The equivocated bundle check is implemented in Add equivocated bundle check by NingLin-P · Pull Request #2775 · subspace/subspace · GitHub, its cost is similar to other bundle checks like bundle limit, proof of election, receipt, etc.

Is the proof of election persisted or tracked somehow? What if the operator/farmer tries to use the same proof in different consensus blocks?

1 Like

The proof of election is not tracked, but we do track the slot of the proof (per operator), which can be considered as the identity of the proof and it is increasing from block to block, so we can detect and reject the same proof.

1 Like