Skip to content
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

VIP: Custom Storage Types #1954

Open
Tracked by #2445
fubuloubu opened this issue May 7, 2020 · 5 comments
Open
Tracked by #2445

VIP: Custom Storage Types #1954

fubuloubu opened this issue May 7, 2020 · 5 comments
Labels
VIP: Discussion Used to denote VIPs and more complex issues that are waiting discussion in a meeting

Comments

@fubuloubu
Copy link
Member

fubuloubu commented May 7, 2020

Simple Summary

Allow logical components of a program to be specified separately from a main contract file

Motivation

It is very important to larger contracts to be able to break apart functionality from the main file for logical separation. This means we have to find an appropriate way to allow to break out logical functionality that has a high degree of separation. This could also simplify the implementation of several proposed features such as #484 and #1020 by making them internal library components.

Specification

A Component is defined very similarly to a contract, with certain features disallowed:

  1. Interface imports (importing other components allowed)
  2. Function decorators (full access by default)
  3. Event logging
  4. Struct definitions
  5. External calls
  6. Environment variables disallowed for internal methods

Examples

Constructor methods are defined using __init__(self, *args):

component MyComponent:
    def __init__(self, _a: uint256):
        ... # do something with _a

Components can have internal storage:

component MyComponent:
    ...

    bar: uint256  # internal state

    def foo(self):
        self.bar += 1

Components can use environment variables:

component MyComponent:
    ...

    def baz() -> uint256:
        return msg.timestamp

Usage

A Component can be imported into a contract file similar to an interface:

from my_component import MyComponent

It is defined similar to Python objects, and must be instantiated:

...
c: MyComponent = MyComponent(...)
...

Their implementation would be similar to structs, but with the addition of methods as struct members. They can be used in the same way as structs:

c: MyComponent

def bar() -> uint256:
    self.c.foo()  # self.c.bar += 1
    return self.c.bar

Backwards Compatibility

No backwards incompatibilities.

Dependencies

No dependencies.

References

https://diligence.consensys.net/blog/2020/05/an-experiment-in-designing-a-new-smart-contract-language/

Copyright

Copyright and related rights waived via CC0

@fubuloubu fubuloubu added the VIP: Discussion Used to denote VIPs and more complex issues that are waiting discussion in a meeting label May 7, 2020
@fubuloubu fubuloubu mentioned this issue May 7, 2020
7 tasks
@fubuloubu
Copy link
Member Author

Meeting notes: Come back to this when it's more concrete.

@fubuloubu fubuloubu changed the title VIP: Composables VIP: Components Jan 4, 2021
This was referenced Aug 30, 2021
@charles-cooper
Copy link
Member

charles-cooper commented Oct 18, 2021

Right now the thinking is if a contract has storage variables in it, then it's one of these (storage variables + methods on them), otherwise it's a stateless "library" as in #2431. Unclear if there should be syntactic difference from a regular contract.

@charles-cooper charles-cooper changed the title VIP: Components VIP: Advanced Storage Types Oct 18, 2021
@charles-cooper charles-cooper changed the title VIP: Advanced Storage Types VIP: Custom Storage Types Oct 18, 2021
@charles-cooper
Copy link
Member

One question is: should components be instantiable in memory? Or can they have HashMaps as members.

@fubuloubu
Copy link
Member Author

One question is: should components be instantiable in memory? Or can they have HashMaps as members.

In Solidity, it is possible to define a struct with a mapping as a member, however it implicitly precludes it from being used as a memory variable, which is weird.

@charles-cooper
Copy link
Member

i ported an example solidity contract (https://github.com/tellor-io/TellorPlayground/blob/575cfc565c9526df1320d3389fcb015bc86d1107/contracts/TellorPlayground.sol#L224-L279) to play around with this idea. so far, the encapsulation looks good, but it might be more natural if the "component" could access the parent contract's methods.

compare methods depositStake(), requestStakingWithdraw(), withdrawStake() at https://gist.github.com/charles-cooper/c40d8ea66b8afc0d552dc8776d0fc952#file-tellor_playground-vy. the fact that storage variables are not needed is nice. however, there is a bit of awkardness, because withdrawStake() and depositStake() require a call to self._transfer() in the parent contract. it might be better if it were possible to add the transfer logic inside of StakeInfo.mark_stake_withdrawn() and StakeInfo.deposit_stake(), because it would be easier to verify the invariants.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
VIP: Discussion Used to denote VIPs and more complex issues that are waiting discussion in a meeting
Projects
None yet
Development

No branches or pull requests

2 participants