Speeding up EVM/JS SDK with hot/cold contracts and immediate gas refund. Application to storage speed up

Motivation

Our contract ecosystem evolves in the direction of having language-enclaves. The most prominent are:

  • Aurora EVM;
  • JS SDK.
    Language enclaves allows to have a host contract implementing a VM with language interpreter that can host contracts written in language like Solidity and JS/TS. This creates a second layer of virtualization with secondary account system emulated inside the host contract.

These enclaves evolve because they have the following advantages:

  • It allows support for other virtual machines used by other blockchains;
  • It addresses the need for sync contact calls, see [Discussion] Synchronous contracts ;
  • It expand the diversity of contract languages;
  • It allows low contract deployment costs;

The issue is however that every time contract in enclave is called through transaction/receipt is requires loading entire host contract into memory, which is costly, given that host contract implements a complex virtual machine.

Updated Solution

Previously, we discussed the solution of differentiating hot and cold contracts here: [Proposal] Differentiate cold and hot contracts · Issue #97 · near/NEPs · GitHub . This solution however had a fundamental issue of breaking DevX, since it would require developers to be aware of whether their contract is hot/cold which can change with time. If developer incorrectly assumes that the contract is hot and passes insufficient gas for cold execution, the contract might fail.

In the future, once we switch to attaching NEAR instead of gas, this problem will be irrelevant, since we would also have a mechanism for bumping contracts that run out tokens. However, we need another medium-term solution for it.

Reminding the idea of hot/cold contracts

Currently, at the end of each epoch validators publish a header that contains a list of future validators based on the validator proposal transactions scattered throughout the epoch.

Similarly validators can keep track of how much gas each unique contract consumed throughout the epoch and at the end of the epoch include in the block body the list of top-20 most used contracts by hash. Hot contracts then would be required to always be pre-loaded by Wasmer VM, and Runtime would charge lower fees for interacting with them.

Fixing DevX for hot/cold contracts

To avoid breaking DevX, while still allowing to benefit from increase in TPS, we can do the following:

  • Cold contracts will behave the usual way;
  • Hot contracts will use the fees of cold contracts, but at the very end of receipt execution NEAR runtime will compute how burnt gas using hot fees and refund the difference, reducing the total amount of burnt gas.

This will make contracts unaware of whether they were cold or hot, since refund happens only at the end of execution, and it allows to squish more transactions/receipts into a single block.

Also, given that we don’t need to publish the list of hot contracts in the header, this protocol change does not affect the light client.

Extension to state optimization

Similarly we can differentiate other hot/cold operations without breaking DevX, e.g. hot/cold state keys. This can significantly increase the TPS towards the most used contracts even if they have heavy storage usage. At the end of each epoch validators would include the most used state keys into block body, and then after one more epoch all validators will be required to store these keys in memory and charge lower fees.

3 Likes