Documentation
¶
Overview ¶
Package headers is a chain tracker over a header source: an overlay bridge's native /v1 routes (github.com/lightwebinc/overlay-bridge), the public WhatsOnChain API, a chaintracks v2 service, a block-headers-service, or the chaintracks server an arcade installation embeds.
It is the root of trust for every proof checked against it. A transaction is only as trustworthy as the headers its BUMP is checked against, so the question of WHO answers "what root does height N commit to" is the whole security question, not a configuration detail. A bridge that received the headers itself, off the same network that delivered the transaction, needs no further check. A source that serves header fields (every other kind) is not taken at its word: every header it answers is hashed here and must carry the work its bits claim, at or above the network's floor, so a lie costs a mined block rather than an edited response.
It speaks HTTP and imports nothing from the bridge. That is deliberate: this module has exactly one direct dependency, and an HTTP contract plus a vendored fixture is a cheaper coupling than a Go dependency on a service. The fixtures in testdata/fixtures are the bridge's own generated bytes, copied verbatim, so a change to its wire shape fails here rather than in production.
Index ¶
Constants ¶
const ( Mainnet = "main" Testnet = "test" Regtest = "regtest" )
Networks a source may be checked against. The network decides the proof-of-work floor, nothing else.
const MainnetMinDifficulty = 4e9
MainnetMinDifficulty is the lowest difficulty a mainnet header may claim.
Every mainnet block since the 2018 split has carried a difficulty between about 2.6e10 and 5.2e11 (sampled across that range in 2026). The floor sits well below the lowest of those, so a real header never trips it, and well above what anyone could mine for the price of a lie: a header at 4e9 takes about 1.7e19 hashes. Without a floor a lying source would hand back a header whose bits claim a target nobody needs to work for, and the header would pass its own proof-of-work check.
Variables ¶
var ErrBodyTooLarge = errors.New("headers: response body exceeds the bound")
ErrBodyTooLarge refuses a response above the bound.
var ErrProofOfWork = errors.New("headers: header fails its proof of work")
ErrProofOfWork is a header that does not carry the work it claims, or claims less than its network's floor. It is the header source lying (or serving another chain), never a proof that failed: a caller must not read it as "not yet".
var ErrSource = errors.New("headers: bad header source")
ErrSource is a header source specification that cannot be used.
var ErrUnknownHeight = errors.New("headers: the source does not hold that height")
ErrUnknownHeight is a height the source does not hold yet.
Functions ¶
This section is empty.
Types ¶
type Client ¶
type Client struct {
// Base is the source's base URL, with no path suffix.
Base string
// Kind is the dialect Base speaks. The zero value is a bridge's /v1.
Kind Kind
// Network sets the proof-of-work floor for a source that serves header
// fields: Mainnet checks MainnetMinDifficulty, anything else checks each
// header against its own target only.
Network string
// MinDifficulty overrides the network's floor when positive.
MinDifficulty float64
// HTTP is optional.
HTTP *http.Client
// Timeout defaults to 10s when HTTP is nil.
Timeout time.Duration
// Token, when set, is sent as a bearer token on every request: a
// block-headers-service requires one unless its operator turned
// authentication off.
Token string
// contains filtered or unexported fields
}
Client reads block headers from one header source.
func New ¶
New returns a client for a header source specification (see Parse). A specification that does not parse yields a client whose every call returns the parse error, so a caller that cannot handle an error at construction still refuses rather than guessing.
func NewSource ¶ added in v0.3.0
NewSource returns a client for a header source specification (see Parse). A source with header fields is checked for proof of work at the floor of the network it implies; set Network after construction to check it against another.
func (*Client) CurrentHeight ¶
CurrentHeight reports the header service's tip.
Needed as well as root validation, not instead of it: a health check reports how far the header source has got, and a service that answers roots while reporting height zero is a service that has not started.
func (*Client) HeaderAt ¶ added in v0.14.0
HeaderAt reads the header at height from a source that serves header fields (WhatsOnChain, chaintracks, block-headers-service, arcade) and checks it as IsValidRootForHeight does: its fields hash to its hash, the hash carries the work its bits claim, at or above the network's floor. It is how an application with no node reads a block's hash or time by height. A native source carries no header fields and is an error.
func (*Client) IsValidRootForHeight ¶
func (c *Client) IsValidRootForHeight(ctx context.Context, root *chainhash.Hash, height uint32) (bool, error)
IsValidRootForHeight reports whether root is the merkle root committed at height.
A 404 is (false, nil): the bridge does not hold that height yet, which means the proof cannot be checked, not that anything is broken. Any OTHER non-ok status is an ERROR, and the distinction is load-bearing. Collapsing the two makes an unreachable or misconfigured header service look exactly like a forged proof, and a verifier that cannot tell those apart will either accept forgeries during an outage or reject good proofs during one, depending on which way it guessed.
type Header ¶ added in v0.14.0
type Header struct {
Height uint32
Hash chainhash.Hash
Prev chainhash.Hash
MerkleRoot chainhash.Hash
Version uint32
Time uint32
Bits uint32
Nonce uint32
}
Header is a block header a source served, its proof of work checked: the fields its hash commits to, the hash, and the height the source placed it at. Time is the block's own timestamp (Unix seconds).
type Kind ¶ added in v0.3.0
type Kind int
Kind names the dialect a header source speaks.
const ( // Native is an overlay bridge's /v1 routes: a root per height and a tip, // with no header fields, so no proof of work can be checked. Native Kind = iota // WhatsOnChain is the public WhatsOnChain API for one network. WhatsOnChain // Chaintracks is a chaintracks v2 service (GET /height and // GET /header/height/{h} under the base). Chaintracks // BlockHeadersService is a block-headers-service (bsv-blockchain) // API: GET /chain/tip/longest and GET /chain/header/byHeight under // /api/v1, with a bearer token when the service requires one. BlockHeadersService // Arcade is the chaintracks server an arcade installation embeds, // under /chaintracks/v2: GET /height and GET /header/height/{h}, each // answering the value bare rather than in a status envelope. Arcade )
func Parse ¶ added in v0.3.0
Parse reads a header source specification:
woc:main | woc:test the public WhatsOnChain API
chaintracks:https://host/v2 a chaintracks v2 service
bhs:https://host:8080 a block-headers-service (/api/v1 is added
to a URL with no path); set Client.Token
when it requires one
arcade:https://host an arcade installation's embedded
chaintracks server (/chaintracks/v2)
https://host:port an overlay bridge's native /v1 routes
and reports the kind, the base URL and the network the kind implies ("" for a native source, which carries no header fields to check). chaintracks, bhs and arcade imply mainnet; set Client.Network for a testnet one.