poanetwork / parity-ethereum

Fast, light, robust Ethereum implementation.
https://parity.io
Other
10 stars 12 forks source link

Feature request for AuRa: random numbers #51

Closed varasev closed 5 years ago

varasev commented 5 years ago

We have the Random contract for AuRa: https://github.com/poanetwork/pos-contracts/blob/master/contracts/RandomAuRa.sol

There're several functions needed to generate random numbers in randao manner. This is how it should work for AuRa in our case:

I propose to have so-called collection rounds. The length of each collection round is 200 blocks. Each collection round is split into two equal phases of 100 blocks: commits phase and reveals phase.

Each phase is determined by the current block number: https://github.com/poanetwork/pos-contracts/blob/f7d080fbf5e16bd9b8cdb474bf9541bfe292c796/contracts/RandomAuRa.sol#L182-L188

In the commits phase validator's node must generate a random number, call commitHash function and pass the keccak256 hash of the number. That must be done by each validator's node only once per commits phase. E.g., if we have 10 validators, the function will be called only 10 times during the commits phase.

The node can call isCommitPhase() function to know what's the current phase for the current block: https://github.com/poanetwork/pos-contracts/blob/f7d080fbf5e16bd9b8cdb474bf9541bfe292c796/contracts/RandomAuRa.sol#L182

Then during the reveals phase each validator's node must call revealSecret function and pass the random number that was generated by the node earlier (during the commits phase). The revealSecret function must only be called once during reveals phase.

Once reveals phase is completed, the XORed random number is stored by the contract in a public array (max length of which is 20).

Then the next collection round begins and so on.

Totally, we will have 20 random numbers refreshed permanently several times a staking epoch (which duration is one week).

If we take 200 blocks as the length of collection round, there will be ~600 collection rounds per staking epoch which is more than enough to generate 20 random numbers during the staking epoch even if not all validators reveal their numbers sometimes.

To implement the described mechanism we need to make Parity call those functions of Random contract with zero gas price.

For AuRa the ReportingValidatorSet contract will deny making the changes in stakes for the last 6 hours of staking epoch so that the users couldn't manipulate the outcome in this case. The users will see the random numbers at the last blocks of staking epoch but won't be able to influence the outcome.

UPDATE - the struck out things below will be are implemented in contracts (not in Parity):

We should consider it malicious behavior to not reveal (and to not commit), to make sure the last validator can't freely decide whether to reveal or not.

So, if Parity discovers on the last block of commits phase that a validator produced at least one block during the commits phase but didn't make a commit, this must be treated as misbehavior. The same is for reveals phase: if Parity discovers on the last block of reveals phase that a validator produced at least one block during the reveals phase but didn't make a reveal, this must be treated as misbehavior.

An exception: if a validator didn't call commitHash or revealSecret during the first 400 blocks of new staking epoch, this shouldn't be treated as misbehavior because new validators need to have time to commit/reveal during the full collection round.

The contracts keep track of intentional nonparticipation in revealing secret numbers as described in the struck out sentences above. To reduce the risk of unintentional node's disconnection, we will recommend the validators to launch more than one node (AuRa supports this) and separate them by different Internet providers (channels).

afck commented 5 years ago

what if the last validator intentionally disconnects from the network at the end of staking epoch not to reveal his committed random number?

I'd say that also needs to be reported as misbehavior? I don't think we can even distinguish between disconnecting and just refusing to reveal.

varasev commented 5 years ago

We can't know if the validator wanted to disconnect intentionally or just lost connection, so I think the disconnection shouldn't be treated as misbehavior :thinking:

If he just lost connection and this is reported as misbehavior, the validator will be removed from the set (his stake and his stakers' stakes will be frozen for 3 months), but this seems to be too strict.

UPDATE: Considering that in AuRa the validators can launch more than one node, we assume that losing connection is an unlikely event. So, nonparticipation in revealing secret numbers due to node's disconnection will be treated by contracts as misbehavior.

afck commented 5 years ago

I think making sure you have a stable connection is one of the responsibilities of a validator, and failure to do so should be punished. The question is to what extent, and whether we should have different kinds of penalties. (But I don't fully understand the economics behind the new contracts yet, so I'm not sure.)

DemiMarie commented 5 years ago

I agree — with a caveat: Validators are individuals, and are generally non-technical people. They cannot be expected to maintain a complicated high-availability setup. Furthermore, they are likely connecting over residential internet with no SLA.

Unreliability should be punished far less severely than malicious behavior.

On Dec 12, 2018 9:47 AM, "Andreas Fackler" notifications@github.com wrote:

I think making sure you have a stable connection is one of the responsibilities of a validator, and failure to do so should be punished. The question is to what extent, and whether we should have different kinds of penalties.

— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub https://github.com/poanetwork/parity-ethereum/issues/51#issuecomment-446612805, or mute the thread https://github.com/notifications/unsubscribe-auth/AGGWByAPDOgE6Pnx-PEhVCkAUS2D182Cks5u4Rb2gaJpZM4ZPOJX .

mbr commented 5 years ago

Unreliability should be punished far less severely than malicious behavior.

That only works if there is not plausible way for a technically savvy entity to always mask their malicious behavior as unreliable behavior. If that's the case, only incompetent malicious nodes will ever be "caught" with a punishment worse as the "mild" one for being unreliable.

So I agree with @afck, we should err on the side of severe punishment. It's probably better to ensure that the punishment for manipulation is as mild as possible, while still being harsh enough to efficiently deter/prevent the unwanted behavior.

Edit: I just thought of a nice analogy, look how video games treat disconnects during ranked matches =).

varasev commented 5 years ago

The description was updated today :point_up_2: (the _signature param was introduced for the commitHash and revealSecret functions).

varasev commented 5 years ago

The task above was simplified a bit:

image

mbr commented 5 years ago

A check whether or not a commit/reveal has already been made should be performed, as in the sections of the contract:

getCommit(collectRound, validator) == bytes32(0)

and

!sentReveal(collectRound, validator)

The second case (sentReveal(collectRound, validator)) is complete, but I believe it would be beneficial to encode the fact that "commit equal 0 means no commit made yet" into a similar function isCommitted(collectRound, validator), which would perform said check. All this helps to avoid exposing contract internals to the clients.

mbr commented 5 years ago

As far as I understand it, we do not need the funds held in escrow like randao does, because the other validators will police potential culprits effectively?

So, breaking the changes down into bits:

varasev commented 5 years ago

it would be beneficial to encode the fact that "commit equal 0 means no commit made yet" into a similar function isCommitted(collectRound, validator)

Ok, isCommitted function has been added: https://github.com/poanetwork/pos-contracts/commit/8fd5c082132d448a8c0c70d1baf24728283ef2df

As far as I understand it, we do not need the funds held in escrow like randao does, because the other validators will police potential culprits effectively?

Right. The contracts will take care of it.

DemiMarie commented 5 years ago

@mbr what instructions should we give validators, as far as ensuring that they have continuous service? The vast majority of individuals cannot afford, and do not have the knowledge to maintain, a true high-availability setup.

Can you give concrete expected availability numbers?

varasev commented 5 years ago

@DemiMarie We can recommend validators to launch more than one node (AuRa supports this) and separate them by different Internet providers (channels). E.g., for two validator's nodes: if one of the nodes disconnects, the second node will continue to work as a reserve.

DemiMarie commented 5 years ago

@varasev That makes sense, though we will need to see how well that works in practice.

mbr commented 5 years ago

@DemiMarie It all depends on the punishment you are dishing out. You could come up with a scheme that allows some temporary "lapses", from something simple like a "three strikes and you're out" to something more sophisticated. I imagine that the implementation would take place in the smart contract though.

varasev commented 5 years ago

Since we decided that we can't use system transactions, we'll use service transactions instead.

So, the functions commitHash and revealSecret must be called by regular transactions with zero gas price.

The functions' signatures and the description of this issue have been updated accordingly :point_up_2:

afck commented 5 years ago

Some more ideas that probably don't work (feel free to ignore this, but if we can make something like this work, that would be great): I was trying to think of other ways in which we could avoid having to store any secret locally (so that we wouldn't have to store any additional information on disk just to avoid being punished if e.g. our node crashes and restarts). With our current approach, we do have a secret that we mustn't lose, and the commitment is the secret's hash.

varasev commented 5 years ago

We could consider this in the future as an enhancement. For now, I think we shouldn't complicate things.

DemiMarie commented 5 years ago

This is almost complete, except for rand_secret being initialized to None. That is tracked as #67, so I am closing this issue.