Global Constants ================ The size limit for :doc:`Michelson ` contracts is quite small, limited to 60 kilobytes as of Granada protocol. Global constants are a feature added in Hangzhou protocol that enables the re-use of user-defined Micheline chunks in Michelson scripts, allowing for larger and more complex contracts on the chain. It works in the following way: - Fragments of Michelson code (written in the :doc:`Micheline format <../shell/micheline>`) are registered on the chain via a new operation ``register_global_constant``. An example expression might be the integer ``999`` or the lambda expression ``{ PUSH int 999; ADD }`` - Included in the receipt of the operation is a hash of the expression registered. For example the hash ``999`` is ``expruQN5r2umbZVHy6WynYM8f71F8zS4AERz9bugF8UkPBEqrHLuU8``. - Constants can be referenced inside a Michelson script with the new primitive ``constant``. For example, we could write a lambda equivalent to the one above like so: ``{ PUSH int (constant "expruQN5r2umbZVHy6WynYM8f71F8zS4AERz9bugF8UkPBEqrHLuU8"); ADD }`` Global Constant Registration ---------------------------- The new ``register_global_constant`` operation includes an object with a single key ``"value"``, the value of which is the Micheline expression to be registered. You can submit this operation conveniently through a new :doc:`octez-client ` command. For example, the command: .. code:: sh octez-client register global constant "999" from bootstrap1 --burn-cap 0.017 would result in the output: :: Node is bootstrapped. Estimated gas: 1440 units (will add 100 for safety) Estimated storage: 68 bytes added (will add 20 for safety) Operation successfully injected in the node. Operation hash is 'onsFknW5iWa6eiTYqAghY4peQZ7JYQUJg5fR8MwAQkMKjXfNqGf' NOT waiting for the operation to be included. Use command octez-client wait for onsFknW5iWa6eiTYqAghY4peQZ7JYQUJg5fR8MwAQkMKjXfNqGf to be included --confirmations 5 --branch BLockGenesisGenesisGenesisGenesisGenesisCCCCCeZiLHU and/or an external block explorer to make sure that it has been included. This sequence of operations was run: Manager signed operations: From: tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx Fee to the baker: ꜩ0.000385 Expected counter: 1 Gas limit: 1540 Storage limit: 88 bytes Balance updates: tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx ................ -ꜩ0.000385 fees(the baker who will include this operation,0) ... +ꜩ0.000385 Register Global: Value: 999 This global constant registration was successfully applied Balance updates: tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx ... -ꜩ0.017 Consumed gas: 1440 Storage size: 68 bytes Global address: expruQN5r2umbZVHy6WynYM8f71F8zS4AERz9bugF8UkPBEqrHLuU8 As you can see, the address of the constant is returned in the operation receipt in the field ``Global address``. This address is the Base58-encode Blake2b hash of the binary serialization of the registered Micheline expression. This means constants are content-addressable - given a particular Micheline expression, you can always calculate its on-chain address and check if it’s registered. A few points about registering global constants: - Global constants may contain references to other constants; however, any referenced constants must already be registered on the chain. As a corollary, you cannot have cyclic references. - Global constants are not type-checked before registration - any valid Micheline expression may be registered. That said, attempting to originate a contract that uses a constant in an ill-typed way will fail. - The total depth of the expression registered as a constant (after expanding all constant references) may not exceed 10,000. - The total number of nodes in the Micheline expression being registered (after expanding all constant references) may not exceed the ``max_micheline_node_count`` protocol constant. As of Hangzhou this is 50,000. - The total number of bytes in the Micheline expression being registered (after expanding all constant references) may not exceed the ``max_micheline_bytes_limit`` protocol constant. As of Hangzhou this is 50,000. Originating a Contract that uses Global Constants ------------------------------------------------- A global constant can be referenced in Michelson scripts via the primitive ``constant``, which accepts a single string argument, being the hash of the expression to be referenced at runtime. This primitive can be used to replace any Micheline node in the bodies of the ``parameter``, ``storage``, ``code``, or ``view`` fields of a Michelson script. For example, we replace every instance of the type ``lambda unit unit`` and value 999 with their respective hashes: .. code-block:: michelson parameter (constant "exprtYirrFwYKm6yKLzJNtYRbq49zedYq16BonRvMzHiwSbUekB9YL"); storage (big_map int (constant "exprtYirrFwYKm6yKLzJNtYRbq49zedYq16BonRvMzHiwSbUekB9YL")); code { PUSH int (constant "expruQN5r2umbZVHy6WynYM8f71F8zS4AERz9bugF8UkPBEqrHLuU8"); # }; The full expansion of this contract would be: .. code-block:: michelson parameter (lambda unit unit); storage (big_map int (lambda unit unit)); code { PUSH int 999; # }; During origination, all constants are expanded recursively. The operation will fail if the resulting contract is ill-typed. Global constant expansion consumes gas; thus, the operation may also fail due to gas exhaustion. Global Constants at Runtime --------------------------- Contracts that use global constants are semantically equivalent to the contract with all constants expanded. Note that using the `UNPACK `__ operation to deserialize a lambda which contains a reference to a global constant is not supported. Similarly, originating a contract which contains a reference to a global constant using the `CREATE_CONTRACT `__ instruction will also fail.