vyper icon indicating copy to clipboard operation
vyper copied to clipboard

VIP: Tightly packed structs/arrays and smaller unsigned integers

Open haydenadams opened this issue 5 years ago • 5 comments

Smart contract efficiency is one of the most important methods of scaling. There is no good reason:

struct Gucci:
   yolo: bool
   swag: bool

needs two separate 32 bytes storage slots. Currently, the only good way to store multiple values in a single storage slot is something like this:

doubleStorage: public(bytes32)

@public
def doubleStore(amount1: uint256, amount2: uint256):
    amount1_bytes32: bytes32 = convert(amount1, bytes32)
    amount2_bytes32: bytes32 = convert(amount2, bytes32)
    amount1_bytes: bytes[16] = slice(amount1_bytes32, start=16, len=16)
    amount2_bytes: bytes[16] = slice(amount2_bytes32, start=16, len=16)
    self.doubleStorage = convert(concat(amount1_bytes, amount2_bytes), bytes32)
    
    
@public
@constant
def getAmounts() -> (uint256, uint256):
    firstAmount: bytes[16] = slice(self.doubleStorage, start=0, len=16)
    secondAmount: bytes[16] = slice(self.doubleStorage, start=16, len=16)
    return convert(firstAmount, uint256), convert(secondAmount, uint256)

With the addition of new uint sizes and tightly packed structs, this could become:

struct tightlyPacked:
   amount1: uint128
   amount2: uint128

Lower values would support tighter packing, with the following would taking only one storage slot:

struct evenTighter:
   amount1: uint64
   amount2: uint64
   amount3: uint64
   amount4: uint64

truuuu: bool[256]

As per a convo with @jacqueswww this probably only makes sense for structs (and possibly arrays). This should take two storage slots:

yolo: public(uint64)
swag: public(uint64)

Thanks @jacqueswww for helping me think through some of this!

haydenadams avatar Jul 30 '19 20:07 haydenadams

Similar closed issue https://github.com/ethereum/vyper/issues/599

haydenadams avatar Jul 30 '19 20:07 haydenadams

Notes from meeting: although the gas savings would be really large, added complexity with this that would be introduced is also quite high:

  • Shift in & Shift out of storage
  • Have read(sload) before doing sstore of a single value
  • Coalesce/Batch both Read & Write steps
  • Adding of new types

jacqueswww avatar Aug 06 '19 15:08 jacqueswww

@jacqueswww where does that leave this proposal? "Still possible but requires lots of work and not a priority" or "unlikely"?

haydenadams avatar Aug 08 '19 21:08 haydenadams

Unlikely to come sooner than later. We'd accept some contributions to work on this as an experimental feature, but it's too much of a rabbit hole to go after now.

fubuloubu avatar Aug 08 '19 21:08 fubuloubu

An interesting approach using bit fields to pack 256 bool variables into one word (32 bytes): https://mudit.blog/solidity-tips-and-tricks-to-save-gas-and-reduce-bytecode-size/#2a76

pcaversaccio avatar Sep 04 '22 15:09 pcaversaccio