substrate icon indicating copy to clipboard operation
substrate copied to clipboard

[contracts] Introduce immutable variables to WASM contracts

Open agryaznov opened this issue 2 years ago • 1 comments

Solidity has the concept of immutable variables, which value can be set once in contract’s constructor and guaranteed to stay unchanged afterwards. OpenZeppelin has recently recommended ink! to introduce this feature too, to provide contract developers with more flexibility in designing and building secure and efficient smart contracts. In this issue we’ll try to think about how we can introduce the similar concept into ink! and Pallet Contracts.

WebAssembly has indeed the similar construct - immutable global. Its initializer lives in the Globals section of the WASM module, and uses a constant initializing expression.

The constructor of WASM contracts in the pallet_contracts is the deploy exported function. This function is called once at the time of contract instantiation on-chain. Contract instantiation is done after the re-instrumentation and uploading the contract WASM blob on-chain, and it in general can be done in a separate (from uploading) extrinsic, when deploying a new contract instance of a code already stored on-chain. This approach allows to save gas and storage deposit for the caller account. Changing the Global section of the module on the step of contract instantiation would require its code altering and re-uploading on chain, implying an additional costs for contract authors.

Another approach could be to use an imported global in the contract module (note: currently importing globals to WASM contracts is forbidden). Pallet contracts could define the global and initialize it in the “env” module during the instantiation of the module to the WASM engine. For that it would need to somehow get the initializing expression from the constructor (deploy exported function of a module, which is to be designed by contract developer in #[ink(constructor)]). We can e.g. expose a host function init_immutable_global to the contracts API for that purpose on the pallet side.

But the core problem here is that we instantiate the module first to the WASM engine, and only after that we call the exported deploy function. My gut feeling it that probably we’d have to use WebAssembly start function for solving this issue, which is by design intended for initializing the state of a module (and is currently forbidden in WASM contracts as well).

@athei @cmichi @ascjones @HCastano wdyt?

agryaznov avatar Feb 23 '23 12:02 agryaznov