Contract pinning
Contract pinning is a feature of the CosmWasm virtual machine which ensures that a previously stored compiled contract code (module) is started from a dedicated in-memory cache. Starting a module from memory takes ~45 µs compared to 1.5 ms when loaded from disk (33x faster).
In contrast to the node-specific Least Recently Used (LRU) memory cache, pinning guarantees this performance boost across the network. As a consequence wasmd can charge discounted gas cost.
Pinning is an incredibly valuable tool for chains to optimize gas costs. According to a case study by one of our subscribers, Neutron, pinning improved the gas cost of their contracts somewhere between 15 and 50%!
Caches
CosmWasm has 3 different caches for modules:
FileSystemCache
the.module
files stored in the cache directory of the node.InMemoryCache
the LRU cache.PinnedMemoryCache
a separate cache.
Both memory caches (2. and 3.) work the same in terms of performance but their elements
are tracked separately. A pinned contract is never added to the standard InMemoryCache
and the size of pinned contracts is not counted towards its cache size limit.
Pinning and unpinning
In order to add a contract to the PinnedMemoryCache
, you need to call Cache::pin
in Rust or
func (vm *VM) Pin(checksum Checksum) error
in wasmvm. To remove a contract from the cache use
Cache::unpin
/ func (vm *VM) Unpin(checksum Checksum) error
. In both cases a contract is
identified by its checksum (sha256 hash of the Wasm blob).
The VM does not persist pinned memory entries. I.e. you need to call Pin
every time you start the
process. This is implemented in InitializePinnedCodes
in wasmd.
At the chain level pinning and unpinning are done via governance proposals. See
MsgPinCodes
/MsgUnpinCodes
in wasmd.
When contracts are migrated from one code to another, there is no automatic pinning or unpinning. This is primarily since the migration of a single instance does not mean all instances of the same code become unused. In the future we want to provide hit stats for each checksum in order to easily find unused codes in the pinned memory cache.
Best practices
Pinning contracts is a balance between increasing memory usage and boosting execution speed. Contracts that are known to be heavily used should be pinned. This can include contracts that are executed as part of begin/end block or the IBC light client implementations of the Wasm Light Client (08-wasm). If a chain is permissioned and runs on a small number of well known contracts, they can all be pinned. A permissionless chain might select certain contracts of strategic importance and pin them.
The estimated size of the pinned contracts is visible in the Metrics struct you can access through Prometheus. In order to better estimate which contracts are worth pinning, CosmWasm also exports metrics per pinned contract.
These metrics are:
- The contract size.
- The number of times it was loaded from cache.
That way you can better estimate which contracts are worth keeping pinned.