omgnetwork / research

43 stars 2 forks source link

Bond size #107

Closed boolafish closed 4 years ago

boolafish commented 5 years ago

Idea

Leverage tx.gasprice to calculate the bond. (doc)

Formula: tx.grasprice * gas_cost (usually in challenge, or whatever next step is)

You won't get the "future" gas price but is probably the closest price we can get.

Attack on this

Miner can mine 0 gas price tx and make the bond to zero.

Mitigation

  1. Set a min bond. Easy, simple, quite likely good enough
  2. Saves gas price per block submission, calculate some average of N blocks to be as price to use.

Optimization

Since this requires saving gas price info or bond size info on chain. We can just have some levels of bond to be used as we don't really need bond to be super granulated. We can round it to the closest level of bond to be used. And then we can safe some bits when saving it.

boolafish commented 5 years ago

Since this requires saving gas price info or bond size info on chain.

Do we? we just need to hardcode the gas cost of challenge and times it with tx.gasprice to be as bond. Why we need to save the data?

cc @paulperegud

paulperegud commented 5 years ago

Tx.gasprice of transaction that is placing the deposit is not available when it is needed - on processExits (standard exit as the simple example). And since we need to store it - I was worried about paying for storage. By placing information about amount in address field of exit owner (or any other address field associated with exit) we can recompute the bond size that needs to be transferred.

paulperegud commented 5 years ago

Additional benefit that should be mentioned - the challenger run by Omise or by anyone else will be able to pay for itself by challenging as soon as it sees a fraudulent exit. This would help to reduce risk of exit going unchallenged.

paulperegud commented 5 years ago

One more note - as @pdobacz rightfully pointed, betting on one mechanism to work without tweaks is risky in this case. Lets make this thing update'able.

Pongch commented 5 years ago

Just wanted to get a good idea on where we are with the bond-size. Are we a) confident that this model is sufficient enough for exit bond to be implemented ? b) if so, how big is the scope of work needed to be implemented here ?

btw, really like the notion that the challenger applications will be self-sustainable @paulperegud but I assume the caveat there is a user would still have to pay for failed transaction, ie. multiple parties race to challenge an exit.

paulperegud commented 5 years ago

btw, really like the notion that the challenger applications will be self-sustainable @paulperegud but I assume the caveat there is a user would still have to pay for failed transaction, ie. multiple parties race to challenge an exit.

It's not really a problem. Racing parties will compete by setting gas price higher and higher until the game will become unprofitable. This is not a type of game where you can make money. It's a game you can play without losing money. By setting the bond size this way, we make our "default challenging strategy" acceptable to participants - this should prevent them from turning it off.

Default challenging strategy

  1. I (watcher) see a fraudulent exit.
  2. I compute how much time all participants have to challenge the exit.
  3. I roll the dice to determine where in this time window I will challenge.
  4. When time arrives, I check if the exit was challenged. If not - I issue the challenge.

With big enough set of watchers running this strategy, someone will challenge early and will get a good gas price. If some profit driven party will run custom strategy, watching the gas price closely and will make profit - great! Otherwise some community member will probably get a bit worse gas price, taking a small loss.

Pongch commented 5 years ago

I see, got it.

In this case if we want bond size calculation to be updatable, shall we add abstract-layer tag on this issue then ? then we can put this into the back-log and tackle it.

boolafish commented 5 years ago

As for updatable, do we want the ability to directly update in existing working tx type or do we want to deploy a new tx type with the updated bond mechanism?

@Pongch @paulperegud

Pongch commented 5 years ago

Hey @boolafish I believe the first ability to update in existing working tx type is a more viable path

deploying a new tx type with updated bond mechanism > this would be useful but could get messy quickly in a situation that says- we have a bug in the exit bond and want to upgrade. We will ended up with too many unused tx types.

Are there any other pro's and con's to these two options related to the actual implementation in the contract ?

boolafish commented 5 years ago

well...this is sort of same question on this: https://github.com/omisego/plasma-contracts/issues/108. Whether we prefer to bump the version or to use new tx type as an upgrade.

Pros on Upgrade by Version

  1. Easier to maintain and support from our side. Less tx types to support. This would actually also decrease complexity in our tools like block explorer, omg-js.....
  2. No extra action to take on the user side.
  3. Easy upgrade process

Cons on upgrade by version

  1. User cannot choose to opt in or not. They either exit or accept. With new tx type, they can choose: exit, stay, or upgrade.
  2. Slightly more gas cost and complexity to exit game contract. To support upgrade by version, we need to move all storage out from exit game contract because storage is not upgradeable. As a result, there is an extra interaction on external contract. (generally around 1k cost per external call)

Back to bond, and assumes we allow upgrade bond mechanism only, and not the whole exit game, this means we would call an external "bond contract" to decide the fee.

Pros

Cons

boolafish commented 5 years ago

Add https://github.com/omisego/plasma-contracts/issues/192 to track solidity implementation.

boolafish commented 5 years ago

FYI, post this in Plasma.build as well to see if we can get any feedback from plasma community and I think this would be generally useful.

https://plasma.build/t/potential-bond-size-construction/135

kevsul commented 5 years ago

So starting an exit will now have 2 steps:

  1. Get the value of the bond e.g. by calling getStandardExitBond()
  2. Call startStandardExit({value: bond})

Then startStandardExit() will have to recalculate the value of the bond and reject if the passed in bond is not the same. I think we definitely need to round up to some level as suggested, otherwise this will cause confusion if gas price changes between these two steps.

By placing information about amount in address field of exit owner (or any other address field associated with exit) we can recompute the bond size that needs to be transferred.

@paulperegud What do you mean by placing it in an address field?

boolafish commented 5 years ago

@kevsul that's basically optimization on gas for storage. The idea is address would only use 20 bytes, so there are still another 12 bytes of space to put things together to be as one 32 bytes.

As we are using struct when storing, I think we can simply optimize by arranging the order of our variables to make sure it would optimize to pack fields in struct together instead of packing into a field.

https://fravoll.github.io/solidity-patterns/tight_variable_packing.html

boolafish commented 5 years ago

reject if the passed in bond is not the same

hmmm I guess we can change the mechanism to make user pass in some large enough value and the contract would return the remaining? But if rounding is good enough and the price doesn't fluctuate that fast then it should be fine without that.

kevsul commented 5 years ago

The more I think about this, the more complex it gets.

The problem, I think, is that basing the bond size on the gas price of the startExit transaction is too unreliable. Currently on ETH Gas Station the recommended gas prices are (in gwei): Fast: 10 Standard: 3 Slow: 1

So there's potentially a 10X variance in gas prices, depending on how urgently the user wants their tx to be mined.

I believe we want the bond size to at least cover the gas cost of a challenge. So to guard against a startExit transaction with a gas price that's too low to cover the challenge, we'll need to set a minimum bond size (as originally suggested).

But if we're setting a minimum bond size then why not just use it always as a fixed bond size?

A dynamic bond size only means that honest users may pay more than the minimum (e.g. if they increase gas to get their tx accepted quicker), but if the exit is valid then the bond size doesn't matter anyway. However, I suspect that malicious users will always pay the minimum possible bond, to minimise their losses in the event of their exit being challenged. So the only bond size that does matter will be the minimum bond, which is fixed.

kevsul commented 5 years ago

To follow on from above, the problem with a fixed bond size is that if gas price goes up too much then it may be insufficient to cover challenge gas. Or if it goes down, then an exit may require an unreasonably large bond.

How about using the gas price of the challenge tx instead of the startExit tx?

For each successful challenge, take the difference between its gas price and its bond size, and modify the next bond size by a percentage of that difference, so that over time the bond size tends towards the gas cost of a challenge. (There should probably be a greater tendency to increase, so that if the bond size ever goes below the gas cost, then the challenger will take a small loss, but the next bond size will likely be back above the gas cost)

I think this way is less gameable - you can only affect the bond size slightly by a successful challenge. A malicious miner could still mine a 0 gas challenge, but they would need to do that many times to bring the bond size down substantially and in the meantime other challenges could bring it back up.

One drawback that I can see with this approach is that the bond size is only modified via successful challenges, so if there are none for a long period of time then the gas cost may have diverged significantly from the bond size. However the same problem applies to fixed bond sizes.

boolafish commented 5 years ago

Hmmm...one thing I’m afraid is that challenge should be rare case. What we want is the gas price then we can potentially use average of several other measureable txs instead? We multiply the price with the challenge gas afterward.

paulperegud commented 5 years ago

So there's potentially a 10X variance in gas prices, depending on how urgently the user wants their tx to be mined.

We care only about lowest of those. If attacker wants to overpay for her invalid exit, it's her own right. Attacker being able to mine for zero is a potential problem (a malicious Ethereum miner).

If honest Bob wants his exit to be mined early, he can provide a large bond that he is not risking. He knows that there were no double spends.

However, I suspect that malicious users will always pay the minimum possible bond, to minimise their losses in the event of their exit being challenged.

We want malicious exit attempts to move money from cheaters to challengers, otherwise we create a potential money drain vector from honest users of the system. Single malicious exit is not really a problem. Tons and tons of malicious exits that force honest users to burn money is a problem. One obvious actor capable of performing such attack are Ethereum miners. They still can defeat bonds, but since it would be obvious that they are behind the attack, they will damage Ethereum reputation greatly.

kevsul commented 5 years ago

We want malicious exit attempts to move money from cheaters to challengers, otherwise we create a potential money drain vector from honest users of the system.

Right. So as long as the bond size (almost) always covers the challenge cost, then we're fine.

I still think that linking the bond size to a single startExit call is too open to manipulation.

So how about this:

  1. Maintain an average gas price (exponential weighted moving average is cheap) using e.g. startExit calls.
    1. Bond size = average gas price gas cost for challenge safety multiplier (e.g. 1.5)

Pros:

Cons:

POC code here

paulperegud commented 5 years ago

I still think that linking the bond size to a single startExit call is too open to manipulation.

I'm much more worried about someone's ability to make subsequent startExit's prohibitively expensive.

kevsul commented 5 years ago

I'm much more worried about someone's ability to make subsequent startExit's prohibitively expensive.

Same thing though, right? Manipulation can be in either direction.

boolafish commented 5 years ago

Some quick feedback from plasma call. In general it seems making sense, like our direction of averaging tx price and also a min bond (btw, @kevsul I think we didn't set min value on the PR, shall we?)

However, Karl does also mentioned that if it was him, he might prefer a single high enough bond as that is a way simpler mechanism and it is always hard to justify and think about how a heuristic model would work for bond.

Some sort of gas future mechanism is also mentioned but it seems there is no simple or good implementation yet. We also talked a bit on gas token but that cannot cover 100% as it relies on deleting storage which can at most cover half.

kevsul commented 5 years ago

What's the point of a minimum bond? Is it to protect against somebody somehow gaming the system to achieve a low bond value?

And what's a reasonable value for a minimum bond?

The thing is, I think it's likely that any minimum value we set now will end up being a fixed value for every bond.

Currently, a challenge costs about 700000 gas, so for the sake of argument let's use a 1 gwei gas price and set a minimum bond of 700000 gwei. Now, what happens if the price of ETH goes up, say 2x? Gas price should go down 2x, so now the minimum bond will always be used because it will always be higher than the gas cost multiplied by average gas price.

Of course, if the price of ETH goes down significantly then so does the value of the minimum bond, so does it still serve its purpose?

BTW, I'm actually with Karl on this - setting a fixed high value bond is way simpler. The problem is how to choose that value?

boolafish commented 5 years ago

What's the point of a minimum bond?

Hmmm, I recall he was thinking using minimum bond as a baseline and then we do heuristic on top of that baseline. Probably averaging tx price is a good enough protection so we don't need min bond?

Looking at the average gas price chart: https://etherscan.io/chart/gasprice, it seems moving averaging price with some safetyFactor would be good to cover "most" of the cases. There are still some crazy high gas price days luckily in recent year it usually only last a day. The problem would be how close our average tx.price would be anchoring the real average gas price.

Or, we can probably just draw a line on that chart and say that is our constant gas price and says that it covers like most of the cases from history data.

paulperegud commented 5 years ago

I'm much more worried about someone's ability to make subsequent startExit's prohibitively expensive.

Same thing though, right? Manipulation can be in either direction.

Not really. If the bond size is proportional to gas size, than I can affect my own startExit but only it. If bond size is a function of some kind of average of N last calls, than by placing N calls I can make call N+1 expensive. Yeah, one can also manipulate required gas price, but that is an attack against the Ethereum network, not against our contract. It's much more expensive.

What's the point of a minimum bond? Is it to protect against somebody somehow gaming the system to achieve a low bond value?

Miners are capable at mining their own transactions at zero gas price. By setting minimal bond size to correspond to 0.1 Gwei, we plug this hole.

Or, we can probably just draw a line on that chart and say that is our constant gas price and says that it covers like most of the cases from history data.

Will it survive changes in both tech (e.g. upcoming increase in gas cost of SLOAD from 200 to 800 in EIP1984) and network utilization changes?

kevsul commented 5 years ago

The main issue I have with having the bond size proportional to the gas price of the startExit call is the UX. The value of the startExit transaction is tied to the gas price of the startExit transaction. If you initially set a low value and subsequently need to increase gas price to get the transaction mined, then you also need to increase the value (bond size) of the transaction. This is not standard behaviour and I think will cause confusion. However, if this is the way we want to go, then we can lessen the confusion by letting our wallet handle it automatically, or at least by educating users.

Will it survive changes in both tech (e.g. upcoming increase in gas cost of SLOAD from 200 to 800 in EIP1984)

This is a good point, but I don't think any of the proposals take it into account. We store the pre-calculated gas cost of the challenge and multiply it by the gas price. Do you think the gas cost should be dynamic as well, or should we just upgrade the contract when something like EIP1984 happens?

boolafish commented 5 years ago

oh....aw.....so it is not only on tx price but on gas cost change @@.....

Let's just use our upgrade mechanism then. btw @kevsul have you found the preferred way to do upgrade for bond?

paulperegud commented 5 years ago

Fixed size bond cons

1) Opens a griefing vector at times of high gas prices.

Memory-less bond price cons

1) UX - bond size is a function of attached gas price. 2) Can be gamed by miners.

Weighted average bond price cons

1) UX - bond size needs to be read from the contract. 2) Can be gamed by miners. 3) Introduces tx race - of two startExit tx emitted at the same moment one might not mine, if other one would raise the average. 4) Cheaper DoS vector.

kevsul commented 5 years ago

After some discussion, we've decided to keep it simple and set a fixed bond size that should cover challenge cost.

This bond size is upgradeable by the operator to keep aligned with gas price and gas cost changes.

However, to protect against a malicious operator setting an unreasonably low or high value, the upgrade is restricted as follows:

  1. The current value can only be modified by +/- 50% (or +100% / - 50% ?)
  2. There is a vacatio legis period of 2 days until the new value comes into effect.
  3. A new upgrade will cancel an upgrade currently in vacatio legis, but it can still only modify the current bond value, as in point 1.

Some observations:

If gas price increases suddenly, then it will take 2 days before the bond size reflects the change. If it increases enough so that the bond size is less than the cost of a challenge, then a griefer can start invalid exits that will cost money to challenge. However, it will cost the griefer their bond and gas as well.

An upgrade of bond size should be reported by the Watcher. The user can then decide to start an exit before the bond size increases, or conversely wait for it to decrease.

Point 3. above allows us to 'cancel' an upgrade. For example, imagine gas price increases significantly due to network congestion and we start an upgrade in response. Now congestions alleviates while the upgrade is still in the vacatio legis period - we can initiate another upgrade, setting the bond size back to its previous value and effectively cancelling the first upgrade.

boolafish commented 4 years ago

closing this as we've implemented the idea here in ALD