catch up#1
Open
Corey-Code wants to merge 957 commits into
Open
Conversation
* chore(currencyRateTicker): remove strings.toLower normalization to avoid converting base58 tron addresses * fix(fiatRates): test expectations * refactor(public_test): extend the setup http server method by passing currency rates tickers to properly test the /tickers/ endpoint * feat(public_test): extend current fiat rates tests to cover all tickers endpoint for both HTTP and websocket * chore(tron): change platformVsCurrency to "usd" cuz coingecko doesnt support "trx"
#1464) * feat(test-websocket): add tron presets and ability to switch between tron/ethereum using button * chore(test-websocket): remove hard-coded values in the inputs for ethereum as they are in the presets * feat(tron): add preset values for estimateFee in test-websocket.html
* feat(tron): add account activation recognizition * tests(tron): add account creation transaction to rpc testdata
… voting rewards (#1463) * chore(tron): do not set tx.value for delegation, trc-10 transfers * feat(tron): freeze/unfreeze to be count as out/ingoing correctly * refactor(balanceHistory): balanceHistory code refactor and Tron staking semantics * feat(tron): add support for tron voting reward to be counted as ingoing tx in balanceHistory * fix(tron tests): tron rpc tx expectations for trc10 and delegation transactions * tests(tron): account creation detection * tests(tron): add tron transactions to RPC testdata for unfreeze, withdraw, votereward, account creation * feat(tron): use unfreeze balance field for stake 1.0 unfreeze tx
* chore(erc4626): adding ws endpoint to fetch 4626 data for token * chore(erc4626): evolve getErc4626 into getContractInfo endpoint * chore(erc4626): unify getAccountInfo with getContractInfo * chore(erc4626): cleanup * chore(erc4626): add EVM-only guard for getContractInfo * chore(erc4626): add EVM-only guard for getAccountInfo * chore(erc4626): add tron spec to ContractInfoResult, Token and TokenTransfer
…ddress LRU eviction
Fetching the confirmed nonce on every address request adds a second
eth_getTransactionCount("latest") backend call for every EVM address,
which most callers do not need. Gate it so the extra call is made only
when the client opts in.
- REST: GET /api/v2/address/<addr>?confirmedNonce=true
- WebSocket: getAccountInfo request gains a confirmedNonce boolean
- both map to AddressFilter.WithConfirmedNonce
When the flag is off (default), behavior is identical to before this
feature: only the pending nonce is fetched (single call) and the
confirmedNonce field is omitted from the response. When the flag is on,
pending + latest are fetched in a single JSON-RPC batch round-trip
(sequential fallback when the client does not support batching), and
confirmedNonce is included. Tron is unaffected: its single NonceAt call
already returns the latest nonce, so it ignores the flag.
openapi.yaml gains the confirmedNonce query parameter and the
WsAccountInfoReq.confirmedNonce property; blockbook-api.ts is updated in
lockstep. Server tests cover both gated-on (REST + WebSocket) and the
gated-off default. Verified by build, unit tests, and the OpenAPI parity
typecheck.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…aths Address review follow-up on the confirmed-nonce feature. Best-effort confirmed nonce: once a client opts in with confirmedNonce=true, a transient failure of the "latest" lookup must not take down the whole address/getAccountInfo response (balance, txs, tokens). EthereumTypeGetNonces now returns (pending, confirmed, confirmedOK, err): the pending nonce is required (error is fatal), while the confirmed nonce is best-effort — if only the latest lookup fails it is logged and reported as confirmedOK=false, and the worker simply omits confirmedNonce from the response. This applies to the batched, sequential-fallback, and alternative-provider paths alike. Tests: - new bchain/coins/eth unit tests for EthereumTypeGetNonces covering: gated-off fetches pending only (no "latest" call), gated-on batched success, confirmed failure is best-effort (pending returned, no error), pending failure and batch transport failure are fatal, and the sequential fallback (client without BatchCallContext) incl. its best-effort confirmed path - new OpenAPI e2e test GetAddressConfirmedNonceEVM (enabled for EVM coins): asserts the opt-in gate (no confirmedNonce without the flag), and when opted in validates the field and that confirmed <= pending, skipping gracefully on backends where the feature is not deployed yet No wire/contract change: confirmedNonce remains an optional response field, so openapi.yaml and blockbook-api.ts are unchanged. Verified by build, unit tests, the OpenAPI parity typecheck, and render_grafana.py --check. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Mirror the REST GetAddressConfirmedNonceEVM e2e check on the WebSocket getAccountInfo path: assert confirmedNonce is absent without the opt-in flag, and when confirmedNonce:true is passed validate the field and that confirmed <= pending, skipping gracefully on backends where the feature is not deployed yet. Enabled for the EVM coins in tests/tests.json. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
watchMempoolTxs ran on a ticker for the process lifetime with no way to stop it. Add a stop channel closed by a nil-safe, idempotent shutdown(), wired into EthereumRPC.Shutdown alongside consensusMonitor.shutdown() and mirroring the existing consensusVersionMonitor lifecycle. Harmless for the process-lifetime singleton today, but prevents a goroutine leak if per-chain teardown is ever added and aligns with the recent "cancel in-flight RPCs on shutdown" work. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
A fresh address (no indexed data) skipped the nonce fetch entirely, so an opted-in caller got nonce:"0" but confirmedNonce omitted - ambiguous with "feature not deployed". Since every tx sender is recorded in the index, ca==nil means the account never sent a tx, so both nonces are genuinely 0; synthesize confirmedNonce:"0" locally (no backend call) for symmetry with the indexed path. The default (flag-off) response is byte-for-byte unchanged. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
reconcileMempoolTxs evicted timed-out txs via RemoveTransaction, which only deletes from the alternative provider's own cache map. The provider_missing / mined / nonce_superseded paths instead use removeMempoolTx, which prefers the removeTransactionFromMempool callback and therefore clears BOTH the main b.Mempool (the addrDesc->txid index that drives address/WS mempool listings) and the alternative cache. As a result a timed-out tx was dropped from the cache but lingered as a ghost "pending" entry in the main mempool until that mempool's own, independently configured (and by default longer) timeout expired - and with private/Blink relays there is no backend re-query to clear it lazily. The nonce-superseded healing commit explicitly stated evictions go "via removeMempoolTx (both Blockbook mempool and cache), consistent with the mined/provider_missing removals", but the two timeout branches diverged from that contract. Use removeMempoolTx in both timeout branches so every reconcile eviction path removes the tx from both the main mempool and the alternative cache. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
AlternativeSendTxProvider.getNonces is the production nonce path for private/Blink relay coins and duplicates getNoncesRPC's batch + best-effort logic, but no test exercised it: every nonce test in nonce_test.go leaves alternativeSendTxProvider nil and hits the primary RPC. A regression in its pending-fatal vs latest-best-effort handling would have gone uncaught. Add a batch-aware JSON-RPC httptest server (the batched path uses BatchCallContext, which the existing method-keyed mock cannot serve) and mirror the getNoncesRPC cases: pending-only when gated off (asserting the latest tag is not queried), batched pending+confirmed when gated on, best-effort confirmed failure (pending returned, confirmedOK=false, no error), fatal pending failure, and fatal batch transport failure. Green under -race. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The reconcile tests fixed mempoolTxsTimeout at time.Hour with a tx timestamped ~2 check periods ago, so timedOut was always false and neither timeout-eviction branch ran. The PR repeatedly calls the timeout path the "safety net" that bounds premature-eviction risk, yet it had zero coverage. Add a table-driven test that shrinks mempoolTxsTimeout so the cached tx is timed out, covering both branches: provider error + timed out, and still-pending (nonce not superseded) + timed out. Both assert via assertReconcileOutcome, which requires the removeTransactionFromMempool callback to have fired - so this also guards the preceding fix that routes timeout eviction through removeMempoolTx (reverting it makes this test fail). Green under -race. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
decodeConfirmedNonce has two best-effort failure paths: a lookup/transport
error, and a successful call that returns unparsable hex. Only the former
was tested (errs:{"latest":...}); the decode branch - which feeds the
public confirmedNonce field when a backend answers 200 with garbage - was
unverified on the RPC path.
Add batched and sequential-fallback cases that return "0xZZ" for the
latest tag with no error, asserting pending is still returned with
confirmedOK=false and no error surfaced.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…etMetrics SetMetrics has a single caller (blockchain.go NewBlockChain), which runs it before bc.Initialize(); the alternative provider is only created later inside Initialize -> InitAlternativeProviders, which already passes b.metrics into NewAlternativeSendTxProvider. So b.alternativeSendTxProvider is always nil when SetMetrics runs and the inner assignment never executed - dead and redundant. Remove it. This also makes provider.metrics write-once (set only at construction, before SetupMempool starts the reconcile goroutine that reads it), removing the only post-construction mutation site and the latent data race it would become if the construction ordering ever changed. Documented the invariant in a comment so the branch is not reintroduced. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The PR converted every Tron address assertion to ?confirmedNonce=true, removing the prior full-body match that implicitly proved confirmedNonce absence. Re-add a no-flag case for TronAddrTZ asserting a substring that spans the nonce->tokens boundary, which matches only when confirmedNonce is not inserted after nonce - mirroring the EVM gated-off check and covering Tron's opt-in gate end to end. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…'s first page GetAddressTxids / GetAddressTxs / WsGetAccountInfo derived the sample address as the first vin/sender of a recent tx, then asserted that tx appears in the address's first page (addressPageSize=10). On busy account-based chains this breaks: a Tron USDT transfer's sender is a hot wallet with thousands of txs, so the sampled tx sits hundreds of entries deep and is paged out, failing the assertion (the recipient, by contrast, is low-traffic and lists it on page 1). Replace the blind sender pick with a self-verifying resolver (getSampleAddressTx / sampleAddressTxOrSkip): it walks a tx's participants - token recipients and outputs first, then inputs - and selects the first one whose first page actually lists the tx, probing additional recent txs if needed. The three address-listing tests now assert against a pair that is structurally guaranteed consistent, instead of assuming the sender lists the tx early. Verified against the live Tron backend: the resolver picks the token recipient and both the txids and txs first pages contain the sample tx; simulated over several current tip-block txs it finds a valid pair every time. No Blockbook/production code changed; typecheck passes. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The e2e suite dials the dev backends directly, so it can't run from a network that only permits outbound traffic via HTTP(S)_PROXY (e.g. a sandboxed/corporate environment): fetch() gets EAI_AGAIN and the ws client can't connect. Node's fetch (undici) and the ws library both ignore the proxy env by default. Wire both transports through the proxy when one is configured, and no-op otherwise (zero effect in CI / direct-network dev): - runner.ts: when proxyFromEnv() is set, install an undici ProxyAgent as the global fetch dispatcher (requestTls drops cert verification for the proxied target under OPENAPI_INSECURE_TLS, since dev backends are self-signed); otherwise keep the previous plain insecure-TLS Agent. - context.ts: the ws client doesn't use undici's dispatcher, so pass an https-proxy-agent as its `agent` (proxyFromEnv/wsProxyAgent helpers, shared with runner.ts). - declare https-proxy-agent (already present transitively via @redocly/cli) as a direct devDependency. Verified by running the full Tron suite through a proxy: 35 ok, 3 skip, 0 fail (incl. the HTTP GetAddressTxids/GetAddressTxs and the ws WsGetAccountInfo). typecheck passes. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…timeout The reconcile loop added in #1562 evicted a still-pending tx the moment a single eth_getTransactionByHash returned empty ("provider_missing"). Blink-style private/MEV relays stop surfacing a still-mineable tx via getTransactionByHash while it stays broadcast, so a tx that showed "Unconfirmed" on both sender and recipient disappeared from both ~1-2 min after send - before either the 5-min alternative cache timeout or the 10-min mempool timeout. Pre-#1562 there was no proactive reconcile and the tx stayed visible until mined or timed out. Treat an empty getTransactionByHash as non-authoritative: defer eviction to the absolute cache timeout, keeping `mined` and `nonce_superseded` as the only deterministic early evictions (both are positive, irreversible on-chain facts). Also run the nonce-superseded check even when the provider no longer surfaces the tx, so a provably spent nonce is still cleaned up promptly. The new metric label `provider_missing_pending` marks the kept-not-evicted case. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Three independently-merged PRs each assigned the same Grafana panel ids (321-325) on master, so the render --check fails (Grafana refuses to import a dashboard with duplicate panel ids) - including this PR's CI. Panel ids are internal to Grafana and only need to be unique; panels.yaml joins by x-panel-key, not by id. Keep the REST API row at its contiguous 321-326 block and renumber the two colliding groups into the free range (max id was 331): - sync.eth_alternative_mempool_reconciliation: 321 -> 332 - row.fiat_rates + 4 panels: 321-325 -> 333-337 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The Grafana render --check is pure static analysis (no secrets, no backend) - the same profile as the coin backend-artifact lint - and its only dependency is the pinned PyYAML. Keeping it in the self-hosted unit-tests job had two downsides: it was the sole reason that job installed Python deps, and - because unit-tests is skipped for fork PRs - dashboard regressions in fork PRs went unvalidated. Fold both render_grafana checks into the lint job (renamed backend-artifact-lint -> lint, on the ephemeral GitHub-hosted runner that already runs for forks) and drop the now-unused Python setup from unit-tests, leaving it pure Go. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
base_archive runs blockbook against op-geth on the OP-Stack chain, whose non-sequencer nodes have no usable public mempool - the node rejects eth_subscribe newPendingTransactions with "invalid subscription type for subscribe", which aborted startup (exitCodeFatal -> systemd crash loop). Set disableMempoolSync: true so the pending-tx subscription is skipped, matching the polygon_archive/bsc_archive precedent; mempool/sendtx data is sourced from the alternative mempool provider instead. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The reconcile loop added in #1562 only had a decision counter labeled by action, which shows the rate of each reconcile outcome but not the thing #1573 is really about: how long an unconfirmed tx actually survives in the alternative-provider-only send-tx cache, and why it eventually disappears. That lifetime is non-deterministic (mined fast, or held to the 5/10-min timeout, or evicted early), so it needs to be measured, not reasoned about. Add two metrics and the panels to read them: - eth_alternative_mempool_tx_residence_seconds (histogram by action): the age of a cache entry at the moment it leaves the cache, per exit reason. This is the signal that would have surfaced the regression #1573 fixed - provider_missing evictions clustering at ~1-2 min instead of near the timeout - and shows how quickly relays actually confirm. - eth_alternative_mempool_cache_size (gauge): current cache depth, sampled at the end of each reconcile cycle. Route every cache-exit through the same observation so neither metric undercounts: the reconcile-loop removals (via a new evictMempoolTx helper), GetTransaction's read-path timeout eviction, and handleMempoolTransaction's RBF replacement. Without the latter two the timeout series would be biased low and RBF lifetimes invisible. Also refresh the now-stale reconciliation counter help/panel text (it never mentioned provider_missing_pending, kept or skipped_fresh). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…#1578) * mq existence check added to tronrpc.go to fix mempool initialization without it * Add polling only mode to tipWatchdog * tipWatchdogTick now know about case when b.mq == nil * Apply 1s floor in tipWatchdog when mq is disabled to avoid hammering the RPC if averageBlockTimeMs is misconfigured * tests added * spaces -> tabs * chore(tron): remove dead code capping the block polling interval * chore(tron): avoid race condition when initializing MQ subscription * chore(tron): briefer comment for bchain.MQ --------- Co-authored-by: Henrik Mesropyan <henrik.m@nownodes.io> Co-authored-by: Jakub Jerabek <xjerab28@stud.fit.vutbr.cz>
Blockbook reads operator secrets and per-coin tunables (INFURA_API_KEY, COINGECKO_API_KEY, <coin>_* limits, ...) from its process environment at runtime. These were provided out of band via systemd DefaultEnvironment in /etc/systemd/system.conf, hand-maintained per host. Add an optional EnvironmentFile=-/etc/blockbook/blockbook.env to the blockbook service unit so a single file can supply them per host. The leading '-' keeps the file optional, so public/community installs and existing hosts that still use DefaultEnvironment are unaffected when it is absent; a unit-level value also overrides a DefaultEnvironment value for the same key, allowing a no-flag-day migration off system.conf. On the dev deploy path (bbcli -> deploy.yml on self-hosted runners) the file is materialized from the BB_BLOCKBOOK_ENV GitHub Actions secret before the service restart; the step is a no-op when the secret is unset so it is safe to merge before the secret exists. Prod hosts will render the same file via bbctl. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The set of BB_ build-time variable prefixes was duplicated in three places that had to be hand-synced: the Makefile forwarding regex, the export-env-vars action normalizer, and templates.go. A drift failed silently (e.g. a var exported to GITHUB_ENV but absent from the Makefile regex never reaches the build). Introduce build/bb-build-var-prefixes.txt as the canonical list. The Makefile now derives the forwarding match from it (output verified identical to the old regex; BB_BUILD_ENV continues to be forwarded separately via -e on each docker run), and the action reads it for coin-alias normalization. templates.go keeps its typed constants but a new test (TestCanonicalPrefixesCoverTemplateConsumers) asserts every prefix it relies on is present in the file, so drift now fails in CI instead of at build time. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The materialize step wrote the env file with `tee` (umask default, ~0644) and only then chmod'd it to 0600, leaving a brief window where the secrets were world-readable on the runner. Pre-create the file 0600 root:root with `install /dev/null`; tee then truncates it without changing the mode, closing the window and dropping the now-redundant chown/chmod. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…sconfigured EVM coins that set `alternative_estimate_fee` to "infura"/"1inch" require the matching API-key env var (INFURA_API_KEY / ONE_INCH_API_KEY). Previously a missing key only logged an error and silently reverted to default fee estimation, so a misconfigured node started and served wrong fees. Propagate the provider-construction error from initAlternativeFeeProvider through the existing InitAlternativeProviders path (already checked by every EVM coin), so a node whose config selects a provider it cannot construct fails to start instead of degrading silently. A coin with no provider configured stays a no-op. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The fail-fast added in c468fa3 makes EVM chain initialization abort when a configured alternative_estimate_fee provider cannot be built because its API-key env var is unset. Integration tests render the production coin configs and call chain.Initialize(); avalanche selects "infura", but the test environment is never given INFURA_API_KEY (the CI Makefile only forwards BB_* vars), so TestIntegration/avalanche=main/rpc now fails during init. Supply harmless placeholder keys for the EVM fee providers at the start of the integration run so the chain initializes and falls back to default fee estimation; the background fee fetch just 401s and is ignored. These tests assert RPC/sync behavior, not fees, and a real key in the environment is still respected. Production fail-fast is unchanged and covered by the unit tests in bchain/coins/eth. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
BB_BLOCKBOOK_ENV was redundant (BB already stands for Blockbook) and did not convey that its content is the runtime environment file. Rename the GitHub Actions secret reference to BB_RUNTIME_ENV, consistent with the new BB_ADMIN_USER/BB_ADMIN_PASSWORD runtime variables. The GitHub repository secret must be renamed to match; until it is, the materialize step no-ops and leaves blockbook.env untouched. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The internal server binds all interfaces by default (configs/coins/*: internal_binding_template is ":<port>"), so its /admin pages and state-mutating POST handlers (internal-data refetch, contract-info updates) were reachable unauthenticated by any peer that could reach the port. Gate the whole /admin surface behind HTTP Basic auth, credentials from BB_ADMIN_USER/BB_ADMIN_PASSWORD (delivered via blockbook.env). Basic auth (rather than a bearer token) lets the admin HTML pages and forms be used directly from a browser via its native login prompt, and still works for scripts via curl -u. The surface is fail-closed: unless both variables are set, every /admin route returns 503. /metrics, the status page and static assets are unaffected, so Prometheus scraping is unchanged. - A trailing-slash catch-all (/admin/) is gated too, so unregistered or trailing-slash paths can't fall through to the unauthenticated index. - Credentials are trimmed of surrounding whitespace at load (a stray newline in blockbook.env won't lock the operator out) and only their SHA-256 digests are retained; user and password are compared in constant time with both comparisons evaluated before being combined. Transport is the existing self-signed cert, intended for a trusted, firewalled internal segment (see docs/env.md). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The /admin/ trailing-slash catch-all added to gate unknown admin subpaths also returned 404 for a bare "/admin/", so navigating to the natural trailing-slash URL dead-ended after login instead of showing the admin index (served at /admin, no trailing slash). Redirect "/admin/" to the canonical "/admin" while still returning a gated 404 for any genuinely unknown /admin/* path, so the subtree stays authenticated. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…di, nile) (#1575) * fix(tests): keep testnet network suffix in matchable test name getMatchableName/matchable_name collapsed every "<coin>_testnet*" key to "<coin>=test", so sibling testnets (sepolia vs hoodi, testnet vs testnet4) shared one subtest name. The deploy connectivity regex built for one testnet then also selected its siblings, so a deploy could fail because an unrelated testnet's blockbook was unreachable. Preserve the network suffix after "_testnet" so the mapping is injective ("ethereum_testnet_sepolia" -> "ethereum=test_sepolia"), and anchor each name in the connectivity regex so "bitcoin=test" no longer substring-matches "bitcoin=test4". Add Go and Python regression guards and update the docs. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * test(integration): add tron_testnet_nile integration tests Mirror the mainnet tron entry (connectivity http, api, rpc). The rpc fixture tests/rpc/testdata/tron_testnet_nile.json already exists, and the BB_DEV_* RPC/API repository variables for tron_testnet_nile are already provisioned, so no new GitHub variables are required. Adding the connectivity group lets the deploy pipeline gate tron_testnet_nile on backend + Blockbook reachability, and the api group enables the post-deploy OpenAPI e2e suite for it. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * test(integration): add ethereum_testnet_sepolia and _hoodi integration tests Give both Ethereum testnets connectivity (http + ws) and the no-fixture EVM api list (the same list used by avalanche/arbitrum/optimism). The fixture-backed EVM tests (ERC4626, contract-info, protocols) are intentionally omitted because they require tests/openapi/fixtures/<coin>.json with mainnet contract addresses, which only exist for ethereum and base; no rpc group is added for the same reason (no tests/rpc/testdata/<coin>.json fixture yet). The BB_DEV_* RPC/API repository variables for both testnets already exist (the RPC URLs resolve via the *_archive fallback), so no new GitHub variables are required. Connectivity gates their deploys and api enables the OpenAPI e2e suite. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * test(integration): support disabling a coin via tests.json "disabled" flag tron_testnet_nile's backend and Blockbook dev instance are not currently deployed, so its connectivity/rpc/api tests cannot pass. Rather than delete the test definitions, mark the coin "disabled": true in tests/tests.json and teach every consumer to skip it: - tests/integration.go skips disabled coins with a visible SKIP - tests/openapi/src/config.ts drops disabled coins from e2e selection - .github/scripts/runner.py treats disabled coins as non-deployable Remove the flag to re-enable. Documented in AGENTS.md and covered by Go and Python unit tests. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * test(connectivity): gate backend/node RPC checks behind BB_TEST_BACKEND_CONNECTIVITY The connectivity suite dialed both the raw backend/node RPC (rpc_url) and the Blockbook API for every coin. The node RPC endpoints are only routable from the CI/CD network, so local runs failed on unreachable nodes even when Blockbook itself was healthy. Gate the node RPC checks behind BB_TEST_BACKEND_CONNECTIVITY: off by default (local runs verify Blockbook reachability only), on in CI. The flag is set in the testing.yml connectivity job and the deploy.yml post-deploy connectivity step, forwarded into the build container by the Makefile, and exposed locally via a --backend-connectivity flag on run-integration-tests.sh. Documented in AGENTS.md and covered by a unit test. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * test(connectivity): route Blockbook websocket dial through egress proxy BlockbookHTTPIntegrationTest's HTTP client already honors the proxy via http.ProxyFromEnvironment, but the gorilla websocket.Dialer in BlockbookWSIntegrationTest did not, so the WS check failed to resolve the Blockbook host from behind an egress proxy (where it is only reachable through the proxy). Set Proxy: http.ProxyFromEnvironment on the dialer to match the HTTP client and the OpenAPI e2e suite; a no-op when no proxy is configured. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * fix(ci): resolve build/deploy coin aliases against the context, not cwd resolve_build_selection and resolve_deploy_selection normalized the "_"→"-" coin alias with normalize_coin_name(Path.cwd(), ...), so the underscore form of a hyphenated coin (e.g. ethereum_classic → ethereum-classic) only resolved when the process happened to run from the repo root. Run from any other directory (e.g. the unit tests) the alias was left unresolved and rejected as an unknown coin. Resolve against the already-loaded context.all_coins instead, which is derived from the workspace the context was built from, so selection no longer depends on the working directory. Adds a deploy-side regression test alongside the existing build one. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * test(integration): drop fiat-rate e2e tests for ETH testnets (no price feed) ethereum_testnet_sepolia and ethereum_testnet_hoodi disable fiat rates in configs/coins (fiat_rates-disabled instead of fiat_rates), because valueless testnet ETH has no CoinGecko feed — the rate downloader never runs. The WsGetCurrentFiatRates e2e test therefore hard-failed with "No tickers found\!", and GetCurrentFiatRates/GetTickersList/GetMultiTickers/WsGetFiatRatesForTimestamps/ WsGetFiatRatesTickersList only ever skipped. Remove the six fiat-dependent tests from both testnet entries; the non-fiat GetBalanceHistory/WsGetBalanceHistory stay. Mainnet ethereum (fiat enabled) and tron_testnet_nile (fiat enabled via mainnet TRX's CoinGecko id) keep them. Verified: OpenAPI e2e now passes for both coins (54 ok, 4 unrelated skips, 0 fail). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * test(e2e): cover GetContractInfoNonVaultEVM on ethereum_testnet_sepolia Add an OpenAPI fixtures file for Sepolia with two canonical, permanently deployed ERC20s — Chainlink LINK (0x7798…4789) and Circle USDC (0x1c7D…7238) — and enable GetContractInfoNonVaultEVM for the coin. The test GETs /api/v2/contract/<addr>?protocols=erc4626 and asserts the contract resolves and is NOT mis-flagged as an ERC4626 vault (the strict opt-in gate). Both addresses were verified indexed on the deployed Sepolia Blockbook (correct symbol/decimals, protocols absent); e2e passes (29 ok, 1 unrelated skip, 0 fail). Not added for ethereum_testnet_hoodi: that testnet has no token ecosystem indexed, so there is no stable contract to anchor a fixture. The remaining EVM contract/protocol/ERC4626 tests still require curated on-chain vault and holder fixtures that do not exist on these testnets. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * test(ci): harden testnet test plumbing after review Follow-up hardening surfaced by a deep review of the testnet test work; no behavior change on the happy path. - deploy_plan.build_connectivity_regex: fail closed on an empty name list. An empty "()" alternation matches the empty string, so `go test -run` would select EVERY connectivity subtest instead of none. The caller already filters to a non-empty set; this makes the deploy-gating helper safe on its own. - runner_test: pin canonical_coin_name's check ordering so underscore-native coins (e.g. base_archive, ethereum_testnet_sepolia) are returned unchanged rather than rewritten to a hyphen variant — a reorder regression would otherwise stay green. - config.ts: document the "disabled" stay-in-sync contract on the actual filtering logic (it previously lived only on the types.ts declaration) and explain why the explicit-OPENAPI_COINS guard is needed alongside the filter. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
… convention Token transfer / token balance responses dropped the `decimals` field whenever it was 0 (the JSON tag carried `,omitempty`), so clients could not distinguish a genuine 0-decimal token from missing metadata and had to guess (trezor-suite defaults to 18). See #1577. - Remove `,omitempty` from api.Token.Decimals and api.TokenTransfer.Decimals so the field is always present (matches the existing ContractInfoResult). - In getContractDescriptorInfo, when a contract's metadata cannot be read on-chain, fall back to the coin's default decimals (18 for ERC-20) instead of surfacing/persisting an ambiguous 0. Genuinely 0-decimal tokens always carry a resolved (handled) standard, so they keep their 0. - Mirror the always-present field into blockbook-api.ts and mark decimals required in openapi.yaml for Token and TokenTransfer (parity typecheck). - Add a regression test asserting decimals is serialized even when 0. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Add assertTokenDecimals and wire it into GetAddressTokensEVM (Token) and GetTransactionEVMShape (TokenTransfer), making the #1577 expectation explicit on top of the schema's `required: decimals`. The check reuses already-fetched responses (no extra requests), runs on all EVM coins, and additionally enforces a non-negative integer, which the schema does not. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
No description provided.