fee

package
v1.4.6 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 27, 2026 License: BSD-3-Clause Imports: 4 Imported by: 0

Documentation

Overview

Package fee is the native fee/gas SETTLEMENT primitive for Lux service chains (K-Chain keyvm today; M-Chain and F-Chain next). It is the half the 2026-05 fee audit found missing: node/vms/types/fee declares an ADMISSION policy (is a submitted fee acceptable at the gate?), but nothing could actually METER, DEBIT, and BURN a fee during block execution the way the C-Chain EVM does (evm/core/state_transition.go buyGas: balance check -> ErrInsufficientFunds -> SubBalance). Service chains charged "fees" that were unbacked integers a caller wrote into a JSON request — never settled against real on-chain balance.

This package supplies the three pillars those chains lacked, modelled on the EVM's buyGas but for the native account model (P/X-Chain style direct usage, not EVM-gas yet — that is a later dual-metering layer that composes on top):

  • Balances (balance.go) — a debitable balance surface the VM can Burn from. Burn(acct, amount) is the debit: it removes funds from the payer AND reduces circulating supply (no coinbase credit) — i.e. a native burn. Credit funds an account (genesis / future treasury inflows). Ledger (ledger.go) is the canonical KV-backed implementation; any chain whose state is a luxfi/database.Database gets a working ledger with no bespoke code.

  • GasMeter (meter.go) — per-operation gas metering with a hard limit, mirroring the EVM gas pool (SubGas / ErrOutOfGas). A VM meters each operation's real cost against the payer's GasLimit before pricing it.

  • Settlement (settle.go) — Cost converts metered gas to nLUX at a price; CanPay is the read-only affordability check a block runs in Verify (so an unpayable block is never accepted — fail closed); Charge is the authoritative debit+burn a block runs in Accept. Settlement happens INSIDE consensus block processing, atomically with the operation's state effect via the VM's versiondb commit — never in a synchronous RPC.

Orthogonality. This package is deliberately separate from, and complementary to, node/vms/types/fee: that package is ADMISSION POLICY (the boot-time floor declaration Manager validates); this package is SETTLEMENT MECHANISM (the per-block debit+burn). A VM declares a Policy AND settles through a Ledger; the two compose, they do not overlap. The schedule of "which operation costs how much gas" is supplied BY THE VM (keyvm prices per cryptographic algorithm) — this package is the pure mechanism, the VM owns the values.

It lives in the chains module (not node) on purpose: a service VM must be able to build and settle fees under the reproducible GOWORK=off build, where the chains module resolves a pinned node from the module cache and therefore cannot see VM-local additions made to the node tree. Keeping the settlement primitive beside the VMs that use it is what makes it buildable and reusable by K/M/F under that build.

Index

Constants

This section is empty.

Variables

View Source
var (
	// ErrInsufficientFunds mirrors the EVM's error of the same intent
	// (core/state_transition.go buyGas): the payer cannot cover the fee.
	ErrInsufficientFunds = errors.New("fee: insufficient funds")

	// ErrBalanceOverflow is returned by Credit when an account balance or the
	// burned-supply counter would exceed 2^64-1 nLUX.
	ErrBalanceOverflow = errors.New("fee: balance overflow")
)

Sentinel errors. Settlement is fail-secure: every error path denies the operation (the block fails Verify or Accept) — none silently proceeds.

View Source
var ErrOutOfGas = errors.New("fee: out of gas")

ErrOutOfGas is returned by GasMeter.Consume when an operation's gas exceeds the remaining limit. It mirrors the EVM gas pool's exhaustion error and is fail-secure: the operation does not proceed.

Functions

func CanPay

func CanPay(b Balances, acct Account, fee uint64) error

CanPay is the read-only affordability check a block runs in Verify, for every fee-bearing transaction, BEFORE the block can be accepted. It never mutates state, so verifying a block cannot move funds; it only proves the payer could cover the fee. A block containing any unaffordable transaction fails Verify and is never accepted — fail closed.

func Charge

func Charge(b Balances, acct Account, fee uint64) error

Charge is the authoritative settlement a block runs in Accept: it debits the fee from the payer and burns it (reduces circulating supply). It is the native analogue of the EVM's buyGas SubBalance, but burning rather than crediting a coinbase. Because it writes through the VM's versiondb, the debit commits atomically with the operation it pays for. If the payer cannot cover the fee (which Verify should already have prevented), Charge returns ErrInsufficientFunds and the caller MUST abort block acceptance — a key operation never takes effect unpaid.

func Cost

func Cost(gasUsed, price Gas) (uint64, error)

Cost converts metered gas to a fee in nLUX at the given per-unit price, refusing overflow (fail-secure: a fee must never wrap to a smaller number). price is nLUX per unit of Gas.

Types

type Account

type Account = ids.ShortID

Account is a fee payer identity. It is the canonical 20-byte Lux address (ids.ShortID) — the same type P/X-Chain use for UTXO owners — so balances here interoperate with existing address tooling. It is PUBLIC: an account identifier never carries secret material.

type Balances

type Balances interface {
	Balance(acct Account) (uint64, error)
	Credit(acct Account, amount uint64) error
	Burn(acct Account, amount uint64) error
	Burned() (uint64, error)
}

Balances is the debitable balance surface a fee-charging VM exposes to the settler. It is the minimal contract the EVM expresses as GetBalance / SubBalance, adapted to the native account model and to BURNING (no coinbase):

  • Balance reports an account's spendable nLUX.
  • Credit adds nLUX (genesis seeding; future treasury/bridge inflows).
  • Burn removes nLUX from the payer AND reduces circulating supply — the fee debit. It is the only spend path here; there is intentionally no account->account transfer, because service-chain fees are burned, not paid to a validator. (A treasury split, if ever wanted, is a new method, not a reinterpretation of Burn.)
  • Burned reports cumulative burned supply, for audit.

Implementations MUST be atomic with respect to a single call and MUST be driven inside a transaction/versiondb whose commit is the block's commit, so a fee debit and the operation it pays for either both land or neither does.

type Gas

type Gas uint64

Gas is a unit of metered work. A VM's gas schedule assigns a Gas cost to each operation (keyvm prices per cryptographic algorithm); Cost converts Gas to nLUX at a per-unit price.

type GasMeter

type GasMeter struct {
	// contains filtered or unexported fields
}

GasMeter meters gas consumption against a hard limit, exactly like the EVM gas pool (SubGas / out-of-gas). A VM constructs one per fee-bearing operation with the payer's declared GasLimit, then Consumes the operation's metered cost; Consume past the limit denies the operation rather than overdraw.

func NewGasMeter

func NewGasMeter(limit Gas) *GasMeter

NewGasMeter returns a meter with the given limit, fully unconsumed.

func (*GasMeter) Consume

func (m *GasMeter) Consume(amount Gas) error

Consume deducts amount from the remaining gas. It returns ErrOutOfGas (and changes nothing) if amount exceeds what remains.

func (*GasMeter) Limit

func (m *GasMeter) Limit() Gas

Limit reports the meter's hard limit.

func (*GasMeter) Remaining

func (m *GasMeter) Remaining() Gas

Remaining reports unconsumed gas.

func (*GasMeter) Used

func (m *GasMeter) Used() Gas

Used reports consumed gas (limit - remaining).

type KV

type KV interface {
	Has(key []byte) (bool, error)
	Get(key []byte) ([]byte, error)
	Put(key []byte, value []byte) error
}

KV is the minimal key/value surface Ledger needs. It is the read/write subset of luxfi/database.Database (satisfied by versiondb, memdb, and any backing store), declared locally so the settlement primitive does not pin a database module version — keeping it buildable beside any VM under GOWORK=off.

type Ledger

type Ledger struct {
	// contains filtered or unexported fields
}

Ledger is the canonical KV-backed Balances implementation. It writes to the VM's state KV (a versiondb in production), so every Credit/Burn participates in the block's atomic commit: a fee burn and the operation it pays for land together or not at all. Balances are nLUX (1e-6 LUX), matching the node/vms/types/fee floor units.

func NewLedger

func NewLedger(kv KV) *Ledger

NewLedger returns a Ledger over kv. kv is the VM's state database; in a block Accept it is the versiondb whose Commit the block performs.

func (*Ledger) Balance

func (l *Ledger) Balance(acct Account) (uint64, error)

Balance returns acct's spendable nLUX (0 if never funded).

func (*Ledger) Burn

func (l *Ledger) Burn(acct Account, amount uint64) error

Burn debits amount nLUX from acct and reduces circulating supply by the same amount (the burned counter rises). It is the fee settlement op: it returns ErrInsufficientFunds if acct cannot cover amount, leaving state untouched.

func (*Ledger) Burned

func (l *Ledger) Burned() (uint64, error)

Burned returns cumulative burned supply in nLUX.

func (*Ledger) Credit

func (l *Ledger) Credit(acct Account, amount uint64) error

Credit adds amount nLUX to acct. Overflow is refused (fail-secure: minting must never silently wrap to a smaller balance).

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL