Farmer equivocation is problematic

Currently in Subspace consensus we have a notion of equivocation. After thinking about it some I’m convinced that it is a UX hazard and should be re-designed in the way it functions.

For background, equivocation is supposed to punish malicious farmers that produce more than one block/vote with the same exact solution in it. I’m not going to go into details why that is desirable, just providing the gist of it briefly.

The implementation is inspired by equivocation for BABE in Substrate/Polkadot and results in identity of the plot being banned, essentially burning the whole plot.

That makes sense on the surface, except keypair generation cost is negligible for farmer comparing to sector creation. As such, truly malicious farmer will not actually get their plot burned, they’ll get a single sector of deterministically derived single-use keypair burned, yet it will indefinitely (right now, can be changed) occupy on-chain runtime state.

The only case when the whole plot will be burned is when farmer that uses reference implementation accidentally runs the cloned plot on two machines. While we can re-design implementation to also derive unique identities for each sector, it is unnecessary complexity if plot burning for actually malicious farmers is pointless in the first place.

What I think should happen instead is the reward for solution that was equivocating should be burned/taken away from farmer and the plot itself should remain valid because it is likely more costly to store record of it on chain comparing to generating sector in the first place.

Remaining question is how to do what I have described in above paragraph exactly.

1 Like

If it’s not too complicated to implement, it’d be great.

But I have concern about the ‘consensus’ since block time is 6s only: how do we know and reach to the consensus state across the network within 2s (?) that for a particular challenge, there is the proof from 2 nodes with the same sector id?

Subspace is different to all other blockchains, that’s for each challenge, there’re many winners (block and vote reward). Right now the number is 1+9, but what if we implement the dynamic reward that has the flexible number of vote reward based on netspace?

I don’t imagine enough the complexity in such case for consensus mechanism.

All I can imagine to add a similar feature is to keep going at plot id level. And every nodes in the blockchain keeps a table of a list of node id - plot id. So as soon as a new node is getting connected, the existing peers can validate and refuse the duplicated plot id. This validation is at the start of the node, so there won’t be any change during the consensus for block/vote reward.

P/S: I don’t think my solution works out well, after re-thinking about it. There should be delay until all nodes in the network get updated about new node and its plot id.

This topic is primarily targeted at discussing this with our research team. Discussion of block times and other things are off-topic here, this thread is only about discussing equivocation design.

Perhaps a stupid question: If we use hash(farmer id, piece id) for a farmer to select pieces to archive, then a different farmer id will lead to different pieces to archive. How does a truly malicious farmer avoid getting their plot burned?

1 Like

Current reference implementation creates multiple sectors under the same exact identity, so by blocking that identity we burn all the plots. But malicious farmer would derive a new identity for every single sector since sectors are independent, such that exactly one sector will be burned at a time and other sectors will remain intact.

What kind of record for equivocation do we keep (onchain)? And what is the case if a farmer creates multiple blocks with the same solution – would we still store a single record?

Also, there should be a time window for equivocation, right? What is it?

We did discuss this in research sync and agree that burning the whole plot is punishing honest, but uncareful users more than smart attackers. And storing the block list is also not useful given the repetition probabilities.

Remaining question is how to do what I have described in above paragraph exactly.

Is the challenge in the fact that when we see a solution first time we issue a reward and then when we see an equivocating one the first reward was already accredited?

Yes, that is the issue

A quick note about storing a list of equivocating public keys (in case it will be used somewhere): burned plots, like all other plots, have an expiry date, therefore we may store the malicious public key only until the expiry date (which we can roughly estimate at any point in time). After that the malicious farmer, even if using the same key, will have to create a new plot anyway.

Rewards should be given only after some amount of blocks (Bitcoin has a 100-block cooldown period). Isn’t that the case in Subspace?

It is probabilistic, so expiration will have to be quite large, but as described originally malicious farmer will not attempt to create more than one sector with the same identity, so their plot will remain intact regardless of what we do with banning.

Bitcoin is using UTXO model, so adding maturity in there is easy. But Subspace is using accounting model, so when reward is received it is immediately added to reward address’s balance and is immediately spendable.

Doesn’t have to be this way, right? The fact that Bitcoin uses a UTXO model may make the implementation easier, but the rational and main objective are similar.
We can have that block n+100 mints the coinbase reward for the farmer key for block n, and this is checked upon block validation.

Absolutely, we can design it however we want

Right, I was also thinking of delaying the reward as the right approach. We may not need 100, since our blocks are also ordered in PoT sense so there’s a very limited window for somebody to propose a block for a given slot.

1 Like

In addition to the already-discussed mitigations, I recommend that when honest farmers notice an equivocation – and if the tip of the chain(s) they see consists of an equivocated block – they “ignore” this block, basically consider it invalid. If an honest farmer is to produce the next block, it will build it on top of the parent of the equivocated block.

This will help in the situation where the dishonest farmer releases the equivocated blocks simultaneously, trying to cause a split in the network. If the dishonest farmer releases a second block at a later time (specifically after the original block is no longer at the tip), then this farmer will still get punished, but the probability of causing a sustained fork decreases, as honest farmers should already agree on the longest chain, in most cases.

@dariolina I looked at removing equivocation and replacing with banning on P2P level, but that is not easy to implement.

Block verification doesn’t have context of where the block comes from and at least in the block verification context we do not track which peer sent us the block (and don’t even have access to PeerId).

As such it would be unfair to reject block as invalid and ban (or even decrease reputation of) someone simply because attacker sent one version to one peer and another version to another peers. Moreover, chain reorg might happen later and we may need to import the block after all.

We need a better well designed solution for what to do here.

I can implement client-side banning of peers, but it will not be quite the same as burning of plots we have right now and may also result in network partitioning due to some peers accepting and some rejecting the block based on their local information.

Problematic implementation was removed in Remove problematic equivocation by nazar-pc · Pull Request #3072 · autonomys/subspace · GitHub