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 ¶
const ( DefaultTTL = 5 * time.Minute DefaultStale = 24 * time.Hour DefaultTimeout = 5 * time.Second )
Defaults for an ARC source's zero fields.
const ( SourceStatic = "static" SourceARC = "arc" SourceCache = "cache" )
Source names, as Config.Source and Status.Source spell them.
Variables ¶
var ( DefaultMinRate = mint.Rate{Sats: 100, Bytes: 1000} DefaultMaxRate = mint.Rate{Sats: 100, Bytes: 1000} )
Guard defaults: the network rate published today, 100 satoshis per 1000 bytes, as both the least a live policy may lower the rate to and the most it may raise it to. A live policy above it is lowered to it, so a miner that raises its rate refuses the transaction until the operator raises max_rate; nothing is ever overpaid by default.
var ErrConfig = errors.New("feepolicy: bad fee configuration")
ErrConfig is a fee configuration that cannot be used.
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 ¶
Fees returns Base with the policy's rate, guarded. Its error is only a Base that cannot be 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": 100,
"floor": 100,
"max_rate": {"bytes": 1000, "satoshis": 100},
"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 ¶
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 ¶
ParseConfig reads a fee block's JSON, refusing unknown keys.
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 ¶
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 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.