Skip to content

Commit

Permalink
draft of gas model adjustment for user programmability.
Browse files Browse the repository at this point in the history
  • Loading branch information
raulk committed Mar 17, 2022
1 parent 7342630 commit 7b1e4d0
Showing 1 changed file with 238 additions and 0 deletions.
238 changes: 238 additions & 0 deletions FIPS/fip-nnnn.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,238 @@
---
fip: "nnnn"
title: Gas model adjustment for for user programmability
author: Raúl Kripalani (@raulkr), Steven Allen (@stebalien)
discussions-to: https://github.com/filecoin-project/FIPs/discussions/316
status: Draft
type: Technical
category: Core
created: 2022-03-09
spec-sections:
- TBD
requires:
- FIP-0030
- FIP-0031
- FIP-0032
replaces: N/A
---

# FIP-nnnn: Gas model adjustment for user programmability

## Simple Summary

This FIP expands on FIP-0032 (Gas model adjustment for non-programmable FVM). It
introduces new gas fees to cover the costs of functionalities and system tasks
related to the deployment and execution of user-deployed on-chain actors. It
also prices syscalls that were previously free for built-in actors.

## Abstract

This FIP introduces gas fees for actor deployment, actor loading, and actor
memory expansion. It modifies existing fees, such as the hashing fee, which is
now made dynamic. Finally, it prices syscalls that are currently unpriced, and
adjusts the permissions on syscalls that are now considered privileged.

## Change Motivation

The ability to deploy user-defined actors results in new workloads and tasks for
the network to execute. These introduce new resource consumption pressures in
terms of compute, memory, chain bandwidth, state footprint, and other axes. User
transactions triggering these workloads need to be subjected to gas fees in
order to compensate the network for this new work, as well as to size blocks
appropriate to sustain the 30s epoch time.

## Specification

Here’s an overview of proposed changes to the existing gas model. We explain
each one in detail in the following sections.

- Introduce a fee for *actor installation,* the act of deploying of new actor
code to the chain.
- Introduce a fee for *actor loading,* the act of loading an actor’s Wasm module
to handle a call.
- Introduce memory expansion gas.
- Adjust the hashing fee to vary depending on digest function and length of
plaintext.
- Price currently unpriced syscalls.
- Restrict the charge_gas syscall.

### Actor installation fee

We specify an actor installation fee. This fee covers the cost of accepting Wasm
bytecode submitted by a user, persisting it, and preparing it for execution.

This includes:

- Storing the Wasm bytecode in the state tree.
- Validating the Wasm bytecode: includes the cost of performing static code
analysis to validate its structure, integrity, and conformance with system
policies (e.g. number of functions, maximum stack length, usage of Wasm
extensions, etc.)
- Potentially optimizing the Wasm bytecode.
- Weaving in the gas metering logic.
- Compiling the Wasm bytecode into machine code.
- Potentially progressively optimizing the machine code.

**Pricing formula**

`<<TODO>>`

### Actor loading fee

We introduce an actor loading fee. In the FVM, all Wasm bytecode is compiled and
cached as machine code on disk (notwithstanding that clients may apply caching
policies to retain the hottest actors in memory).

For every non-value transfer message[^1], the actor’s precompiled module must be
loaded and the actor’s entrypoint must be invoked. The actor loading fee covers
that cost, and is computed over the length of the original Wasm bytecode[^2] and
complexity factors. These factors are determined at deployment time through
static code analysis, and include:

- number of imported syscalls
- number of globals
- number of exported entrypoints[^3]

The loading fee is additive to the extant *call fee*: loading bytecode and
invoking the loaded bytecode are two separate acts. In fact, an actor loaded
once can be invoked multiple times during a single call stack. This FIP proposes
no fee discount/exemption on deduplicated actor loading (such as on
recursion/reentrancy), but we may consider it in the future.

**Pricing formula**

`<<TODO>>`

### Memory expansion gas

FVM actors are allowed to allocate memory within predefined bounds. Wasm memory
is measured and allocated in pages. A page equates to 64KiB of memory. Page
usage is metered and limited per call; reentrant or recursive calls are
independent of one another for purposes of memory consumption.

Starting with this FIP, actor invocations are granted 1 page for free (64KiB),
and the cost of that page is accounted for in the call fee. This avoids an
immediate memory expansion operation on every invocation, as most actors need
*some* memory to do useful work.

An actor can use any number of pages, but the total page count for the entire
call stack cannot exceed 8192 pages, i.e. 512MiB. The next allocation must fail
with an `SysErrOutOfMemory`.

We introduce a memory expansion fee. Today, we charge a fee for the memory
expansion operation, dependent on the number of pages requested at a time. This
is to account for the memory zeroing cost on allocation.

This fee does not aim to model the cost of memory *usage*, because the presence
of a hard limit in a sequential execution environment means that all
implementations must preallocate and reserve the maximum amount of allocatable
memory (512MiB) anyway. So, in this context, memory is not a shared or scarce
resource to tax[^4].

`<<TODO: consider moving the memory policy to a FIP of its own>>`

**Pricing formula**

`<<TODO>>`

### Multihash-dependent hashing fee

Today’s syscall for hashing assumes a Blake2b-256 digest function. This syscall
will be generalized, so it can hash over a predetermined set of multihash digest
functions. Because the computational effort varies per digest function, so does
the updated hashing fee.

`<<TODO: specify the syscall generalization in a FIP of its own, or bundle with
memory policy>>`

**Pricing formula**

`<<TODO>>`

### Price currently unpriced syscalls

In Filecoin network version 15 and below, these syscalls (or equivalent
operations) are unpriced. With this FIP, they will acquire a price:

- `network::epoch, network::version`, `network::base_fee`, `message::caller`,
`message::receiver`, `message::method_number`, `message::value_received` ,
`debug::debug_enabled`
- These syscalls retrieve static, contextual information. They are charged a
flat syscall fee of <<TODO: value>>.
- `actor::get_actor_code_cid`, `actor::new_actor_address` ,
`self::current_balance()`
- These syscalls query the actor’s node in the state tree. They are charged
a flat syscall fee of <<TODO: value>>.
- `rand::get_randomness_from_tickets` , `rand::get_randomness_from_beacon`:
- These syscalls access randomness. They do so traversing the FVM<>node
boundary. The cost of these syscalls is proportional to the length of
their input, but not to the lookback because nodes are expected to cache
randomness up to the maximum lookback in a ring buffer like data
structure.
- `<<TODO: limit the lookback>>`
- The cost of these syscalls is: <<TODO: formula>>.

### Restrict usage of `gas_charge` syscall

This syscall is available to all actors, but it will be restricted such that
only built-in actors can effectively make use of it. User-deployed actors will
have their transactions aborted with exit code `SysErrForbidden` when attempting
to invoke this syscall.

## Design Rationale

`<<TODO>>`

## Backwards Compatibility

`<<TODO>>`

## Test Cases

`<<TODO>>`

## Security Considerations

`<<TODO>>`

## Incentive Considerations

`<<TODO>>`

## Product Considerations

`<<TODO>>`

## Implementation

For clients relying on the reference FVM implementation
([filecoin-project/ref-fvm](https://github.com/filecoin-project/ref-fvm)), the
implementation of this FIP will be transparent, as it is self-contained inside
the FVM.

## Copyright

Copyright and related rights waived via
[CC0](https://creativecommons.org/publicdomain/zero/1.0/).

## Footnotes

[^1]: Ideally, it would depend on the length of the compiled *machine code* (as
this is what’s effectively loaded at invocation time). But because machine
code is compiler- and platform-dependent, that approach is not feasible.

[^2]: Today, value transfers are handled entirely inside the VM. In the future,
we may want to delegate to the actor. This could be achieved by introducing
the notion of a *value transfer entrypoint:* a publicly exported function
invoked to handle messages with no payload. At deployment time, the FVM
would need to memorize if a *value transfer entrypoint* exists, to determine
when actor code should be loaded and when not.

[^3]: Currently, actors only support one entrypoint: the `invoke` function.
Support for multiple entrypoints may be added in the future to handle value
transfers, code upgrades, and lazy state migrations.

[^4]: This will change once Filecoin switches to parallel execution, and memory
becomes a shared resource that determines scheduling decisions and task
bin-packing. But even under that model, it is unlikely for memory usage
costs to be folded into gas.

0 comments on commit 7b1e4d0

Please sign in to comment.