Module ink_storage::alloc [−][src]
Expand description
The default dynamic storage allocator.
Allows to allocate storage cells in a dynamic fashion.
This is important if users want to combine types of varying storage
footprints. For example, dynamic allocations are required whenever
a user wants to use a storage collection (e.g. storage::Vec
) in
another storage collection: storage::Vec<storage::Vec<T>>
Simplification
The contracts pallet is using 256-bit keys for identifying storage cells.
This implies a storage space of 2^256
cells which is big enough to say that
there are probably never going to happen collisions anywhere at any time
if keys are chosen randomly. Using the built-in crypto hashers on unique
input we can be sure that there are never going to be collisions in this
space of 2^256
cells.
This way we can reduce the problem of finding another region in our storage
that fits certain requirements (e.g. a minimum size) to the problem of
finding another uniform slot. Since we are on 32-bit WebAssembly we have
memory limitations that make it impractical to have more than 2^32
dynamic
allocated entities, so we can create another limitation for having a total of
2^32
dynamic allocations at any point in time.
This enables us to have 32-bit keys instead of 256-bit keys.
We can convert such 32-bit keys (represented by e.g. a u32
) into 256-bit
keys by using one of the built-in crypto hashes that has a 256-bit output,
e.g. KECCAK, SHA-2 or BLAKE-2. For technical reasons we should prepend the
bytes of the 32-bit key by some unique byte sequence, e.g.:
let key256 = blake2x256(b"DYNAMICALLY ALLOCATED", bytes(key32));
Internals
As described in [# Simplification] there are 2^32
possible uniform dynamic
allocations available. For each such slot the dynamic allocator stores via
a single bit in a bitvector if that slot is free or occupied.
This bitvector is called the free
list.
However, searching in this free
list for a 0 bit and thus a free slot
for a dynamic allocation would mean that for every 256 consecutively
occupied dynamic allocations there was a contract storage lookup required.
This might seem a lot but given that there could be thousands or
tens of thousands of dynamic allocations at any given time this might not scale
well.
For the reason of improving scalability we added another vector: the
so-called set_bits
vector.
In this vector every u8
element densely stores the number of set bits
(bits that are 1
or true
) for each 256-bit package in the free
list.
(Note that the free
list is organized in 256-bit chunks of bits.)
This way, to search for an unoccupied dynamic allocation we iterate over
the set-bits vector which is 32 times more dense than our free
list.
The additional density implies that we can query up to 8192 potential
dynamic storage allocations with a single contract storage look-up.
Structs
Enums
The phase in which a contract execution can be.
Functions
Returns a new dynamic storage allocation.
Finalizes the global dynamic storage allocator instance.
Frees the given dynamic storage allocation.
Tells the global dynamic storage allocator instance how it shall initialize.