feepolicy

package
v0.14.2 Latest Latest
Warning

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

Go to latest
Published: Oct 7, 2026 License: Apache-2.0 Imports: 14 Imported by: 0

Documentation

Overview

Package feepolicy is where a producer's miner fee comes from: a static rate it was configured with, or the policy a broadcaster publishes at GET /v1/policy (ARC, and arcade, which answers the same shape), cached, bounded and degrading to the last good answer and then to the static rate. It does the I/O so that package mint stays pure: a Source answers the mint.Fees a build is given.

The policy endpoint is plain HTTPS and unsigned, so its answer is held to guards before it is used: it must parse as whole numbers in range, a rate below the minimum is raised to it (a broadcast below the miners' rate is refused anyway), and a rate above the maximum is lowered to it, which is what bounds a compromised or mistaken endpoint's power to drain a wallet. The per-transaction ceiling, mint.Fees.Max, is refused rather than clamped.

Live policy is opt-in. The default Source is Static at mint.DefaultFees, and the policy URLs follow the broadcaster a deployment settles through.

Index

Constants

View Source
const (
	DefaultTTL     = 5 * time.Minute
	DefaultStale   = 24 * time.Hour
	DefaultTimeout = 5 * time.Second
)

Defaults for an ARC source's zero fields.

View Source
const (
	SourceStatic = "static"
	SourceARC    = "arc"
	SourceCache  = "cache"
)

Source names, as Config.Source and Status.Source spell them.

Variables

View Source
var (
	DefaultMinRate = mint.Rate{Sats: 100, Bytes: 1000}
	DefaultMaxRate = mint.Rate{Sats: 1, Bytes: 1}
)

Guard defaults: the network rate published today as the least a live policy may lower the rate to, and one satoshi a byte, ten times that, as the most it may raise it to.

TODO(D4): the maximum follows the proposal (10x the network rate) until the owner rules.

View Source
var ErrConfig = errors.New("feepolicy: bad fee configuration")

ErrConfig is a fee configuration that cannot be used.

View Source
var ErrPolicy = errors.New("feepolicy: policy answer refused")

ErrPolicy is a policy answer that does not hold to the validation.

Functions

This section is empty.

Types

type ARC

type ARC struct {
	URLs []string
	// Key, when set, is sent as a bearer token.
	Key string
	// Base is the fees returned with the policy's rate in place of its
	// own: floor, dust and per-transaction maximum, and the rate used when
	// no policy is at hand.
	Base mint.Fees
	// Min and Max bound the policy's rate; zero is DefaultMinRate and
	// DefaultMaxRate.
	Min, Max mint.Rate
	// TTL, Stale and Timeout default to DefaultTTL, DefaultStale and
	// DefaultTimeout.
	TTL, Stale, Timeout time.Duration
	// Client is optional; the default takes no proxy from the environment.
	Client *http.Client
	// Note, when set, receives a line on a failed fetch or a clamped rate.
	Note func(format string, args ...any)
	// Now is the clock; nil is time.Now.
	Now func() time.Time
	// contains filtered or unexported fields
}

ARC is a Source over broadcasters' published policy. It asks each URL's GET /v1/policy (a URL with a path, such as https://arc.example.com/v1, is asked at that path plus /policy), takes the highest rate of those that answered (a transaction must be accepted by whichever is used), holds it to [Min, Max], and returns Base with that rate. One fetch per TTL; a failed fetch answers the last good policy while it is younger than Stale, and Base itself after that. Fees never fails on the network: a mint is never blocked on a policy fetch.

Safe for concurrent use.

func (*ARC) Fees

func (a *ARC) Fees(ctx context.Context) (mint.Fees, error)

Fees returns Base with the policy's rate, guarded. Its error is only a Base that cannot be used.

func (*ARC) Policy

func (a *ARC) Policy(ctx context.Context) *Policy

Policy is the policy in use: fresh, cached, or nil when there is none younger than Stale (Base's rate is then in force).

func (*ARC) Status

func (a *ARC) Status() Status

Status is what the last Fees used.

type Config

type Config struct {
	Dust       *uint64    `json:"dust,omitempty"`
	Floor      *uint64    `json:"floor,omitempty"`
	MaxRate    *mint.Rate `json:"max_rate,omitempty"`
	MaxTx      uint64     `json:"max_tx,omitempty"`
	MinRate    *mint.Rate `json:"min_rate,omitempty"`
	PolicyURLs []string   `json:"policy_urls,omitempty"`
	Rate       *mint.Rate `json:"rate,omitempty"`
	// Source is "static" (the default) or "arc" (also spelled "arcade"):
	// the policy of PolicyURLs, live.
	Source string `json:"source,omitempty"`
}

Config is the fee block of an application's configuration, its keys sorted as they are written:

"fee": {
  "dust": 250,
  "floor": 250,
  "max_rate": {"bytes": 1, "satoshis": 1},
  "max_tx": 0,
  "min_rate": {"bytes": 1000, "satoshis": 100},
  "policy_urls": ["https://arcade.gorillapool.io"],
  "rate": {"bytes": 1000, "satoshis": 100},
  "source": "static"
}

Every key is optional; an absent one takes the value of the defaults a caller passes to Source (usually mint.DefaultFees) or the guard default. Rate field names follow ARC's (satoshis, bytes), so a policy answer pastes in as a rate.

func MergeLegacy

func MergeLegacy(c *Config, satPerByte, floor *uint64) (*Config, error)

MergeLegacy folds the older keys fee_sat_per_byte and fee_floor into c, which they alias: a rate {fee_sat_per_byte, 1} and a floor. Either old key beside the new key it aliases is ambiguous and refused, as is a zero fee_sat_per_byte. nil pointers are absent keys. c may be nil.

func ParseConfig

func ParseConfig(b []byte) (*Config, error)

ParseConfig reads a fee block's JSON, refusing unknown keys.

func (*Config) Build

func (c *Config) Build(defaults mint.Fees) (Source, error)

Build builds the configured Source over defaults: Static, or an ARC policy source whose fallback is the static fees.

func (*Config) Fees

func (c *Config) Fees(defaults mint.Fees) (mint.Fees, error)

Fees is the static fees the configuration describes over defaults.

type Policy

type Policy struct {
	Rate mint.Rate
	// MaxTxSize and MaxScriptSize are maxtxsizepolicy and
	// maxscriptsizepolicy; zero when not stated. Across several answers,
	// the lowest stated.
	MaxTxSize     uint64
	MaxScriptSize uint64
}

Policy is what a broadcaster's GET /v1/policy says, held to the guards' validation: the mining fee rate and the size limits it states.

func ParsePolicy

func ParsePolicy(b []byte) (*Policy, error)

ParsePolicy reads a GET /v1/policy answer: policy.miningFee as whole numbers, satoshis at least 1 and bytes 1 to 1e9, and the size limits when stated. Anything else is ErrPolicy.

type Source

type Source interface {
	Fees(ctx context.Context) (mint.Fees, error)
}

Source answers the fees a build uses now.

type Static

type Static mint.Fees

Static is a fixed fee policy.

func (Static) Fees

func (s Static) Fees(context.Context) (mint.Fees, error)

Fees returns the configured fees, refusing a rate over zero bytes.

type Status

type Status struct {
	// Source is SourceARC (a fresh answer), SourceCache (the last good
	// answer, the endpoints failing) or SourceStatic (the static rate:
	// never answered, or the last answer is older than Stale).
	Source string
	// Age is how old the policy in use is; zero for static.
	Age  time.Duration
	Rate mint.Rate
	// Err is the last fetch's failure, nil after a good one.
	Err error
}

Status is what an ARC source last used, for a metric or a status line.

Jump to

Keyboard shortcuts

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