Relayer authorization refresh

AstralBeam admits P2P relayers only when their Ethereum address is authorized by both the EVM MultiSigERC20Locker and Casper EthClient.

Refresh ownership

The two bridge-direction workers each run a PeerDiscovery 60-second timer. They share one registry only when the Ethereum endpoint and locker plus the Casper endpoint, chain, and EthClient package all match. A configuration change uses a separate registry and cannot inherit another network's cached work.

Discovery start/stop retains/releases one shared deadline scheduler. Authorization refresh runs independently of peer connection work, with its next deadline 60 seconds after each refresh start, including off-phase ingress recovery or force. Both chain operations must settle before the shared promise is released. A call longer than the interval delays the next attempt rather than overlapping it; provider availability still limits when fresh membership can be delivered.

Peer timers observe the scheduler's outcome; ingress may retry failed work early. Force bypasses fresh cache and joins in-flight work. Invalidation makes older successful work reject to waiting consumers, not merely skip cache publication. It does not cancel RPCs; explicitly starting a new generation can overlap the detached old work. Stopping the last discovery removes the scheduler. Casper URL identity uses transport normalization (https://node equals https://node/rpc).

Invalidation re-arms the retained authorization deadline even without a new ingress read. Stop/restart preserves that deadline (an overdue deadline runs on the next timer turn). A refresh starting at 60 seconds, invalidated at 65 and settling at 70, still retries at 120 with 17-second peer work; the old completion cannot release a newer generation's lock.

Casper snapshot and request budget

Every enumeration first selects one state root, then resolves the latest enabled Casper 2 Package or legacy ContractPackage version at that root. Count, threshold, every indexed address, and every authorization flag are read from that same root and entity. Resolution is repeated on the next refresh so contract upgrades are observed.

The Casper request budget is 4 + 2N: root, package, count, threshold, then an address and flag for each of N relayers. At five relayers this is 14 requests (previously 36). With two discovery instances started 30 seconds apart and a 10-second simulated refresh, measured starts over 180 seconds changed from 60/90/120/150/180 seconds to 60/120/180 seconds. The shared 60-second cadence is unchanged; redundant offset work is removed. The repository runbook records the root/package/dictionary request breakdown and regression fixtures.

Off-phase recovery/force fixtures start refreshes at 60/65/125/185 seconds with two actual discovery instances and real registry scheduling. Peer connection delays vary from 0 to 17 to 23 seconds without moving the authorization deadline. This fixes the freshness-only implementation's 85-second recovery gap.

Publication is all-or-nothing. A missing or malformed required value rejects the candidate; a valid false authorization flag simply excludes that address. The EVM/Casper threshold policy is unchanged, including the existing minority warning and minimum-of-both effective threshold.

Reading failure logs

Casper lookup errors report kind, stage, method, elapsedMs, timeout, a safe endpointLabel, and available httpStatus or rpcCode. The main stages are state-root, package-resolution, relayer-count, threshold, relayer-address, and authorization-flag.

Nested errors and bounded causes are retained in console and file output. Secrets, credentials, headers, request payloads, URL userinfo and URL query values are redacted. Only code -32003 together with recognized ValueNotFound text is treated as a missing dictionary entry; other failures remain failures, including processed-event checks.

Remote JSON-RPC message/data are omitted from direct errors and logs; canonical labels and numeric codes remain. Timeouts while reading the HTTP body retain kind=timeout; body transport failures are not mislabeled as malformed JSON. A real loopback server with an unfinished JSON body exercised the production 10-second abort signal: timeout at 10002 ms, then 10004 ms on rerun, with TimeoutError cause. This was a local transport test, not a captured live-node fault.

At the direct RPC boundary, transport and body-parser exceptions are reduced to an allowlisted name/code and a bounded chain of similarly reduced causes. Raw exception messages, stacks, arbitrary properties and response snippets are never retained, including in direct CLI output outside the logger. Unknown names become Error; unknown codes are omitted. The outer typed error retains safe message, stack, stage, method, timing and status. Generic non-RPC nested error logging remains unchanged. Native URL-credential rejection and native Response.json() syntax failures are covered through the CLI and both actual console/file formatters.

Strict mapping reads preserve root/package error context. Legacy display/value helpers still log typed errors at debug level and return null; the structured exception guarantee is scoped to authorization and strict mapping reads.

Stale data behavior

A failed refresh never advances the successful snapshot timestamp. With the default maxStaleMs=900000, fallback is allowed through exactly 900000 ms and fails closed only above that age. Zero disables the ceiling. Cold-start failure does not create authorized membership.

Once the ceiling is exceeded, an authenticated /message request receives HTTP 500 before its handler runs. Discovery has a different, intentionally retained outbound behavior: it keeps the previous peer view, emits the snapshot age, and retries at the next tick. Operators should not interpret the ceiling as a claim that every outbound relay activity stops.

results matching ""

    No results matching ""