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

Interaction between non-continuity of inflation and proposer reward #2763

Closed
cwgoes opened this Issue Nov 11, 2018 · 6 comments

Comments

Projects
None yet
4 participants
@cwgoes
Copy link
Contributor

cwgoes commented Nov 11, 2018

Paying summed inflation once per hour vastly increases the reward for being the proposer of that particular block (this is especially lucrative when the proposer reward and inflation are high, but is true regardless). Were the proposer of that block randomly determined, this would average out to the intended allocation over time, but in Tendermint that is not the case.

The difference is substantial - if inflation dwarfs fees (as is likely initially and quite possibly forever), in the pathological case where a particular proposer (with, say, enough stake to produce on average one block per hour where blocks are produced once per minute) manages to be the proposer on this special block every time, they claim essentially all of the proposer reward and all the other validators get zero (since inflation is not applied on their blocks).

Even without collusion, individual validators can attempt to time changes in their bonded stake (and censorship of other validators attempting to do the same) to increase the likelihood that they will get this special "inflation block" slot or vote for different timestamps to change which block height will be at the end of the hour. Penalizing rebonding (ref tendermint/tendermint#2718 (comment)) does nothing to prevent this, since the validator can remain in the bonded set the whole time. P2P layer prevote/precommit censorship and DoS would also be plausible vectors (no need to maintain sustained DoS, and even DoS that fails half the time would be profitable).

Reasoning through the exact calculations is involved (we should do it though), but I think that the reward curve for this attack will be better than linear (in the amount of bonded stake held by the validator or a colluding set of validators, up to 34% where the group can always be the special proposer) - the base chance is already linear, and additional stake makes altering bonded stake (by e.g. redelegating between multiple bonded validators), changing timestamps, and P2P-layer censorship more likely to succeed.

I think the simplest and best solution for this problem is to ensure we have sufficient precision and simply pay inflation every block, which shouldn't be too expensive - I'm not entirely sure why we implemented it hourly in the first place.

cc @Slamper - who caught this problem first in Riot
cc @ValarDragon @rigelrozanski

@cwgoes

This comment has been minimized.

Copy link
Contributor

cwgoes commented Nov 11, 2018

I think there's another attack too. Because of the interaction of non-continuous inflation and the reward distribution system, it would be advantageous to force other validators to withdraw their share of accum right before the inflationary block - this can be done e.g. by delegating to them, which cannot be prevented - if you manage to do this for all of the other bonded validators except yours, you will be able to immediately withdraw after the inflationary block and capture nearly all the pooled reward!

@cwgoes

This comment has been minimized.

Copy link
Contributor

cwgoes commented Nov 11, 2018

^ This problem is more general, splitting into a new issue: #2764.

@ValarDragon

This comment has been minimized.

Copy link
Member

ValarDragon commented Nov 11, 2018

Paying summed inflation once per hour vastly increases the reward for being the proposer of that particular block (this is especially lucrative when the proposer reward and inflation are high, but is true regardless). Were the proposer of that block randomly determined, this would average out to the intended allocation over time, but in Tendermint that is not the case.

I'm surprised, is this how our payout mechanism works? My understanding was that every proposer got a reward within their block, it wasn't accumulated over an hour? If for some reason adding it to the validator who proposed in a given block is hard (which I don't understand), then we could just remove the global fee pool, since that isn't necessary given that we already iterate over the validator set in slashing.

@Slamper

This comment has been minimized.

Copy link
Contributor

Slamper commented Nov 11, 2018

@ValarDragon
x/mint adds the inflation to the fee pool every 1h. So the proposer of that block gets his baseReward + bonus on the fees including the inflation

@rigelrozanski rigelrozanski self-assigned this Nov 12, 2018

@rigelrozanski

This comment has been minimized.

Copy link
Member

rigelrozanski commented Nov 12, 2018

As mentioned in the phone call - we should:

  • make the minting happen every block
  • make the minting inflation mechanism occur once per hour (as it's more computationally heavy)

Also, it's coming back to me, further insights as to why this was chosen as hourly was this period was dreamed when we still had bonded atoms rewards, meaning that it didn't go through the fee distribution and the proposer reward mechanism wasn't applied. But this has changed now.

good catch!

@rigelrozanski rigelrozanski referenced this issue Nov 15, 2018

Merged

R4R: blockly minting #2825

4 of 5 tasks complete
@rigelrozanski

This comment has been minimized.

Copy link
Member

rigelrozanski commented Nov 16, 2018

A new fun consideration - as I just implemented this - the reward per block is based on the duration of time passed since the last block (*inflation) which makes sense for achieving the desired inflation, however it creates an incentive for each proposer to slow down their block creation as much as possible without timing out.

Proposed solution: apply an "expected block time" - easy enough, however now we have to calculate expected block time... I'd propose that we just leave this as a param in the param store for now, which governance can update, and then soon introduce some code to just calculate this metric on-chain maybe once a week or something... there are a few nuance considers to this calculation (ex. what period of window should be used)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment