Git Product home page Git Product logo

Comments (4)

Robbepop avatar Robbepop commented on June 30, 2024

Commit 45e2f71 is an initial attempt at solving this issue as stated above.

It features

/// The result of a storage allocation.
struct MaybeUninitialized<T>(T);

/// Implemented by all types that allow to be allocated on the storage.
trait AllocateUsing {
    unsafe fn allocate_using<A>(alloc: &mut A) -> MaybeUninitialized<Self>
    where
        A: Allocator;
}

/// Implemented by all types that need special initialization after allocation on the storage.
///
/// # Example
///
/// The utility wrapper `storage::Value` is such a type.
trait Initialize {
    type Args;
    fn initialize(&mut self, args: Self::Args);
}

MaybeUninitialized provides two methods, unwrap to just directly access the maybe uninitialized underlying value and initialize that is only implemented if the underlying type implements Initialize. The initialize method basically forwards its arguments to the Initialize implementation and returns the result.

Summary

With this all three scenarios are approachable.

  • CREATE:
    • Foo::allocate_using(&mut bump_alloc).initialize(bar) or
    • No code needed to deploy the smart contract.
  • CALL:
    • Foo::allocate_using(&mut bump_alloc).unwrap()
  • DYNAMIC:
    • Foo::allocate_using(&mut cc_alloc).initialize(baz) or
    • Foo::allocate_using(&mut cc_alloc).unwrap() if initialization is not required

Note that all of this is going to be hidden from users normally as soon as the pdsl_derive is done.

from ink.

Robbepop avatar Robbepop commented on June 30, 2024

Due to problems involving recursive calls to allocate_using we shifted the approach slightly.
The helper struct MaybeUninitialized<T> has been removed and allocate_using now returns Self instead of MaybeUninitialized<Self>.
Besides that we introduced another helper trait method Initialize::initialize_into(self, Self::Args) -> Self so that users can still use chaining.

Summary

With these changes the following scenarios are approachable in the following ways.

  • CREATE
    • Foo::allocate_using(&mut bump_alloc).initialize_into(bar) or
    • No code required to deploy the smart contract.
  • CALL
    • Foo::allocate_using(&mut bump_alloc)
  • DYNAMIC
    • Foo::allocate_using(&mut cc_alloc).initialize_into(baz) or
    • Foo::allocate_using(&mut cc_alloc) if no initialization is required

Note that all of this is going to be hidden from users normally as soon as the pdsl_derive is done.

from ink.

Robbepop avatar Robbepop commented on June 30, 2024

To improve safety and security we should transit towards encapsulating the state and everything that modifies it.
For this we should separate state modifying environment functions out of Env into an own dedicated State trait.

This State trait could look like the following:

trait State {
    fn store(key: Key, bytes: &[u8]);
    fn load(key: Key) -> Option<Vec<u8>>;
    fn clear(key: Key);
}

It would be nice to have some compile-time niceties to check that a certain instance exists only once.
For runtime-based check there is https://crates.io/crates/once. With such a check we can secure that there is really just one state operating on contract state so that we can actually have single ownership of it. Maybe the future eDSL could provide this check to its users. Also note that the State trait is agnostic over EnvTypes and thus doesn't need to be generic over them.

The Env trait needs more polish. Types implementing it must also include in their state a type implementing the State trait. With this setup we can determine an ownership when using a single environment which is the default. Also the Env implementation could handle all dynamic and static allocations.

struct SrmlEnv<S: State> {
    state: S,
    bump_alloc: BumpAlloc,
    dyn_alloc: DynAlloc,
}
impl Env for SrmlEnv { ... }

Now we can actually form an API to allocate contract entities dynamically using an Env implementer for that purpose.

impl SrmlEnv {
    fn on_storage<T>(&mut self, args: <T as Initialize>::Args>) -> T
    where
        T: AllocateUsing + Initialize
    {
        T::allocate_using(&mut self.dyn_alloc).initialize_into(args)
    }
}

Note that dynamically allocated storage entities clear their associated storage upon Drop (going out of scope) whereas statically allocated storage entities do not. To fix the current situation for statically allocated entities we need to wrap them in a certain utility type in order to not clear their associated storage upon Drop.

struct NoDrop<T>(PhantomData<T>);

impl Drop for NoDrop {
    fn drop(&mut self) {
        // Do nothing on purpose!
        // Note that this should not break types that require cleanup on `Drop`
        // since we are leaving contract execution anyway when calling `Drop`
        // of statically allocated storage entities.
    }
}

from ink.

Robbepop avatar Robbepop commented on June 30, 2024

Done (since ages). Closed.

from ink.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.