substrate icon indicating copy to clipboard operation
substrate copied to clipboard

EPM/Staking-miner: commit-reveal based submission

Open kianenigma opened this issue 2 years ago • 1 comments

Overview

The current signed phase of the election-provider-multi-phase pallet has a major flaw: There is a single transaction (submit), quite heavy, that submits both the solution score and the payload of a signed solution.

This is a lot of burden on the chain, and a lot of tx-fee for miners, even if they are honest.

For example, in polkadot, the tx-fee for this call is around 10DOTs and the deposit is around 50DOTs.

To partially fix this, we introduced #11002, so that a number of honest miners get their transaction fee back, even if they are not the winner, as long as they are not found to be dishonest.

This is still not totally ux-friendly, and also lacks ideal security.

The ideal solution is to split the solution submission into two phases:

  1. Commit: a cheap transaction in which a signed account only claims the score that they wish to submit. Once claimed, they reserve their full hefty deposit on the spot.
  2. Reveal: an expensive transaction in which miners, in order, each get a number of blocks to submit their full payload. Upon successful submission, they should get their deposit and their transaction fee back.

A possibility here is to use the pre-image pallet, if it can support using the score as the pre-image and the solution is the image.

Details

A new phase is added, called Commitment. A new transaction is added, fn commit(origin, score). It should work somewhat similar to the current signed phase. scores are kept sorted, and the weakest one will get ejected. So, a new type type MaxCommitments: Get` is added.

Committing will reserve a large deposit, similar to the current deposit.

Then, there is a new phase called Reveal(..). The duration of this phase is type RevealDuration * MaxCommitments. In essence, this means that for every commitment, we will allocate a maximum of RevealDuration block for the signer to reveal their payload.

For example, we could have 12 commitments, and with allowing 10 blocks per reveal, we need a total of 12 minutes to revel.

Note that this is intentionally designed this way to alleviate any race condition among miners. Each miner will get its own allocated blocks to submit, and there should be no races.

A Reval phase is actually Revel(submitter, left_blocks). The first argument is the committer that is allowed to submit. The second is the number of blocks they have left. For example, in the previous example, we will have Reveal(Alice, 10) -> Reveal(Alice, 9) -> Reveal(Alice, 8) ...

During the reveal phase, the submitter can submit a solution payload. This is verified on the fly, and has a similar logic as the current submission’s verification: If good, everything is refunded + reward is given, if bad, everything is slashed.

If a committer fails to submit, i.e. we reach Reveal(_, 0), and we receive nothing, this is also considered as a misbehavior and the committer will lose their deposit.

Upon verifying the first solution, if it is valid, then we are done, and there is no point in verifying anything and anyone else. This is mainly because we must have verified the BEST solution that we has been claimed. Recall that bids are kept sorted.


All in all, this approach is one way to go about this, but I am not sure if it is the best. This approach is optimizing the scenario for miners, making sure they each have their own dedicated slot to submit freely, avoiding race conditions. On the other hand, the downside the current one is that the duration of the reveal phase cannot be too long, ergo the number of commitments cannot also be too big.

kianenigma avatar Jun 30 '22 11:06 kianenigma

Marking it as unconfirmed for now to allow discussion around the design.

cc @niklasad1 your input will be useful.

kianenigma avatar Jun 30 '22 11:06 kianenigma