anchorverify

package
v1.9.2 Latest Latest
Warning

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

Go to latest
Published: Jul 23, 2026 License: Apache-2.0, MIT Imports: 9 Imported by: 0

Documentation

Overview

Package anchorverify hardens Lantern's boot-time trusted-root selection (security issue #54).

Background. Every block Lantern fetches downstream of the anchor is content-address-verified (hamt.VerifyBlockCID). That protects the *integrity* of state under a given root: a malicious source cannot forge state for a root we already trust. It does NOT protect the *choice* of root — i.e. "is this the canonical/heaviest chain, or an attacker's valid-but-non-canonical fork (or a stale, superseded head)?".

The default daemon boot historically accepted the head returned by a single source (the gateway, or the Glif fallback) on faith. This package closes that gap with three independent, cheap checks that need no full header-sync pipeline:

  1. Multi-source agreement. Fetch the head from >=2 independent sources and require them to agree on (StateRoot, TipSetKey). Agreement across independent operators is a strong signal the head is canonical.

  2. F3 finality cross-check. When an F3 latest finality certificate is available, require the selected anchor to be consistent with the F3-finalized tipset (equal to it, or a descendant of it by epoch). F3 certs carry BLS-aggregate signatures from the power table, so this is a cryptographic anchor, not a trust-the-endpoint anchor.

  3. Heaviest-weight tiebreak. On disagreement with no F3 resolution, pick the candidate with the greatest ParentWeight (Filecoin's fork-choice rule) and emit a loud warning rather than silently trusting source #1.

An operator can bypass all of this with InsecureAllowSingleSource (the --insecure-anchor flag) for localhost/dev against a single endpoint.

Index

Constants

View Source
const GatherTimeout = 12 * time.Second

GatherTimeout bounds how long Gather waits for all sources combined.

Variables

View Source
var (
	// ErrNoCandidates means every source failed to return a head.
	ErrNoCandidates = errors.New("anchorverify: no usable head candidates from any source")
	// ErrNoAgreement means sources disagreed and nothing (F3 or weight)
	// could safely resolve the canonical head.
	ErrNoAgreement = errors.New("anchorverify: sources disagree on head and no F3 finality could resolve it")
	// ErrF3Conflict means the agreed/selected head conflicts with the
	// F3-finalized chain (selected epoch is at/below F3 finality but the
	// tipset differs — a fork below finality, which must never be accepted).
	ErrF3Conflict = errors.New("anchorverify: selected head conflicts with F3 finalized tipset")
)

Functions

This section is empty.

Types

type Candidate

type Candidate struct {
	Source       string // human label, e.g. "gateway", "glif"
	Epoch        abi.ChainEpoch
	StateRoot    cid.Cid
	TipSetKey    ltypes.TipSetKey
	ParentWeight ltypes.BigInt
}

Candidate is one source's view of the current head, normalized to the fields the verifier compares. Sources that cannot supply a field leave it at its zero value; only StateRoot + TipSetKey + Epoch are load-bearing.

func Gather

func Gather(ctx context.Context, pol Policy, fetchers ...HeadFetcher) []Candidate

Gather queries every fetcher (best-effort, in parallel-ish sequence) and returns all candidates that succeeded. Failures are reported via warnf but do not abort — the verifier decides whether the survivors are enough.

type F3Finalized

type F3Finalized struct {
	Available bool
	Instance  uint64
	Epoch     abi.ChainEpoch
	TipSetKey ltypes.TipSetKey
}

F3Finalized is the (epoch, tipset) the latest F3 finality certificate finalized. Used for the cryptographic cross-check. Zero value means "no F3 finality available", which makes the cross-check a no-op (multi-source agreement still applies).

func FinalizedFromCert

func FinalizedFromCert(cert *certs.FinalityCertificate) (F3Finalized, error)

FinalizedFromCert extracts the finalized (epoch, tipset key) from an F3 finality certificate. Returns Available=false on any nil/empty cert so callers can treat "no F3" uniformly.

type HeadFetcher

type HeadFetcher interface {
	FetchCandidate(ctx context.Context) (Candidate, error)
}

HeadFetcher fetches one source's current head as a Candidate. Implemented by thin adapters over the gateway/Glif clients in cmd/lantern.

type Policy

type Policy struct {
	// MinAgreeingSources is the number of independent sources that must
	// agree on the same (StateRoot, TipSetKey) for an anchor to be
	// accepted without an F3 cross-check or weight tiebreak. Default 2.
	MinAgreeingSources int

	// InsecureAllowSingleSource bypasses agreement + F3 + tiebreak and
	// accepts a single source on faith. Maps to --insecure-anchor. Intended
	// for localhost/dev only.
	InsecureAllowSingleSource bool

	// Warnf, if set, receives human-readable warnings (e.g. source
	// disagreement). Defaults to a no-op.
	Warnf func(format string, args ...any)
}

Policy controls how strict the verifier is.

type Result

type Result struct {
	// Chosen is the accepted candidate.
	Chosen Candidate
	// Method explains how Chosen was selected, for logging/audit.
	Method string
	// AgreeingSources is how many sources backed Chosen's identity.
	AgreeingSources int
	// F3Checked is true when an F3 finality cross-check was applied.
	F3Checked bool
}

Result is the outcome of a verification.

func Verify

func Verify(cands []Candidate, f3 F3Finalized, pol Policy) (Result, error)

Verify applies the policy to the gathered candidates + optional F3 finality and returns the accepted candidate or an error.

Decision order:

insecure?            -> accept first valid candidate (loud no-op of checks)
0 valid candidates   -> ErrNoCandidates
F3 available:
  reject any candidate that conflicts below finality (ErrF3Conflict)
  prefer the largest agreeing group consistent with F3
agreement >= Min     -> accept agreed identity
no agreement:
  if F3 available, accept the F3-consistent heaviest candidate
  else ErrNoAgreement

Jump to

Keyboard shortcuts

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