Ethereum 2.0 Data Model: Actors and Assets


#1

As a summary from this week, I think I have realized that the execution and data structure components of the ETH 2.0 roadmap are still very much in flux, especially the data structures.

One idea I have been thinking about this week is a few concepts relating primarily to the “actor model” that Erlang and Elixer uses (Read this for more info), thanks to some conversations with @expede. Another undercurrent is the idea of treating assets (tokens, Ether, other forms of controllable state with value) as first class citizens in this “asset control network” we’re building called Ethereum. Agoric is also doing some neat things along this concept (see talk here). @johba’s Plasma Leap (see thread here) also has some very similar concepts of a token that controls it’s own state.


More narrowly, the idea I have been playing with would be functionality that allows certain “actors” (like token contracts) to issue pieces of state to other actors (regular users). We would store these pieces of state in a new key-value data structure called “asset storage” (similar to how Ether balances are kept). Each asset could contain specific logic for transfer to other actors, or could link back to a function in that contract for more complex coordination logic (conditional transfers). They could issue logs, etc.

In this data structure, the issuing contract would be the key, so access control is built into the data structure as we could enforce only the issuing contract is allowed to modify given state or make external calls, etc. For upgradability, there might be a way for the issuer to change the key by calling a specific operation. Transfer of simple, uncontrolled tokens could even happen without ever requiring interaction with the issuer contract. Minting comes from the issuer, and burning could be a feature of the token internally. I am sure there are other useful features for an asset to have, but I think this can be reduced quite nicely to a few core features, and augmented with allowing the asset to store it’s own rules.

A nice side effect of all of this is that tokens (and other relevant state e.g. access rights to the issuing contract) no longer fully depend on a central contract for their control, which means the central issuer contract has much less authority over these valuable pieces of state in case of a hack.

This also has another nice side effect relating to storage rent: since much less state is being stored in central contracts, the concept of who pays for a particular contract to stay alive is reduced (we could define minimums to eliminate it). Each account is now in charge of managing their own assets, and in a rent scheme, this means ensuring the upkeep of their assets too. Rent could allow you to “drop” tokens you don’t care about.


This idea is definitely not fully baked, but I would say that now is the time for re-architecting the data model in order to make sure that the future state of Ethereum makes more sense to developers (I think the actor-asset model is very clear), and can be sustainable as well.

Thoughts?


#2

Totally agree with you!

I actually talked about it with ATjohba :slight_smile: as well during devcon4.

Another side effect is signature curve upgradability where actor can upgrade their signature going from Secp256k1 to Ed2551.

Another good side effect are the possilbity to upgrade actor smart contract from one sig to multi-sig easily or provide easily social recovery options.

And also cherry on the top, we could add actor ID immutability which means that we can generate a first public/private key where the public address is the actor ID. When we want to create our actor smart contract, the public address could stay the same which give us a nice user experience (so we could upgrade the same generated address with the custom actor smart contract). So for a standard user, the Actor ID never changes from the first generation of public/private key which is a very good property. We don’t need to add an extra layer such a ENS to provide Actor ID immutability.


#3

Hmm, another interesting side effect might be that cross-shard communication gets a little easier as we reduce the reliance on central contracts to perform transfers, since they can now be p2p instead.


#4

You framed the topic nicely :clap:

It may be worth mentioning that the idea for transfer restrictions has come up in Bitcoin Covenants already.

I’m intrigued how the Zexe paper has extended this and allows to model any asset with only a birth and death predicate.

My curiosity currently circles around off-chain breeding of crypto-kitties. Is there a way that my kitty is born on a side-chain and the main-net would be able to verify that it’s genetic transition was correct and all cool-off durations has been adhered to by the parents once it gets back to main-net :thinking:


#5

Smart Contract as Actor

One idea I have been thinking about this week is a few concepts relating primarily to the “actor model” […] I think the actor-asset model is very clear), and can be sustainable as well.

:clap::clap::clap:

…and also…

To be clear, at this point I [Vitalik] quite regret adopting the term “smart contracts”. I should have called them something more boring and technical, perhaps something like “persistent scripts”.

Yep, obviously @fubuloubu and I chatted a bit about this Prague, so I’m broadly in favour of this line of thought :+1:

The words that we use impact how we work with a system. I think that “actor” is a really nice match here, is an existing concept, and has no legalistic implications while emphasizing that these are separate chunks of autonomous code. Actors are best known as a way to model concurrency, but you can restrict your model to a single-threaded version. This ends up describing exactly what smart contracts are today, plus allow for extension for in-transaction concurrency (rather than the macro-level superposition that we currently use).

(Also, “actor” is much shorter to say and type than “smart contract” :wink:)

Reworking Storage/Control

no longer fully depend on a central contract for their control […] reduce the reliance on central contracts to perform transfers, since they can now be p2p instead

I totally get that this is a sketch of an idea at this point, but to help clarify, do you have a concrete example of how this would be used?

AFAICT, the current data layout and one where the data “actually lives in your account” are isomorphic for most uses, though this reworked version does add some complexity to things like upgrades resetting or proliferating the number of pointers to other contracts (like the creating/controlling one).

To use tokens as an example: they’re simply a balance (a number), and invariants, access control, and so on are handled by the wrapping contract; you’ll need to check in with that contract in any case, since it may have effects beyond simply what the user is doing directly (ex. change totalSupply). There are workaround (such as a broadcast event stream), but there is a nontrivial increase in overall complexity (which is fine — it’s a question of cost/benefit).

A Brief Case for Decoupling

While we’re tossing around ideas, I wonder if there may be another architecture to achieve these aims using decoupled storage and behaviour? OZ is already starting to approach this, but they’re treating it more as something to hide (in the data hiding OO tradition) rather than to embrace (in the actor model or networked styles). This can be done today with no hard forks (opt-in and backwards compatible)

Referenced Account
        ^
        |
        |
        V
    Data Store <----- Direct Consumer Contract
        ^
        |
        |
        V
Parent Contract <----- Collaborator

Cross-Shard

another interesting side effect might be that cross-shard communication gets a little easier as we reduce the reliance on central contracts to perform transfers

For sure. This ended up getting raised briefly during a Devcon talk, as well. I’m guessing that it’s uncontroversial that we want this coordination/routing/etc to happen below the application layer.


#6

Well, guess what I was doing on the plane?


Actor: a smart contract or private key, referenced by address

Issuer: an actor (typically a smart contract) that has the ability to define and issue state according to an immutable specification (non-contract actors can only issue a “basic” ether-like token)

Asset storage tree: merkle tree of key-value pairs, replacing the eth balance tree. The key corresponds to the issuing actor (in the case of ether, this is the 0x0 address). The value corresponds to an asset whose data type is defined by the issuing actor.


The asset’s type can be one of 3 options, with the following formats:

  1. A uint256 (ether, ERC-20)
  2. A list of bytes objects (ERC721, NFTs)
  3. A mapping of bytes32 -> uint256 (ERC-1400, PFTs)

The asset balances are publicly available, and can be queried using an opcode to return the data from the tree at the specific issuer address.

The issuer should provide an entry in the ABI for non-essential information about the asset (such as ticker symbol, etc). The issuer contract can define this for convenience as well.

The issuing actor defines the asset’s structure by calling an opcode that allows the issuing actor to define the asset’s type and initialize the supply characteristics. Nodes can use this to store tracking information. This information is as follows for each of these formats:

  1. Total supply of 0 (represented by uint256)
  2. Empty merkle tree root hash
  3. Total supply of 0 (represented by uint256)
    The issuer can only issue one asset.

Transferring an asset requires the issuer to send a message with the following data field:
SEND_OPCODE, issuer’s address, recipient’s address, assets to transfer (also matches asset structure). In order to be successful, this message’s asset structure must meet the conditions corresponding to it’s asset type:

  1. Asset is a uint256 GT 0, but LEQ the balance in asset storage
  2. Asset is a non-empty subset of entries in owner’s asset storage list
  3. Asset is a list of key-value pairs, where the value is a uint256 GT 0, but LEQ the balance of the sub-asset referenced by the key.
    If these conditions are not met, the transfer reverts execution.

Assets can have complex requirements for a transfer function if the issuer defines a transfer predicate. This predicate must match the signature transfer(to: address, from: address, asset: asset_type) and is called against the issuer’s address. The function can revert the transfer for whatever reason, as well as make internal state changes (if necessary) to it’s own storage (never the owner or receipient). If no matching function is present, the asset is assumed freely moveable (this takes care of selfdestructed contracts as well as ether) as the predicate cannot revert.

The account receiving the asset will then merge them according to the following rules:

  1. Current balance adds received balance. Reverts if GEQ 2**256. Transferred balance is deducted from sender’s account.
  2. Received entries are appended to the receiver’s list, and removed from the sender’s. Empty lists can be deleted.
  3. Balance of sub-assets are merged according to rule 1. Empty keys can be deleted.
    If the structure does not exist in the receiver’s account for the issuer’s key, a new entry will be created.

The receiver (if a contract) can define a receive function that matches the signature recieve(issuer: address, from: address, asset: asset_type). It can revert or do whatever it would like with this information as it sees fit. If no function is defined, the transfer is successful

Transaction receipts should contain a summary of all transfer messages that occurred in a given transaction.


An asset can be destroyed by sending a transfer message to the 0x0 account. This triggers the explicit removal of the asset from data storage as the 0x0 account does not store any tokens except ether (as it did issue all ether). Nodes will remove this entry from state.

An asset can only be minted by the issuer with the same opcode used to encode the structure in the orignal issuance, and can be passed by transfer message to another account, if desired. The rules for minting are as follows:

  1. Number minted must not overflow total supply
  2. ID minted cannot be in list of all assets (merkle tree proof)
  3. Sum of the increases of all sub-assets cannot overflow the total supply.
    Updates are captured if the minting does not violate these invariants.

Positive attributes:

  • Stateful message passing of assets (Ether receive logic! Token receive logic!)
  • Decentralization of asset storage (security and storage rent benefits!)
  • Decentralization of message passing (sharding benefits!)
  • Reduced complexity of token issuance contracts
  • Assets as a first class citizen (not just eth!)
  • May enable token gas payments? :scream:

Negative attributes:

  • Increased complexity at protocol layer
  • More inflexible API (did I miss one?)
  • Requires changes to ether balances :sweat_smile:
  • 4 opcodes added (register, issue, transfer, query)
  • NFT MT is probably a DoS vector. There is probably a better way to prove nonmembership in the set of already minted UIDs that the issuer may not own.

Other ideas:

  • Add a bool asset type, used primarily for ownership and access rights. Could also be an enumeratation.

#7

I believe this conversation extremely interesting. The actor-asset is for sure the base of any next generation blockchain.

Regarding the asset storage, i am not sure this is the most urgent issue to fix.

ERC20 are working pretty well on the way to save states of an ERC20. However, the missing part of the ERC20 is how it has been designed. The basic Transfer function of a ERC20 check directly the address signature where ideally we would need to delegate to the actor authorization. This way, the ERC20 Token will not need to check if the signature is correct but the actor will check if the signature is correct. This way, the transfer of asset goes from one actor to another actor. Crypto address are not first class citizen, Actors are.

In the current ERC20 Token, i cannot easily change my public signature without moving my assets to a new address which is huge pain for mass-adoption. Traditional end-user not familiar to crypto already have the opportunity to increase the security of their Gmail account without the need to “re-create an account”. Ideally being able to to deploy a smart contract to the my current public address would be very useful (kind of a new opcode CREATE3) because it gives a seamless experience for end-user to upgrade their actor account security. At the beginning my public address is my actor ID then later on, it is not necessarily anymore the case because i always keep my Actor ID however I can still switch to another type of Curve or multi-sig to transfer assets.

I consider there is 2 main types of condition to transfer an asset:

  • internal condition delegated and checked by the actor, does my signature (1 or several) matches the condition to move my asset
  • external condition from the issuer. does this asset can be moved from Actor A to Actor B (ex: checked how TPL works https://tplprotocol.org/)

In my opinion, before improving the asset storage, the actor model needs to be well defined.

To get mass adoption from the end-user, we need to make sure end-user can create an actor account easily, defining easily how many and which public key/private key will be used to allow transfer and potentially optiinally how to recover their private key from a social recovery schema (https://www.youtube.com/watch?v=FAC9uqHJ4H0)

I hope my comment helps. I suggest we co-write an article regarding this topic?

I believe this topic is a major to get mass adoption solved.

Kind regards,

Antoine