-
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
SSTORE/SLOAD for byte arrays #97
Comments
Possible implementation concern. Leveldb doesn't handle large values very well. To get around this, break large values into chunks and append nonce to the key. Since leveldb sorts key lexicographical it very efficient to stream the chunks. Leveldb has lg and lt operations, so the query needed here would be |
If you look at the bytes per second from that benchmark, you get 779k writes/sec * 100 bytes/write = 77.9 mbps for small values and 1100 writes/sec * 100000 bytes/write = 110 mbps for large values. So it doesn't seem to be fatal or even that problematic. |
If this is adopted and should be usable from Solidity, it will add another layer of complexity. This "store as single blob" has to be an optional feature for structs and arrays, because otherwise, elements of the structs and arrays are not accessible as lvalues anymore. Furthermore, the fact that storage size is dynamic will need some additional handling: If sloadbytes does not write to the full range of memory, we always have to check the size beforehand and optionally even throw if the size is not what we expect. Finally, as already commented on the original issue, I think that having two "types" of storage slots will add similar complexity, although I think that this is not too big an issue. |
@chriseth can you give more details? |
Are there any other rationales behind this EIP besides optimization? |
What is the status of this? |
There has been no activity on this issue for two months. It will be closed in a week if no further activity occurs. If you would like to move this EIP forward, please respond to any outstanding feedback or add a comment indicating that you have addressed all required feedback and are ready for a review. |
This issue was closed due to inactivity. If you are still pursuing it, feel free to reopen it and respond to any feedback or request a review in a comment. |
Some thoughts on backward compatibility for SSTORE/SLOAD:
Further, to keep the IO loads of SSTORE/SLOAD as before, we could implement the storage layout by maintaining two mappings:
SSIZE would simply read This should make SSTOREBYTES/SLOADBYTES/SSIZE as a pure add-on feature of existing EVM - existing SSTORE/SLOAD semantics are kept and their IO costs are the same as before. However, if a contract mixes the usage of fixed-bytes SSTORE/SLOAD and arbitrary-size SSTOREBYTES/SLOADBYTES/SSIZE, then the gas metering of all these opcodes needs further discussions. |
NOTE: this is split off from #86, and updated to incorporate what was agreed on the dev call on 2016.04.25.
Parameters
BASE_COST
: 2500BYTE_STORAGE_COST
: 250BYTE_CHANGE_COST
: 40MIN_COST
: 2500GSSIZE
: 50GSLOADBYTES
: 50METROPOLIS_FORK_BLKNUM
: TBASpecification
If
block.number >= METROPOLIS_FORK_BLKNUM
, then:SLOADBYTES
at 0xe1, which takes three arguments off the stack:key
,mstart
,msize
. Reads the storage of the account at the given key, and outputs the result into memory; unused memory is left unmodified, and memory is only extended to the point where it is needed (eg. ifmsize = 2**200
but the result only returns 1000 bytes, then you only pay gas for extending up tomstart + 1000
). Gas costGSLOADBYTES
, plusGCOPY
gas per 32 bytes (eg. 319 bytes -> 9 * GCOPY, 320 -> 10 * GCOPY, 321 -> 10 * GCOPY, just likeCALLDATACOPY
,CODECOPY
andEXTCODECOPY
)SSTOREBYTES
at 0xe2, which takes three arguments off the stack:key
,mstart
,msize
. Copies the given memory slice into that key in storage. Gas cost is computed according to the following schedule:total_cost = BASE_COST + BYTE_STORAGE_COST * (adjusted byte count of memory slice - adjusted byte count of previous contents) + BYTE_CHANGE_COST * (adjusted byte count of memory slice)
,gas_cost = max(total_cost, MIN_COST)
,refund = MIN_COST - min(total_cost, MIN_COST)
. Adjusted byte count = 32 + length if length is nonzero, otherwize 0. AnSLOAD
operation on contract data that was previously filled withSSTOREBYTES
return the last 32 bytes of the data, right-zeropadded. Also, note that usingSSTOREBYTES
to save a slice of zero bytes actually saves the zero bytes; it does not delete the slot.SSIZE
at 0xe3, which takes a key off the stack, and returns the length of the value in storage there. Gas costGSSIZE
.Code for SSTOREBYTES
Rationale
This allows contracts to store data more efficiently by reducing the number of trie/DB writes and reads needed for contract execution. Recent measurements show that trie and DB writes are a primary source of overhead, and serenity tests show a >2x speed improvement in some cases if code is written well. The canonical examples include:
Additionally, compiler logic may be simplified as storing data in sequential slots is no longer required. This does come at the cost of requiring updates to blockchain tools that currently assume that all storage values are either empty or exactly 32 bytes long.
The rationale behind adding a 32 byte cost to nonempty storage slots is that even a one-byte storage value will necessarily have overhead including key/value storage size costs, merkle tree branches/leaves, etc; additionally, an incentive is required to encourage saving a constant 320-byte chunk in a single key rather than splitting it up among 10 keys.
The text was updated successfully, but these errors were encountered: