8000 Tags · lavanet/lava · GitHub
[go: up one dir, main page]

Skip to content

Tags

Tags

v6.2.9

Toggle v6.2.9's commit message

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
feat(rpcclient): support Starknet v0.9+ websocket subscriptions (#2318)

* feat: update starknet spec for Starknet 0.14.3 / JSON-RPC v0.10

Starknet 0.14.3 (and pathfinder v0.23.0, released 2026-07-20) removed
JSON-RPC v0.8 and older; nodes now serve v0.9 (root default) and v0.10
(final v0.10.1 spec on the v0_10 routes). Update STRK and STRKS specs
accordingly:

- add /rpc/v0_10 and /ws/rpc/v0_10 collections (inheritance-only,
  mirroring the v0_9 pair)
- remove the /rpc/v0_8 and /ws/rpc/v0_8 collections (RPC 0.8 removed
  by Starknet 0.14.3; pathfinder no longer serves these endpoints)
- add missing spec methods: starknet_getBlockWithReceipts,
  starknet_getCompiledCasm, starknet_getMessagesStatus,
  starknet_getStorageProof
- remove starknet_pendingTransactions (dropped from the RPC spec; no
  served version supports it)
- replace the legacy pathfinder_subscribe/pathfinder_unsubscribe WS API
  (removed in pathfinder 0.18.0) with the spec WS subscription family:
  starknet_subscribeNewHeads/Events/TransactionStatus/NewTransactions/
  NewTransactionReceipts + starknet_unsubscribe, one SUBSCRIBE parse
  directive per method (solana-style)
- pathfinder extension collection: drop pathfinder_getProof and
  pathfinder_getTransactionStatus (removed in pathfinder 0.17.0,
  superseded by starknet_getStorageProof/starknet_getTransactionStatus),
  add pathfinder_lastL1AcceptedBlockHashAndNumber
- average_block_time 30000/32000 -> 2000 for Starknet 0.14.x fast
  blocks (matches base/optimism convention for ~2s chains)

Update TestJsonRpcInternalPathsMultipleVersionsStarkNet to the new path
set and refresh the starknet provider example configs (v0_9/v0_10).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MC6w48eT5tW9K8iUNCm7PG

* feat: support starknet v0.9+ ws subscription envelope in rpcclient

The starknet_subscribe* APIs added to the spec need runtime support the
node ws client lacked:

- notifications use methods named starknet_subscriptionXxx with params
  {subscription_id, result}; none of the existing dispatch shapes
  (ethereum "_subscription" suffix, solana "Notification" suffix,
  legacy pathfinder top-level result) matched, so they were silently
  dropped. Add a dedicated predicate and handler keyed by
  params.subscription_id.
- Client.Subscribe rejected the canonical starknet subscribe forms:
  by-name object params without a tendermint "query" key errored, and
  omitted params hit "unknown parameters type". Make "query" optional
  (tendermint-only) and accept nil params.

Also apply spec calibration from review: starknet_estimateFee block_id
positional index 1 -> 2 (v0.9/v0.10 params are [request,
simulation_flags, block_id]) and allowed_block_lag_for_qos_sync -> 5,
matching the base/optimism convention for ~2s block chains now that
average_block_time is 2000.

Adds predicate unit tests and an end-to-end mock-node websocket test
covering object params, string subscription ids, envelope delivery and
unknown-id drops.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MC6w48eT5tW9K8iUNCm7PG

* fix: order subscription registration before unblocking Subscribe caller

handleResponse sent op.resp <- msg before writing op.err and
registering the subscription in clientSubs, racing with requestOp.wait
which reads op.err immediately after receiving. On an error response
the caller could observe a stale nil error and treat a failed
subscription as successful. The race was previously unreachable in
tests; the new starknet subscription end-to-end test tripped it
deterministically under -race.

Move all op.err writes and subscription registration before the op.resp
send for subscription responses (matching upstream go-ethereum's
ordering) while preserving this fork's behavior of returning the raw
response message to the caller.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MC6w48eT5tW9K8iUNCm7PG

* chore: move Starknet spec changes to their own PR

Restore the STRK/STRKS spec, the Starknet provider examples and the
Starknet internal-path test to main. They move to the
ofir/starknet-spec-v010 PR, which must merge only after this code is
released and providers have upgraded. This PR keeps the rpcclient
runtime support.

Claude-Session: https://claude.ai/code/session_01NDkG48rHipQHQWQgcAGKM9

* fix(consumer): match by-name unsubscribe params to subscriptions

The consumer only matched an unsubscribe to its subscription when the
id came positionally (["0x1"]). starknet.js sends starknet_unsubscribe
by name ({"subscription_id": "0x1"}), which got "subscription not
found" and left the subscription open until the websocket closed.

When the raw params match nothing and they are a single-entry object
with a string value, retry with that value. The raw match still runs
first, so tendermint (whose id is the whole params object) is
unchanged.

Claude-Session: https://claude.ai/code/session_01NDkG48rHipQHQWQgcAGKM9

* fix(rpcclient): reject non-string tendermint query param

Subscribe stopped erroring when by-name params carried a "query" that
was not a string. That subscription then registered under the response
id, while tendermint notifications are routed by query, so they were
all dropped silently.

Error again when "query" is present but not a string. When "query" is
absent (starknet by-name params), the id still comes from the response.

Claude-Session: https://claude.ai/code/session_01NDkG48rHipQHQWQgcAGKM9

* test(rpcclient): use TestComponent_Scenario names for Starknet tests

Rename TestIsStarknetNotification and TestStarknetSubscriptionEndToEnd
to TestStarknetNotification_Detection and
TestStarknetSubscription_EndToEnd, per the repo's test naming
convention.

Claude-Session: https://claude.ai/code/session_01NDkG48rHipQHQWQgcAGKM9

* chore: bump protocol TARGET_VERSION to 6.2.9

Gives the release with the Starknet v0.9+ subscription support its own
protocol version, so ProviderMin/ProviderTarget can require it before
the Starknet spec (#2341) goes live.

Claude-Session: https://claude.ai/code/session_01NDkG48rHipQHQWQgcAGKM9

---------

Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Ignacio Rodriguez <ignacio.rsg@gmail.com>

V.6.2.9

Toggle V.6.2.9's commit message

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
feat(rpcclient): support Starknet v0.9+ websocket subscriptions (#2318)

* feat: update starknet spec for Starknet 0.14.3 / JSON-RPC v0.10

Starknet 0.14.3 (and pathfinder v0.23.0, released 2026-07-20) removed
JSON-RPC v0.8 and older; nodes now serve v0.9 (root default) and v0.10
(final v0.10.1 spec on the v0_10 routes). Update STRK and STRKS specs
accordingly:

- add /rpc/v0_10 and /ws/rpc/v0_10 collections (inheritance-only,
  mirroring the v0_9 pair)
- remove the /rpc/v0_8 and /ws/rpc/v0_8 collections (RPC 0.8 removed
  by Starknet 0.14.3; pathfinder no longer serves these endpoints)
- add missing spec methods: starknet_getBlockWithReceipts,
  starknet_getCompiledCasm, starknet_getMessagesStatus,
  starknet_getStorageProof
- remove starknet_pendingTransactions (dropped from the RPC spec; no
  served version supports it)
- replace the legacy pathfinder_subscribe/pathfinder_unsubscribe WS API
  (removed in pathfinder 0.18.0) with the spec WS subscription family:
  starknet_subscribeNewHeads/Events/TransactionStatus/NewTransactions/
  NewTransactionReceipts + starknet_unsubscribe, one SUBSCRIBE parse
  directive per method (solana-style)
- pathfinder extension collection: drop pathfinder_getProof and
  pathfinder_getTransactionStatus (removed in pathfinder 0.17.0,
  superseded by starknet_getStorageProof/starknet_getTransactionStatus),
  add pathfinder_lastL1AcceptedBlockHashAndNumber
- average_block_time 30000/32000 -> 2000 for Starknet 0.14.x fast
  blocks (matches base/optimism convention for ~2s chains)

Update TestJsonRpcInternalPathsMultipleVersionsStarkNet to the new path
set and refresh the starknet provider example configs (v0_9/v0_10).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MC6w48eT5tW9K8iUNCm7PG

* feat: support starknet v0.9+ ws subscription envelope in rpcclient

The starknet_subscribe* APIs added to the spec need runtime support the
node ws client lacked:

- notifications use methods named starknet_subscriptionXxx with params
  {subscription_id, result}; none of the existing dispatch shapes
  (ethereum "_subscription" suffix, solana "Notification" suffix,
  legacy pathfinder top-level result) matched, so they were silently
  dropped. Add a dedicated predicate and handler keyed by
  params.subscription_id.
- Client.Subscribe rejected the canonical starknet subscribe forms:
  by-name object params without a tendermint "query" key errored, and
  omitted params hit "unknown parameters type". Make "query" optional
  (tendermint-only) and accept nil params.

Also apply spec calibration from review: starknet_estimateFee block_id
positional index 1 -> 2 (v0.9/v0.10 params are [request,
simulation_flags, block_id]) and allowed_block_lag_for_qos_sync -> 5,
matching the base/optimism convention for ~2s block chains now that
average_block_time is 2000.

Adds predicate unit tests and an end-to-end mock-node websocket test
covering object params, string subscription ids, envelope delivery and
unknown-id drops.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MC6w48eT5tW9K8iUNCm7PG

* fix: order subscription registration before unblocking Subscribe caller

handleResponse sent op.resp <- msg before writing op.err and
registering the subscription in clientSubs, racing with requestOp.wait
which reads op.err immediately after receiving. On an error response
the caller could observe a stale nil error and treat a failed
subscription as successful. The race was previously unreachable in
tests; the new starknet subscription end-to-end test tripped it
deterministically under -race.

Move all op.err writes and subscription registration before the op.resp
send for subscription responses (matching upstream go-ethereum's
ordering) while preserving this fork's behavior of returning the raw
response message to the caller.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MC6w48eT5tW9K8iUNCm7PG

* chore: move Starknet spec changes to their own PR

Restore the STRK/STRKS spec, the Starknet provider examples and the
Starknet internal-path test to main. They move to the
ofir/starknet-spec-v010 PR, which must merge only after this code is
released and providers have upgraded. This PR keeps the rpcclient
runtime support.

Claude-Session: https://claude.ai/code/session_01NDkG48rHipQHQWQgcAGKM9

* fix(consumer): match by-name unsubscribe params to subscriptions

The consumer only matched an unsubscribe to its subscription when the
id came positionally (["0x1"]). starknet.js sends starknet_unsubscribe
by name ({"subscription_id": "0x1"}), which got "subscription not
found" and left the subscription open until the websocket closed.

When the raw params match nothing and they are a single-entry object
with a string value, retry with that value. The raw match still runs
first, so tendermint (whose id is the whole params object) is
unchanged.

Claude-Session: https://claude.ai/code/session_01NDkG48rHipQHQWQgcAGKM9

* fix(rpcclient): reject non-string tendermint query param

Subscribe stopped erroring when by-name params carried a "query" that
was not a string. That subscription then registered under the response
id, while tendermint notifications are routed by query, so they were
all dropped silently.

Error again when "query" is present but not a string. When "query" is
absent (starknet by-name params), the id still comes from the response.

Claude-Session: https://claude.ai/code/session_01NDkG48rHipQHQWQgcAGKM9

* test(rpcclient): use TestComponent_Scenario names for Starknet tests

Rename TestIsStarknetNotification and TestStarknetSubscriptionEndToEnd
to TestStarknetNotification_Detection and
TestStarknetSubscription_EndToEnd, per the repo's test naming
convention.

Claude-Session: https://claude.ai/code/session_01NDkG48rHipQHQWQgcAGKM9

* chore: bump protocol TARGET_VERSION to 6.2.9

Gives the release with the Starknet v0.9+ subscription support its own
protocol version, so ProviderMin/ProviderTarget can require it before
the Starknet spec (#2341) goes live.

Claude-Session: https://claude.ai/code/session_01NDkG48rHipQHQWQgcAGKM9

---------

Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Ignacio Rodriguez <ignacio.rsg@gmail.com>

v6.2.8

Toggle v6.2.8's commit message

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
fix(specs): move Cardano mempool and tx-evaluate routes to addons (#2339

)

The CARDANO spec (inherited by CARDANOT) declared five Blockfrost routes in
the mandatory base collections that the self-hosted blockfrost-backend-ryo
does not implement:

  GET  /mempool
  GET  /mempool/{hash}
  GET  /mempool/addresses/{address}
  POST /utils/txs/evaluate
  POST /utils/txs/evaluate/utxos

Confirmed absent from the RYO route tree on master: there is no mempool
route directory, and utils holds only addresses/xpub. Serving the mempool
needs a live LocalTxMonitor subscription to the node, and evaluation needs
a Plutus evaluator; RYO reads confirmed data from its chain index, so both
are capability gaps rather than a misconfiguration. The hosted Blockfrost
service serves all five.

A RYO-backed provider still stakes successfully, because the stake check
validates whole collections rather than individual APIs, but every relay to
those five routes fails with HTTP 400 and costs it QoS.

Move them into a "mempool" GET addon and a "txs-evaluate" POST addon. All
116 API definitions are relocated verbatim: same compute units, categories
and block parsing. A provider opts in per node-url and in its stake entry;
one that cannot serve them simply omits them and is no longer measured on
them. CARDANOT needs no change of its own, since spec expansion carries
over parent collections the child does not declare.

Addon collections deliberately carry no headers block. Headers register
per connection type rather than per addon, so the base project_id header
already applies, matching the ETH1 and ETHBEACON addons.

No "enabled" verification is defined for either addon yet. An empty mempool
is normal, so a naive PARSE_BY_ARG probe of GET /mempool would fail on an
idle chain and jail honest providers, and a POST evaluate probe would need
a valid CBOR transaction as a static template. Left for a follow-up rather
than shipping a flaky verification.

Consumers reach an addon only when their plan policy asks for it, so add
CARDANO and CARDANOT chain policies to the gateway plan requiring both,
with mixed:true so pairing still returns providers that serve the base
collection alone. This must be proposed after the spec proposal passes;
ValidatePlanFields rejects a policy naming an addon the spec lacks.

The four plans carrying an empty chain_policies list are left alone: adding
a single entry to those would make every other chain unreachable for them,
which is a separate decision.

Closes #2333

Claude-Session: https://claude.ai/code/session_0174ZD9merkC3nHPA3KbXLMh

v6.2.7

Toggle v6.2.7's commit message

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
bump protocol TARGET_VERSION to 6.2.7 (#2332)

Claude-Session: https://claude.ai/code/session_016JygNdE3rTnASE8vgQJZzP

v6.2.6

Toggle v6.2.6's commit message

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
refactor: replace custom compression with native gRPC compression (#2328

)

* refactor(provider): serve native gRPC instead of the grpc-web wrapper

The provider listener wrapped its gRPC server in grpc-web and h2c so that
browser based lava-sdk clients could reach it. The SDK is gone, so the
wrapper only costs us the supported grpc.Server.Serve path: native
connection management, graceful stop, and no protocol translation.

The listener now runs a real grpc.Server, with cmux routing connections by
the protocol they open with: the HTTP/2 client preface goes to gRPC,
everything else to the HTTP/1.1 health endpoint that kubernetes httpGet
probes use. Matching the preface is a cheap prefix compare and resolves at
connection time, unlike matching the gRPC content-type which would have to
wait for the first request. The gRPC health checking protocol is registered
alongside it for native clients and load balancers, and Shutdown now drains
both servers, reports NOT_SERVING while draining, and releases the port.

When TLS is enabled the listener advertises ALPN explicitly. gRPC clients
offer only "h2" and refuse a connection that negotiated no protocol at all,
so terminating TLS without advertising it would have broken every consumer
of a TLS enabled provider. "http/1.1" is listed first because ALPN resolves
in server preference order, which keeps HTTP health probes on HTTP/1.1
while gRPC clients still get "h2".

Relay compression is left to gRPC as well. The consumer already dials with
grpc.UseCompressor(gzip) when compression is enabled, and the server echoes
that compressor back on the response, so the hand rolled compress/decompress
pass and its lava-compression headers were compressing already compressed
payloads. The flag is renamed to --enable-grpc-compression accordingly, with
the old name still accepted so existing deployments keep working. The gzip
helpers stay for the cache, which compresses entries at rest.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ka44Dzff68tLrAQ5SJPmaC

* refactor(provider): drop the grpc-web CORS check from provider testing

PerformCORSCheck required every provider to answer an HTTPS request on any
path with Access-Control-Allow-Origin and an Access-Control-Allow-Headers
list containing x-grpc-web. Those headers existed only so browsers could
preflight grpc-web calls, and the provider listener no longer speaks
grpc-web, so the check now fails against every provider.

It is a hard failure in both callers: lavap test rpcprovider reports
"invalid CORS check" for every endpoint, and the health monitor marks every
provider unhealthy. Nothing else is lost by removing it, both callers probe
the endpoint over gRPC first, and TLS reachability is already covered by
ConnectRawClientWithTimeout and its insecure retry.

The cors_test.go scaffolding went with it, including the self signed
certificate it wrote into the package directory on every run.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ka44Dzff68tLrAQ5SJPmaC

---------

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>

v6.2.5

Toggle v6.2.5's commit message

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
chore: bump protocol TARGET_VERSION to 6.2.5 (#2329)

The x/protocol TARGET_VERSION constant was left at 6.1.0 while the repo
released v6.2.0 through v6.2.4, so lavap self-reported 6.1.0 in its
version output, relay metadata and protocol version metrics.

The constant is compiled into the binary via upgrade.GetCurrentVersion,
so the already-published v6.2.4 artifacts cannot be corrected in place.
Target 6.2.5 instead, to be shipped by the next tag.

Document the constants while here, so the next release does not miss the
manual bump.


Claude-Session: https://claude.ai/code/session_0117V1emoRbzp5M19LFjnVs3

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>

v6.2.4

Toggle v6.2.4's commit message

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
fix: improve handleConsistency to wait for tracker polls instead of b…

…ailing (#2326)

* fix(provider): gate consistency bail on tracker poll time, not block production

handleConsistency's early bail used a Poisson model of block production to
decide whether the provider could reach the consumer's seenBlock. That model
does not describe what this code path waits for.

Every path that reaches the bail targets a block <= seenBlock (blockGap is
clamped to seenBlock - latestBlock just above), and seenBlock was already
served to the consumer by another provider — so those blocks already exist on
chain. The provider is not waiting for the chain to produce blocks, it is
waiting for its own ChainTracker to poll blocks that are already there, which
takes at most averageBlockTime/(MostFrequentPollingMultiplier/4) — well under
one block time.

Modelling it as block production makes the bail fire whenever the spec's
average_block_time overstates the chain's real block time. On NEAR (spec says
1200ms, chain runs at ~600ms since the May 2025 optimistic-block upgrade)
probabilityBlockError evaluates to 0.62-0.97 for every realistic combination
of blockGap >= 2 and relay timeout, so the bail was unconditional and the
catch-up wait below it — which would have closed a 2-3 block gap on the next
poll — was unreachable.

Keep probabilityBlockError for observability and gate the early bail on
whether waiting can help at all:
  - blockGap beyond blockLagForQosSync*2: the node is genuinely behind and
    polling won't fix it, bail immediately (unchanged)
  - not enough time left for a single tracker poll: waiting is pointless
Otherwise fall through to the existing bounded wait, which already re-checks
the tracker every 50ms and whose post-wait check still returns
ConsistencyError if the provider truly did not catch up.

Trade-off: a provider whose node is genuinely behind by <= blockLagForQosSync*2
now spends up to halfTimeLeft before failing instead of failing instantly. That
budget was already spent this way for blockGap == 1, and the consumer races
providers in parallel, so it does not serialize onto end-user latency.

Adds halfTimeLeft and trackerPollInterval to the bail warning so operators can
see which term fired.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YCMc3dBY9QkwHkX8H4iK1Q

* fix(test): stop uniqueAddressGenerator spinning forever on port probes

protocol/integration times out under `go test -timeout 15m` with no output and
no report file, taking the whole test-protocol job down with it. The hang is in
the first line of the first test, in uniqueAddressGenerator.GetAddress.

Two defects combine:

isPortInUse treats every error from resolve/listen as "this port is taken". A
host without IPv6 loopback fails the [::1] bind with EAFNOSUPPORT, so every port
reports busy even though none of them are.

GetAddress then loops on that, and its `currentPort > maxPort` guard sits after
the loop rather than inside it. When every probe says "in use" the loop never
terminates and never reaches the guard, so the intended
panic("all ports have been exhausted") is unreachable and the package spins
until the test binary is killed.

Fixes both: probe failures that mean the address family is unavailable
(EAFNOSUPPORT, EADDRNOTAVAIL) now skip that address instead of condemning the
port, and the bound is checked inside the loop so exhaustion panics with a
usable message instead of hanging.

Verified on a host without IPv6 loopback, where this reproduces every time:
TestConsumerProviderBasic went from a 15m timeout to passing in 2.09s, and the
full protocol/integration suite from timing out to green in 37s.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YCMc3dBY9QkwHkX8H4iK1Q

---------

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>

v6.2.3

Toggle v6.2.3's commit message

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
feat: add grpcwebcompat package for canonical trailer encoding (#2321)

* fix(grpcweb): emit canonical grpc-web trailers

gRPC-Web moves grpc-status/grpc-message out of the HTTP/2 TRAILERS frame and
into the response body, as a final frame holding an HTTP/1 style header block.
improbable-eng/grpc-web builds that block with http.Header.Write, which emits
"key: value", so the response ended with:

    \x80\x00\x00\x00\x10grpc-status: 0\r\n

RFC 7230 permits that optional whitespace and requires receivers to strip it,
but a receiver that splits on ':' reads the status as " 0" and rejects the call
with "transport: malformed grpc-status: strconv.ParseInt: parsing \" 0\":
invalid syntax". Since a grpc-status seen at the header stage marks the response
Trailers-Only, the RPC ends as Internal and the message already on the wire is
never delivered.

Serve gRPC-Web through protocol/grpcwebcompat, which writes "key:value\r\n" -
the form Envoy and the other reference implementations emit - with lower-cased
names and with values stripped of the surrounding whitespace and of CR/LF, which
would otherwise split or truncate the trailer block. The library stays a
dependency: native gRPC, CORS pre-flights and gRPC-Websockets still go to it
unchanged, so only gRPC-Web responses differ.

The same wrapper is applied to the other servers built from the same five lines:
the provider listener, the chain tracker and the connection test command.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ThUAjPPzmZ4wqSJcoyXPRm

* fix(grpcweb): satisfy lint and stop reflecting the request content type

Three golangci-lint findings on the new package: rawCodec's forced type
assertions (forcetypeassert), and CanonicalHeaderKey applied to the key of
Header.Set, which already canonicalises (gosimple S1035).

CodeQL flagged the response content type as reflected XSS (go/reflected-xss).
The value was built by rewriting the one grpc-go derived from the request, so a
request could steer what landed in the response header. Assemble it from this
package's constants instead and let the request only select between them, then
set it explicitly with Header.Set rather than by assigning into the map. A
sub-type outside proto and json now collapses to the base content type instead
of being echoed; the sub-types real clients send are unaffected.

Also rename the tests to the TestComponent_Scenario form AGENTS.md asks for,
make the remaining ones table-driven, and unexport wrapHandler and
isGrpcWebRequest, which nothing outside the package uses.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ThUAjPPzmZ4wqSJcoyXPRm

---------

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>

v6.2.2

Toggle v6.2.2's commit message

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
feat(consumer): per-chain latency cutoff for random provider selection (

#2314)

* feat(consumer): per-chain latency cutoff for random provider selection

Adds an optional per-endpoint QoS latency cutoff (MaxProviderLatency,
in seconds) to RPCEndpoint. During the general random/weighted provider
selection, providers whose EWMA latency exceeds the cutoff are put aside
via the existing ignored-providers set, so the optimizer never picks them.

Includes a safety fallback: the cutoff is applied only if at least one
candidate stays under the threshold; otherwise the full pool is kept so
relays keep flowing when the whole pairing is slow. Cold-start providers
(no QoS data) are treated as under-threshold.

Static, header-selected, sticky and stateful selection paths are
unaffected. No optimizer/interface changes; the setting rides on
csm.rpcEndpoint. 0 (default) disables the cutoff.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* test(consumer): unit tests + docs for per-chain latency cutoff

Adds focused unit tests for filterHighLatencyProviders covering: excluding
slow providers, keeping fast ones, the all-slow safety fallback, disabled
cutoff (0), cold-start (no QoS) handling, preserving pre-existing ignored
entries, strict ">" threshold boundary, multi-provider filtering, and a
mixed cold-start/slow/fast case.

Documents max-provider-latency in the rpcconsumer README and adds a
commented example to config/rpcconsumer.yml.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* test(consumer): integration tests + live E2E harness for latency cutoff

Go tests:
- consumer_session_manager_latency_selection_test.go: drives
  getValidProviderAddresses through a stub optimizer to prove the cutoff
  applies only to the general random path (sticky/stateful/selected-provider
  paths are unaffected).
- rpcconsumer_endpoints_test.go: verifies max-provider-latency parses from
  the YAML endpoints config into RPCEndpoint (0/omitted => disabled).

Live E2E (full env: dev chain + mock-backed providers + consumer):
- scripts/pre_setups/init_eth_latency_cutoff.sh: brings up 3 ETH1 providers,
  each behind its own mock RPC backend; one mock is slowed so its provider
  exceeds the cutoff. Modes: cutoff | regression-disabled | regression-fallback.
- scripts/test/verify_latency_cutoff.sh: drives relays and asserts on the
  lava_consumer_provider_selections metric per mode.
- scripts/test/e2e_latency_cutoff.sh: one-command runner (setup -> wait ->
  verify -> teardown).
- config/eth_latency_cutoff_consumer{,_disabled}.yml: the two consumer configs
  (cutoff 1.0 and disabled 0) selected by mode.

The mock RPC server is left untouched; providers use --use-static-spec with a
verification-stripped ETH1 spec so they accept the mock backend while still
proxying real (latency-bearing) relays.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* style(consumer): gofmt latency selection test stub methods

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* log change

---------

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>

v6.2.1

Toggle v6.2.1's commit message

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
fix(chainlib): tolerate non-scalar JSON-RPC request ids in id validat…

…ion (#2302)

* fix(chainlib): tolerate non-scalar JSON-RPC request ids in id validation

ValidateRequestAndResponseIds parsed the request id before reaching the
"null/empty response id" carve-out. A client that sends a non-scalar id
(object/array) — invalid per JSON-RPC 2.0, e.g. a .NET CancellationToken
serialized into the id — therefore hard-failed with "failed parsing ID",
which lavap surfaces as "jsonRPC ID mismatch / insufficient results" plus a
cross-provider retry storm, even when the relay itself was fine.

Captured against live nodes: Polygon rejects the object id and replies
id:null; NEAR accepts it, returns a valid result, and echoes the object id
back. Both were being failed.

- Check the null/empty/[] response-id carve-out first, before parsing the
  request id (covers Polygon's id:null rejection).
- When either id is non-scalar, compare ids semantically (whitespace/key-order
  tolerant) instead of erroring (covers NEAR's verbatim echo, preserving the
  valid response). A genuinely different id is still reported as a mismatch.

Scalar id behaviour is unchanged. Root cause is a non-compliant client; this
makes lavap surface the node's real response instead of masking it.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* test(chainlib): end-to-end coverage for non-scalar JSON-RPC request id

Drives the real ParseMsg -> SendNodeMsg path against a mock node with an
object request id, covering both observed node behaviours: a NEAR-like node
that echoes the id and returns a valid result (must be returned, not
discarded), and a Polygon-like node that rejects with id:null + "invalid
request" (must pass through, not become an "ID mismatch" / retry storm).

Complements the ValidateRequestAndResponseIds unit test by asserting the full
relay outcome.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
0