-
Notifications
You must be signed in to change notification settings - Fork 454
Come up with an idea for generic mutable references #1
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
Comments
Today I tried out a solution that makes use of two new traits /// Types that are mutable by some closure.
pub trait Mutate<T> {
fn mutate<F>(&mut self, f: F)
where
F: FnOnce(&mut T);
}
/// Types that are assignable to some new value.
pub trait Assign<T> {
fn assign(&mut self, val: T);
} With these we could define different ref-mut types for all the different data structures, such as let mut v = my_storage_vec(); // storage::Vec<i32>
v.get_mut(5).unwrap() += 42; The downside to this is that due to the nature of let mut v = my_storage_vec(); // storage::Vec<i32>
v[5] += 42; Note that this implementation of a mutable reference to storage items works without having a proper flushing system. Although the approach implemented today is already pretty nice in certain ways I think we really want a proper flushing system for the best usability we could achieve. Flushing SystemA mandatory problem with flushing systems that allow for raw mutable references is that we somehow need to restrict context switches to be only possible if there are no more mutable captures of storage variables. This can be done by coupling the context switch with the flushing system and also by coupling the contract state itself with the flushing system. An example could help here: If we have the following contract state: struct MyContractState {
vec: storage::Vec<i32>, // some complex data in the storage
map: storage::HashMap<u64, bool>, // some more complex data in the storage
val: storage::Value<u8>, // some not so complex data in the storage
} We would also need a mutable method for the context switch and flushing system, such as impl MyContractState {
fn flush_everything(&mut self) {
self.vec.flush();
self.map.flush();
self.val.flush();
}
} However, this method should not be directly called by users since it would just destroy performance if used incorrectly. Instead it should be coupled with switching contexts, i.e. through calling a remote contract or calling an associated runtime module's functions. impl MyContractState {
fn call_remote(&mut self, remote_call_data: RemoteCallData) {
self.flush_everything();
ContractEnv::call_remotely(remote_call_data)
}
} To encapsulate all this logic we could define some new traits and types such as: /// Types that can flush their synchronized state back into the contract.
trait Flush {
fn flush();
}
/// A builder pattern using type to construct binary data for calling a remote contract or
/// runtime module function encoded in pDSL abi.
struct RemoteCallData { .. } Also we would need to enhance Flush StateThe problem with the above design is that nothing prevents users from using |
Why not just store the state inside |
To come back to this, the real root problem is that the ownership graph is all over the place. |
This is very valuable feedback! |
Btw.: The flushing system has already been implemented and with the flushing system our mutable reference wrappers went extinct. I am currently trying to resolve some issues around storage allocation and initialization and will then continue with this. |
Note that since the flushing system has been successfully implemented and with commit c3a942b even So far it seems to work very well. tldr; I think we can close this issue. |
* fix(revive): apply xcm fix from pallet_contracts * build(deps): align pallet-revive-uapi dependency * fix: update pallet-revive-uapi integration * chore: remove workspace.xml * fix: improve output type length handling * fix: various fixes and improvements * fix(caller): use to_account_id host fn * chore: update cargo.lock
* fix(revive): apply xcm fix from pallet_contracts * build(deps): align pallet-revive-uapi dependency * fix: update pallet-revive-uapi integration * chore: remove workspace.xml * fix: improve output type length handling * fix: various fixes and improvements * fix(caller): use to_account_id host fn * chore: update cargo.lock
* hack together RiscV support for ink! -- works! * fix: various fixes for xcm and pallet-revive-uapi integration (#1) * fix(revive): apply xcm fix from pallet_contracts * build(deps): align pallet-revive-uapi dependency * fix: update pallet-revive-uapi integration * chore: remove workspace.xml * fix: improve output type length handling * fix: various fixes and improvements * fix(caller): use to_account_id host fn * chore: update cargo.lock * Introduce feature flag `revive` * Cleanup prior commits * Update changelog * Debugging faulty `std` import * Make sure `panic_impl` of `sp-io` is not enabled * Clean up changes * Update `Cargo.lock` * Make `[build.rustflags]` an array * Replace `panic`'s with `todo`'s * Revert changes to `Cargo.toml`'s * Convert spaces to tabs * Add `caller_is_root` * Introduce `#[ink::polkadot_derive]` re-export * Forward `std` * Configure `sp-io` * Configure `sp-io` * Forward `std` * Remove unused attribute * Use correct `ErrorCode` enum * Update test fixtures * Fix clippy errors --------- Co-authored-by: Peter White <[email protected]> Co-authored-by: Frank Bell <[email protected]>
Generic Mutable References
Problem
Currently wrappers around objects stored on the contract storage do not provide a way to receive mutable references (
&mut T
) to those objects.Rational
The reason for this is that users could do arbitrary changes to the objects without having an automated way to synchronize the storage.
Example
Storage wrappers like
storage::Vec
andstorage::HashMap
provide APIs likemutate_with
with which it is possible for users to do an efficient in-place mutation of an object owned by the collection.Goal
This is the tracking issue to come up with a user friendly, efficient and possibly general way to allow for mutable references that keep their referenced objects in sync between memory and storage.
Solutions
Solution 1: Do not provide mutable reference wrappers
This is the naive approach that we currently use.
However, it has the downside that it simply doesn't support what some users would like to have.
Solution 2: ?
The text was updated successfully, but these errors were encountered: