You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
When dealing with the Mapping storage facility introduced in #946 we clearly see that ink!'s current storage management and constructors do not allow for storage facilities that do not support caching their intermediate state.
So far this has not been a problem since all major storage facilities provided by the ink_storage crate did in fact cache their intermediate state and this was seen necessary due to the high costs of storage transactions (read/write).
However, due to the most recent developments it became clear that compiled Wasm file size are far more critical to the success of parachains. Caching, while efficient at runtime and good at preventing storage interaction costs, is very costly for Wasm file sizes.
Therefore we need a new ink_storage storage way of storage management that allows for uncached storage facilities.
Proposal
For this we want to extend the SpreadLayout and PackedLayout traits both by yet another trait method:
pubtraitSpreadLayout{fnspread_push(&self,ptr:&mutKeyPtr);fnspread_pull(ptr:&mutKeyPtr) -> Self;fnspread_clean(&self,ptr:&mutKeyPtr);// the below trait method will be newfnspread_allocate(ptr:&mutKeyPtr) -> Self;}
Now it might seem that SpreadLayout::spread_pull and SpreadLayout::spread_allocate are kind of similar.
However, while spread_pull actively pulls from contract storage in order to create the new Self instance spread_allocate won't touch contract storage and instead relies fully on the given KeyPtr parameter to fully initialize Self without storage look-ups.
For most types and especially Rust primitives SpreadLayout::spread_allocate will create those as their default values.
Ideally we could trivially implement SpreadLayout::spread_allocate for all T: Default where T does not already have a proper SpreadLayout::spread_allocate implementation. For this, however, we'd require spread_allocate to be defined in yet another trait and we'd also require the unstable Rust specialization feature. So let's maybe discuss this in the very future.
Usage
Storage facilities like the new Mapping could use the SpreadLayout::spread_allocate trait method in order to be properly initialized. Users would then initialize an ink! storage struct like the following ERC-20 example smart contract:
mod erc20 {#[ink(storage)]pubstructErc20{total_supply:Balance,balances:Mapping<AccountId,Balance>,}implErc20{/// Initializes the ERC-20 smart contract.#[ink(constructor]fnnew(initial_supply:Balance) -> Self{// Root key usually is initialized as `[0x00; 32]` in ink!:let root_key = Key::from([0x00;32]);letmut ptr = KeyPtr::from(root_key);letmut contract = <SelfasSpreadLayout>::spread_allocate(&mut ptr);
contract.initialize(initial_supply);
contract
}/// Private and hidden initializer for the `new` constructor.fninitialize(&mutself,initial_supply:Balance){let owner = self.env().caller();self.mapping.insert(owner, initial_supply);self.total_supply = initial_supply;}}}
Downsides
The big downside of this approach is teachability: Users have to learn yet another way how to properly initialize their smart contracts. Funnily the proposed SpreadLayout extension could profit from syntactic sugar that allows for #[ink(initializer)] constructs that are similar to #[ink(constructor)] instances with the difference of not constructing Self but merely initializing an already constructed Self given a &mut Self reference just like in the very old day of ink! version 1.0 where this was the original constructor syntax.
The text was updated successfully, but these errors were encountered:
Manual Storage Allocation
Motivation
When dealing with the
Mapping
storage facility introduced in #946 we clearly see that ink!'s current storage management and constructors do not allow for storage facilities that do not support caching their intermediate state.So far this has not been a problem since all major storage facilities provided by the
ink_storage
crate did in fact cache their intermediate state and this was seen necessary due to the high costs of storage transactions (read/write).However, due to the most recent developments it became clear that compiled Wasm file size are far more critical to the success of parachains. Caching, while efficient at runtime and good at preventing storage interaction costs, is very costly for Wasm file sizes.
Therefore we need a new
ink_storage
storage way of storage management that allows for uncached storage facilities.Proposal
For this we want to extend the
SpreadLayout
andPackedLayout
traits both by yet another trait method:Now it might seem that
SpreadLayout::spread_pull
andSpreadLayout::spread_allocate
are kind of similar.However, while
spread_pull
actively pulls from contract storage in order to create the newSelf
instancespread_allocate
won't touch contract storage and instead relies fully on the givenKeyPtr
parameter to fully initializeSelf
without storage look-ups.For most types and especially Rust primitives
SpreadLayout::spread_allocate
will create those as their default values.Ideally we could trivially implement
SpreadLayout::spread_allocate
for allT: Default
whereT
does not already have a properSpreadLayout::spread_allocate
implementation. For this, however, we'd requirespread_allocate
to be defined in yet another trait and we'd also require the unstable Rust specialization feature. So let's maybe discuss this in the very future.Usage
Storage facilities like the new
Mapping
could use theSpreadLayout::spread_allocate
trait method in order to be properly initialized. Users would then initialize an ink! storage struct like the following ERC-20 example smart contract:Downsides
The big downside of this approach is teachability: Users have to learn yet another way how to properly initialize their smart contracts. Funnily the proposed
SpreadLayout
extension could profit from syntactic sugar that allows for#[ink(initializer)]
constructs that are similar to#[ink(constructor)]
instances with the difference of not constructingSelf
but merely initializing an already constructedSelf
given a&mut Self
reference just like in the very old day of ink! version 1.0 where this was the original constructor syntax.The text was updated successfully, but these errors were encountered: