-
Notifications
You must be signed in to change notification settings - Fork 428
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
Simple Mapping Storage Primitive #946
Conversation
So this PR isn't quite ready yet, but I'm still at a point where I can use
They're basically the same as @xgreenx's |
You are not supporting I think it is better to return an |
Compiling the adjusted ERC-20 with This means that a majority of the cluft comes from copying the huge Ideally we can introduce some traits in order to allow for use cases like these without requiring value types anywhere. edit: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The Mapping
is missing some trivial Debug
implementation:
impl<K, V> core::fmt::Debug for Mapping<K, V> {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
f.debug_struct("Mapping").finish()
}
}
* Add `Mapping` storage collection * Implement `insert` and `get` for `Mapping` * Implement `SpreadLayout` for `Mapping` * Fix typo * Add some basic tests * Fix some documentation formatting * Use `PackedLayout` as trait bound instead of `Encode/Decode` * Avoid using low level `ink_env` functions when interacting with storage * RustFmt * Appease Clippy * Only use single `PhantomData` field * Change `get` API to take reference to `key` * Implement `TypeInfo` and `StorageLayout` for `Mapping` * Properly gate `TypeInfo` and `StorageLayout` impls behind `std` * Replace `HashMap` with `Mapping` in ERC-20 example * Return `Option` from `Mapping::get` * Update ERC-20 to handle `Option` returns * Change `get` and `key` to use `Borrow`-ed values * Add `Debug` and `Default` implementations * Proper spelling * Change `insert` to only accept borrowed K,V pairs * Update ERC-20 example accordingly * Make more explicit what each `key` is referring to * Try using a `RefCell` instead of passing `Key` around * Try using `UnsafeCell` instead * Revert "Try using a `RefCell` instead of passing `Key` around" This reverts commit cede033. Using `RefCell`/`UnsafeCell` doesn't reduce the contract size more than what we have now, and it introduced `unsafe` code. We believe the limiting factor here is the `Key` type definition anyways. * Clean up some of the documentation * adjust the Mapping type for the new SpreadAllocate trait * adjust ERC-20 example for changes in Mapping type * remove commented out code * add doc comment to new_init * make it possible to use references in more cases with Mapping * use references in more cases for ERC-20 example contract * remove unnecessary references in Mapping methods * refactor/improve pull_packed_root_opt utility method slightly * fix ERC-20 example contract The problem with *self.total_supply is that it may implicitly read from storage in case it has not yet read a value from storage whereas Lazy::set just writes the value to the Lazy instance. Co-authored-by: Hernando Castano <hernando@hcastano.com> Co-authored-by: Hernando Castano <HCastano@users.noreply.github.com>
Codecov Report
@@ Coverage Diff @@
## master #946 +/- ##
==========================================
- Coverage 78.86% 78.71% -0.16%
==========================================
Files 245 246 +1
Lines 9246 9260 +14
==========================================
- Hits 7292 7289 -3
- Misses 1954 1971 +17
Continue to review full report at Codecov.
|
@@ -97,6 +97,7 @@ impl Storage<'_> { | |||
derive(::ink_storage::traits::StorageLayout) | |||
)] | |||
#[derive(::ink_storage::traits::SpreadLayout)] | |||
#[derive(::ink_storage::traits::SpreadAllocate)] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
First: You cannot do this since not all #[ink(storage)]
structs should implement SpreadAllocate
which is why it is separate from SpreadLayout
and has not been integrated into the already existing traits.
Second: If this was actually useful (which it isn't) it should reside in another PR.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For ink! codegen to automatically implement SpreadAllocate
optionally we'd need support for Rust trivial trait bounds which currently are unstable.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My bad. I thought that the idea behind merging #995 before the Mapping
was so we could derive SpreadAllocate
for storage types in the codegen instead of manually deriving it
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If Rust had trivial trait bounds we actually could do exactly that ... :(
examples/erc20/lib.rs
Outdated
@@ -59,20 +61,19 @@ mod erc20 { | |||
/// Creates a new ERC-20 contract with the specified initial supply. | |||
#[ink(constructor)] | |||
pub fn new(initial_supply: Balance) -> Self { | |||
ink_lang::codegen::initialize_contract(|contract| Self::new_init(contract, initial_supply)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@Robbepop using the codegen
module here feels wrong, is there a better way to expose this to users?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The actual plan is still that we provide some useful and well designed syntactic sugar so that this line of code won't be necessary but maybe that's not well thought through and maybe writing out this line of code actually isn't so bad. Then we could put this into some other module or into root.
FYI, with the additional bloat from #998 we're currently sitting at 12.1K. |
The bloat can easily be fixed with another PR and more intelligent codegen. |
I tried to build this change and #999.
|
Some other tests: This + use-ink/cargo-contract#358: Original wasm size: 35.4K, Optimized: 11.7K |
@xgreenx I haven't had time to loop back into this, so thanks for your experiments! |
I think we can probably merge this as-is, and fix anything in follow ups (like not using the |
I would like to see the new Mapping type under ink_storage::lazy instead of ink_storage::collections module before we merge this. |
push_packed_root, | ||
ExtKeyPtr, | ||
KeyPtr, | ||
PackedLayout, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
* Add `Mapping` storage collection * Implement `insert` and `get` for `Mapping` * Implement `SpreadLayout` for `Mapping` * Fix typo * Add some basic tests * Fix some documentation formatting * Use `PackedLayout` as trait bound instead of `Encode/Decode` * Avoid using low level `ink_env` functions when interacting with storage * RustFmt * Appease Clippy * Only use single `PhantomData` field * Change `get` API to take reference to `key` * Implement `TypeInfo` and `StorageLayout` for `Mapping` * Properly gate `TypeInfo` and `StorageLayout` impls behind `std` * Replace `HashMap` with `Mapping` in ERC-20 example * Return `Option` from `Mapping::get` * Update ERC-20 to handle `Option` returns * Change `get` and `key` to use `Borrow`-ed values * Add `Debug` and `Default` implementations * Proper spelling * Change `insert` to only accept borrowed K,V pairs * Update ERC-20 example accordingly * Make more explicit what each `key` is referring to * Try using a `RefCell` instead of passing `Key` around * Try using `UnsafeCell` instead * Revert "Try using a `RefCell` instead of passing `Key` around" This reverts commit cede033. Using `RefCell`/`UnsafeCell` doesn't reduce the contract size more than what we have now, and it introduced `unsafe` code. We believe the limiting factor here is the `Key` type definition anyways. * Clean up some of the documentation * Simple Mapping type improvements (use-ink#979) * Add `Mapping` storage collection * Implement `insert` and `get` for `Mapping` * Implement `SpreadLayout` for `Mapping` * Fix typo * Add some basic tests * Fix some documentation formatting * Use `PackedLayout` as trait bound instead of `Encode/Decode` * Avoid using low level `ink_env` functions when interacting with storage * RustFmt * Appease Clippy * Only use single `PhantomData` field * Change `get` API to take reference to `key` * Implement `TypeInfo` and `StorageLayout` for `Mapping` * Properly gate `TypeInfo` and `StorageLayout` impls behind `std` * Replace `HashMap` with `Mapping` in ERC-20 example * Return `Option` from `Mapping::get` * Update ERC-20 to handle `Option` returns * Change `get` and `key` to use `Borrow`-ed values * Add `Debug` and `Default` implementations * Proper spelling * Change `insert` to only accept borrowed K,V pairs * Update ERC-20 example accordingly * Make more explicit what each `key` is referring to * Try using a `RefCell` instead of passing `Key` around * Try using `UnsafeCell` instead * Revert "Try using a `RefCell` instead of passing `Key` around" This reverts commit cede033. Using `RefCell`/`UnsafeCell` doesn't reduce the contract size more than what we have now, and it introduced `unsafe` code. We believe the limiting factor here is the `Key` type definition anyways. * Clean up some of the documentation * adjust the Mapping type for the new SpreadAllocate trait * adjust ERC-20 example for changes in Mapping type * remove commented out code * add doc comment to new_init * make it possible to use references in more cases with Mapping * use references in more cases for ERC-20 example contract * remove unnecessary references in Mapping methods * refactor/improve pull_packed_root_opt utility method slightly * fix ERC-20 example contract The problem with *self.total_supply is that it may implicitly read from storage in case it has not yet read a value from storage whereas Lazy::set just writes the value to the Lazy instance. Co-authored-by: Hernando Castano <hernando@hcastano.com> Co-authored-by: Hernando Castano <HCastano@users.noreply.github.com> * Use new `initialize_contract()` function * Derive `SpreadAllocate` for `ink(storage)` structs * Stop manually implementing SpreadAllocate for ERC-20 * Stop implementing `SpreadAllocate` in the storage codegen * Derive `SpreadAllocate` manually for ERC-20 * RustFmt example * Move `Mapping` from `collections` to `lazy` * Remove extra `0` in docs Co-authored-by: Robin Freyler <robin.freyler@gmail.com>
An implementation of what's described in #945.
Some things I'm still unsure about:1. The handling ofMapping
'skey
fieldNot sure if this should be user initialized since it's kinda an implementation detail
which is there to make sure we don't have any collisions in storage.
2. TheSpreadLayout
implementationSo from what I can tell, when we implement this trait we're supposed to indicate how our
structure should be represented in the contract storage. In the case of
Mapping
, sinceit doesn't actually own any data, its really just a proxy for how we represent
Key
instorage. Am I thinking about this correctly?