Global constants

Introduction

This is an idea that’s been going around for a while, but I’m not sure if there’s been a proper discussion thread on it, so here it is.

A global constant is a michelson constant accessible from any contract and registered in the context. Most of the discussions around the topic have assumed that the constant is a lambda expression, but this needs not be the case. However, if the constant is not a lambda expression, we may want to be careful to ensure it is not (or does not contain) a ticket handle, which could introduce mutation, though storing tickets wouldn’t be an issue per se, just pointless.

Proposition

It could work as follow:

  1. a new manager operation: register_constant takes a Michelson constant and writes it in the context and assigns an address to it (typically this could be the hash of the packed representation of the value, but it could be prudent to not guarantee this property). The manager pays the associated storage burn.
  2. a new michelson opcode: REGISTER_CONTANT emits an operation which does the same thing
  3. a new michelson type: constant_address represents the address of a constant that has been registered in the context.
  4. a new michelson type constructor: Constant_address "CST1x2344..." which constructs a lambda address from a string representing a valid address
  5. a new michelson opcode LOAD_CONSTANT parametrized with a type t which takes a constant_address and returns an t option, depending on whether or not that address is inhabited.

Discussion

This is useful for lambdas

This is primarily useful for lambdas because it allows the creation of libraries. It also means that contracts no longer need to be fully deserialized when called. A contract could register each of its entrypoint as a constant and load them on demand.

Since many contracts are bound to repeat code (e.g. token standard code), a cache of the most commonly called function can offer much lower gas and even introduce heavy optimizations by precompiling the functions being called.

Non lambda uses

It’s not super clear that this is useful beyond lambdas, but we could imagine it being helpful for some big_map containining useful data. There is also no particularly good reason to restrict this to lambdas, even if they seem like the primary use case.

3 Likes

I’ve collected this into an official TZIP: https://gitlab.com/tzip/tzip/-/merge_requests/117
There’s also a post in the TZIP section of the agora waiting to be approved.

Arthur, you’ll notice we’ve basically only kept the register_constant manager operation and the LOAD_CONSTANT commands, excluding the rest. I don’t see the purpose in more than that, but could easily be missing something.

Re: the constant_hash type. I’m inclined to make these static and impossible to construct at runtime. We could simply validate the string is a valid constant address at type checking time. I don’t know off the top of my head what bad things might happen if we allow runtime construction, but I think we can get all the benefits of the table of constants without finding out.

Re: REGISTER_CONSTANT, off the top of my head I don’t see any major difficulties in implementing this, but I’m inclined to leave it out in the first pass for simplicity, sicne the manager operation covers the main use case.

Contracts used to be storable which created a really pointless dependency between the typechecker and the entire tezos context which historically impeded a lot of developer tooling.

Not having to know the exact state of the context to be able to typecheck a contract seems like a reasonable thing to want.

The said static values might be faster to handle. To alleviate the problem above, we could also have a mode for the typechecker where you tell it the type of the stuff that is supposed to be in the context.

Agree that programmatically emitting constants doesn’t seem immediately useful.

1 Like

Ah, this makes sense then. I will do a first pass as you initially outlined, and we can adjust from there.