-
Notifications
You must be signed in to change notification settings - Fork 5.4k
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
Long-term gas cost changes for IO-heavy operations to mitigate transaction spam attacks #150
Comments
Very surprising that the fix is more guessing at constants, this is practically equivalent to any other solution that makes the right costs quadratic. Could there not be a market mechanism for gas costs of different opcodes? |
IMO that would add much more complexity than either of my own proposals. I have thought about market mechanisms for opcode prices, as has Gav, but so far I have not seen anything that I would not consider exploitable. That said, pricing by category is something that I have looked into within narrow ranges, particularly in the context of state size control vs block processing time control. |
version 2 seems like a good first step. With CALL, CALLDELEGATE, CALLCODE at 400 it may be OK to set SLOAD a bit lower, perhaps to 100. I'm guessing it's cost is more important to complex dapps that require more storage loads, and in particular, SLOAD is harder to abuse DoS wise because it already requires the cost of calling a contract - clients can easier optimize storage reads for an already-loaded contract compared to e.g. EXTCODESIZE calls to a ton of (random) contracts. We should do some benchmarks in both geth and parity to confirm this. Though wouldn't aim for perfection here - rather encourage multiple gas tuning HFs to continuously approach optimal values. HFs that change gas costs are significantly easier than other type of consensus protocol changes, and also much easier to get community support around. Right now the most important thing is to tune these codes approx 1 order of magnitude to avoid severe DoS. Tuning of gas costs reminds me of the tuning Blizzard has done over the years of fighting units (e.g. speed, damage) in Starcraft I and II. Impossible to get 100% right - every tuning causes pro gamers to find so-far-unknown strategies where some units are a bit off balance. But over 20 or so turnings in each game, the end result is extremely balanced. |
There is also an EIP #142 to lower SSTORE cost. Worth considering here? |
For reference, this appears to be the original 1.0 gas costs table: https://docs.google.com/spreadsheets/d/1m89CVujrQe5LAFJ8-YAUCcNK950dUzMQPMJBxRtGCqs/edit#gid=0
The tables above were presumably generated by benchmarks. Outlining the benchmarking methodology would help with measuring costs across different implementations. |
Only one column of that table was generated by benchmarks: the computation table. The other columns are either estimates (as in the case of Merkle proofs) or common sense (1 byte = 1 byte, etc). In this EIP, it's only the other columns that are an issue. |
@axic, fine. But as I understand it, the side effect of the will be lowered gas cost of storage modification (non-zero value to non-zero value). |
how will backwards compatibility work for old contracts? |
Market for contract gasPrices: I agree that a market for opcodes gas prices doesn't seem to be feasible. But there could be a market for gasPrices of certain contracts. The good thing with this solution is, that no protocol change would be needed, it's only an optimization for the miners. A problem is the use of CALL's, where the code executed can depend on input parameters or logic in the contract. |
EIP 90 ensures calls won't get broken; otherwise, this is indeed a compatibility-breaking change, and that's how it must be: if old contracts were somehow grandfathered in, then they could be used for ongoing DoS attacks. |
👍 for a gas-price-only HF. |
@CJentzsch couldn't price per codehash be used for miners as a way to censor some contract categories? I fear it could open up some DDoS possibilities like the soft fork attempt did. |
@alexvandesande Miners could censor anything they want currently in there blocks, but yes, this would make it even easier for them. This suggestion is not a protocol update, and the DDoS possibilities for the soft fork were different. Since there miners did run code, without including the transaction and therefore they would not get any payment. |
Market-based gas cost schemes are cool, but I personally consider them too complex for a hard fork that should be scheduled to happen quickly so as to resolve present issues. |
Version 2, I think, overestimates the cost of contiguous reads, and underestimates the cost of seeks. Version 1b seems like a good idea to me, and I very much like the manner in which it can limit call depth without resorting to a fixed recursion limit. Regarding backwards compatibility, it's important to note that Solidity does not currently cache storage reads in contract memory or on the stack - presumably because they're so cheap. There will be a lot of contracts out there that are suddenly a lot more expensive because of this. |
@vbuterin I agree, my market-based gas costs suggestion does not need a protocol change and therefore does not need to be implemented with this hard fork. But I would suggest to increase all gas costs by a multiplier between 100-10000. |
If we can't figure out a market based solution why not use the same voting mechanism we use for the block gas limit. Every miner can (optionally) vote gas costs for each opcode up or down in the range of +/- (1/1024) (rounded up the full integer obv.). I guess we all agree that hard coding the costs is always a guessing game. There is no way to know today wether in x years storage, bandwidth or computation will be the bottleneck. |
I'm concerned that that would facilitate new types of attack, particularly if most miners aren't voting. And it would certainly make optimising compilers a lot more complicated.
That doesn't make it a guessing game; it just means that it needs periodic revision. |
This implements version 1c of EIP150 ethereum/EIPs#150.
All these "magic" numbers seems a bit "trial and error"... Is there not a way to let the numbers be determined organically in some way? |
Can someone make a properly formated EIP out of it and put it in the repo? |
Can someone shed the light what was the final revision used in the HF? Is it 1c above (including everything form 1b and 1) at block 2463000? |
This EIP is now located at https://github.com/ethereum/EIPs/blob/master/EIPS/eip-150.md. Please go there for the correct specification. The text in this issue may be incorrect or outdated, and is not maintained. |
EDITOR UPDATE (2017-08-15): This EIP is now located at https://github.com/ethereum/EIPs/blob/master/EIPS/eip-150.md. Please go there for the correct specification. The text below may be incorrect or outdated, and is not maintained.
UPDATE: version 1c of this spec has been implemented and is active on the mainnet as of block 2463000. Spec is kept unmodified for archival purposes.
Specification (version 1)
If
block.number >= FORK_BLKNUM
, then:That is, substitute:
With:
Specification (version 1b)
All of the above, but:
N
asN - floor(N / 64)
Specification (version 1c)
All of the above, and:
If SUICIDE hits a newly created account, it triggers an additional gas cost of 25000 (similar to CALLs)
Specification (version 2)
If
block.number >= METROPOLIS_FORK_BLKNUM
, then:N
asN - floor(N / 64)
When executing EXTCODESIZE, EXTCODECOPY, CALL, CALLDELEGATE or CALLCODE (but NOT BALANCE), let CODELOADING_GAS be
int(400 + len(code) / 6)
. At the end of the call, refund an additional 4000 - CODELOADING_GAS (if CODELOADING < 0, refund nothing). CREATE only provides 63/64 of the parent gas to the child call.Rationale
Recent denial-of-service attacks have shown that opcodes that read the state tree are under-priced relative to other opcodes. There are software changes that have been made, are being made and can be made in order to mitigate the situation; however, the fact will remain that such opcodes will be by a substantial margin the easiest known mechanism to degrade network performance via transaction spam. The concern arises because it takes a long time to read from disk, and is additionally a risk to future sharding proposals as the "attack transactions" that have so far been most successful in degrading network performance would also require tens of megabytes to provide Merkle proofs for. This EIP increases the cost of storage reading opcodes to address this concern. The costs have been derived from an updated version of the calculation table used to generate the 1.0 gas costs: https://docs.google.com/spreadsheets/d/15wghZr-Z6sRSMdmRmhls9dVXTOpxKy8Y64oy9MvDZEQ/edit#gid=0 ; the rules attempt to target a limit of 8 MB of data that needs to be read in order to process a block, and include an estimate of 500 bytes for a Merkle proof for SLOAD and 1000 for an account.
The first version of the EIP aims to be simple, and adds a flat penalty of 300 gas on top of the costs calculated in this table to account for the cost of loading the code (~17-21 kb in the worst case). The second version of the EIP instead adds an explicit parameter to take into account the size of code loading. Note that this parameter is weighted ~60% below the computed weight; this is to account for the fact that loading a large contiguous of code is, on a per-byte basis, much more efficient in terms of disk seeks (which often have a minimum size of 4kb regardless of the size of the actual object) than making several Merkle queries. A worst-case contract would take 3000 gas to load; a contract 2kb in size would take ~720 gas. This also has the benefit that it prevents a potential DoS vector against precomputation-heavy JIT VMs, where an attacker calls a large contract, requires the VM to just-in-time compile its entire code, only executes for perhaps ten cycles and then leaves. Version 2b fixes a problem where EXTCODESIZE is called with a small amount of gas, so that execution tries to fetch the contract code but runs out-of-gas upon seeing its size, thereby adding a large number of bytes to the merkle proof (and required DB load unless proper caching is added) but still only costing a relatively small amount of gas.
BALANCE is not affected by the per-byte changes because checking an account's balance does not require loading its code.
The EIP 90 gas mechanic is introduced because without it, all current contracts that make calls would stop working as they use an expression like
msg.gas - 40
to determine how much gas to make a call with, relying on the gas cost of calls being 40. In the more complex version, EIP 114 is introduced because, given that we are making the cost of a call higher and less predictable, we have an opportunity to do it at no extra cost to currently available guarantees, and so we also achieve the benefit of replacing the call stack depth limit with a "softer" gas-based restriction, thereby eliminating call stack depth attacks as a class of attack that contract developers have to worry about and hence increasing contract programming safety. Note that with the given parameters, the de-facto maximum call stack depth is limited to ~340 (down from ~1024), mitigating the harm caused by any further potential quadratic-complexity DoS attacks that rely on calls.The gas limit increase is recommended so as to preserve the de-facto transactions-per-second processing capability of the system for average contracts.
The text was updated successfully, but these errors were encountered: