Skip to content

Latest commit

 

History

History
108 lines (67 loc) · 7.2 KB

cap-0056.md

File metadata and controls

108 lines (67 loc) · 7.2 KB
CAP: 0056
Title: Soroban intra-transaction module caching
Working Group:
    Owner: Graydon Hoare <@graydon>
    Authors: Graydon Hoare <@graydon>
    Consulted: Jay Geng <@jayz22>, Dmytro Kozhevin <@dmkozh>, Nicolas Barry <@MonsieurNicolas>, Tomer Weller <@tomerweller>
Status: Implemented
Created: 2024-03-13
Discussion: https://github.com/stellar/stellar-protocol/discussions/1460
Protocol version: 21

Simple Summary

Lower total costs by caching parsed Wasm modules within a Soroban transaction.

Working Group

As specified in the Preamble.

Motivation

To lower the CPU cost charged for each contract invocation transaction thereby admitting more such transactions per ledger and increasing total throughput.

Goals Alignment

This change is aligned with the goal of lowering the cost and increasing the scale of the network.

Abstract

Soroban transactions may invoke the same contract more than once in a transaction, for example by making multiple calls to different methods on the same token contract. Currently each such cross-contract call re-parses the called contract as part of instantiating it. This CAP proposes adding a module cache to the Soroban host, such that contracts are only parsed once per transaction.

Specification

Each Soroban transaction typically consists of a tree of contract invocations. Each contract in that tree of invocations must be parsed and instantiated at least once, but if the tree calls the same contract more than once within a transaction, there is an easy opportunity for a performance improvement by not parsing the contract repeatedly for each call, but reusing a cached copy.

To do this requires both caching parsed contracts, as well as separately charging for parsing (which can be done one per module per transaction) and later phases of instantiation (which must be repeated per invocation). This separation existed in the previous (unused) distinction between the VmInstantiation and VmCachedInstantiation cost types, and is preserved by the separation of new cost types in CAP-0054. This CAP can be accepted with or without CAP-0054, but the split in cost-types in CAP-0054 between parsing and instantiation is motivated by this CAP.

XDR changes

There are no XDR changes beyond those proposed in CAP-0054, which as mentioned above are actually optional too. This CAP works with or without it.

Semantics

Normative

This section describes the change to observable behaviour.

  • When a Soroban transaction is constructed, before it begins executing:
    • For each ContractCode ledger entry mentioned in the read footprint of the transaction:
      • If CAP-0054 is accepted and the ledger entry contains the new CAP-0054 refined cost model input types:
        • The transaction is charged the new refined ParseWasm* module-parsing cost models with the new refined cost model inputs
      • Else:
        • The transaction is charged the old VmInstantiation cost type, which will have been recalibrated by this change to only cover the cost of parsing the ContractCode's Wasm module, not fully instantiating it.
  • When a Soroban transaction performs an invocation on some contract implemented by some Wasm module:
    • If CAP-0054 is accepted and the ledger entry contains the new CAP-0054 refined cost model input types:
      • The transaction is charged the new refined InstantiateWasm* module-instantiating cost models with the new refined cost model inputs
    • Else:
      • The transaction is charged the old VmCachedInstantiation cost type, which will have been recalibrated by this change to only cover the cost of instantiating an already-parsed module.

Informative

This section explains the implementation. It is intended for illustration purposes, and other possible impementations that achieve the same observable normative behaviour are possible.

  • When a Soroban Host is constructed for a transaction, it contains a new module cache that will hold parsed Wasm modules.
  • The module cache is then, before any modules are executed, unconditionally populated with a parsed Wasm module for every contract mentioned in the transaction's read footprint.
    • When parsing a module for caching, it will be charged to either the cost model of the old VmInstantiation cost type, or the new refined cost models for the CAP-0054 ParseWasm* cost types.
  • As invocations require instantiation of parsed modules, pre-parsed modules will be extracted from the cache and instantiated.
    • When instantiating a cached module, it will be charged to either the cost modelof the old VmCachedInstantiation cost type, or the new refined cost models for the CAP-0054 InstantiateWasm* cost types.

Design Rationale

For the most part the design is straightforward: add a cache and use it.

The only subtle rationale is the need for eager instantiation. Due to particularities of the way the Wasm VM in Soroban works -- the VM's "engine" is locked during execution -- the cache must be fully populated before any execution begins; caching cannot happen "on demand" as a contract runs.

As a result, the set of cached contracts will depend solely on the read footprint, not any further deviation from the footprint in the contract's execution: every contract present in the read footprint of a transaction will be parsed and cached eagerly when initializing the transaction.

Eager cache population is also the most likely structure to be compatible with future extensions of this work to include caching modules across transactions, or even across ledgers. However, such future work requires more complex fee and transaction-queueing logic, and is out of scope for the current proposed change.

Protocol Upgrade Transition

Backwards Incompatibilities

The change is broadly backward compatible (new software can continue to process old data).

The change will charge nonzero costs to a cost type that, before the change, sees only zero costs. But users and operators should not be relying on those costs to be zero.

Resource Utilization

While it is possible to construct a transaction that is charged more with the eager parsing in this CAP than it would with lazy parsing on today's network, such a transaction is quite contrived: it would require contract A to call contract B during simulation (when the footprint is recorded and initial fee is estimated) and then change its decision when executing on-chain for real and not call contract B, typically just moments after the simulation that recorded its intent to call B.

This type of transaction seems sufficiently unlikely to occur that we think it can be discounted, especially given that the only penalty for it occurring would not be a transaction failure but merely a slightly higher-than-necessary fee being charged: the fee returned from simulation, rather than a lower one that (somehow) anticipated the transaction's changed decision.

We expect in practice that all transactions will be charged either the same as they are before the change (if there are no cache hits) or significantly less (if there are cache hits).

Security Concerns

None apparent.

Test Cases

TBD

Implementation

A preliminary implementation is underway in the soroban-env-host repository