Documentation
¶
Overview ¶
Package vm implements a minimal, pure-Go execution shell sufficient for Curio's read-only and gas-estimation calls against Lantern.
Scope and non-scope ¶
Filecoin's reference FVM (ref-fvm, Rust) executes WASM-compiled actor code with a full gas-metered runtime, syscalls, and IPLD store. Lantern cannot import ref-fvm (CGo) and there is no pure-Go FVM in the ecosystem today. So this package is deliberately **not** a full VM.
What this package DOES:
- Decode and dispatch a Filecoin Message against the built-in actor method tables shipped in go-state-types (v17/v18).
- Execute Account → Account `Send` (method 0) end-to-end: balance check, value transfer, gas accounting. This is the only on-chain write path we model with full fidelity.
- For every other built-in actor method, run "gas accounting only": return a synthetic `MessageReceipt` with `ExitCode=0`, `Return=nil`, and a `GasUsed` value derived from the message size, method parameters and the canonical Filecoin gas schedule. **State is not mutated.** This matches what Lotus' `GasEstimateGasLimit` actually needs: it binary-searches for a gas value that succeeds without caring about the receipt body.
- For user-deployed actors (EVM, native FVM actors v3+) and any unknown method, return `ExitCode=SysErrUnsupportedMethod`.
What this package DOES NOT do:
- It does not execute actor logic (no PreCommit/ProveCommit math, no PoSt verification, no FIL+ allocation accounting).
- It does not produce a new state root. `ApplyMessage` returns the input state root unchanged (modulo a synthetic per-message receipt CID we accumulate in an AMT for block-template assembly).
- It does not run cron, vesting, reward issuance, or any of the per-block "implicit" messages a full Filecoin block would.
Why this is enough for Phase 7:
- StateCall: callers only need ExitCode + GasUsed + ReturnValue for gas estimation and dry-run validation. For Curio's writes (PreCommit, ProveCommit, PoSt, etc.) the network's full nodes execute the message for real; Lantern only has to produce a plausible gas envelope so Curio can sign+broadcast.
- GasEstimateMessageGas: binary search for the gas limit becomes trivial because our VM never charges more than a fixed per-method ceiling. We compose this with the real on-chain `BaseFee` and a mempool-derived premium percentile.
- MinerCreateBlock (Phase 7 Part C): in dry-run mode the block's `ParentStateRoot` field is taken verbatim from the parent tipset (i.e. "no change"). We document this clearly: Lantern cannot produce a *publishable* block, but it can produce a syntactically valid `*types.BlockMsg` Curio's WinPoSt task can hand to its normal signing pipeline.
Provenance
- Gas constants and per-message costs come from go-state-types/builtin/v18 (in particular the price-list lifted from Lotus 1.36's `chain/vm/gas_v15.go`).
- Method dispatch uses the public `Methods` map shipped in `go-state-types/builtin/v{N}/<actor>/methods.go`.
- No code is lifted from `lotus/chain/vm` directly.
All limitations are documented in PHASE7-BLOCKERS.md.
Index ¶
- Constants
- Variables
- func EpochAt(s *hstore.Store, ep abi.ChainEpoch) (int64, error)
- func MaxGasCost(msg *types.Message) big.Int
- type ApplyOptions
- type ApplyResult
- type BaseFeeSource
- type CallResult
- type FilBigInt
- type GasCost
- type GasEstimator
- func (e *GasEstimator) EstimateFeeCap(ctx context.Context, premium big.Int, _ int64) (big.Int, error)
- func (e *GasEstimator) EstimateGasLimit(ctx context.Context, msg *types.Message) (int64, error)
- func (e *GasEstimator) EstimateGasPremium(ctx context.Context, nblocksincl uint64) (big.Int, error)
- func (e *GasEstimator) EstimateMessageGas(ctx context.Context, msg *types.Message, maxFee big.Int) (*types.Message, error)
- type HeaderStoreFeeSource
- type MempoolPremiumSource
- type MethodInfo
- type PremiumSource
- type PriceList
Constants ¶
const MaxBlockGas int64 = 10_000_000_000
MaxBlockGas is the per-block gas budget (10 billion units).
This matches `build.BlockGasLimit` in Lotus 1.36.
Variables ¶
var ZeroSenderAddr addr.Address
ZeroSenderAddr is convenience for tests; not used internally.
Functions ¶
Types ¶
type ApplyOptions ¶
type ApplyOptions struct {
// NetworkVersion is the current Filecoin network version (e.g. nv26
// for v18 actors).
NetworkVersion network.Version
// PriceList is the gas schedule. If zero-value, V15PriceList is used.
PriceList PriceList
// BaseFee is the parent tipset's base fee in attoFIL.
BaseFee big.Int
// DryRun = true means do not commit state. Always true in Phase 7
// (we have no place to commit it anyway).
DryRun bool
}
ApplyOptions controls execution behaviour.
type ApplyResult ¶
type ApplyResult struct {
Receipt types.MessageReceipt
MethodInfo *MethodInfo // nil for Send / unknown
GasCost GasCost
Error string
// ParamsDecoded is the human-readable representation of the params,
// when we can decode them. Useful for tracing.
ParamsDecoded interface{}
}
ApplyResult is the structured return from Apply.
func Apply ¶
func Apply(ctx context.Context, acc *accessor.Accessor, msg *types.Message, opts ApplyOptions) (*ApplyResult, error)
Apply executes a single message against the accessor's view of state.
`acc` is a read-only state accessor bound to the tipset's parent state root. We use it to (a) resolve `msg.From` and `msg.To` to ID addresses, (b) read the receiver actor's code CID for method dispatch, (c) check the sender's balance.
The returned ApplyResult.Receipt has:
- ExitCode: 0 on success, SysErrUnsupportedMethod for unknown actors, SysErrInsufficientFunds when the sender can't cover gas+value.
- GasUsed: estimated gas consumed.
- Return: empty bytes (we don't synthesize return-typed payloads).
type BaseFeeSource ¶
type BaseFeeSource interface {
// CurrentBaseFee returns the latest known ParentBaseFee.
CurrentBaseFee(ctx context.Context) (big.Int, error)
}
BaseFeeSource is the minimum chain-history surface the gas estimator needs.
type CallResult ¶
type CallResult struct {
Receipt types.MessageReceipt
MethodInfo *MethodInfo
GasCost GasCost
Duration time.Duration
Error string
}
CallResult mirrors the parts of api.InvocResult that callers care about.
func StateCall ¶
func StateCall(ctx context.Context, acc *accessor.Accessor, msg *types.Message, opts ApplyOptions) (*CallResult, error)
StateCall runs `msg` in dry-run mode against `acc`'s state.
`acc` must already be bound to the desired tipset's parent state root. Phase 7 does not support specifying an arbitrary tipset key — callers must build the right accessor up-front.
type GasCost ¶
type GasCost struct {
GasUsed int64
BaseFeeBurn big.Int
OverEstimationBurn big.Int
MinerTip big.Int
MinerPenalty big.Int
Refund big.Int
TotalCost big.Int
}
GasCost mirrors api.MessageGasCost.
type GasEstimator ¶
type GasEstimator struct {
Acc *accessor.Accessor
BaseFee BaseFeeSource
Premium PremiumSource
PriceList PriceList
}
GasEstimator computes Lotus-compatible gas estimates without executing the message.
func (*GasEstimator) EstimateFeeCap ¶
func (e *GasEstimator) EstimateFeeCap(ctx context.Context, premium big.Int, _ int64) (big.Int, error)
EstimateFeeCap returns BaseFee * 1.5 + premium, with a floor of MinimumBaseFee. `maxqueueblocks` follows Lotus' convention but is currently ignored: we always assume "include within the next few blocks".
func (*GasEstimator) EstimateGasLimit ¶
EstimateGasLimit returns a conservative gas-limit ceiling for `msg`.
We compute the union of:
- The fixed-shape overhead (OnChainMessage + OnInvoke).
- A per-method ceiling: 75M for known Curio-write methods (PreCommit, ProveCommit, PoSt, PublishStorageDeals), 30M for simple builtin sends, 10M for Send (method 0).
- Plus a 25% safety margin.
Numbers are deliberately conservative: better to over-estimate than have Curio's message run out of gas mid-execution.
func (*GasEstimator) EstimateGasPremium ¶
EstimateGasPremium returns the 60th percentile premium from the last `nblocksincl` epochs. Falls back to 100k attoFIL if no sample is available.
func (*GasEstimator) EstimateMessageGas ¶
func (e *GasEstimator) EstimateMessageGas(ctx context.Context, msg *types.Message, maxFee big.Int) (*types.Message, error)
EstimateMessageGas fills in `msg.GasLimit`, `msg.GasFeeCap`, and `msg.GasPremium` and returns the modified message. If any of those fields are already non-zero, they are preserved (matching Lotus's "don't clobber explicit user input" rule).
type HeaderStoreFeeSource ¶
HeaderStoreFeeSource implements BaseFeeSource against a persistent header store. CurrentBaseFee reads the latest tipset's ParentBaseFee.
func (*HeaderStoreFeeSource) CurrentBaseFee ¶
CurrentBaseFee returns the head tipset's ParentBaseFee. If the store is empty, returns build.MinimumBaseFee.
type MempoolPremiumSource ¶
type MempoolPremiumSource struct {
Pending func() []*types.SignedMessage
}
MempoolPremiumSource implements PremiumSource against an in-memory gossipsub mempool. Lantern's `net/mpool` package exposes a Pending() list of locally observed SignedMessages; we sample their GasPremium values directly.
func (*MempoolPremiumSource) RecentPremiums ¶
func (m *MempoolPremiumSource) RecentPremiums(_ context.Context, _ int64, samples int) ([]big.Int, error)
RecentPremiums returns the GasPremium values of all currently-pending messages, up to `samples`. `lookback` is unused — gossipsub already constrains the freshness window.
type MethodInfo ¶
type MethodInfo struct {
Kind actors.Kind
Version int
Method abi.MethodNum
Meta builtin.MethodMeta
}
MethodInfo is the resolved metadata for one built-in method.
func ResolveMethod ¶
func ResolveMethod(_ context.Context, kind actors.Kind, version int, m abi.MethodNum) (*MethodInfo, error)
ResolveMethod looks up the (kind, version, method) -> MethodMeta.
Returns an error if either the actor version is unsupported, or the method number is not registered for that actor.
func (*MethodInfo) String ¶
func (mi *MethodInfo) String() string
String returns a human-readable description: "<kind>.<MethodName>".
type PremiumSource ¶
type PremiumSource interface {
// RecentPremiums returns up to `samples` recent GasPremium values
// from messages included in the last `lookback` epochs. Order is
// not specified.
RecentPremiums(ctx context.Context, lookback int64, samples int) ([]big.Int, error)
}
PremiumSource exposes a rolling sample of recently included messages' premiums (attoFIL/gas) over the last `n` tipsets.
type PriceList ¶
type PriceList struct {
// OnChainMessageComputeBase is the constant component of per-message
// gas. Lotus v15: 38863.
OnChainMessageComputeBase int64
// OnChainMessageStorageBase is the per-message base storage cost.
// Lotus v15: 36 gas per byte over the encoded message length.
OnChainMessageStoragePerByte int64
// OnChainReturnValuePerByte is charged per byte returned to the caller.
// Lotus v15: 1.
OnChainReturnValuePerByte int64
// OnMethodInvocation is the per-call base cost. Lotus v15: 75000.
OnMethodInvocation int64
// OnMethodInvocationValue is added when the call transfers value
// (i.e. msg.Value > 0). Lotus v15: 39750.
OnMethodInvocationValue int64
// OnIpldGet / OnIpldPut are per-block costs charged inside actor
// methods. We use the average cost of a HAMT load.
OnIpldGetBase int64
OnIpldPutBase int64
// OnHashingBase is added once per cryptographic hashing operation.
OnHashingBase int64
// OnVerifySignatureBLS / Secp / Delegated.
OnVerifySignatureBLS int64
OnVerifySignatureSecp256k1 int64
OnVerifySignatureDelegated int64
}
PriceList is the gas schedule applied to a single message.
func V15PriceList ¶
func V15PriceList() PriceList
V15PriceList returns the network-version-≥17 gas schedule.
Numbers transcribed from `github.com/filecoin-project/lotus/chain/vm/gas_v15.go` at commit a0ecb8687 (Lotus 1.36). They are deliberately constants here, not imported, to keep this package CGo-free and Lotus-import-free.
func (PriceList) OnChainMessage ¶
OnChainMessage computes the per-message base cost (compute + storage). `encodedLen` is the CBOR-encoded length of the SignedMessage.
func (PriceList) OnChainReturnValue ¶
OnChainReturnValue charges per byte of the return blob.
Source Files
¶
Directories
¶
| Path | Synopsis |
|---|---|
|
Package evm is a minimal, read-only EVM interpreter for executing view/pure contract calls against locally-verified Filecoin FEVM state (lantern#43 Part B, Stage 3).
|
Package evm is a minimal, read-only EVM interpreter for executing view/pure contract calls against locally-verified Filecoin FEVM state (lantern#43 Part B, Stage 3). |