Skip to content

Comments

feat: load certificate from gRPC#2256

Merged
stalniy merged 7 commits intoakash-network:mainfrom
jzsfkzm:features/2188-certificates-from-grpc
Nov 28, 2025
Merged

feat: load certificate from gRPC#2256
stalniy merged 7 commits intoakash-network:mainfrom
jzsfkzm:features/2188-certificates-from-grpc

Conversation

@jzsfkzm
Copy link
Contributor

@jzsfkzm jzsfkzm commented Nov 19, 2025

closes #2188

Summary by CodeRabbit

  • New Features

    • Automatic retry with exponential backoff for certificate retrieval to improve resilience.
  • Chores

    • Migrated provider backend to gRPC and updated environment variable to GRPC_NODE_URL.
    • Bumped chain SDK and added a retry library dependency.
  • Tests

    • Updated functional tests and local mock server to exercise gRPC-based flows.

✏️ Tip: You can customize this high-level summary in your review settings.

@jzsfkzm jzsfkzm requested a review from a team as a code owner November 19, 2025 17:10
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Nov 19, 2025

Walkthrough

This PR migrates provider-proxy certificate retrieval from an HTTP/fetch-based REST call to a gRPC-based flow using @akashnetwork/chain-sdk, updates environment variables to GRPC_NODE_URL, adds cockatiel retry logic, changes ProviderService constructor/signature, and rewrites test fixtures to use an HTTP/2 gRPC-like test server.

Changes

Cohort / File(s) Summary
Environment files
apps/provider-proxy/env/.env.sample, apps/provider-proxy/env/.env.sandbox, apps/provider-proxy/env/.env.mainnet
Replaced REST_API_NODE_URL with GRPC_NODE_URL and updated endpoint values to gRPC URLs.
Dependencies
apps/provider-proxy/package.json
Bumped @akashnetwork/chain-sdk from 1.0.0-alpha.121.0.0-alpha.18; added cockatiel ^3.2.1.
Config schema
apps/provider-proxy/src/config/env.config.ts
Renamed schema key REST_API_NODE_URLGRPC_NODE_URL (keeps z.string().url()).
Container / wiring
apps/provider-proxy/src/container.ts
Instantiate ProviderService with createChainNodeSDK({ query: { baseUrl: appConfig.GRPC_NODE_URL } }) instead of passing REST URL + fetch; added createChainNodeSDK import.
ProviderService implementation
apps/provider-proxy/src/services/ProviderService/ProviderService.ts
Replaced fetch/HTTP logic with Chain SDK calls; constructor now accepts a ChainNodeSDK client; added cockatiel ExponentialBackoff retry policy (max 3 attempts) with retriable error detection; new fetchCertificate method, logging/error utilities, and removed legacy JSON parsing types.
ProviderService tests
apps/provider-proxy/src/services/ProviderService/ProviderService.spec.ts
Tests migrated from fetch mocks to ChainNodeSDK-style mocks; updated test fixtures, certificate Buffer handling, and retry/error-case scenarios to align with SDK behavior.
Functional test server fixture
apps/provider-proxy/test/setup/chainApiServer.ts
Replaced HTTP/1.1 test server with HTTP/2 gRPC-like stream handling; renamed ChainApiOptionsGrpcServerOptions, stopChainAPIServerstopChainApiServer, changed interceptRequest signature, implemented protobuf-like request/response framing, session lifecycle and certificate filtering.
Functional tests
apps/provider-proxy/test/functional/provider-proxy-http.spec.ts, apps/provider-proxy/test/functional/provider-proxy-ws.spec.ts
Updated test wiring and descriptions to use GRPC_NODE_URL and the new gRPC test server APIs; adapted teardown to use stopChainApiServer() and concurrent shutdowns.

Sequence Diagram(s)

sequenceDiagram
    participant Client as Caller
    participant ProviderSvc as ProviderService
    participant Retry as RetryPolicy (cockatiel)
    participant ChainSDK as Chain SDK Client
    participant Grpc as gRPC Test/Node Server
    participant Logger as Logger

    Client->>ProviderSvc: getCertificate(providerAddress, serialNumber)
    ProviderSvc->>ProviderSvc: build QueryCertificatesRequest
    ProviderSvc->>Retry: execute(request) with ExponentialBackoff (max 3)
    Retry->>ChainSDK: akash.cert.v1.getCertificates(request)
    ChainSDK->>Grpc: gRPC call (protobuf payload)
    alt Success
        Grpc-->>ChainSDK: QueryCertificatesResponse (certificate bytes)
        ChainSDK-->>Retry: response
        Retry-->>ProviderSvc: certificates[]
        ProviderSvc->>ProviderSvc: parse/filter, build X509Certificate
        ProviderSvc-->>Client: X509Certificate | null
    else Retriable Error (Unavailable/Internal)
        Grpc-->>ChainSDK: gRPC error (code 14/13)
        ChainSDK-->>Retry: error -> RetryPolicy triggers backoff & retry
        Retry->>Logger: log retry attempt with context
        Retry->>ChainSDK: retry request (up to 3 attempts)
    else Non-retriable Error
        Grpc-->>ChainSDK: error
        ChainSDK-->>Retry: non-retriable -> fail
        Retry-->>ProviderSvc: null / propagate
        ProviderSvc->>Logger: log failure (providerAddress, serialNumber)
        ProviderSvc-->>Client: null
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60–80 minutes

  • Pay extra attention to:
    • apps/provider-proxy/src/services/ProviderService/ProviderService.ts — new Chain SDK usage, retry logic, error-code handling, and signature change.
    • apps/provider-proxy/test/setup/chainApiServer.ts — HTTP/2 stream framing, protobuf-like encoding, session cleanup, and changed public test API.
    • apps/provider-proxy/src/services/ProviderService/ProviderService.spec.ts — mocks and retry scenario accuracy with SDK error shaping.

Possibly related PRs

Suggested reviewers

  • baktun14
  • devalpatel67

Poem

🐇
I hopped from REST to gRPC bright,
Retries in cockatiel flight,
SDK in paw, I fetch with glee,
Certificates dance back to me,
Tiny rabbit, big network night.

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title 'feat: load certificate from gRPC' accurately reflects the main objective of replacing HTTP certificate retrieval with gRPC-based certificate loading using chain-sdk.
Linked Issues check ✅ Passed All objectives from issue #2188 are implemented: HTTP calls replaced with chain-sdk gRPC client [ProviderService.ts], environment variables updated from REST_API_NODE_URL to GRPC_NODE_URL, chain-sdk alpha version added as dependency, and read-only mode used without tx option.
Out of Scope Changes check ✅ Passed All code changes are directly related to implementing gRPC certificate loading: ProviderService refactoring, dependency additions (cockatiel for retry logic, chain-sdk), environment configuration updates, and corresponding test updates. No unrelated changes detected.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@codecov
Copy link

codecov bot commented Nov 19, 2025

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 48.18%. Comparing base (2a35102) to head (3d2ddef).
⚠️ Report is 2 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #2256      +/-   ##
==========================================
+ Coverage   47.60%   48.18%   +0.57%     
==========================================
  Files        1036     1022      -14     
  Lines       29356    29009     -347     
  Branches     7607     7527      -80     
==========================================
+ Hits        13976    13979       +3     
+ Misses      14978    14574     -404     
- Partials      402      456      +54     
Flag Coverage Δ *Carryforward flag
api 84.41% <ø> (+2.59%) ⬆️ Carriedforward from 35388a9
deploy-web 26.43% <ø> (+<0.01%) ⬆️ Carriedforward from 35388a9
log-collector 75.35% <ø> (ø)
notifications 93.39% <ø> (+5.45%) ⬆️ Carriedforward from 35388a9
provider-console 81.48% <ø> (ø)
provider-proxy 84.13% <100.00%> (-0.22%) ⬇️

*This pull request uses carry forward flags. Click here to find out more.

Files with missing lines Coverage Δ
apps/provider-proxy/src/config/env.config.ts 100.00% <ø> (ø)
apps/provider-proxy/src/container.ts 100.00% <100.00%> (ø)
...xy/src/services/ProviderService/ProviderService.ts 100.00% <100.00%> (+7.69%) ⬆️

... and 47 files with indirect coverage changes

🚀 New features to boost your workflow:
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@socket-security
Copy link

socket-security bot commented Nov 19, 2025

Review the following changes in direct dependencies. Learn more about Socket for GitHub.

Diff Package Supply Chain
Security
Vulnerability Quality Maintenance License
Added@​cosmjs/​amino@​0.36.21001007494100
Added@​cosmjs/​encoding@​0.36.21001007594100
Added@​akashnetwork/​chain-sdk@​1.0.0-alpha.188310010097100

View full report

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🧹 Nitpick comments (4)
apps/provider-proxy/test/setup/grpcServer.ts (2)

9-48: Consider using a protobuf library for encoding.

The manual protobuf encoding implementation works but is fragile and harder to maintain than using a protobuf library like protobufjs or the generated types from cosmjs-types. If the proto schema changes, these encoders will need manual updates.

For test code, this approach is acceptable if it reduces dependencies, but ensure the encoding format matches the actual chain-sdk expectations.


97-110: Document the limitations of regex-based proto parsing.

The regex-based extraction of requestedOwner and requestedSerial from the raw proto buffer is heuristic and fragile. It relies on the binary data containing readable UTF-8 strings, which may not always be true.

Potential issues:

  • Could match false positives in other proto fields
  • May break if proto encoding changes
  • Assumes specific string patterns in binary data

Since this is test infrastructure and appears to work for the current use case, this is acceptable. However, add a comment documenting these limitations so future maintainers understand the tradeoffs.

+        // Heuristic parsing: extract owner (bech32) and serial from UTF-8 representation
+        // This is fragile but sufficient for test mocking. May break if proto encoding changes.
         if (requestData.length > 5) {
           const protoData = requestData.slice(5);
apps/provider-proxy/src/services/ProviderService/ProviderService.ts (2)

25-33: Consider adding maxDelay to exponential backoff.

The exponential backoff could grow indefinitely. Consider adding a maxDelay parameter to cap the retry interval and prevent excessively long waits.

   private retryPolicy = retry(
     handleWhen(error => {
       return hasErrorCode(error) && RETRIABLE_ERROR_CODES.includes(error.code!);
     }),
     {
       maxAttempts: 3,
-      backoff: new ExponentialBackoff()
+      backoff: new ExponentialBackoff({ maxDelay: 5000 })
     }
   );

45-45: Validate serialNumber format before BigInt conversion.

If serialNumber contains invalid hex characters, the BigInt conversion will throw a SyntaxError. While the try-catch will prevent crashes, the error message won't clearly indicate the root cause.

Add validation before the query:

   async getCertificate(providerAddress: string, serialNumber: string): Promise<X509Certificate | null> {
+    if (!/^[0-9A-Fa-f]+$/.test(serialNumber)) {
+      this.logger?.error({ event: "INVALID_SERIAL_NUMBER", providerAddress, serialNumber });
+      return null;
+    }
+
     const queryParams: DeepPartial<QueryCertificatesRequest> = {
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e58863a and 1e81ba8.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (12)
  • apps/provider-proxy/env/.env (1 hunks)
  • apps/provider-proxy/env/.env.sample (1 hunks)
  • apps/provider-proxy/package.json (2 hunks)
  • apps/provider-proxy/src/config/env.config.ts (1 hunks)
  • apps/provider-proxy/src/container.ts (2 hunks)
  • apps/provider-proxy/src/services/ProviderService/ProviderService.spec.ts (2 hunks)
  • apps/provider-proxy/src/services/ProviderService/ProviderService.ts (1 hunks)
  • apps/provider-proxy/test/functional/provider-proxy-http.spec.ts (26 hunks)
  • apps/provider-proxy/test/functional/provider-proxy-ws.spec.ts (16 hunks)
  • apps/provider-proxy/test/setup/chainApiServer.ts (0 hunks)
  • apps/provider-proxy/test/setup/grpcServer.ts (1 hunks)
  • apps/provider-proxy/test/setup/providerServer.ts (1 hunks)
💤 Files with no reviewable changes (1)
  • apps/provider-proxy/test/setup/chainApiServer.ts
🧰 Additional context used
🧠 Learnings (5)
📚 Learning: 2025-11-19T15:15:07.266Z
Learnt from: ygrishajev
Repo: akash-network/console PR: 2254
File: apps/api/test/functional/sign-and-broadcast-tx.spec.ts:4-4
Timestamp: 2025-11-19T15:15:07.266Z
Learning: In the Akash Network Console project, when tests use native Node.js fetch (available in Node 18+), fetch-mock should be used for HTTP mocking instead of nock, as nock does not support intercepting native fetch calls. This applies to apps/api/test/functional/sign-and-broadcast-tx.spec.ts and any other tests using native fetch.

Applied to files:

  • apps/provider-proxy/test/functional/provider-proxy-ws.spec.ts
  • apps/provider-proxy/package.json
  • apps/provider-proxy/test/functional/provider-proxy-http.spec.ts
  • apps/provider-proxy/src/services/ProviderService/ProviderService.spec.ts
📚 Learning: 2025-09-25T20:34:55.117Z
Learnt from: jigar-arc10
Repo: akash-network/console PR: 1970
File: apps/provider-console/src/config/network.config.ts:17-28
Timestamp: 2025-09-25T20:34:55.117Z
Learning: In cosmos-kit integration, nodesUrl and versionUrl should point to Cosmos API endpoints (not console backend API endpoints) as cosmos-kit expects these to be Cosmos REST endpoints for proper functionality.

Applied to files:

  • apps/provider-proxy/env/.env.sample
  • apps/provider-proxy/env/.env
📚 Learning: 2025-09-04T04:27:50.638Z
Learnt from: stalniy
Repo: akash-network/console PR: 1868
File: apps/api/src/billing/services/managed-signer/managed-signer.service.ts:1-1
Timestamp: 2025-09-04T04:27:50.638Z
Learning: In the akash-network/console project, importing MsgCreateLease from "akashnetwork/akash-api/v1beta3" instead of v1beta4 is considered non-critical by the maintainers, likely due to backward compatibility or project-specific requirements.

Applied to files:

  • apps/provider-proxy/package.json
📚 Learning: 2025-11-12T09:03:40.132Z
Learnt from: stalniy
Repo: akash-network/console PR: 0
File: :0-0
Timestamp: 2025-11-12T09:03:40.132Z
Learning: For backend services (like the Indexer), prefer using createOtelLogger from "akashnetwork/logging/otel" to include OpenTelemetry trace context in logs.

Applied to files:

  • apps/provider-proxy/src/container.ts
📚 Learning: 2025-06-08T03:07:13.871Z
Learnt from: stalniy
Repo: akash-network/console PR: 1436
File: apps/api/src/provider/repositories/provider/provider.repository.ts:79-90
Timestamp: 2025-06-08T03:07:13.871Z
Learning: The getProvidersHostUriByAttributes method in apps/api/src/provider/repositories/provider/provider.repository.ts already has comprehensive test coverage in provider.repository.spec.ts, including tests for complex HAVING clause logic with COUNT(*) FILTER (WHERE ...) syntax, signature conditions (anyOf/allOf), and glob pattern matching.

Applied to files:

  • apps/provider-proxy/src/services/ProviderService/ProviderService.spec.ts
🧬 Code graph analysis (5)
apps/provider-proxy/test/functional/provider-proxy-ws.spec.ts (4)
apps/provider-proxy/test/setup/providerServer.ts (2)
  • stopProviderServer (73-75)
  • startProviderServer (14-71)
apps/provider-proxy/test/setup/proxyServer.ts (2)
  • stopServer (12-14)
  • startServer (7-10)
apps/provider-proxy/test/setup/grpcServer.ts (3)
  • stopGrpcServer (183-201)
  • generateBech32 (208-216)
  • startGrpcServer (50-181)
apps/provider-proxy/test/seeders/createX509CertPair.ts (1)
  • createX509CertPair (4-26)
apps/provider-proxy/test/functional/provider-proxy-http.spec.ts (4)
apps/provider-proxy/test/setup/proxyServer.ts (2)
  • stopServer (12-14)
  • startServer (7-10)
apps/provider-proxy/test/setup/providerServer.ts (2)
  • stopProviderServer (73-75)
  • startProviderServer (14-71)
apps/provider-proxy/test/setup/grpcServer.ts (3)
  • stopGrpcServer (183-201)
  • generateBech32 (208-216)
  • startGrpcServer (50-181)
apps/provider-proxy/test/seeders/createX509CertPair.ts (1)
  • createX509CertPair (4-26)
apps/provider-proxy/src/services/ProviderService/ProviderService.ts (1)
packages/logging/src/services/logger/logger.service.ts (1)
  • error (141-143)
apps/provider-proxy/src/container.ts (1)
apps/provider-proxy/src/services/ProviderService/ProviderService.ts (1)
  • ProviderService (24-73)
apps/provider-proxy/src/services/ProviderService/ProviderService.spec.ts (2)
apps/provider-proxy/src/services/ProviderService/ProviderService.ts (1)
  • ProviderService (24-73)
apps/provider-proxy/test/seeders/createX509CertPair.ts (2)
  • CertificateOptions (33-38)
  • createX509CertPair (4-26)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (14)
  • GitHub Check: validate / validate-app
  • GitHub Check: test-build
  • GitHub Check: validate / validate-app
  • GitHub Check: test-build
  • GitHub Check: validate / validate-app
  • GitHub Check: test-build
  • GitHub Check: validate / validate-app
  • GitHub Check: validate / validate-app
  • GitHub Check: test-build
  • GitHub Check: test-build
  • GitHub Check: test-build
  • GitHub Check: validate / validate-app
  • GitHub Check: test-build
  • GitHub Check: Socket Security: Pull Request Alerts
🔇 Additional comments (29)
apps/provider-proxy/package.json (2)

35-38: LGTM! Dependencies align well with the gRPC migration.

The new dependencies are appropriate:

  • cockatiel for resilient retry policies
  • cosmjs-types for Cosmos protobuf message types
  • long for handling 64-bit integers in gRPC responses

25-25: I'll now search for security advisories on this package to complete the verification.

Let me search more specifically for this npm package's vulnerability status.

Alpha version is available; no specific security advisories found for this package.

The version @akashnetwork/chain-sdk@1.0.0-alpha.18 exists in the npm registry. However, no known CVEs or security advisories were found for this specific package version. The original concern about production use of an alpha version is valid from a stability perspective, but this is a design/maturity decision rather than a security issue.

If the project requires this version for compatibility with the Akash Network chain, the alpha designation should be acceptable as long as the team is aware of potential breaking changes in future updates. Consider monitoring the package for updates to stable releases when available.

apps/provider-proxy/env/.env (1)

1-1: LGTM! Valid gRPC endpoint configuration.

The GRPC_NODE_URL correctly uses HTTPS scheme (gRPC over TLS/HTTP2) with standard port 443.

apps/provider-proxy/env/.env.sample (1)

1-1: LGTM! Sample configuration points to sandbox environment.

The sample GRPC_NODE_URL correctly points to the sandbox-2 environment with appropriate gRPC port 9090.

apps/provider-proxy/test/setup/providerServer.ts (1)

10-10: LGTM! Import path correctly updated for gRPC test infrastructure.

The import of generateBech32 is correctly moved from the old chain API server module to the new gRPC server module.

apps/provider-proxy/src/config/env.config.ts (1)

4-4: LGTM! Config schema correctly updated for gRPC.

The environment variable is properly renamed from REST_API_NODE_URL to GRPC_NODE_URL with URL validation maintained. Note that this is a breaking change requiring environment variable updates in deployment configurations.

apps/provider-proxy/src/container.ts (2)

1-1: LGTM! Correct import for the chain SDK client.

The createChainNodeSDK function is properly imported from the upgraded chain-sdk package.


17-24: LGTM! Service initialization correctly migrated to gRPC-based client.

The ProviderService is now initialized with a ChainNodeSDK client instead of REST URL and fetch function. This aligns perfectly with the PR objective to migrate from HTTP to gRPC for reduced latency and better type safety.

The configuration correctly:

  • Creates a ChainNodeSDK client with the gRPC endpoint
  • Removes the fetch dependency
  • Maintains logger integration
apps/provider-proxy/test/functional/provider-proxy-http.spec.ts (6)

8-8: LGTM! Test imports correctly updated for gRPC test infrastructure.

The imports are correctly updated to use the new gRPC server utilities (startGrpcServer, stopGrpcServer, generateBech32) replacing the old chain API server.


18-18: LGTM! Test cleanup correctly stops all servers including gRPC.

The afterEach hook properly cleans up all test servers including the new gRPC server.


25-27: LGTM! Test correctly uses gRPC server for certificate validation.

The test properly:

  • Starts the gRPC server with the valid certificate
  • Configures the proxy with the gRPC endpoint
  • Validates the proxied request succeeds

72-89: LGTM! Excellent test for cached certificate fallback.

This test validates that the proxy can continue operating with cached certificates even when the gRPC server becomes unavailable. This is important for resilience.


225-256: LGTM! Great test coverage for retry logic on gRPC unavailability.

This test validates the retry mechanism by:

  1. Starting a gRPC server to reserve the port
  2. Stopping it to simulate unavailability
  3. Making a request (which will retry)
  4. Restarting the server on the same port mid-retry
  5. Confirming the request succeeds

This ensures the retry policy works correctly with transient network issues.


258-291: LGTM! Excellent test for gRPC error code 14 retry logic.

This test validates that the proxy correctly retries when receiving gRPC error code 14 (UNAVAILABLE), which is a retriable error. The test uses an interceptor to simulate one failure before succeeding, confirming the retry policy works as expected.

apps/provider-proxy/src/services/ProviderService/ProviderService.spec.ts (9)

1-2: LGTM! Correct imports for gRPC-based testing.

The imports correctly bring in SDKError for testing error scenarios and the createChainNodeSDK type for proper mocking.


8-8: LGTM! Type extraction provides proper typing for mocks.

Extracting the ChainNodeSDK type from the return type of createChainNodeSDK ensures type safety in test mocks.


12-30: LGTM! Comprehensive test for no certificate found scenario.

The test correctly:

  • Mocks an empty certificate response
  • Verifies the query parameters (state, owner, serial, pagination)
  • Confirms null is returned when no certificate exists

The serial number conversion from hex to decimal is properly tested (177831BE7F249E66 → 1691156354324274790).


32-40: LGTM! Test validates single certificate retrieval.

The test correctly verifies that when exactly one certificate is found, it's returned with the correct serial number.


42-50: LGTM! Good edge case coverage for multiple certificates.

This test validates that when multiple certificates are returned (which shouldn't happen with limit=1, but could indicate a data issue), the service returns null for safety.


52-63: LGTM! Excellent test for retry success after transient failures.

This test validates that the retry policy:

  • Retries on gRPC error code 14 (UNAVAILABLE)
  • Eventually succeeds after transient failures
  • Makes exactly 3 calls (2 failures + 1 success)

74-81: LGTM! Correct behavior for non-retriable errors.

This test validates that errors other than code 14 (e.g., code 12 for UNIMPLEMENTED) are not retried, which is the correct behavior. The service fails fast and returns null immediately.


124-134: LGTM! Mock setup correctly reflects ChainNodeSDK structure.

The setup function properly mocks the nested structure of the ChainNodeSDK (akash.cert.v1.getCertificates), allowing individual test cases to override the getCertificates implementation.


136-138: LGTM! Certificate builder updated to match gRPC response format.

The certificate is now returned as a Buffer (from .toJSON()) instead of a base64 string, which aligns with the actual protobuf/gRPC response format.

apps/provider-proxy/test/functional/provider-proxy-ws.spec.ts (1)

8-307: LGTM! Test infrastructure migration is consistent.

All changes correctly migrate from the Chain API server to the gRPC server infrastructure. The test logic and assertions remain unchanged, which is appropriate.

apps/provider-proxy/test/setup/grpcServer.ts (2)

113-123: LGTM! Certificate matching logic is correct.

The serial number conversion from hex to decimal (line 116) correctly matches the reverse conversion in ProviderService.ts (line 45), and the optional matching logic handles null filters appropriately.


125-161: LGTM! gRPC response handling is properly implemented.

The gRPC framing (5-byte header + message) and response construction correctly handles both empty results and certificate responses with appropriate grpc-status codes.

apps/provider-proxy/src/services/ProviderService/ProviderService.ts (3)

62-66: LGTM! Retry policy correctly wraps the SDK call.

The type cast from DeepPartial to QueryCertificatesRequest is necessary and safe since all required fields are provided in the query parameters.


52-59: LGTM! Error handling with appropriate logging.

The error handling correctly logs failures with context (providerAddress, serialNumber, code) and returns null, which is appropriate for a certificate lookup operation. The retry policy already handles transient failures before reaching this catch block.


1-2: Verified: Import path is consistent with established codebase patterns.

The import path from @akashnetwork/chain-sdk/private-types/akash.v1 is widely used throughout the codebase across 17+ files (notifications, deploy-web, api, stats-web, and provider-proxy apps), indicating it is the standard and accepted way to access these types in this project. Despite extensive usage, there is no evidence of breakage. The project uses pre-release version 1.0.0-alpha.12, which is context appropriate for accepting this import pattern.

@jzsfkzm jzsfkzm force-pushed the features/2188-certificates-from-grpc branch 2 times, most recently from 7787709 to bd4e7ef Compare November 21, 2025 09:57
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

♻️ Duplicate comments (1)
apps/provider-proxy/src/services/ProviderService/ProviderService.spec.ts (1)

64-71: Inconsistent retry count expectation needs resolution.

The test expects 4 calls on line 70, but with maxAttempts: 3 in the retry policy (line 28 of ProviderService.ts), cockatiel will make only 3 total attempts (1 initial + 2 retries). A previous review comment indicated this should be changed from 4 to 3 and was marked "Addressed", but the code still shows 4.

Please verify the correct behavior and update accordingly:

-      expect(getCertificates).toHaveBeenCalledTimes(4);
+      expect(getCertificates).toHaveBeenCalledTimes(3);

Also consider updating the test description for clarity:

-    it("retries getCertificates() request 3 times and then fails in case of grpc-status=14", async () => {
+    it("attempts getCertificates() 3 times (maxAttempts) and then fails in case of grpc-status=14", async () => {
🧹 Nitpick comments (3)
apps/provider-proxy/src/services/ProviderService/ProviderService.spec.ts (1)

123-133: Consider extracting ChainNodeSDK type to avoid repetition.

The ChainNodeSDK type alias could be defined once at module level (line 7) and reused here, improving maintainability.

  function setup({ getCertificates }: { getCertificates?: ChainNodeSDK["akash"]["cert"]["v1"]["getCertificates"] } = {}) {
apps/provider-proxy/test/setup/chainApiServer.ts (1)

9-48: Manual protobuf encoding is functional but undocumented.

The manual protobuf encoding functions implement the necessary wire format for gRPC testing. Consider adding a comment explaining why manual encoding is used instead of a protobuf library.

// Manual protobuf encoding for test server to avoid heavy protobuf.js dependency
// Implements minimal wire format needed for Certificates response
function encodeVarint(value: number): Buffer {
apps/provider-proxy/src/services/ProviderService/ProviderService.ts (1)

64-68: Consider removing type cast if QueryInput types are correct.

The cast as QueryCertificatesRequest on line 66 suggests a potential type mismatch. If QueryInput<QueryCertificatesRequest> should be compatible with QueryCertificatesRequest, consider investigating why the cast is needed.

#!/bin/bash
# Check the QueryInput type definition in chain-sdk
ast-grep --pattern 'type QueryInput<$T> = $$$'
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 1e81ba8 and bd4e7ef.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (10)
  • apps/provider-proxy/env/.env (1 hunks)
  • apps/provider-proxy/env/.env.sample (1 hunks)
  • apps/provider-proxy/package.json (3 hunks)
  • apps/provider-proxy/src/config/env.config.ts (1 hunks)
  • apps/provider-proxy/src/container.ts (2 hunks)
  • apps/provider-proxy/src/services/ProviderService/ProviderService.spec.ts (2 hunks)
  • apps/provider-proxy/src/services/ProviderService/ProviderService.ts (1 hunks)
  • apps/provider-proxy/test/functional/provider-proxy-http.spec.ts (26 hunks)
  • apps/provider-proxy/test/functional/provider-proxy-ws.spec.ts (10 hunks)
  • apps/provider-proxy/test/setup/chainApiServer.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (3)
  • apps/provider-proxy/env/.env
  • apps/provider-proxy/test/functional/provider-proxy-ws.spec.ts
  • apps/provider-proxy/env/.env.sample
🧰 Additional context used
🧠 Learnings (4)
📚 Learning: 2025-11-12T09:03:40.132Z
Learnt from: stalniy
Repo: akash-network/console PR: 0
File: :0-0
Timestamp: 2025-11-12T09:03:40.132Z
Learning: For backend services (like the Indexer), prefer using createOtelLogger from "akashnetwork/logging/otel" to include OpenTelemetry trace context in logs.

Applied to files:

  • apps/provider-proxy/src/container.ts
📚 Learning: 2025-11-19T15:15:07.283Z
Learnt from: ygrishajev
Repo: akash-network/console PR: 2254
File: apps/api/test/functional/sign-and-broadcast-tx.spec.ts:4-4
Timestamp: 2025-11-19T15:15:07.283Z
Learning: In the Akash Network Console project, when tests use native Node.js fetch (available in Node 18+), fetch-mock should be used for HTTP mocking instead of nock, as nock does not support intercepting native fetch calls. This applies to apps/api/test/functional/sign-and-broadcast-tx.spec.ts and any other tests using native fetch.

Applied to files:

  • apps/provider-proxy/package.json
  • apps/provider-proxy/test/functional/provider-proxy-http.spec.ts
  • apps/provider-proxy/test/setup/chainApiServer.ts
  • apps/provider-proxy/src/services/ProviderService/ProviderService.spec.ts
📚 Learning: 2025-09-04T04:27:50.638Z
Learnt from: stalniy
Repo: akash-network/console PR: 1868
File: apps/api/src/billing/services/managed-signer/managed-signer.service.ts:1-1
Timestamp: 2025-09-04T04:27:50.638Z
Learning: In the akash-network/console project, importing MsgCreateLease from "akashnetwork/akash-api/v1beta3" instead of v1beta4 is considered non-critical by the maintainers, likely due to backward compatibility or project-specific requirements.

Applied to files:

  • apps/provider-proxy/package.json
📚 Learning: 2025-06-08T03:07:13.871Z
Learnt from: stalniy
Repo: akash-network/console PR: 1436
File: apps/api/src/provider/repositories/provider/provider.repository.ts:79-90
Timestamp: 2025-06-08T03:07:13.871Z
Learning: The getProvidersHostUriByAttributes method in apps/api/src/provider/repositories/provider/provider.repository.ts already has comprehensive test coverage in provider.repository.spec.ts, including tests for complex HAVING clause logic with COUNT(*) FILTER (WHERE ...) syntax, signature conditions (anyOf/allOf), and glob pattern matching.

Applied to files:

  • apps/provider-proxy/src/services/ProviderService/ProviderService.spec.ts
🧬 Code graph analysis (4)
apps/provider-proxy/src/container.ts (1)
apps/provider-proxy/src/services/ProviderService/ProviderService.ts (1)
  • ProviderService (22-75)
apps/provider-proxy/src/services/ProviderService/ProviderService.ts (1)
packages/logging/src/services/logger/logger.service.ts (1)
  • error (141-143)
apps/provider-proxy/test/functional/provider-proxy-http.spec.ts (4)
apps/provider-proxy/test/setup/proxyServer.ts (2)
  • stopServer (12-14)
  • startServer (7-10)
apps/provider-proxy/test/setup/providerServer.ts (2)
  • stopProviderServer (73-75)
  • startProviderServer (14-71)
apps/provider-proxy/test/setup/chainApiServer.ts (3)
  • stopChainApiServer (183-201)
  • generateBech32 (208-216)
  • startChainApiServer (50-181)
apps/provider-proxy/test/seeders/createX509CertPair.ts (1)
  • createX509CertPair (4-26)
apps/provider-proxy/src/services/ProviderService/ProviderService.spec.ts (2)
apps/provider-proxy/src/services/ProviderService/ProviderService.ts (1)
  • ProviderService (22-75)
apps/provider-proxy/test/seeders/createX509CertPair.ts (2)
  • CertificateOptions (33-38)
  • createX509CertPair (4-26)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: validate / validate-app
  • GitHub Check: validate / validate-app
🔇 Additional comments (10)
apps/provider-proxy/src/config/env.config.ts (1)

4-4: LGTM! Clean environment variable migration.

The rename from REST_API_NODE_URL to GRPC_NODE_URL properly reflects the architectural shift to gRPC-based communication.

apps/provider-proxy/test/functional/provider-proxy-http.spec.ts (2)

8-8: LGTM! Consistent test migration to gRPC terminology.

All test scaffolding properly updated to use gRPC naming conventions (grpcServer, stopChainApiServer, GRPC_NODE_URL) while preserving test logic.

Also applies to: 18-18, 25-27, 50-52


265-274: No issues found—callback signature correctly aligns with the updated interface.

The interface definition in chainApiServer.ts specifies interceptRequest?: () => boolean, which precisely matches the test implementation at lines 265-274 where the callback takes no parameters and returns a boolean value. The change is correct.

apps/provider-proxy/src/container.ts (1)

17-24: LGTM! Clean Chain SDK integration.

The container properly instantiates the Chain SDK client with the gRPC endpoint and passes it to ProviderService, replacing the previous REST-based approach.

apps/provider-proxy/src/services/ProviderService/ProviderService.spec.ts (1)

11-29: LGTM! Test properly validates empty certificate response.

The test correctly mocks an empty certificates array and verifies null is returned, with proper query parameter construction including hex-to-decimal serial conversion.

apps/provider-proxy/test/setup/chainApiServer.ts (2)

50-181: LGTM! HTTP/2 server implementation for gRPC testing.

The HTTP/2-based test server properly implements gRPC-style framing and certificate lookup logic, with appropriate session cleanup and error handling.


203-206: Signature change is properly integrated across all call sites.

Verification confirms the interceptRequest signature change from (req, res) => boolean to () => boolean has been fully applied:

  • Call site (line 65): Invoked as options?.interceptRequest?.() with no arguments
  • Implementation (line 267): Defined as interceptRequest() { ... } with no parameters
  • Interface (line 205): Typed as interceptRequest?: () => boolean
  • Scope: Used only in test code; no production usages require updating

All locations are consistent and correctly updated.

apps/provider-proxy/src/services/ProviderService/ProviderService.ts (2)

23-31: LGTM! Well-structured retry policy with exponential backoff.

The retry configuration properly handles transient gRPC errors (internal and unavailable) with bounded retries and exponential backoff.


38-62: LGTM! Robust certificate fetching with proper error handling.

The implementation correctly:

  • Constructs the query with hex-to-decimal serial conversion
  • Uses safe optional chaining for certificate extraction
  • Logs errors with full context
  • Returns null on any failure (defensive)
apps/provider-proxy/package.json (1)

25-25: Review verification inconclusive—manual check recommended.

The version jump from alpha.12 to alpha.18 (6 intermediate versions) is real and confirmed in provider-proxy/package.json. The codebase imports JwtTokenManager, createChainNodeSDK, and type definitions from chain-sdk, but definitive breaking change documentation for alpha.13→alpha.18 could not be retrieved.

The package is already at alpha.18, suggesting either migration is complete or not yet tested. Verify that:

  • Intermediate version breaking changes (if any) were handled
  • Test suite passes with alpha.18
  • No API incompatibilities remain in ProviderService.ts, container.ts, or schema.ts

@jzsfkzm jzsfkzm force-pushed the features/2188-certificates-from-grpc branch from bd4e7ef to d54cd43 Compare November 24, 2025 15:14
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

♻️ Duplicate comments (2)
apps/provider-proxy/src/services/ProviderService/ProviderService.spec.ts (1)

64-71: Retry-count assertion doesn’t match cockatiel’s maxAttempts semantics

In it("retries getCertificates() request 3 times and then fails in case of grpc-status=14"), ProviderService is configured with maxAttempts: 3, and cockatiel interprets that as the total number of attempts (initial call included). So for a permanent SDKError("unavailable", 14) you should see 3 calls, not 4.

The current assertion:

expect(getCertificates).toHaveBeenCalledTimes(4);

is inconsistent with that and with the previous test that correctly expects 3 calls after two failures and a success. I’d change it to:

-      expect(getCertificates).toHaveBeenCalledTimes(4);
+      expect(getCertificates).toHaveBeenCalledTimes(3);

(and optionally tweak the test title to say “retries up to maxAttempts and then fails” to avoid confusion about “3 times” vs “3 total attempts”).

apps/provider-proxy/src/services/ProviderService/ProviderService.ts (1)

9-20: Limit retries to UNAVAILABLE (14), avoid auto‑retrying INTERNAL (13).

Including gRPC INTERNAL (13) in RETRIABLE_ERROR_CODES risks hiding real server/implementation bugs; typically only UNAVAILABLE (14) is treated as transient and retried. I’d strongly suggest restricting retries to 14 here and investigating why 13 is being observed when the service is down instead of broadening the retriable set.

A minimal change would be:

-const RETRIABLE_ERROR_CODES = [
-  13, // internal
-  14 // unavailable
-];
+const RETRIABLE_ERROR_CODES = [
+  14 // unavailable
+];

You may also want to additionally guard that error.code is a number before checking includes to avoid surprising matches from non‑gRPC errors.

🧹 Nitpick comments (3)
apps/provider-proxy/src/services/ProviderService/ProviderService.spec.ts (1)

1-8: Prefer a direct ChainNodeSDK type instead of import type createChainNodeSDK + ReturnType

Here you import createChainNodeSDK as a type and then use ReturnType<typeof createChainNodeSDK> to define ChainNodeSDK. That’s a bit round‑about and, depending on TS configuration, mixing import type with typeof on the same symbol can be brittle.

If @akashnetwork/chain-sdk exposes a ChainNodeSDK type, I’d strongly prefer:

import type { ChainNodeSDK } from "@akashnetwork/chain-sdk";

and drop the ReturnType indirection. If it doesn’t, consider a normal value import of createChainNodeSDK for the type query instead of import type.

Also applies to: 123-133

apps/provider-proxy/test/setup/chainApiServer.ts (1)

6-8: Optionally clear sessions on shutdown to avoid stale references

Both the close function returned from startChainApiServer and stopChainApiServer destroy every entry in the global sessions array but never reset the array itself. Over many test runs this can leave a growing list of stale ServerHttp2Session references.

Not a functional bug in this test harness, but you could add sessions.length = 0; after the sessions.forEach(session => session.destroy()); blocks to keep the state clean between server lifecycles.

Also applies to: 170-177, 188-200

apps/provider-proxy/src/services/ProviderService/ProviderService.ts (1)

38-48: Tighten serial parsing error handling and align QueryInput typing with the SDK.

Two small follow‑ups to consider:

  1. Serial parsing can throw before the try block.
    BigInt(\0x${serialNumber}`)will throw on malformed input, and that happens before yourtry/catch, so such errors won’t be logged as CERTIFICATE_FETCH_ERROR. Parsing the serial inside a try/catch(and logging/returningnull` on failure) would keep error reporting consistent and prevent unexpected rejections from bad input.

  2. Avoid the as QueryCertificatesRequest cast in fetchCertificate.
    fetchCertificate accepts QueryInput<QueryCertificatesRequest> but then casts to QueryCertificatesRequest for the SDK call:

    return await this.chainSdkClient.akash.cert.v1.getCertificates(
      getCertificatesParams as QueryCertificatesRequest
    );

    To preserve the stronger typings you get from QueryInput, it’s better to align this with the actual chain-sdk signature and drop the cast. For example, if getCertificates indeed expects a QueryInput<QueryCertificatesRequest>, you can do:

  • private async fetchCertificate(getCertificatesParams: QueryInput): Promise {
  • return this.retryPolicy.execute(async () => {
  •  return await this.chainSdkClient.akash.cert.v1.getCertificates(getCertificatesParams as QueryCertificatesRequest);
    
  • });
  • }
  • private async fetchCertificate(
  • getCertificatesParams: QueryInput
  • ): Promise {
  • return this.retryPolicy.execute(async () => {
  •  return await this.chainSdkClient.akash.cert.v1.getCertificates(getCertificatesParams);
    
  • });
  • }
    
    If the SDK method instead truly expects a plain `QueryCertificatesRequest`, consider changing the parameter type of `fetchCertificate` to that and building the exact shape there, rather than casting.
    
    

These are mainly about robustness and type‑safety; the overall flow and certificate extraction logic otherwise look good.

Also applies to: 50-62, 64-67

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between bd4e7ef and d54cd43.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (10)
  • apps/provider-proxy/env/.env (1 hunks)
  • apps/provider-proxy/env/.env.sample (1 hunks)
  • apps/provider-proxy/package.json (3 hunks)
  • apps/provider-proxy/src/config/env.config.ts (1 hunks)
  • apps/provider-proxy/src/container.ts (2 hunks)
  • apps/provider-proxy/src/services/ProviderService/ProviderService.spec.ts (2 hunks)
  • apps/provider-proxy/src/services/ProviderService/ProviderService.ts (1 hunks)
  • apps/provider-proxy/test/functional/provider-proxy-http.spec.ts (26 hunks)
  • apps/provider-proxy/test/functional/provider-proxy-ws.spec.ts (10 hunks)
  • apps/provider-proxy/test/setup/chainApiServer.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (4)
  • apps/provider-proxy/env/.env.sample
  • apps/provider-proxy/src/config/env.config.ts
  • apps/provider-proxy/env/.env
  • apps/provider-proxy/test/functional/provider-proxy-http.spec.ts
🧰 Additional context used
🧠 Learnings (6)
📚 Learning: 2025-11-19T15:15:07.283Z
Learnt from: ygrishajev
Repo: akash-network/console PR: 2254
File: apps/api/test/functional/sign-and-broadcast-tx.spec.ts:4-4
Timestamp: 2025-11-19T15:15:07.283Z
Learning: In the Akash Network Console project, when tests use native Node.js fetch (available in Node 18+), fetch-mock should be used for HTTP mocking instead of nock, as nock does not support intercepting native fetch calls. This applies to apps/api/test/functional/sign-and-broadcast-tx.spec.ts and any other tests using native fetch.

Applied to files:

  • apps/provider-proxy/package.json
  • apps/provider-proxy/test/setup/chainApiServer.ts
  • apps/provider-proxy/test/functional/provider-proxy-ws.spec.ts
  • apps/provider-proxy/src/services/ProviderService/ProviderService.spec.ts
📚 Learning: 2025-09-04T04:27:50.638Z
Learnt from: stalniy
Repo: akash-network/console PR: 1868
File: apps/api/src/billing/services/managed-signer/managed-signer.service.ts:1-1
Timestamp: 2025-09-04T04:27:50.638Z
Learning: In the akash-network/console project, importing MsgCreateLease from "akashnetwork/akash-api/v1beta3" instead of v1beta4 is considered non-critical by the maintainers, likely due to backward compatibility or project-specific requirements.

Applied to files:

  • apps/provider-proxy/package.json
📚 Learning: 2025-10-31T11:26:42.138Z
Learnt from: stalniy
Repo: akash-network/console PR: 2138
File: apps/api/src/billing/lib/batch-signing-client/batch-signing-client.service.ts:379-382
Timestamp: 2025-10-31T11:26:42.138Z
Learning: In TypeScript/JavaScript, the pattern of checking a cached value and then performing an async operation to fetch it without proper synchronization is race condition unsafe:
```typescript
private async getAddress() {
  if (!this.address) {
    this.address = await this.wallet.getFirstAddress();
  }
  return this.address;
}
```
Multiple concurrent calls can all pass the `if (!this.address)` check before any of them sets the value, leading to duplicate async operations. This should be flagged as a race condition. Proper synchronization (mutex, atomic promise caching, or guaranteed single-threaded execution) is required.

Applied to files:

  • apps/provider-proxy/test/setup/chainApiServer.ts
📚 Learning: 2025-09-04T04:27:40.858Z
Learnt from: stalniy
Repo: akash-network/console PR: 1868
File: apps/api/src/billing/services/managed-signer/managed-signer.service.ts:98-107
Timestamp: 2025-09-04T04:27:40.858Z
Learning: In the Akash protocol, when processing MsgCreateLease messages, the bidId.dseq field is always required and guaranteed to be present at runtime, even though TypeScript types may suggest it could be undefined. The non-null assertion operator (!) is appropriate to use in this context.

Applied to files:

  • apps/provider-proxy/test/setup/chainApiServer.ts
📚 Learning: 2025-11-12T09:03:40.132Z
Learnt from: stalniy
Repo: akash-network/console PR: 0
File: :0-0
Timestamp: 2025-11-12T09:03:40.132Z
Learning: For backend services (like the Indexer), prefer using createOtelLogger from "akashnetwork/logging/otel" to include OpenTelemetry trace context in logs.

Applied to files:

  • apps/provider-proxy/src/container.ts
📚 Learning: 2025-06-08T03:07:13.871Z
Learnt from: stalniy
Repo: akash-network/console PR: 1436
File: apps/api/src/provider/repositories/provider/provider.repository.ts:79-90
Timestamp: 2025-06-08T03:07:13.871Z
Learning: The getProvidersHostUriByAttributes method in apps/api/src/provider/repositories/provider/provider.repository.ts already has comprehensive test coverage in provider.repository.spec.ts, including tests for complex HAVING clause logic with COUNT(*) FILTER (WHERE ...) syntax, signature conditions (anyOf/allOf), and glob pattern matching.

Applied to files:

  • apps/provider-proxy/src/services/ProviderService/ProviderService.spec.ts
🧬 Code graph analysis (4)
apps/provider-proxy/src/container.ts (1)
apps/provider-proxy/src/services/ProviderService/ProviderService.ts (1)
  • ProviderService (22-75)
apps/provider-proxy/src/services/ProviderService/ProviderService.ts (1)
packages/logging/src/services/logger/logger.service.ts (1)
  • error (141-143)
apps/provider-proxy/test/functional/provider-proxy-ws.spec.ts (3)
apps/provider-proxy/test/setup/proxyServer.ts (2)
  • stopServer (12-14)
  • startServer (7-10)
apps/provider-proxy/test/setup/providerServer.ts (1)
  • stopProviderServer (73-75)
apps/provider-proxy/test/setup/chainApiServer.ts (1)
  • stopChainApiServer (183-201)
apps/provider-proxy/src/services/ProviderService/ProviderService.spec.ts (3)
apps/provider-proxy/src/services/ProviderService/ProviderService.ts (1)
  • ProviderService (22-75)
packages/http-sdk/src/certificates/certificates.service.ts (1)
  • getCertificates (25-37)
apps/provider-proxy/test/seeders/createX509CertPair.ts (2)
  • CertificateOptions (33-38)
  • createX509CertPair (4-26)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (14)
  • GitHub Check: log-collector-ci
  • GitHub Check: validate (packages) / validate-unsafe
  • GitHub Check: test-build
  • GitHub Check: validate / validate-app
  • GitHub Check: test-build
  • GitHub Check: validate / validate-app
  • GitHub Check: test-build
  • GitHub Check: test-build
  • GitHub Check: validate / validate-app
  • GitHub Check: test-build
  • GitHub Check: validate / validate-app
  • GitHub Check: test-build
  • GitHub Check: validate / validate-app
  • GitHub Check: test-build
🔇 Additional comments (5)
apps/provider-proxy/package.json (1)

25-25: Deps bump aligns with new ChainNodeSDK + retry plumbing

Bumping @akashnetwork/chain-sdk and adding cockatiel/ts-node lines up with the new gRPC-based ProviderService and retry logic; nothing concerning here.

Also applies to: 35-35, 65-65

apps/provider-proxy/test/functional/provider-proxy-ws.spec.ts (1)

8-15: Teardown and GRPC wiring look consistent

Using afterEach(async () => await Promise.all([...])) to stop proxy, provider, and chain API servers, plus switching startServer to GRPC_NODE_URL: chainServer.url, matches the new ChainNodeSDK/gRPC flow and keeps the tests’ lifecycle symmetrical. Looks good.

Also applies to: 37-37, 68-68, 88-88, 116-116, 139-139, 167-167, 194-195, 242-242, 305-305

apps/provider-proxy/src/container.ts (1)

1-1: ProviderService wiring with ChainNodeSDK looks correct

Constructing ProviderService with createChainNodeSDK({ query: { baseUrl: appConfig.GRPC_NODE_URL } }) fits the new gRPC-based, read-only usage and centralizes the SDK client in the container; I don’t see issues here. It’s only worth double‑checking against the current chain‑sdk docs that query.baseUrl is indeed the expected knob for the HTTP/2 gRPC endpoint in 1.0.0-alpha.18.

Also applies to: 17-24

apps/provider-proxy/src/services/ProviderService/ProviderService.spec.ts (1)

135-137: Ignore this review comment—it is based on incorrect assumptions about the Node.js crypto API.

The review incorrectly claims that X509Certificate.toJSON() returns "a plain object." Per Node.js documentation, toJSON() actually returns a string containing the PEM-encoded certificate. The current implementation is correct:

  • createX509CertPair(params).cert.toJSON() returns a PEM string
  • Buffer.from(pem_string) successfully creates a buffer from the UTF-8 string
  • new X509Certificate(cert_buffer) in ProviderService.getCertificate successfully parses it

The production test setup in providerServer.ts (line 19) further confirms this works: it uses cert: certPair.cert.toJSON() directly in https.ServerOptions. The code is functioning as intended.

Likely an incorrect or invalid review comment.

apps/provider-proxy/src/services/ProviderService/ProviderService.ts (1)

23-31: Retry policy integration around getCertificates looks appropriate.

Using a shared retryPolicy with maxAttempts: 3 and exponential backoff around the read‑only getCertificates call is a good fit here; the encapsulation in fetchCertificate keeps getCertificate clean and focused, and I don’t see functional issues in how the policy is wired and executed.

Also applies to: 64-67

@jzsfkzm jzsfkzm force-pushed the features/2188-certificates-from-grpc branch from d54cd43 to 0c502e8 Compare November 26, 2025 17:40
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

♻️ Duplicate comments (1)
apps/provider-proxy/src/services/ProviderService/ProviderService.ts (1)

9-12: Remove error code 13 from RETRIABLE_ERROR_CODES.

gRPC INTERNAL (code 13) represents serious invariant/implementation errors that should not be automatically retried. Only UNAVAILABLE (code 14) is the canonical transient code for retries per gRPC best practices.

 const RETRIABLE_ERROR_CODES = [
-  13, // internal
   14 // unavailable
 ];
🧹 Nitpick comments (2)
apps/provider-proxy/test/setup/chainApiServer.ts (2)

7-8: Sessions array is never cleared after server shutdown.

The sessions array accumulates ServerHttp2Session references that are destroyed but never removed. If tests restart the server multiple times within the same process, the array grows with stale references.

Consider clearing the array after destroying sessions:

  return new Promise<void>((resolve, reject) => {
    sessions.forEach(session => {
      session.destroy();
    });
+   sessions.length = 0;

    grpcServer?.close(error => {

85-94: Duplicate session cleanup logic.

The session destruction logic here duplicates what's in stopChainApiServer (lines 106-108). Consider extracting to a shared helper to maintain consistency.

+function destroyAllSessions() {
+  sessions.forEach(session => session.destroy());
+  sessions.length = 0;
+}
+
 // In close callback:
-        close: () =>
-          new Promise<void>((resolve, reject) => {
-            sessions.forEach(session => {
-              session.destroy();
-            });
-
-            server.close(error => {
-              error ? reject(error) : resolve();
-            });
-          })
+        close: () =>
+          new Promise<void>((resolve, reject) => {
+            destroyAllSessions();
+            server.close(error => {
+              error ? reject(error) : resolve();
+            });
+          })
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between d54cd43 and 0c502e8.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (12)
  • apps/provider-proxy/env/.env.mainnet (1 hunks)
  • apps/provider-proxy/env/.env.sample (1 hunks)
  • apps/provider-proxy/env/.env.sandbox (1 hunks)
  • apps/provider-proxy/package.json (2 hunks)
  • apps/provider-proxy/src/config/env.config.ts (1 hunks)
  • apps/provider-proxy/src/container.ts (2 hunks)
  • apps/provider-proxy/src/services/ProviderService/ProviderService.spec.ts (2 hunks)
  • apps/provider-proxy/src/services/ProviderService/ProviderService.ts (1 hunks)
  • apps/provider-proxy/test/functional/provider-proxy-http.spec.ts (26 hunks)
  • apps/provider-proxy/test/functional/provider-proxy-ws.spec.ts (10 hunks)
  • apps/provider-proxy/test/setup/chainApiServer.ts (1 hunks)
  • apps/provider-proxy/test/setup/proxyServer.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • apps/provider-proxy/env/.env.sample
🧰 Additional context used
📓 Path-based instructions (2)
**/*.{ts,tsx,js}

📄 CodeRabbit inference engine (.cursor/rules/general.mdc)

**/*.{ts,tsx,js}: Never use type any or cast to type any. Always define the proper TypeScript types.
Never use deprecated methods from libraries.
Don't add unnecessary comments to the code.

Files:

  • apps/provider-proxy/src/container.ts
  • apps/provider-proxy/test/functional/provider-proxy-http.spec.ts
  • apps/provider-proxy/test/setup/proxyServer.ts
  • apps/provider-proxy/src/config/env.config.ts
  • apps/provider-proxy/test/functional/provider-proxy-ws.spec.ts
  • apps/provider-proxy/src/services/ProviderService/ProviderService.ts
  • apps/provider-proxy/test/setup/chainApiServer.ts
  • apps/provider-proxy/src/services/ProviderService/ProviderService.spec.ts
**/*.spec.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/no-jest-mock.mdc)

Don't use jest.mock() in test files. Instead, use jest-mock-extended to create mocks and pass mocks as dependencies to the service under test

Use setup function instead of beforeEach in test files. The setup function must be at the bottom of the root describe block, should create an object under test and return it, accept a single parameter with inline type definition, avoid shared state, and not have a specified return type.

**/*.spec.{ts,tsx}: Use <Subject>.name in the root describe suite description instead of hardcoded class/service name strings to enable automated refactoring tools to find all references
Use either a method name or a condition starting with 'when' for nested suite descriptions in tests
Use present simple, 3rd person singular for test descriptions without prepending 'should'

Files:

  • apps/provider-proxy/test/functional/provider-proxy-http.spec.ts
  • apps/provider-proxy/test/functional/provider-proxy-ws.spec.ts
  • apps/provider-proxy/src/services/ProviderService/ProviderService.spec.ts
🧠 Learnings (8)
📚 Learning: 2025-11-19T15:15:07.283Z
Learnt from: ygrishajev
Repo: akash-network/console PR: 2254
File: apps/api/test/functional/sign-and-broadcast-tx.spec.ts:4-4
Timestamp: 2025-11-19T15:15:07.283Z
Learning: In the Akash Network Console project, when tests use native Node.js fetch (available in Node 18+), fetch-mock should be used for HTTP mocking instead of nock, as nock does not support intercepting native fetch calls. This applies to apps/api/test/functional/sign-and-broadcast-tx.spec.ts and any other tests using native fetch.

Applied to files:

  • apps/provider-proxy/package.json
  • apps/provider-proxy/test/functional/provider-proxy-http.spec.ts
  • apps/provider-proxy/test/functional/provider-proxy-ws.spec.ts
  • apps/provider-proxy/test/setup/chainApiServer.ts
  • apps/provider-proxy/src/services/ProviderService/ProviderService.spec.ts
📚 Learning: 2025-09-04T04:27:50.638Z
Learnt from: stalniy
Repo: akash-network/console PR: 1868
File: apps/api/src/billing/services/managed-signer/managed-signer.service.ts:1-1
Timestamp: 2025-09-04T04:27:50.638Z
Learning: In the akash-network/console project, importing MsgCreateLease from "akashnetwork/akash-api/v1beta3" instead of v1beta4 is considered non-critical by the maintainers, likely due to backward compatibility or project-specific requirements.

Applied to files:

  • apps/provider-proxy/package.json
📚 Learning: 2025-09-25T20:34:55.117Z
Learnt from: jigar-arc10
Repo: akash-network/console PR: 1970
File: apps/provider-console/src/config/network.config.ts:17-28
Timestamp: 2025-09-25T20:34:55.117Z
Learning: In cosmos-kit integration, nodesUrl and versionUrl should point to Cosmos API endpoints (not console backend API endpoints) as cosmos-kit expects these to be Cosmos REST endpoints for proper functionality.

Applied to files:

  • apps/provider-proxy/env/.env.sandbox
  • apps/provider-proxy/env/.env.mainnet
📚 Learning: 2025-11-12T09:03:40.132Z
Learnt from: stalniy
Repo: akash-network/console PR: 0
File: :0-0
Timestamp: 2025-11-12T09:03:40.132Z
Learning: For backend services (like the Indexer), prefer using createOtelLogger from "akashnetwork/logging/otel" to include OpenTelemetry trace context in logs.

Applied to files:

  • apps/provider-proxy/src/container.ts
📚 Learning: 2025-11-25T17:45:58.258Z
Learnt from: CR
Repo: akash-network/console PR: 0
File: .cursor/rules/test-descriptions.mdc:0-0
Timestamp: 2025-11-25T17:45:58.258Z
Learning: Applies to **/*.spec.{ts,tsx} : Use `<Subject>.name` in the root describe suite description instead of hardcoded class/service name strings to enable automated refactoring tools to find all references

Applied to files:

  • apps/provider-proxy/test/functional/provider-proxy-http.spec.ts
  • apps/provider-proxy/test/functional/provider-proxy-ws.spec.ts
📚 Learning: 2025-11-25T17:45:49.180Z
Learnt from: CR
Repo: akash-network/console PR: 0
File: .cursor/rules/query-by-in-tests.mdc:0-0
Timestamp: 2025-11-25T17:45:49.180Z
Learning: Applies to {apps/deploy-web,apps/provider-console}/**/*.spec.tsx : Use `queryBy` methods instead of `getBy` methods in test expectations

Applied to files:

  • apps/provider-proxy/test/functional/provider-proxy-ws.spec.ts
📚 Learning: 2025-10-31T11:26:42.138Z
Learnt from: stalniy
Repo: akash-network/console PR: 2138
File: apps/api/src/billing/lib/batch-signing-client/batch-signing-client.service.ts:379-382
Timestamp: 2025-10-31T11:26:42.138Z
Learning: In TypeScript/JavaScript, the pattern of checking a cached value and then performing an async operation to fetch it without proper synchronization is race condition unsafe:
```typescript
private async getAddress() {
  if (!this.address) {
    this.address = await this.wallet.getFirstAddress();
  }
  return this.address;
}
```
Multiple concurrent calls can all pass the `if (!this.address)` check before any of them sets the value, leading to duplicate async operations. This should be flagged as a race condition. Proper synchronization (mutex, atomic promise caching, or guaranteed single-threaded execution) is required.

Applied to files:

  • apps/provider-proxy/test/setup/chainApiServer.ts
📚 Learning: 2025-06-08T03:07:13.871Z
Learnt from: stalniy
Repo: akash-network/console PR: 1436
File: apps/api/src/provider/repositories/provider/provider.repository.ts:79-90
Timestamp: 2025-06-08T03:07:13.871Z
Learning: The getProvidersHostUriByAttributes method in apps/api/src/provider/repositories/provider/provider.repository.ts already has comprehensive test coverage in provider.repository.spec.ts, including tests for complex HAVING clause logic with COUNT(*) FILTER (WHERE ...) syntax, signature conditions (anyOf/allOf), and glob pattern matching.

Applied to files:

  • apps/provider-proxy/src/services/ProviderService/ProviderService.spec.ts
🧬 Code graph analysis (5)
apps/provider-proxy/test/functional/provider-proxy-http.spec.ts (4)
apps/provider-proxy/test/setup/proxyServer.ts (2)
  • stopServer (12-14)
  • startServer (7-10)
apps/provider-proxy/test/setup/providerServer.ts (2)
  • stopProviderServer (73-75)
  • startProviderServer (14-71)
apps/provider-proxy/test/setup/chainApiServer.ts (3)
  • stopChainApiServer (100-118)
  • generateBech32 (125-133)
  • startChainApiServer (10-98)
apps/provider-proxy/test/seeders/createX509CertPair.ts (1)
  • createX509CertPair (4-26)
apps/provider-proxy/test/setup/proxyServer.ts (2)
apps/api/src/core/services/start-server/start-server.ts (1)
  • startServer (18-64)
apps/provider-proxy/src/config/env.config.ts (1)
  • AppConfig (8-8)
apps/provider-proxy/test/functional/provider-proxy-ws.spec.ts (3)
apps/provider-proxy/test/setup/proxyServer.ts (2)
  • stopServer (12-14)
  • startServer (7-10)
apps/provider-proxy/test/setup/providerServer.ts (1)
  • stopProviderServer (73-75)
apps/provider-proxy/test/setup/chainApiServer.ts (1)
  • stopChainApiServer (100-118)
apps/provider-proxy/src/services/ProviderService/ProviderService.ts (1)
packages/logging/src/services/logger/logger.service.ts (1)
  • error (141-143)
apps/provider-proxy/src/services/ProviderService/ProviderService.spec.ts (3)
apps/provider-proxy/src/services/ProviderService/ProviderService.ts (1)
  • ProviderService (22-75)
packages/http-sdk/src/certificates/certificates.service.ts (1)
  • getCertificates (25-37)
apps/provider-proxy/test/seeders/createX509CertPair.ts (2)
  • CertificateOptions (33-38)
  • createX509CertPair (4-26)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (16)
  • GitHub Check: validate (apps/notifications) / validate-unsafe
  • GitHub Check: validate (apps/provider-console) / validate-unsafe
  • GitHub Check: validate (apps/log-collector) / validate-unsafe
  • GitHub Check: validate (apps/indexer) / validate-unsafe
  • GitHub Check: validate / validate-app
  • GitHub Check: test-build
  • GitHub Check: test-build
  • GitHub Check: validate / validate-app
  • GitHub Check: test-build
  • GitHub Check: validate / validate-app
  • GitHub Check: test-build
  • GitHub Check: test-build
  • GitHub Check: validate / validate-app
  • GitHub Check: test-build
  • GitHub Check: validate / validate-app
  • GitHub Check: test-build
🔇 Additional comments (27)
apps/provider-proxy/package.json (2)

25-35: LGTM on dependency updates.

The @akashnetwork/chain-sdk version bump to 1.0.0-alpha.18 and the addition of cockatiel for retry logic align with the PR objective to migrate to gRPC-based Chain SDK calls.


29-29: The review comment's premise appears to be incorrect.

Based on web search results, @cosmjs/encoding is a standalone utility package providing encoding/decoding helpers (bech32, hex, base64, utf8) essential for CosmJS-based applications. The claim that it's redundant because "chain-sdk provides all cosmjs types" is not accurate—chain-sdk is a separate, independent Node SDK unrelated to the CosmJS ecosystem, and @cosmjs/encoding provides utility functions rather than just types. This dependency should likely remain.

apps/provider-proxy/test/setup/proxyServer.ts (1)

7-10: LGTM!

Using Partial<AppConfig> provides appropriate flexibility for test setup, allowing tests to specify only the configuration properties they need while still enforcing PORT: 0 for dynamic port allocation.

apps/provider-proxy/src/services/ProviderService/ProviderService.spec.ts (3)

123-133: Setup function follows coding guidelines.

The setup function is correctly placed at the bottom of the describe block, accepts a single parameter with inline type definition, and returns the object under test. This aligns with the coding guidelines for test files.


11-29: Test structure and assertions are well-designed.

The test correctly verifies:

  • Query parameters structure including the hex-to-decimal serial number conversion
  • The expected null return value when no certificates are found
  • Proper mocking of the getCertificates function

64-71: Based on the cockatiel documentation, I've found the key detail:

maxAttempts is the total number of attempts (including the initial try). Retries performed = maxAttempts − 1.

This means:

  • maxAttempts: 3 = 1 initial attempt + 2 retries = 3 total function calls
  • The test expects 4 calls at line 70

This indicates a mismatch between the test expectation and what maxAttempts: 3 should produce.

However, I cannot access the repository to verify:

  1. Whether ProviderService actually uses maxAttempts: 3 or something else
  2. Whether the past review's "addressed in commits" actually fixed the implementation or test
  3. If there are other retry mechanisms involved

Retry count expectation at line 70 appears inconsistent with cockatiel's maxAttempts semantics. According to cockatiel documentation, maxAttempts: 3 should result in exactly 3 total function calls (1 initial + 2 retries), not 4. Verify whether ProviderService uses maxAttempts: 3 or maxAttempts: 4, and ensure the test expectation matches the actual implementation.

apps/provider-proxy/src/services/ProviderService/ProviderService.ts (2)

22-31: LGTM on retry policy implementation.

The retry policy using cockatiel with ExponentialBackoff and conditional handling based on error codes is well-structured.


38-62: Certificate fetching logic handles edge cases appropriately.

The method correctly:

  • Builds query parameters with proper hex-to-decimal serial number conversion
  • Handles single certificate response defensively with optional chaining
  • Logs errors with relevant context (providerAddress, serialNumber)
  • Returns null for error cases to prevent cascading failures
apps/provider-proxy/env/.env.mainnet (1)

1-1: Endpoint verified as valid and operational.

The gRPC endpoint https://akash.lavenderfive.com:443 is confirmed as a legitimate Akash mainnet gRPC endpoint maintained by Lavender.Five. The configuration change aligns with the PR objective to use gRPC instead of REST. Port 443 is the correct standard for gRPC-web over HTTPS. No issues identified.

apps/provider-proxy/env/.env.sandbox (1)

1-1: LGTM!

Environment variable correctly renamed to reflect the gRPC endpoint usage.

apps/provider-proxy/src/config/env.config.ts (1)

3-6: LGTM!

Schema correctly updated to use GRPC_NODE_URL with appropriate URL validation.

apps/provider-proxy/test/functional/provider-proxy-http.spec.ts (4)

17-19: Proper async cleanup pattern.

Good use of Promise.all to parallelize server shutdowns and ensure all cleanup operations are awaited.


72-78: Test title and setup correctly updated for gRPC flow.

Test accurately describes caching behavior when gRPC is unavailable, and the setup uses the new GRPC_NODE_URL configuration.


225-256: Retry test correctly validates gRPC resilience.

Test properly verifies the retry logic when the gRPC server is initially unavailable, then comes back online.


258-291: gRPC error 14/unavailable retry test is well structured.

The interceptor pattern correctly simulates a transient gRPC error (status 14) followed by recovery.

apps/provider-proxy/test/functional/provider-proxy-ws.spec.ts (2)

12-15: Proper async cleanup for WebSocket tests.

The afterEach correctly uses Promise.all to cleanly shut down all servers, preventing resource leaks between tests.


37-38: Configuration correctly updated throughout WebSocket tests.

All startServer calls consistently use GRPC_NODE_URL with the chain server URL.

apps/provider-proxy/src/container.ts (2)

1-1: LGTM!

Import of createChainNodeSDK aligns with the PR objective to integrate chain-sdk.


17-24: Chain SDK configuration is correctly implemented with the documented query.baseUrl pattern.

The createChainNodeSDK API accepts the configuration object structure used in the code. The query.baseUrl setting for read-only operations is the standard documented pattern for the @akashnetwork/chain-sdk library, and the implementation in ProviderService instantiation correctly omits the tx configuration, which aligns with read-only usage.

apps/provider-proxy/test/setup/chainApiServer.ts (8)

57-62: Good use of protobuf decoding from chain-sdk.

The implementation correctly uses QueryCertificatesRequest.decode() to parse the gRPC payload after stripping the 5-byte frame header, addressing the previous fragile regex parsing concern.


100-118: Implementation looks correct.

The early return when the server isn't listening is good defensive coding. The optional chaining on grpcServer handles the undefined case properly.


120-123: Clean interface definition.

The simplified interceptRequest signature that returns a boolean for short-circuiting is appropriate for this test helper.


125-133: LGTM for test purposes.

Using Math.random() for test address generation is acceptable. For production code, crypto.getRandomValues() would be preferred, but this is fine for test infrastructure.


135-154: Good implementation using chain-sdk types.

The helper correctly converts X509Certificate to the protobuf format expected by QueryCertificatesResponse, using the State.valid enum from chain-sdk as suggested in past reviews.


156-167: Proper use of chain-sdk encoding.

The implementation correctly uses QueryCertificatesResponse.fromPartial() and encode().finish() as suggested in past reviews, ensuring type-safe protobuf encoding.


169-181: Correct gRPC framing implementation.

The 5-byte frame header (compression flag + big-endian length) and the response headers (grpc-status: "0") follow the gRPC over HTTP/2 specification correctly.


67-68: Based on my web search verification, toLegacyObject() is NOT deprecated in Node.js. The method remains fully documented and available in the Node.js crypto API. While modern alternatives like toJSON() and direct property access (publicKey, validFromDate) exist, they are optional enhancements, not required replacements.

The code at lines 67-68 is using toLegacyObject() appropriately and does not require changes based on deprecation concerns.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

♻️ Duplicate comments (1)
apps/provider-proxy/src/services/ProviderService/ProviderService.ts (1)

9-12: Consider removing error code 13 (INTERNAL) from retriable codes.

Per gRPC best practices, INTERNAL (code 13) represents serious invariant/binary errors that typically indicate bugs rather than transient failures. UNAVAILABLE (code 14) is the canonical transient code for retries. Automatically retrying INTERNAL errors may mask server-side bugs.

 const RETRIABLE_ERROR_CODES = [
-  13, // internal
   14 // unavailable
 ];
🧹 Nitpick comments (2)
apps/provider-proxy/test/setup/chainApiServer.ts (1)

98-114: Reset module state after server close for test isolation.

After closing the server, grpcServer should be reset to undefined to ensure clean state for subsequent test runs that may call startChainApiServer again.

     grpcServer?.close(error => {
       if (error) {
         reject(error);
       } else {
+        grpcServer = undefined;
         resolve();
       }
     });
apps/provider-proxy/src/services/ProviderService/ProviderService.ts (1)

23-31: The non-null assertion on error.code! is potentially fragile.

The hasErrorCode type guard only confirms that "code" in error is true, but code could still be undefined. While RETRIABLE_ERROR_CODES.includes(undefined) returns false (safe behavior), the non-null assertion is misleading.

   private retryPolicy = retry(
     handleWhen(error => {
-      return hasErrorCode(error) && RETRIABLE_ERROR_CODES.includes(error.code!);
+      return hasErrorCode(error) && typeof error.code === "number" && RETRIABLE_ERROR_CODES.includes(error.code);
     }),
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 0c502e8 and 38e2081.

📒 Files selected for processing (2)
  • apps/provider-proxy/src/services/ProviderService/ProviderService.ts (1 hunks)
  • apps/provider-proxy/test/setup/chainApiServer.ts (1 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**/*.{ts,tsx,js}

📄 CodeRabbit inference engine (.cursor/rules/general.mdc)

**/*.{ts,tsx,js}: Never use type any or cast to type any. Always define the proper TypeScript types.
Never use deprecated methods from libraries.
Don't add unnecessary comments to the code.

Files:

  • apps/provider-proxy/test/setup/chainApiServer.ts
  • apps/provider-proxy/src/services/ProviderService/ProviderService.ts
🧠 Learnings (4)
📚 Learning: 2025-11-19T15:15:07.283Z
Learnt from: ygrishajev
Repo: akash-network/console PR: 2254
File: apps/api/test/functional/sign-and-broadcast-tx.spec.ts:4-4
Timestamp: 2025-11-19T15:15:07.283Z
Learning: In the Akash Network Console project, when tests use native Node.js fetch (available in Node 18+), fetch-mock should be used for HTTP mocking instead of nock, as nock does not support intercepting native fetch calls. This applies to apps/api/test/functional/sign-and-broadcast-tx.spec.ts and any other tests using native fetch.

Applied to files:

  • apps/provider-proxy/test/setup/chainApiServer.ts
📚 Learning: 2025-10-31T11:26:42.138Z
Learnt from: stalniy
Repo: akash-network/console PR: 2138
File: apps/api/src/billing/lib/batch-signing-client/batch-signing-client.service.ts:379-382
Timestamp: 2025-10-31T11:26:42.138Z
Learning: In TypeScript/JavaScript, the pattern of checking a cached value and then performing an async operation to fetch it without proper synchronization is race condition unsafe:
```typescript
private async getAddress() {
  if (!this.address) {
    this.address = await this.wallet.getFirstAddress();
  }
  return this.address;
}
```
Multiple concurrent calls can all pass the `if (!this.address)` check before any of them sets the value, leading to duplicate async operations. This should be flagged as a race condition. Proper synchronization (mutex, atomic promise caching, or guaranteed single-threaded execution) is required.

Applied to files:

  • apps/provider-proxy/test/setup/chainApiServer.ts
📚 Learning: 2025-07-03T14:40:49.886Z
Learnt from: jzsfkzm
Repo: akash-network/console PR: 1498
File: apps/api/src/services/external/templates/template-fetcher.service.ts:0-0
Timestamp: 2025-07-03T14:40:49.886Z
Learning: In the TemplateFetcherService class in apps/api/src/services/external/templates/template-fetcher.service.ts, the error handling strategy should maintain process resilience by catching all errors and returning null rather than re-throwing critical errors, to avoid breaking the whole template fetching process.

Applied to files:

  • apps/provider-proxy/src/services/ProviderService/ProviderService.ts
📚 Learning: 2025-11-25T17:45:39.561Z
Learnt from: CR
Repo: akash-network/console PR: 0
File: .cursor/rules/general.mdc:0-0
Timestamp: 2025-11-25T17:45:39.561Z
Learning: Applies to **/*.{ts,tsx,js} : Never use type `any` or cast to type `any`. Always define the proper TypeScript types.

Applied to files:

  • apps/provider-proxy/src/services/ProviderService/ProviderService.ts
🧬 Code graph analysis (1)
apps/provider-proxy/src/services/ProviderService/ProviderService.ts (1)
packages/logging/src/services/logger/logger.service.ts (1)
  • error (141-143)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (10)
  • GitHub Check: validate / validate-app
  • GitHub Check: test-build
  • GitHub Check: test-build
  • GitHub Check: validate / validate-app
  • GitHub Check: test-build
  • GitHub Check: test-build
  • GitHub Check: test-build
  • GitHub Check: test-build
  • GitHub Check: validate / validate-app
  • GitHub Check: test-build
🔇 Additional comments (10)
apps/provider-proxy/test/setup/chainApiServer.ts (6)

1-8: LGTM! Clean imports and proper use of chain-sdk types.

The imports correctly use QueryCertificatesRequest, QueryCertificatesResponse, and State from the chain-sdk private types, addressing the previous review feedback to use proper protobuf encoding/decoding instead of fragile regex parsing.


10-96: Well-structured gRPC mock server implementation.

The stream-based handling with proper protobuf decoding via QueryCertificatesRequest.decode() is clean. The 5-byte frame stripping at line 58 correctly handles gRPC message framing.

One minor observation: the server.listen callback doesn't handle potential errors from the listen operation itself, but this is acceptable for test infrastructure.


116-119: LGTM!

The interface is clean and well-typed. The interceptRequest callback signature is simple and appropriate for test interception.


121-129: LGTM!

Using Math.random() for generating test addresses is acceptable. For production use, crypto.getRandomValues() would be preferred, but this is test infrastructure.


131-136: LGTM!

Clean session cleanup implementation using pop() to drain the array while destroying each session.


138-184: Excellent use of chain-sdk types for protobuf encoding.

The implementation correctly uses QueryCertificatesResponse.encode() and fromPartial() as suggested in past reviews. The gRPC frame construction (compression flag byte + 4-byte big-endian length) at lines 173-176 follows the gRPC wire protocol correctly.

apps/provider-proxy/src/services/ProviderService/ProviderService.ts (4)

1-7: LGTM!

Clean type imports and the ChainNodeSDK type alias using ReturnType<typeof createChainNodeSDK> is a good pattern for deriving types from factory functions.


14-20: LGTM!

Clean type guard implementation for narrowing unknown errors to check for the code property. This follows TypeScript best practices for safe error handling.


38-62: LGTM! Good defensive error handling.

The defensive certificate access pattern at lines 52-54 properly addresses the past review comment about null safety. The error handling with unknown type and logging follows best practices while maintaining process resilience by returning null rather than throwing.


64-75: LGTM!

Clean implementation of fetchCertificate with retry policy delegation. The isValidationServerError method correctly identifies validation-related error messages.

@jzsfkzm jzsfkzm force-pushed the features/2188-certificates-from-grpc branch from 38e2081 to b64eaa1 Compare November 26, 2025 19:17
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

♻️ Duplicate comments (2)
apps/provider-proxy/src/services/ProviderService/ProviderService.spec.ts (1)

64-71: Fix the retry count expectation.

The test expects 4 calls, but the ProviderService is configured with maxAttempts: 3. In cockatiel, maxAttempts represents the total number of attempts (1 initial + 2 retries = 3 total), not the number of retries. This is inconsistent with line 61, which correctly expects 3 calls.

Apply this diff:

-    expect(getCertificates).toHaveBeenCalledTimes(4);
+    expect(getCertificates).toHaveBeenCalledTimes(3);

Additionally, consider updating the test description for clarity:

-  it("retries getCertificates() request 3 times and then fails in case of grpc-status=14", async () => {
+  it("attempts getCertificates() request 3 times (1 initial + 2 retries) and then fails in case of grpc-status=14", async () => {
apps/provider-proxy/src/services/ProviderService/ProviderService.ts (1)

9-12: Remove error code 13 (INTERNAL) from retry logic.

Error code 13 (gRPC INTERNAL) represents server-side implementation errors that should not be automatically retried. This was previously flagged as a blocking issue. Additionally, consider adding error code 4 (DEADLINE_EXCEEDED) to handle timeout scenarios.

Apply this diff:

 const RETRIABLE_ERROR_CODES = [
-  13, // internal
+  4,  // deadline_exceeded - timeout scenarios
   14 // unavailable
 ];

Based on past review discussions, error code 14 (UNAVAILABLE) covers transient network failures, service downtime, and redeployment scenarios. Error code 4 handles cases where the service is unresponsive or extremely slow without breaking the connection.

🧹 Nitpick comments (2)
apps/provider-proxy/test/setup/chainApiServer.ts (1)

57-62: Consider documenting the gRPC framing protocol.

The 5-byte slice at line 58 implements standard gRPC framing (1-byte compression flag + 4-byte message length), but this isn't immediately obvious to future maintainers.

Consider adding a comment:

 if (requestData.length > 5) {
+  // gRPC framing: skip 5-byte header (1 byte compression flag + 4 bytes message length)
   const protoData = requestData.slice(5);
   const certRequest = QueryCertificatesRequest.decode(protoData);
apps/provider-proxy/src/services/ProviderService/ProviderService.ts (1)

14-26: Consider avoiding non-null assertion in retry policy.

While the non-null assertion error.code! at line 25 is technically safe (because hasErrorCode confirms the property exists), it could be more explicit for maintainability.

Consider refining the type guard and interface:

 interface ErrorWithCode {
-  code?: number;
+  code: number;
 }
 
 function hasErrorCode(error: unknown): error is ErrorWithCode {
-  return typeof error === "object" && error !== null && "code" in error;
+  return typeof error === "object" && error !== null && "code" in error && typeof (error as any).code === "number";
 }

Then remove the non-null assertion:

-      return hasErrorCode(error) && RETRIABLE_ERROR_CODES.includes(error.code!);
+      return hasErrorCode(error) && RETRIABLE_ERROR_CODES.includes(error.code);
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 38e2081 and b64eaa1.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (12)
  • apps/provider-proxy/env/.env.mainnet (1 hunks)
  • apps/provider-proxy/env/.env.sample (1 hunks)
  • apps/provider-proxy/env/.env.sandbox (1 hunks)
  • apps/provider-proxy/package.json (2 hunks)
  • apps/provider-proxy/src/config/env.config.ts (1 hunks)
  • apps/provider-proxy/src/container.ts (2 hunks)
  • apps/provider-proxy/src/services/ProviderService/ProviderService.spec.ts (2 hunks)
  • apps/provider-proxy/src/services/ProviderService/ProviderService.ts (1 hunks)
  • apps/provider-proxy/test/functional/provider-proxy-http.spec.ts (26 hunks)
  • apps/provider-proxy/test/functional/provider-proxy-ws.spec.ts (10 hunks)
  • apps/provider-proxy/test/setup/chainApiServer.ts (1 hunks)
  • apps/provider-proxy/test/setup/proxyServer.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • apps/provider-proxy/package.json
  • apps/provider-proxy/env/.env.mainnet
🧰 Additional context used
📓 Path-based instructions (2)
**/*.{ts,tsx,js}

📄 CodeRabbit inference engine (.cursor/rules/general.mdc)

**/*.{ts,tsx,js}: Never use type any or cast to type any. Always define the proper TypeScript types.
Never use deprecated methods from libraries.
Don't add unnecessary comments to the code.

Files:

  • apps/provider-proxy/src/services/ProviderService/ProviderService.spec.ts
  • apps/provider-proxy/test/functional/provider-proxy-ws.spec.ts
  • apps/provider-proxy/test/functional/provider-proxy-http.spec.ts
  • apps/provider-proxy/test/setup/proxyServer.ts
  • apps/provider-proxy/src/services/ProviderService/ProviderService.ts
  • apps/provider-proxy/test/setup/chainApiServer.ts
  • apps/provider-proxy/src/container.ts
  • apps/provider-proxy/src/config/env.config.ts
**/*.spec.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/no-jest-mock.mdc)

Don't use jest.mock() in test files. Instead, use jest-mock-extended to create mocks and pass mocks as dependencies to the service under test

Use setup function instead of beforeEach in test files. The setup function must be at the bottom of the root describe block, should create an object under test and return it, accept a single parameter with inline type definition, avoid shared state, and not have a specified return type.

**/*.spec.{ts,tsx}: Use <Subject>.name in the root describe suite description instead of hardcoded class/service name strings to enable automated refactoring tools to find all references
Use either a method name or a condition starting with 'when' for nested suite descriptions in tests
Use present simple, 3rd person singular for test descriptions without prepending 'should'

Files:

  • apps/provider-proxy/src/services/ProviderService/ProviderService.spec.ts
  • apps/provider-proxy/test/functional/provider-proxy-ws.spec.ts
  • apps/provider-proxy/test/functional/provider-proxy-http.spec.ts
🧠 Learnings (9)
📚 Learning: 2025-11-19T15:15:07.283Z
Learnt from: ygrishajev
Repo: akash-network/console PR: 2254
File: apps/api/test/functional/sign-and-broadcast-tx.spec.ts:4-4
Timestamp: 2025-11-19T15:15:07.283Z
Learning: In the Akash Network Console project, when tests use native Node.js fetch (available in Node 18+), fetch-mock should be used for HTTP mocking instead of nock, as nock does not support intercepting native fetch calls. This applies to apps/api/test/functional/sign-and-broadcast-tx.spec.ts and any other tests using native fetch.

Applied to files:

  • apps/provider-proxy/src/services/ProviderService/ProviderService.spec.ts
  • apps/provider-proxy/test/functional/provider-proxy-ws.spec.ts
  • apps/provider-proxy/test/functional/provider-proxy-http.spec.ts
  • apps/provider-proxy/src/services/ProviderService/ProviderService.ts
  • apps/provider-proxy/test/setup/chainApiServer.ts
📚 Learning: 2025-06-08T03:07:13.871Z
Learnt from: stalniy
Repo: akash-network/console PR: 1436
File: apps/api/src/provider/repositories/provider/provider.repository.ts:79-90
Timestamp: 2025-06-08T03:07:13.871Z
Learning: The getProvidersHostUriByAttributes method in apps/api/src/provider/repositories/provider/provider.repository.ts already has comprehensive test coverage in provider.repository.spec.ts, including tests for complex HAVING clause logic with COUNT(*) FILTER (WHERE ...) syntax, signature conditions (anyOf/allOf), and glob pattern matching.

Applied to files:

  • apps/provider-proxy/src/services/ProviderService/ProviderService.spec.ts
📚 Learning: 2025-11-25T17:45:58.258Z
Learnt from: CR
Repo: akash-network/console PR: 0
File: .cursor/rules/test-descriptions.mdc:0-0
Timestamp: 2025-11-25T17:45:58.258Z
Learning: Applies to **/*.spec.{ts,tsx} : Use `<Subject>.name` in the root describe suite description instead of hardcoded class/service name strings to enable automated refactoring tools to find all references

Applied to files:

  • apps/provider-proxy/test/functional/provider-proxy-ws.spec.ts
  • apps/provider-proxy/test/functional/provider-proxy-http.spec.ts
📚 Learning: 2025-11-25T17:45:49.180Z
Learnt from: CR
Repo: akash-network/console PR: 0
File: .cursor/rules/query-by-in-tests.mdc:0-0
Timestamp: 2025-11-25T17:45:49.180Z
Learning: Applies to {apps/deploy-web,apps/provider-console}/**/*.spec.tsx : Use `queryBy` methods instead of `getBy` methods in test expectations

Applied to files:

  • apps/provider-proxy/test/functional/provider-proxy-ws.spec.ts
📚 Learning: 2025-09-25T20:34:55.117Z
Learnt from: jigar-arc10
Repo: akash-network/console PR: 1970
File: apps/provider-console/src/config/network.config.ts:17-28
Timestamp: 2025-09-25T20:34:55.117Z
Learning: In cosmos-kit integration, nodesUrl and versionUrl should point to Cosmos API endpoints (not console backend API endpoints) as cosmos-kit expects these to be Cosmos REST endpoints for proper functionality.

Applied to files:

  • apps/provider-proxy/env/.env.sandbox
  • apps/provider-proxy/env/.env.sample
📚 Learning: 2025-07-03T14:40:49.886Z
Learnt from: jzsfkzm
Repo: akash-network/console PR: 1498
File: apps/api/src/services/external/templates/template-fetcher.service.ts:0-0
Timestamp: 2025-07-03T14:40:49.886Z
Learning: In the TemplateFetcherService class in apps/api/src/services/external/templates/template-fetcher.service.ts, the error handling strategy should maintain process resilience by catching all errors and returning null rather than re-throwing critical errors, to avoid breaking the whole template fetching process.

Applied to files:

  • apps/provider-proxy/src/services/ProviderService/ProviderService.ts
📚 Learning: 2025-11-25T17:45:39.561Z
Learnt from: CR
Repo: akash-network/console PR: 0
File: .cursor/rules/general.mdc:0-0
Timestamp: 2025-11-25T17:45:39.561Z
Learning: Applies to **/*.{ts,tsx,js} : Never use type `any` or cast to type `any`. Always define the proper TypeScript types.

Applied to files:

  • apps/provider-proxy/src/services/ProviderService/ProviderService.ts
📚 Learning: 2025-10-31T11:26:42.138Z
Learnt from: stalniy
Repo: akash-network/console PR: 2138
File: apps/api/src/billing/lib/batch-signing-client/batch-signing-client.service.ts:379-382
Timestamp: 2025-10-31T11:26:42.138Z
Learning: In TypeScript/JavaScript, the pattern of checking a cached value and then performing an async operation to fetch it without proper synchronization is race condition unsafe:
```typescript
private async getAddress() {
  if (!this.address) {
    this.address = await this.wallet.getFirstAddress();
  }
  return this.address;
}
```
Multiple concurrent calls can all pass the `if (!this.address)` check before any of them sets the value, leading to duplicate async operations. This should be flagged as a race condition. Proper synchronization (mutex, atomic promise caching, or guaranteed single-threaded execution) is required.

Applied to files:

  • apps/provider-proxy/test/setup/chainApiServer.ts
📚 Learning: 2025-11-12T09:03:40.132Z
Learnt from: stalniy
Repo: akash-network/console PR: 0
File: :0-0
Timestamp: 2025-11-12T09:03:40.132Z
Learning: For backend services (like the Indexer), prefer using createOtelLogger from "akashnetwork/logging/otel" to include OpenTelemetry trace context in logs.

Applied to files:

  • apps/provider-proxy/src/container.ts
🧬 Code graph analysis (6)
apps/provider-proxy/src/services/ProviderService/ProviderService.spec.ts (3)
apps/provider-proxy/src/services/ProviderService/ProviderService.ts (1)
  • ProviderService (22-75)
packages/http-sdk/src/certificates/certificates.service.ts (1)
  • getCertificates (25-37)
apps/provider-proxy/test/seeders/createX509CertPair.ts (2)
  • CertificateOptions (33-38)
  • createX509CertPair (4-26)
apps/provider-proxy/test/functional/provider-proxy-ws.spec.ts (3)
apps/provider-proxy/test/setup/proxyServer.ts (2)
  • stopServer (12-14)
  • startServer (7-10)
apps/provider-proxy/test/setup/providerServer.ts (1)
  • stopProviderServer (73-75)
apps/provider-proxy/test/setup/chainApiServer.ts (1)
  • stopChainApiServer (98-114)
apps/provider-proxy/test/functional/provider-proxy-http.spec.ts (2)
apps/provider-proxy/test/setup/proxyServer.ts (2)
  • stopServer (12-14)
  • startServer (7-10)
apps/provider-proxy/test/setup/chainApiServer.ts (3)
  • stopChainApiServer (98-114)
  • generateBech32 (121-129)
  • startChainApiServer (10-96)
apps/provider-proxy/test/setup/proxyServer.ts (1)
apps/provider-proxy/src/config/env.config.ts (1)
  • AppConfig (8-8)
apps/provider-proxy/src/services/ProviderService/ProviderService.ts (1)
packages/logging/src/services/logger/logger.service.ts (1)
  • error (141-143)
apps/provider-proxy/src/container.ts (1)
apps/provider-proxy/src/services/ProviderService/ProviderService.ts (1)
  • ProviderService (22-75)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (10)
  • GitHub Check: validate / validate-app
  • GitHub Check: test-build
  • GitHub Check: test-build
  • GitHub Check: validate / validate-app
  • GitHub Check: test-build
  • GitHub Check: test-build
  • GitHub Check: validate / validate-app
  • GitHub Check: test-build
  • GitHub Check: test-build
  • GitHub Check: test-build
🔇 Additional comments (14)
apps/provider-proxy/env/.env.sample (1)

1-1: LGTM!

The environment variable update from REST_API_NODE_URL to GRPC_NODE_URL with the gRPC endpoint is correct and aligns with the PR objective to migrate from REST-based to gRPC-based certificate fetching.

apps/provider-proxy/env/.env.sandbox (1)

1-1: LGTM!

Consistent update matching the .env.sample file.

apps/provider-proxy/test/setup/proxyServer.ts (1)

7-7: LGTM!

Changing the parameter type to Partial<AppConfig> improves test flexibility by allowing tests to provide only the necessary configuration fields rather than requiring the complete config object.

apps/provider-proxy/src/config/env.config.ts (1)

4-4: LGTM!

The schema update correctly replaces REST_API_NODE_URL with GRPC_NODE_URL while maintaining proper URL validation. This is the core configuration change enabling the gRPC migration.

apps/provider-proxy/test/functional/provider-proxy-http.spec.ts (1)

8-8: LGTM!

The test file has been consistently updated to use the gRPC-based flow. Variable names, server initialization, and test descriptions properly reflect the migration from REST API to gRPC endpoints. The retry logic tests correctly cover gRPC-specific error scenarios (grpc-status=14).

Also applies to: 18-18, 25-27, 50-52, 76-78, 111-129, 152-157, 188-192, 225-256, 258-291, 316-317, 361-362, 395-396, 419-420, 453-454, 485-486, 524-545, 574-591, 618-630, 688-699

apps/provider-proxy/test/functional/provider-proxy-ws.spec.ts (1)

8-8: LGTM!

The WebSocket test file has been consistently updated to use the gRPC-based flow. The concurrent shutdown using Promise.all in the afterEach hook is a good practice that improves test cleanup efficiency.

Also applies to: 13-14, 37-37, 68-68, 88-88, 116-116, 139-139, 167-167, 194-194, 242-242, 305-305

apps/provider-proxy/src/container.ts (1)

1-1: LGTM!

The ProviderService instantiation correctly migrates from REST-based fetch to the ChainNodeSDK client using gRPC. The SDK is properly configured with the GRPC_NODE_URL and, as per the PR objectives, does not include the tx option, making it read-only for certificate queries.

Also applies to: 17-24

apps/provider-proxy/src/services/ProviderService/ProviderService.spec.ts (1)

1-7: Test structure looks good.

The test migration to use ChainNodeSDK-based mocking is well-structured. The setup function correctly follows coding guidelines by being at the bottom and accepting inline parameter types. The use of ProviderService.name in the describe block is also correct.

Also applies to: 11-80, 123-137

apps/provider-proxy/test/setup/chainApiServer.ts (3)

1-8: LGTM! Proper use of chain-sdk protobuf types.

The imports and server setup correctly use the generated protobuf types from @akashnetwork/chain-sdk, and session tracking is properly initialized.


64-75: LGTM! Correct certificate filtering logic.

The certificate matching logic properly handles optional owner and serial filters, and the hex-to-decimal serial number conversion is correct.


159-184: LGTM! Proper protobuf encoding and gRPC response framing.

The response construction correctly uses QueryCertificatesResponse.encode with fromPartial, and the sendResponse function properly implements gRPC framing (5-byte header + protobuf payload) with appropriate headers.

apps/provider-proxy/src/services/ProviderService/ProviderService.ts (3)

1-7: LGTM! Clean imports and type definitions.

The imports correctly use types from @akashnetwork/chain-sdk, and the ChainNodeSDK type alias properly captures the return type of createChainNodeSDK.


38-62: LGTM! Proper error handling and type safety.

The method correctly constructs the query parameters using QueryInput, handles errors with unknown type (addressing past review feedback), and uses optional chaining to safely extract the certificate.


64-68: LGTM! Clean retry policy integration.

The private fetchCertificate method properly integrates the retry policy with the SDK client call, maintaining clean separation of concerns.

@stalniy
Copy link
Contributor

stalniy commented Nov 27, 2025

@jzsfkzm all tests currently pass for console-api in other PRs, so this failure relates to changes in provider-proxy. There are some tests that rely on provider-proxy behavior (they are almost e2e and this is not good for PR level test).

I assume that sandbox blockchain exposes grpc server over plaintext, not SSL

@stalniy
Copy link
Contributor

stalniy commented Nov 27, 2025

Yes, I'm right:

% grpcurl grpc.sandbox-2.aksh.pw:9090 list
Failed to dial target host "grpc.sandbox-2.aksh.pw:9090": tls: first record does not look like a TLS handshake

 % grpcurl -plaintext grpc.sandbox-2.aksh.pw:9090 list
akash.audit.v1.Query
akash.cert.v1.Query
akash.deployment.v1beta4.Query
akash.escrow.v1.Query
akash.market.v1beta5.Query
akash.provider.v1beta4.Query
akash.take.v1.Query
cosmos.auth.v1beta1.Query
cosmos.authz.v1beta1.Query
cosmos.autocli.v1.Query
cosmos.bank.v1beta1.Query
cosmos.base.node.v1beta1.Service
cosmos.base.reflection.v1beta1.ReflectionService
cosmos.base.reflection.v2alpha1.ReflectionService
cosmos.base.tendermint.v1beta1.Service
cosmos.consensus.v1.Query
cosmos.distribution.v1beta1.Query
cosmos.evidence.v1beta1.Query
cosmos.feegrant.v1beta1.Query
cosmos.gov.v1.Query
cosmos.gov.v1beta1.Query
cosmos.mint.v1beta1.Query
cosmos.params.v1beta1.Query
cosmos.reflection.v1.ReflectionService
cosmos.slashing.v1beta1.Query
cosmos.staking.v1beta1.Query
cosmos.tx.v1beta1.Service
cosmos.upgrade.v1beta1.Query
grpc.reflection.v1alpha.ServerReflection
ibc.applications.transfer.v1.Query
ibc.core.channel.v1.Query
ibc.core.channel.v2.Query
ibc.core.client.v1.Query
ibc.core.client.v2.Query
ibc.core.connection.v1.Query

@jzsfkzm jzsfkzm force-pushed the features/2188-certificates-from-grpc branch 2 times, most recently from a484d13 to f71e1ed Compare November 27, 2025 21:30
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

♻️ Duplicate comments (2)
apps/provider-proxy/src/services/ProviderService/ProviderService.spec.ts (1)

64-71: Fix the retry count expectation.

The test expects 4 calls, but ProviderService is configured with maxAttempts: 3 (line 28 in ProviderService.ts). In cockatiel, maxAttempts represents the total number of attempts including the initial one, so this should be 3 total calls, not 4.

Apply this diff to fix the expectation:

-    expect(getCertificates).toHaveBeenCalledTimes(4);
+    expect(getCertificates).toHaveBeenCalledTimes(3);

Note: This was flagged in a previous review and marked as addressed, but the code still expects 4 calls.

apps/provider-proxy/src/services/ProviderService/ProviderService.ts (1)

9-12: Remove error code 13 from RETRIABLE_ERROR_CODES.

gRPC error code 13 (INTERNAL) represents serious server-side errors and should not be automatically retried. The gRPC best practice is to only retry UNAVAILABLE (code 14) for transient network failures. This was flagged in a previous review as a blocking issue.

Apply this diff:

 const RETRIABLE_ERROR_CODES = [
-  13, // internal
   14 // unavailable
 ];

As per past review feedback.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 2dd4d8f and f71e1ed.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (12)
  • apps/provider-proxy/env/.env.mainnet (1 hunks)
  • apps/provider-proxy/env/.env.sample (1 hunks)
  • apps/provider-proxy/env/.env.sandbox (1 hunks)
  • apps/provider-proxy/package.json (2 hunks)
  • apps/provider-proxy/src/config/env.config.ts (1 hunks)
  • apps/provider-proxy/src/container.ts (2 hunks)
  • apps/provider-proxy/src/services/ProviderService/ProviderService.spec.ts (2 hunks)
  • apps/provider-proxy/src/services/ProviderService/ProviderService.ts (1 hunks)
  • apps/provider-proxy/test/functional/provider-proxy-http.spec.ts (26 hunks)
  • apps/provider-proxy/test/functional/provider-proxy-ws.spec.ts (10 hunks)
  • apps/provider-proxy/test/setup/chainApiServer.ts (1 hunks)
  • apps/provider-proxy/test/setup/proxyServer.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (6)
  • apps/provider-proxy/env/.env.mainnet
  • apps/provider-proxy/env/.env.sandbox
  • apps/provider-proxy/test/setup/proxyServer.ts
  • apps/provider-proxy/src/container.ts
  • apps/provider-proxy/env/.env.sample
  • apps/provider-proxy/src/config/env.config.ts
🧰 Additional context used
📓 Path-based instructions (2)
**/*.{ts,tsx,js}

📄 CodeRabbit inference engine (.cursor/rules/general.mdc)

**/*.{ts,tsx,js}: Never use type any or cast to type any. Always define the proper TypeScript types.
Never use deprecated methods from libraries.
Don't add unnecessary comments to the code.

Files:

  • apps/provider-proxy/test/functional/provider-proxy-ws.spec.ts
  • apps/provider-proxy/src/services/ProviderService/ProviderService.spec.ts
  • apps/provider-proxy/test/setup/chainApiServer.ts
  • apps/provider-proxy/test/functional/provider-proxy-http.spec.ts
  • apps/provider-proxy/src/services/ProviderService/ProviderService.ts
**/*.spec.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/no-jest-mock.mdc)

Don't use jest.mock() in test files. Instead, use jest-mock-extended to create mocks and pass mocks as dependencies to the service under test

Use setup function instead of beforeEach in test files. The setup function must be at the bottom of the root describe block, should create an object under test and return it, accept a single parameter with inline type definition, avoid shared state, and not have a specified return type.

**/*.spec.{ts,tsx}: Use <Subject>.name in the root describe suite description instead of hardcoded class/service name strings to enable automated refactoring tools to find all references
Use either a method name or a condition starting with 'when' for nested suite descriptions in tests
Use present simple, 3rd person singular for test descriptions without prepending 'should'

Files:

  • apps/provider-proxy/test/functional/provider-proxy-ws.spec.ts
  • apps/provider-proxy/src/services/ProviderService/ProviderService.spec.ts
  • apps/provider-proxy/test/functional/provider-proxy-http.spec.ts
🧠 Learnings (9)
📚 Learning: 2025-11-19T15:15:07.283Z
Learnt from: ygrishajev
Repo: akash-network/console PR: 2254
File: apps/api/test/functional/sign-and-broadcast-tx.spec.ts:4-4
Timestamp: 2025-11-19T15:15:07.283Z
Learning: In the Akash Network Console project, when tests use native Node.js fetch (available in Node 18+), fetch-mock should be used for HTTP mocking instead of nock, as nock does not support intercepting native fetch calls. This applies to apps/api/test/functional/sign-and-broadcast-tx.spec.ts and any other tests using native fetch.

Applied to files:

  • apps/provider-proxy/test/functional/provider-proxy-ws.spec.ts
  • apps/provider-proxy/src/services/ProviderService/ProviderService.spec.ts
  • apps/provider-proxy/package.json
  • apps/provider-proxy/test/setup/chainApiServer.ts
  • apps/provider-proxy/test/functional/provider-proxy-http.spec.ts
  • apps/provider-proxy/src/services/ProviderService/ProviderService.ts
📚 Learning: 2025-11-25T17:45:49.180Z
Learnt from: CR
Repo: akash-network/console PR: 0
File: .cursor/rules/query-by-in-tests.mdc:0-0
Timestamp: 2025-11-25T17:45:49.180Z
Learning: Applies to {apps/deploy-web,apps/provider-console}/**/*.spec.tsx : Use `queryBy` methods instead of `getBy` methods in test expectations

Applied to files:

  • apps/provider-proxy/test/functional/provider-proxy-ws.spec.ts
📚 Learning: 2025-11-25T17:45:58.258Z
Learnt from: CR
Repo: akash-network/console PR: 0
File: .cursor/rules/test-descriptions.mdc:0-0
Timestamp: 2025-11-25T17:45:58.258Z
Learning: Applies to **/*.spec.{ts,tsx} : Use `<Subject>.name` in the root describe suite description instead of hardcoded class/service name strings to enable automated refactoring tools to find all references

Applied to files:

  • apps/provider-proxy/test/functional/provider-proxy-ws.spec.ts
📚 Learning: 2025-11-25T17:45:52.965Z
Learnt from: CR
Repo: akash-network/console PR: 0
File: .cursor/rules/setup-instead-of-before-each.mdc:0-0
Timestamp: 2025-11-25T17:45:52.965Z
Learning: Applies to **/*.spec.{ts,tsx} : Use `setup` function instead of `beforeEach` in test files. The `setup` function must be at the bottom of the root `describe` block, should create an object under test and return it, accept a single parameter with inline type definition, avoid shared state, and not have a specified return type.

Applied to files:

  • apps/provider-proxy/test/functional/provider-proxy-ws.spec.ts
📚 Learning: 2025-06-08T03:07:13.871Z
Learnt from: stalniy
Repo: akash-network/console PR: 1436
File: apps/api/src/provider/repositories/provider/provider.repository.ts:79-90
Timestamp: 2025-06-08T03:07:13.871Z
Learning: The getProvidersHostUriByAttributes method in apps/api/src/provider/repositories/provider/provider.repository.ts already has comprehensive test coverage in provider.repository.spec.ts, including tests for complex HAVING clause logic with COUNT(*) FILTER (WHERE ...) syntax, signature conditions (anyOf/allOf), and glob pattern matching.

Applied to files:

  • apps/provider-proxy/src/services/ProviderService/ProviderService.spec.ts
📚 Learning: 2025-09-04T04:27:50.638Z
Learnt from: stalniy
Repo: akash-network/console PR: 1868
File: apps/api/src/billing/services/managed-signer/managed-signer.service.ts:1-1
Timestamp: 2025-09-04T04:27:50.638Z
Learning: In the akash-network/console project, importing MsgCreateLease from "akashnetwork/akash-api/v1beta3" instead of v1beta4 is considered non-critical by the maintainers, likely due to backward compatibility or project-specific requirements.

Applied to files:

  • apps/provider-proxy/package.json
📚 Learning: 2025-10-31T11:26:42.138Z
Learnt from: stalniy
Repo: akash-network/console PR: 2138
File: apps/api/src/billing/lib/batch-signing-client/batch-signing-client.service.ts:379-382
Timestamp: 2025-10-31T11:26:42.138Z
Learning: In TypeScript/JavaScript, the pattern of checking a cached value and then performing an async operation to fetch it without proper synchronization is race condition unsafe:
```typescript
private async getAddress() {
  if (!this.address) {
    this.address = await this.wallet.getFirstAddress();
  }
  return this.address;
}
```
Multiple concurrent calls can all pass the `if (!this.address)` check before any of them sets the value, leading to duplicate async operations. This should be flagged as a race condition. Proper synchronization (mutex, atomic promise caching, or guaranteed single-threaded execution) is required.

Applied to files:

  • apps/provider-proxy/test/setup/chainApiServer.ts
📚 Learning: 2025-07-03T14:40:49.886Z
Learnt from: jzsfkzm
Repo: akash-network/console PR: 1498
File: apps/api/src/services/external/templates/template-fetcher.service.ts:0-0
Timestamp: 2025-07-03T14:40:49.886Z
Learning: In the TemplateFetcherService class in apps/api/src/services/external/templates/template-fetcher.service.ts, the error handling strategy should maintain process resilience by catching all errors and returning null rather than re-throwing critical errors, to avoid breaking the whole template fetching process.

Applied to files:

  • apps/provider-proxy/src/services/ProviderService/ProviderService.ts
📚 Learning: 2025-11-25T17:45:39.561Z
Learnt from: CR
Repo: akash-network/console PR: 0
File: .cursor/rules/general.mdc:0-0
Timestamp: 2025-11-25T17:45:39.561Z
Learning: Applies to **/*.{ts,tsx,js} : Never use type `any` or cast to type `any`. Always define the proper TypeScript types.

Applied to files:

  • apps/provider-proxy/src/services/ProviderService/ProviderService.ts
🧬 Code graph analysis (2)
apps/provider-proxy/test/functional/provider-proxy-ws.spec.ts (3)
apps/provider-proxy/test/setup/proxyServer.ts (2)
  • stopServer (12-14)
  • startServer (7-10)
apps/provider-proxy/test/setup/providerServer.ts (1)
  • stopProviderServer (73-75)
apps/provider-proxy/test/setup/chainApiServer.ts (1)
  • stopChainApiServer (98-114)
apps/provider-proxy/src/services/ProviderService/ProviderService.spec.ts (3)
apps/provider-proxy/src/services/ProviderService/ProviderService.ts (1)
  • ProviderService (22-75)
packages/http-sdk/src/certificates/certificates.service.ts (1)
  • getCertificates (25-37)
apps/provider-proxy/test/seeders/createX509CertPair.ts (2)
  • CertificateOptions (33-38)
  • createX509CertPair (4-26)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (13)
  • GitHub Check: validate (apps/provider-console) / validate-unsafe
  • GitHub Check: validate (apps/deploy-web) / validate-unsafe
  • GitHub Check: validate / validate-app
  • GitHub Check: test-build
  • GitHub Check: test-build
  • GitHub Check: validate / validate-app
  • GitHub Check: test-build
  • GitHub Check: validate / validate-app
  • GitHub Check: test-build
  • GitHub Check: test-build
  • GitHub Check: validate / validate-app
  • GitHub Check: test-build
  • GitHub Check: test-build
🔇 Additional comments (8)
apps/provider-proxy/test/functional/provider-proxy-ws.spec.ts (1)

8-8: LGTM—Test setup updated for gRPC flow.

The renamed function stopChainApiServer (consistent JavaScript casing) and concurrent teardown using Promise.all properly reflect the migration to gRPC-based certificate retrieval.

Also applies to: 13-15

apps/provider-proxy/test/functional/provider-proxy-http.spec.ts (1)

8-8: LGTM—HTTP proxy tests updated for gRPC.

The tests have been properly updated to use the gRPC-based chain API server with:

  • Renamed stopChainApiServer for consistent casing
  • Concurrent teardown in afterEach
  • Updated variable naming (grpcServer instead of chainServer)
  • Simplified interceptRequest signature to a parameterless function returning boolean

Also applies to: 18-18, 25-27, 267-274

apps/provider-proxy/src/services/ProviderService/ProviderService.spec.ts (2)

1-7: LGTM—Test setup migrated to ChainNodeSDK.

The test properly imports createChainNodeSDK and SDKError from chain-sdk, defining a type alias for the return type. This aligns with the production implementation.


123-137: LGTM—Test setup function follows guidelines.

The setup function is correctly placed at the bottom of the describe block, accepts inline-typed parameters, creates and returns the service under test, and avoids shared state.

apps/provider-proxy/test/setup/chainApiServer.ts (2)

1-1: LGTM—Proper protobuf handling implemented.

The test server correctly uses protobuf decode/encode from @akashnetwork/chain-sdk/private-types/akash.v1 instead of fragile regex parsing. This addresses the previous review feedback and provides robust request/response handling for the gRPC-like test server.

Based on past review feedback.

Also applies to: 57-62, 159-170


7-8: LGTM—Proper session lifecycle management.

The HTTP/2 server implementation correctly tracks sessions in an array and provides destroyAllSessions for cleanup. This prevents resource leaks during test teardown.

Also applies to: 20-23, 131-136

apps/provider-proxy/src/services/ProviderService/ProviderService.ts (2)

23-31: LGTM—Retry policy properly configured.

The retry policy uses cockatiel's ExponentialBackoff with maxAttempts: 3 and correctly handles retriable errors. The fetchCertificate method properly wraps the SDK call with retry logic.

Also applies to: 64-68


33-36: LGTM—ChainNodeSDK integration and error handling.

The constructor properly accepts a ChainNodeSDK client, and getCertificate correctly:

  • Builds query parameters using QueryInput<QueryCertificatesRequest>
  • Handles the single-certificate case with safe optional chaining
  • Catches and logs errors with proper context (providerAddress, serialNumber)
  • Uses unknown type for error handling per coding guidelines

Also applies to: 38-62

@stalniy stalniy force-pushed the features/2188-certificates-from-grpc branch from f71e1ed to 35388a9 Compare November 28, 2025 20:32
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

♻️ Duplicate comments (2)
apps/provider-proxy/src/services/ProviderService/ProviderService.spec.ts (1)

64-71: Fix retry call-count expectation for grpc-status=14 failures

In the "retries getCertificates() request 3 times and then fails in case of grpc-status=14" test, you currently expect:

expect(getCertificates).toHaveBeenCalledTimes(4);

But ProviderService configures cockatiel with maxAttempts: 3, which is the total number of attempts (1 initial + 2 retries). When all attempts fail with code 14, getCertificates will be called exactly 3 times.

Update the expectation to:

expect(getCertificates).toHaveBeenCalledTimes(3);

so the test matches the actual retry policy.

#!/bin/bash
# Verify maxAttempts configuration and ensure tests match it
echo "ProviderService retry policy:"
rg -n "maxAttempts" apps/provider-proxy/src/services/ProviderService/ProviderService.ts

echo
echo "Check the failing expectation in the spec:"
rg -n "retries getCertificates\\(\\) request 3 times" apps/provider-proxy/src/services/ProviderService/ProviderService.spec.ts -n -C3
apps/provider-proxy/src/services/ProviderService/ProviderService.ts (1)

9-31: Reconsider retrying on gRPC INTERNAL (code 13)

RETRIABLE_ERROR_CODES currently includes both 13 (INTERNAL) and 14 (UNAVAILABLE):

const RETRIABLE_ERROR_CODES = [
  13, // internal
  14 // unavailable
];

Automatically retrying INTERNAL errors can mask real server bugs or invariant violations; UNAVAILABLE (14) is the canonical transient/network code, and prior review already suggested restricting retries to 14 only. Consider:

  • Dropping 13 from the retriable list so only clearly transient 14 is retried.
  • Optionally tightening hasErrorCode to require a numeric code:
function hasErrorCode(error: unknown): error is ErrorWithCode {
  return (
    typeof error === "object" &&
    error !== null &&
    typeof (error as ErrorWithCode).code === "number"
  );
}

This keeps retries focused on truly transient failures and avoids surprising behavior on other error shapes.

In cockatiel-based retry logic for a gRPC client, should gRPC status code 13 (INTERNAL) typically be treated as retriable, or is it safer to only retry code 14 (UNAVAILABLE)? Provide guidance from gRPC docs and common best practices.
🧹 Nitpick comments (2)
apps/provider-proxy/test/setup/chainApiServer.ts (1)

1-184: HTTP/2 gRPC test server logic looks solid

The http2-based mock gRPC server correctly:

  • Tracks sessions and destroys them on shutdown.
  • Validates the :path and returns 404 for non‑Certificates calls.
  • Parses the gRPC frame (compression flag + length prefix) before decoding QueryCertificatesRequest.
  • Filters certificates by owner/serial and encodes a QueryCertificatesResponse, framing it properly for gRPC.

As an optional clean‑up, you could reset sessions.length = 0 inside startChainApiServer (or keep sessions per server) to make the lifecycle more explicit, but it’s not functionally required for tests.

apps/provider-proxy/src/services/ProviderService/ProviderService.spec.ts (1)

123-137: Test setup helper matches DI pattern; minor placement nit only

The setup helper cleanly injects a partial ChainNodeSDK with a mocked getCertificates, which is exactly what you want for isolating ProviderService. As a minor style alignment with the testing guidelines, you could move buildCertificate above setup so that setup is the last function in the root describe block, but that’s purely cosmetic.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between f71e1ed and 35388a9.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (11)
  • apps/provider-proxy/env/.env.mainnet (1 hunks)
  • apps/provider-proxy/env/.env.sample (1 hunks)
  • apps/provider-proxy/env/.env.sandbox (1 hunks)
  • apps/provider-proxy/package.json (2 hunks)
  • apps/provider-proxy/src/config/env.config.ts (1 hunks)
  • apps/provider-proxy/src/container.ts (2 hunks)
  • apps/provider-proxy/src/services/ProviderService/ProviderService.spec.ts (2 hunks)
  • apps/provider-proxy/src/services/ProviderService/ProviderService.ts (1 hunks)
  • apps/provider-proxy/test/functional/provider-proxy-http.spec.ts (26 hunks)
  • apps/provider-proxy/test/functional/provider-proxy-ws.spec.ts (10 hunks)
  • apps/provider-proxy/test/setup/chainApiServer.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (5)
  • apps/provider-proxy/env/.env.sample
  • apps/provider-proxy/package.json
  • apps/provider-proxy/env/.env.sandbox
  • apps/provider-proxy/src/config/env.config.ts
  • apps/provider-proxy/test/functional/provider-proxy-ws.spec.ts
🧰 Additional context used
📓 Path-based instructions (2)
**/*.{ts,tsx,js}

📄 CodeRabbit inference engine (.cursor/rules/general.mdc)

**/*.{ts,tsx,js}: Never use type any or cast to type any. Always define the proper TypeScript types.
Never use deprecated methods from libraries.
Don't add unnecessary comments to the code.

Files:

  • apps/provider-proxy/src/container.ts
  • apps/provider-proxy/src/services/ProviderService/ProviderService.spec.ts
  • apps/provider-proxy/test/functional/provider-proxy-http.spec.ts
  • apps/provider-proxy/src/services/ProviderService/ProviderService.ts
  • apps/provider-proxy/test/setup/chainApiServer.ts
**/*.spec.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/no-jest-mock.mdc)

Don't use jest.mock() in test files. Instead, use jest-mock-extended to create mocks and pass mocks as dependencies to the service under test

Use setup function instead of beforeEach in test files. The setup function must be at the bottom of the root describe block, should create an object under test and return it, accept a single parameter with inline type definition, avoid shared state, and not have a specified return type.

**/*.spec.{ts,tsx}: Use <Subject>.name in the root describe suite description instead of hardcoded class/service name strings to enable automated refactoring tools to find all references
Use either a method name or a condition starting with 'when' for nested suite descriptions in tests
Use present simple, 3rd person singular for test descriptions without prepending 'should'

Files:

  • apps/provider-proxy/src/services/ProviderService/ProviderService.spec.ts
  • apps/provider-proxy/test/functional/provider-proxy-http.spec.ts
🧠 Learnings (7)
📚 Learning: 2025-11-12T09:03:40.132Z
Learnt from: stalniy
Repo: akash-network/console PR: 0
File: :0-0
Timestamp: 2025-11-12T09:03:40.132Z
Learning: For backend services (like the Indexer), prefer using createOtelLogger from "akashnetwork/logging/otel" to include OpenTelemetry trace context in logs.

Applied to files:

  • apps/provider-proxy/src/container.ts
📚 Learning: 2025-11-19T15:15:07.283Z
Learnt from: ygrishajev
Repo: akash-network/console PR: 2254
File: apps/api/test/functional/sign-and-broadcast-tx.spec.ts:4-4
Timestamp: 2025-11-19T15:15:07.283Z
Learning: In the Akash Network Console project, when tests use native Node.js fetch (available in Node 18+), fetch-mock should be used for HTTP mocking instead of nock, as nock does not support intercepting native fetch calls. This applies to apps/api/test/functional/sign-and-broadcast-tx.spec.ts and any other tests using native fetch.

Applied to files:

  • apps/provider-proxy/src/services/ProviderService/ProviderService.spec.ts
  • apps/provider-proxy/test/functional/provider-proxy-http.spec.ts
  • apps/provider-proxy/src/services/ProviderService/ProviderService.ts
  • apps/provider-proxy/test/setup/chainApiServer.ts
📚 Learning: 2025-06-08T03:07:13.871Z
Learnt from: stalniy
Repo: akash-network/console PR: 1436
File: apps/api/src/provider/repositories/provider/provider.repository.ts:79-90
Timestamp: 2025-06-08T03:07:13.871Z
Learning: The getProvidersHostUriByAttributes method in apps/api/src/provider/repositories/provider/provider.repository.ts already has comprehensive test coverage in provider.repository.spec.ts, including tests for complex HAVING clause logic with COUNT(*) FILTER (WHERE ...) syntax, signature conditions (anyOf/allOf), and glob pattern matching.

Applied to files:

  • apps/provider-proxy/src/services/ProviderService/ProviderService.spec.ts
📚 Learning: 2025-09-25T20:34:55.117Z
Learnt from: jigar-arc10
Repo: akash-network/console PR: 1970
File: apps/provider-console/src/config/network.config.ts:17-28
Timestamp: 2025-09-25T20:34:55.117Z
Learning: In cosmos-kit integration, nodesUrl and versionUrl should point to Cosmos API endpoints (not console backend API endpoints) as cosmos-kit expects these to be Cosmos REST endpoints for proper functionality.

Applied to files:

  • apps/provider-proxy/env/.env.mainnet
📚 Learning: 2025-07-03T14:40:49.886Z
Learnt from: jzsfkzm
Repo: akash-network/console PR: 1498
File: apps/api/src/services/external/templates/template-fetcher.service.ts:0-0
Timestamp: 2025-07-03T14:40:49.886Z
Learning: In the TemplateFetcherService class in apps/api/src/services/external/templates/template-fetcher.service.ts, the error handling strategy should maintain process resilience by catching all errors and returning null rather than re-throwing critical errors, to avoid breaking the whole template fetching process.

Applied to files:

  • apps/provider-proxy/src/services/ProviderService/ProviderService.ts
📚 Learning: 2025-11-25T17:45:39.561Z
Learnt from: CR
Repo: akash-network/console PR: 0
File: .cursor/rules/general.mdc:0-0
Timestamp: 2025-11-25T17:45:39.561Z
Learning: Applies to **/*.{ts,tsx,js} : Never use type `any` or cast to type `any`. Always define the proper TypeScript types.

Applied to files:

  • apps/provider-proxy/src/services/ProviderService/ProviderService.ts
📚 Learning: 2025-10-31T11:26:42.138Z
Learnt from: stalniy
Repo: akash-network/console PR: 2138
File: apps/api/src/billing/lib/batch-signing-client/batch-signing-client.service.ts:379-382
Timestamp: 2025-10-31T11:26:42.138Z
Learning: In TypeScript/JavaScript, the pattern of checking a cached value and then performing an async operation to fetch it without proper synchronization is race condition unsafe:
```typescript
private async getAddress() {
  if (!this.address) {
    this.address = await this.wallet.getFirstAddress();
  }
  return this.address;
}
```
Multiple concurrent calls can all pass the `if (!this.address)` check before any of them sets the value, leading to duplicate async operations. This should be flagged as a race condition. Proper synchronization (mutex, atomic promise caching, or guaranteed single-threaded execution) is required.

Applied to files:

  • apps/provider-proxy/test/setup/chainApiServer.ts
🧬 Code graph analysis (3)
apps/provider-proxy/test/functional/provider-proxy-http.spec.ts (4)
apps/provider-proxy/test/setup/proxyServer.ts (2)
  • stopServer (12-14)
  • startServer (7-10)
apps/provider-proxy/test/setup/providerServer.ts (2)
  • stopProviderServer (73-75)
  • startProviderServer (14-71)
apps/provider-proxy/test/setup/chainApiServer.ts (3)
  • stopChainApiServer (98-114)
  • generateBech32 (121-129)
  • startChainApiServer (10-96)
apps/provider-proxy/test/seeders/createX509CertPair.ts (1)
  • createX509CertPair (4-26)
apps/provider-proxy/src/services/ProviderService/ProviderService.ts (1)
packages/logging/src/services/logger/logger.service.ts (1)
  • error (141-143)
apps/provider-proxy/test/setup/chainApiServer.ts (1)
packages/http-sdk/src/certificates/certificates.service.ts (1)
  • getCertificates (25-37)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (14)
  • GitHub Check: log-collector-ci
  • GitHub Check: validate / validate-app
  • GitHub Check: test-build
  • GitHub Check: validate / validate-app
  • GitHub Check: test-build
  • GitHub Check: test-build
  • GitHub Check: validate / validate-app
  • GitHub Check: validate / validate-app
  • GitHub Check: test-build
  • GitHub Check: validate / validate-app
  • GitHub Check: test-build
  • GitHub Check: test-build
  • GitHub Check: validate / validate-app
  • GitHub Check: test-build
🔇 Additional comments (4)
apps/provider-proxy/env/.env.mainnet (1)

1-1: GRPC_NODE_URL wiring looks correct

The mainnet GRPC_NODE_URL value is well‑formed and consistent with the container wiring that passes it into createChainNodeSDK({ query: { baseUrl } }). No issues here.

apps/provider-proxy/test/functional/provider-proxy-http.spec.ts (1)

8-771: Functional tests correctly exercise GRPC_NODE_URL and gRPC failure modes

The test wiring and scenarios look consistent with the new gRPC/chain‑sdk flow:

  • startServer({ GRPC_NODE_URL: grpcServer.url }) matches the container’s expectation for GRPC_NODE_URL.
  • afterEach teardown now reliably stops proxy, provider, and chain gRPC servers, with stopChainApiServer safely handling mid‑test manual stops.
  • The new retry/caching tests (can work without gRPC by using cached certificates, retries fetching chain certificates if gRPC is unavailable, and retries if gRPC responds with error 14/unavailable) align with the retry policy and cached certificate behavior in ProviderService/CertificateValidator.

No functional or guideline issues spotted here.

apps/provider-proxy/src/container.ts (1)

1-24: ProviderService is correctly switched to ChainNodeSDK over GRPC_NODE_URL

ProviderService is now constructed with createChainNodeSDK({ query: { baseUrl: appConfig.GRPC_NODE_URL } }), with no tx wiring, which matches the requirement to use the chain‑sdk client in read‑only mode over gRPC. The change is minimal, type‑safe, and integrates cleanly with existing logging and DI.

apps/provider-proxy/src/services/ProviderService/ProviderService.ts (1)

38-68: Certificate query + decoding flow is correct and type-safe

  • Using QueryInput<QueryCertificatesRequest> with filter.state = "valid", owner, and decimal serial computed via BigInt(\0x${serialNumber}`).toString(10)` matches how serials are exposed by the chain and the test gRPC server.
  • fetchCertificate wraps getCertificates in a cockatiel retry policy, keeping retry concerns encapsulated.
  • The response handling correctly:
    • Requires exactly one certificate.
    • Safely retrieves certificate?.cert and returns null if missing.
  • The catch block uses error: unknown and logs a structured object including providerAddress, serialNumber, and error, in line with the “no any” guideline and the logger’s unknown signature.

This core flow looks good and aligns with the new chain‑sdk‑based design.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

♻️ Duplicate comments (1)
apps/provider-proxy/src/services/ProviderService/ProviderService.ts (1)

10-18: Refine retryable error detection—avoid retrying on Internal and tighten the guard

Two points here:

  1. Retrying on SDKErrorCode.Internal
    INTERNAL errors usually indicate a server bug or non‑transient failure. Auto‑retrying them can mask issues and add load without much benefit, especially since this is a read path and you already have a dedicated retry policy for transient network problems. Consider limiting retries to clearly transient codes such as SDKErrorCode.Unavailable (and, if the SDK exposes it distinctly, a timeout/deadline code), and stop retrying Internal.

  2. Stronger runtime guard for error.code
    hasErrorCode currently only checks that "code" in error. It may classify arbitrary objects (including ones with string codes like Node’s ECONNREFUSED) as ErrorWithCode, even though RETRIABLE_ERROR_CODES is numeric. You can cheaply tighten this to only accept numeric codes and remove the non‑null assertion:

-const RETRIABLE_ERROR_CODES = [SDKErrorCode.Internal, SDKErrorCode.Unavailable];
+const RETRIABLE_ERROR_CODES = [SDKErrorCode.Unavailable];

-interface ErrorWithCode {
-  code?: number;
-}
+interface ErrorWithCode {
+  code: number;
+}

-function hasErrorCode(error: unknown): error is ErrorWithCode {
-  return typeof error === "object" && error !== null && "code" in error;
-}
+function hasErrorCode(error: unknown): error is ErrorWithCode {
+  if (typeof error !== "object" || error === null || !("code" in error)) {
+    return false;
+  }
+
+  const code = (error as { code?: unknown }).code;
+  return typeof code === "number";
+}

-    handleWhen(error => {
-      return hasErrorCode(error) && RETRIABLE_ERROR_CODES.includes(error.code!);
-    }),
+    handleWhen(error => hasErrorCode(error) && RETRIABLE_ERROR_CODES.includes(error.code)),

This keeps retries focused on the numeric SDK codes you actually want, and it avoids relying on ! for error.code.

Also applies to: 21-29

🧹 Nitpick comments (2)
apps/provider-proxy/src/services/ProviderService/ProviderService.ts (2)

32-32: Validate/document serial number format used for BigInt conversion

The query construction looks good and the use of QueryInput<QueryCertificatesRequest> gives you nice typing. One nuance is the serial conversion:

serial: BigInt(`0x${serialNumber}`).toString(10)

This assumes serialNumber is a hex string without a 0x prefix. If upstream ever passes a decimal value, or an already‑prefixed hex string, BigInt will throw synchronously and the error will be surfaced as a generic fetch failure.

Consider either:

  • Explicitly documenting that serialNumber must be a bare hex string, or
  • Normalizing/validating here (e.g., stripping a leading 0x, or short‑circuiting with a logged validation error and returning null) so input‑format issues are not conflated with network/SDK errors.

Also applies to: 37-46


48-52: Minor defensive and style tweaks in fetch/parse path

Functionally this flow looks correct—single certificate is converted to X509Certificate, and errors are logged with useful context plus the full error object.

A couple of low‑impact refinements you might consider:

  1. Defensive check on certificates array
    If the SDK ever returns certificates as undefined instead of [] on “no results”, response.certificates.length would throw and be caught as a generic error. Using optional chaining is slightly more robust:
-      const response = await this.fetchCertificate(queryParams);
-      if (response.certificates.length === 1) {
+      const response = await this.fetchCertificate(queryParams);
+      if (response.certificates?.length === 1) {
         const cert = response.certificates[0]?.certificate?.cert;
         return cert ? new X509Certificate(cert) : null;
       }
  1. Simplify fetchCertificate’s async/await usage
    Since retryPolicy.execute already returns a promise of the inner function’s result, you don’t need both the async wrapper and the inner await:
-  private async fetchCertificate(getCertificatesParams: QueryInput<QueryCertificatesRequest>): Promise<QueryCertificatesResponse> {
-    return this.retryPolicy.execute(async () => {
-      return await this.chainSdkClient.akash.cert.v1.getCertificates(getCertificatesParams);
-    });
-  }
+  private fetchCertificate(getCertificatesParams: QueryInput<QueryCertificatesRequest>): Promise<QueryCertificatesResponse> {
+    return this.retryPolicy.execute(() =>
+      this.chainSdkClient.akash.cert.v1.getCertificates(getCertificatesParams)
+    );
+  }

Also, good call on typing the catch parameter as unknown and logging the whole error object; this aligns with the project’s “no any” guideline and preserves stack traces.

Also applies to: 55-58, 60-60, 62-65

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 35388a9 and 3d2ddef.

📒 Files selected for processing (1)
  • apps/provider-proxy/src/services/ProviderService/ProviderService.ts (1 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**/*.{ts,tsx,js}

📄 CodeRabbit inference engine (.cursor/rules/general.mdc)

**/*.{ts,tsx,js}: Never use type any or cast to type any. Always define the proper TypeScript types.
Never use deprecated methods from libraries.
Don't add unnecessary comments to the code.

Files:

  • apps/provider-proxy/src/services/ProviderService/ProviderService.ts
🧠 Learnings (4)
📓 Common learnings
Learnt from: ygrishajev
Repo: akash-network/console PR: 2254
File: apps/api/test/functional/sign-and-broadcast-tx.spec.ts:4-4
Timestamp: 2025-11-19T15:15:07.283Z
Learning: In the Akash Network Console project, when tests use native Node.js fetch (available in Node 18+), fetch-mock should be used for HTTP mocking instead of nock, as nock does not support intercepting native fetch calls. This applies to apps/api/test/functional/sign-and-broadcast-tx.spec.ts and any other tests using native fetch.
📚 Learning: 2025-11-19T15:15:07.283Z
Learnt from: ygrishajev
Repo: akash-network/console PR: 2254
File: apps/api/test/functional/sign-and-broadcast-tx.spec.ts:4-4
Timestamp: 2025-11-19T15:15:07.283Z
Learning: In the Akash Network Console project, when tests use native Node.js fetch (available in Node 18+), fetch-mock should be used for HTTP mocking instead of nock, as nock does not support intercepting native fetch calls. This applies to apps/api/test/functional/sign-and-broadcast-tx.spec.ts and any other tests using native fetch.

Applied to files:

  • apps/provider-proxy/src/services/ProviderService/ProviderService.ts
📚 Learning: 2025-07-03T14:40:49.886Z
Learnt from: jzsfkzm
Repo: akash-network/console PR: 1498
File: apps/api/src/services/external/templates/template-fetcher.service.ts:0-0
Timestamp: 2025-07-03T14:40:49.886Z
Learning: In the TemplateFetcherService class in apps/api/src/services/external/templates/template-fetcher.service.ts, the error handling strategy should maintain process resilience by catching all errors and returning null rather than re-throwing critical errors, to avoid breaking the whole template fetching process.

Applied to files:

  • apps/provider-proxy/src/services/ProviderService/ProviderService.ts
📚 Learning: 2025-11-25T17:45:39.561Z
Learnt from: CR
Repo: akash-network/console PR: 0
File: .cursor/rules/general.mdc:0-0
Timestamp: 2025-11-25T17:45:39.561Z
Learning: Applies to **/*.{ts,tsx,js} : Never use type `any` or cast to type `any`. Always define the proper TypeScript types.

Applied to files:

  • apps/provider-proxy/src/services/ProviderService/ProviderService.ts
🧬 Code graph analysis (1)
apps/provider-proxy/src/services/ProviderService/ProviderService.ts (1)
packages/logging/src/services/logger/logger.service.ts (1)
  • error (141-143)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (11)
  • GitHub Check: codecov/project/notifications
  • GitHub Check: validate / validate-app
  • GitHub Check: test-build
  • GitHub Check: test-build
  • GitHub Check: validate / validate-app
  • GitHub Check: test-build
  • GitHub Check: validate / validate-app
  • GitHub Check: test-build
  • GitHub Check: test-build
  • GitHub Check: test-build
  • GitHub Check: test-build
🔇 Additional comments (1)
apps/provider-proxy/src/services/ProviderService/ProviderService.ts (1)

1-3: Imports and SDK typing look solid

Using import type for the SDK symbols and the ChainNodeSDK = ReturnType<typeof createChainNodeSDK> alias keeps this service type‑safe while avoiding an unnecessary runtime dependency on the SDK factory in this module. No issues here.

Also applies to: 5-5, 8-8

@stalniy stalniy merged commit 8018303 into akash-network:main Nov 28, 2025
64 checks passed
stalniy added a commit that referenced this pull request Nov 29, 2025
stalniy added a commit that referenced this pull request Nov 29, 2025
Revert "feat: load certificate from gRPC (#2256)"

This reverts commit 8018303.
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.

Integrate chain-sdk into provider-proxy

2 participants