Adding Read-Only Calls

Current Situation

On Tezos, we can’t “call” another Smart-Contract (SC). What I mean by that is that there is no operation to get some output from another SC. What has to be done is to convert the two contracts into Continuation Passing Style.
This was a conscious decision, made to avoid reentrancy attacks.

However, as it is, this decision has some drawbacks:

  • Reading the state from another SC requires some cooperation from it
  • Writing the code is a bother (which is being mitigated with higher-level languages, but can only be mitigated)

Proposed Improvement

Content

I suggest the addition of two Michelson instructions:

  • GET_STORAGE sc_type, which gets the storage of some SC. (Important for adversarial reads.)
  • VIEW view_name view_type, which calls a view of some SC.

A view is a function from the view parameter and the storage of the SC to some output. Views don’t change the storage nor generate operations.

Advantages

  • With GET_STORAGE, migrating to a new SC becomes much easier.
  • It is easier to define accessors in interfaces.
  • It is easier to interact between contracts in general.

Technical Details

I’m not sure about a lot of implementation details, that I will consequently leave to others. What I am doing:

  • Adding the instructions and their syntax
  • Adding view entry-points
  • Adding some tests

What needs to be done:

  • Deciding what can be outputted by views (can they generate or return big_maps?)
  • Gas
  • More tests and reviews
  • Adding relevant error messages
  • Listing contracts that will be read before applying
  • Adding RPC clients

I’ll post a message once I will have pushed to a branch.

11 Likes

This is great. As I have been looking into using NFT based solutions for identity and reputation, I ran into how limiting it can be to implement these without the ability to get the storage of another contract. I expect those working on NFT based games will also see tremendous value in adding these read only calls.

I look forward to a good Agora discussion around use cases and definitions for views and get_storage.

3 Likes

Current branch is here, there is a test for GET_STORAGE.

EDIT: Just added the first test for the view prototype.
Here are the contracts that have been tested, that show what views currently look like. The first smart-contract exposes that adds its storage to what is passed as parameter.

Smart-contract defining the view

parameter nat ;
storage nat ;
code { CAR ; NIL operation ; PAIR } ;
view "add" nat nat { UNPAIR ; ADD } ;

Smart-contract using the view

parameter (pair nat address) ;
storage nat ;
code { CAR ; UNPAIR ; VIEW "add" nat nat ; NIL operation ; PAIR } ;
2 Likes

Can you elaborate on that? Why do we need the storage copy to happen on chain?

I am afraid that the GET_SOTRAGE instruction could break the buisness model of on-chain oracles that ask for a positive amount to let other smart contracts access part of their storage.

parameter (pair nat address) ;

What happens if the contract at this address does not feature a view called “add”?

Do we need view names to be first-class? Otherwise I would suggest to use annotations instead of strings for consistency with the proposed syntax for entrypoints in Babylon.

1 Like

I am afraid that the GET_SOTRAGE instruction could break the buisness model of on-chain oracles that ask for a positive amount to let other smart contracts access part of their storage.

If it’s on-chain, it’s already available. A smart-contract that needs data from an on-chain oracle could simply exposes entry-point that asks a trusted party to do so.
GET_STORAGE makes it so that no trust is needed.

The mentioned business model will break. But breaking business models that rely on value capture through software obstacles by removing those obstacles is a feature.

Interacting with uncooperative contracts is the main point of GET_STORAGE as opposed to views.

What happens if the contract at this address does not feature a view called “add”?

I believe it fails. The full idea (this is only a prototype) would be to list the contracts that will be called before the operation, so that they can be checked for this and have their views pre-loaded.

Do we need view names to be first-class? Otherwise I would suggest to use annotations instead of strings for consistency with the proposed syntax for entrypoints in Babylon.

Not at all, you are right and I’ll follow this suggestion. (Strings were simply easier.)

Can you elaborate on that? Why do we need the storage copy to happen on chain?

I believe it could enable copying data too big to be cheaply parsed and typed. Given this is not the main advantage, I haven’t given it much more consideration and might be wrong.