Skip to content

feat: NEAR family support (near, near-testnet)#283

Open
artemrootman wants to merge 13 commits into
mainfrom
arootman/near-support
Open

feat: NEAR family support (near, near-testnet)#283
artemrootman wants to merge 13 commits into
mainfrom
arootman/near-support

Conversation

@artemrootman

Copy link
Copy Markdown
Contributor

What

Adds the NEAR blockchain family (BlockchainType = "near"), covering near mainnet and testnet (betanet gets family support for free via the existing registry entry).

Design doc: docs/superpowers/specs/2026-07-17-near-support-design.md.

Stacked on #282 (bitcoin family) — it reuses the JSON-RPC family template; will retarget to main once #282 merges.

How

  • near_specific: poll-based optimistic head (block {"finality":"optimistic"}, dshackle parity); GetFinalizedBlock fetches the final head; nearcore has no subscriptions at all, so head tracking is poll-only.
  • near_validations: chain-id validation via status.chain_id (NEAR chain-ids are network-name strings — no genesis call needed); health = syncing flag + stale-head guard (latest_block_time vs expected block time × syncing lag) + optional network_info peer check.
  • near_labels: client neard, version from status.version.version.
  • near_bounds: sliding GC-window lower bounds from status.sync_info.earliest_block_height (STATE+BLOCK, 3-min period) — NEAR non-archival nodes keep ~5 epochs, the node reports its own boundary.
  • Method spec near: the 14-method dshackle-parity surface, all cacheable: false in v1, send_tx broadcast. No translations, no bans.

Testing

  • Unit tests across all new packages.
  • Live corpus against production near mainnet + testnet nodes: 42/42 checks identical, byte-identical payloads for all deterministic cases (incl. GC'd-block UNKNOWN_BLOCK and the ~10s unknown-tx TIMEOUT_ERROR passthrough). Details in the design doc.

Adds the bitcoin_specific package: GetLatestBlock/GetFinalizedBlock poll
getbestblockhash + getblockheader (bitcoind has no head subscription),
ParseBlock decodes the verbose getblockheader shape shared by Bitcoin Core
and Dogecoin Core. Validators/labels/lower-bounds are left as empty/nil-safe
stubs for later tasks; only the disable-option short-circuits and the
ChainSpecific interface shape are wired up now.

Also fixes parseJsonRpcBody (internal/protocol/parse_response.go) to treat a
JSON `null` "error" field as no-error instead of a failure - bitcoind always
sends an explicit "error":null on success, unlike the other JSON-RPC 2.0
upstreams in this codebase which omit the field entirely, so every real
bitcoind response was being misparsed as an error.
- bitcoin_validations: genesis-hash chain validator (getblockhash 0 keyed by
  chains.Chain; unmapped chains like litecoin skip with a warn) and health
  validator (initialblockdownload / headers-blocks lag -> Syncing, optional
  getconnectioncount peer check -> Unavailable).
- bitcoin_labels: client version/type from getnetworkinfo.subversion
  (/Satoshi:26.1.0/ -> satoshi 26.1.0, dogecoin's /Shibetoshi:1.14.9/ works too).
- bitcoin_bounds: prune-aware lower bounds - pruneheight when pruned, else 1
  (archive), emitted as BlockBound+TxBound with algorand-style cached fallback.
- upstream_factory: case chains.Bitcoin now constructs the family; the
  bitcoin_specific stubs are replaced with the real processors/validators.
nodecore has no per-chain request-rewrite hook (tron solidity is plain REST
methods, not a translation), so this adds a minimal generic seam: a
(spec, method)-keyed translator registry in the flow layer, consulted in
sendUnaryRequest before the connector call.

- getblocknumber -> getblockcount via a reusable jsonRpcMethodAlias
  (request-only rewrite, same wire id/params).
- listunspent -> GET /address/{addr}/utxo on the rest-additional esplora
  connector; response reshaped to the bitcoind listunspent result (sats->BTC
  as exact 8-decimal JSON numbers, confirmations from the upstream's tracked
  head height, no extra RPC calls). Declared only in bitcoin-esplora.json, so
  upstreams without esplora never advertise it and routing skips them.
- protocol.InvalidParamsError (-32602) for malformed listunspent params.
- design doc updated to reflect the flow-layer seam.
Corpus run against a production bitcoin node (mainnet + esplora) and a
production dogecoin node (mainnet/testnet): 65/68 identical; the 3 diffs
are nodecore's own unknown-method -32601 message (local allowlist
rejection, standard for all families).
- near_specific: optimistic-head poll (block finality=optimistic), final
  head on GetFinalizedBlock, base58 hashes verbatim; no subscriptions
  (nearcore has none).
- near_validations: chain-id validation via status.chain_id (network-name
  strings, no genesis call needed) and health validation (syncing flag,
  stale-head guard on latest_block_time vs expected-block-time * syncing
  lag, optional network_info peer check).
- near_labels: client neard + version from status.version.version.
- near_bounds: sliding GC-window lower bounds from
  status.sync_info.earliest_block_height (STATE+BLOCK, 3 min period).
- near method spec bundle: the 14-method dshackle-parity surface, all
  cacheable:false in v1, send_tx dispatched as broadcast.
- factory case chains.Near + getMethodSpecName "near".
Base automatically changed from arootman/bitcoin-support to main July 17, 2026 15:45
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