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.5ms 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 cost1.
Pinning is an incredibly valuable tool for chains to optimize gas costs. According to a case study (opens in a new tab) by one of our subscribers, Neutron, pinning improved the gas cost of their contracts somewhere between 15 and 50%!
The caches
CosmWasm has 3 different caches for modules:
FileSystemCache
the.module
files stored in the cache directory of the nodeInMemoryCache
the LRU cachePinnedMemoryCache
a separate cache
Both memory caches (2./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
(opens in a new tab) in Rust or
func (vm *VM) Pin(checksum Checksum) error
in wasmvm. To remove a contract from the cache use
Cache::unpin
(opens in a new tab) / 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 (opens in a new tab).
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 cache2.
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 (opens in a new tab)). 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 (opens in a new tab) struct you can access through Prometheus (opens in a new tab). 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.
History
Pinning was developed in 2021 (CosmWasm 0.14) for the Proof of Engagement consensus system of Tgrade which required certain contracts to be executed in every block.