Skip to content

feat(#91): ChainExchange client — gateway-free header-chain fetch#110

Open
Reiers wants to merge 1 commit into
feat/108-no-fallback-rpcfrom
feat/91-chainxchg-client
Open

feat(#91): ChainExchange client — gateway-free header-chain fetch#110
Reiers wants to merge 1 commit into
feat/108-no-fallback-rpcfrom
feat/91-chainxchg-client

Conversation

@Reiers

@Reiers Reiers commented Jul 2, 2026

Copy link
Copy Markdown
Owner

Closes the client half of #91 (Stage A of #87). The responder side landed in #17; this adds the requester so a bridge-off Lantern (#76, `--no-fallback-rpc`) can backfill a gossip head+N gap by pulling the whole CID-verified header chain from a real Filecoin peer in ONE request — zero upstream RPC (no Glif, no gateway).

What's in

  • net/chainxchg/client.goClient.FetchTipsetChain(head, length), headers-only, parent-ward. Handwritten CBOR both directions (zero-dep, cross-checked vs Lotus chain/exchange cbor_gen). Trust model: every header CID-verified, level 0 == requested head set, each deeper level == previous level's Parents, heights strictly decreasing → a bad peer can only refuse, never splice. Partial(101) accepted; NotFound(201)/GoAway(202) rotate to next peer. Bounded 32 MiB read, peer cap, trusted-floor-first ordering, ClientStats.
  • net/blockingest/blockingest.goChainFetcher interface + SetChainFetcher; parent-walk (bridge-off) mode prefers one ChainExchange request over the per-CID bitswap walk, falling back on error.
  • net/chainxchg/client_test.go — two-host libp2p harness: happy path, partial, NotFound, spliced-chain rejection, no-peers.

Evidence

  • go build ./... OK
  • go vet ./net/chainxchg/ ./net/blockingest/ clean
  • gofmt -l clean
  • go test -count=1 ./net/chainxchg/ ./net/blockingest/ → both ok

Scope / follow-ups

…r libp2p

Adds the requesting half of /fil/chain/xchg/0.0.1 (the responder landed
in #17). A bridge-off Lantern (#76, --no-fallback-rpc) can now backfill a
gossip head+N gap by pulling the whole verified header chain from a real
Filecoin peer in ONE request, with zero upstream RPC (no Glif, no gateway).
This is Stage A of the snapshot-free full-node epic (#87).

net/chainxchg/client.go
  - Client.FetchTipsetChain(head, length): headers-only request, walks
    parent-ward newest->oldest. Handwritten CBOR both directions (same
    zero-dependency policy as the responder), cross-checked against Lotus
    chain/exchange cbor_gen layout.
  - Trust model: every header CID-verified; level 0 must equal the
    requested head set, each deeper level must equal the previous level's
    Parents, heights strictly decreasing. Caller derives head from
    already-verified data (a gossip block's Parents / the quorum anchor),
    so a malicious peer can only refuse, never splice.
  - Partial (101) responses accepted; NotFound (201)/GoAway (202) fail
    that peer and rotate to the next. Bounded response read (32 MiB),
    peer cap, trusted-floor-first peer ordering, observable ClientStats.

net/blockingest/blockingest.go
  - ChainFetcher interface + SetChainFetcher: in parent-walk (bridge-off)
    mode the ingestor prefers ONE ChainExchange request over the per-CID
    bitswap walk, falling back to the walk on error (or surfacing the
    error when there is no per-CID source).

net/chainxchg/client_test.go
  - Two-host libp2p harness: happy path, partial, NotFound, spliced-chain
    rejection, no-peers. Full suite green, build+vet+fmt clean.

Stacks on feat/108-no-fallback-rpc (#76 scaffolding). Server-side chain
serving remains a separate follow-up.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant