near / nearcore

Reference client for NEAR Protocol
https://near.org
GNU General Public License v3.0
2.31k stars 618 forks source link

Expose storage prefetching to contracts, to avoid reliance on cache as much #8932

Open nagisa opened 1 year ago

nagisa commented 1 year ago

Today our runtime relies heavily on the caches in the storage system in order to provide better performance and therefore lower execution cost. If we wanted to remove this cache, the costs to access storage would be outrageously high.

An alternative to on-demand caching could be to be predictive about it. As a most basic solution, we could just fetch the entire contract state into memory as we prepare the contract for execution, but that would only work for the smaller contracts. We could probably reasonably do so for those contracts that are limited to 100KiB state or-so.

In practice, most contracts can probably tell the majority of storage keys they will be accessing given the name of the function being invoked and the arguments passed in, well ahead of the function being invoked in the first place.

From there on any accesses to such pre-fetched storage keys would be comparatively free-ish, being stored in some HashMap in the main memory.

In cases a contract does, in fact, need to make decisions on what keys to fetch based on some other fetches (thus depending on I/O dependencies) they could probably afford to pay realistic storage fees.

The primary reason this operation could be cheaper than a regular storage access is its being able to fetch data from the storage in bulk. Having a mechanism to access multiple keys at once allows the runtime to tell that these accesses are independent and fetch all the keys at once in an optimal way. This would basically convert the accesses from queue-depth=1 to queue-depth=N.


In addition to a regular host function to “simply” read&write multiple keys, we will want a mechanism to inform the runtime that certain keys will be accessed in contract execution at the benefit of cheaper accesses during the execution.

This could be a special exported function which would return the keys accessed for given function call description. The contract runtime could then pre-fetch the keys in the background as it gets ready to execute the transaction. This function would need to be pure, and therefore most of the host functions would be unavailable (panic at runtime) for the contract when the runtime invokes this function.

nagisa commented 4 months ago

This is probably not something we will need to do anymore with memtrie enablement. cc #10965