Join GitHub today
GitHub is home to over 31 million developers working together to host and review code, manage projects, and build software together.
Sign upSSTORE/SLOAD for byte arrays #97
Comments
vbuterin
referenced this issue
Apr 26, 2016
Open
Proposed initial abstraction changes for Metropolis #86
This comment has been minimized.
This comment has been minimized.
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 |
This comment has been minimized.
This comment has been minimized.
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. |
This comment has been minimized.
This comment has been minimized.
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. |
This comment has been minimized.
This comment has been minimized.
@chriseth can you give more details? |
This comment has been minimized.
This comment has been minimized.
Are there any other rationales behind this EIP besides optimization? |
Souptacular
added
the
editor-needs-to-review
label
Feb 10, 2017
This comment has been minimized.
This comment has been minimized.
tawaren
commented
Feb 17, 2017
•
What is the status of this? |
vbuterin commentedApr 26, 2016
•
edited
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.