Skip to content

Add emerald grpc#128

Open
a10zn8 wants to merge 4 commits intomainfrom
add-emerald-grpc
Open

Add emerald grpc#128
a10zn8 wants to merge 4 commits intomainfrom
add-emerald-grpc

Conversation

@a10zn8
Copy link

@a10zn8 a10zn8 commented Mar 6, 2026

No description provided.

@a10zn8 a10zn8 force-pushed the add-emerald-grpc branch from 96a0b8b to 08ca6f6 Compare March 6, 2026 20:58
@a10zn8 a10zn8 requested review from KirillPamPam and Copilot and removed request for KirillPamPam March 7, 2026 07:42
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Adds Emerald gRPC support to Nodecore by importing/providing generated protobuf bindings, wiring up a gRPC server, and introducing optional JWT-based gRPC authentication.

Changes:

  • Added generated Emerald protobuf + gRPC stubs under pkg/dshackle and a Makefile target to regenerate them from the emerald-grpc submodule.
  • Implemented gRPC server bootstrap plus Blockchain/Auth services (including session-based auth).
  • Extended chain configuration to include GrpcId resolution and added tests around gRPC chain lookup and gRPC service logic.

Reviewed changes

Copilot reviewed 20 out of 22 changed files in this pull request and generated 8 comments.

Show a summary per file
File Description
pkg/dshackle/common.pb.go Adds generated protobuf types/enums used by Emerald API (ChainRef, addresses, etc.).
pkg/dshackle/blockchain_grpc.pb.go Adds generated gRPC client/server interfaces for Blockchain service.
pkg/dshackle/auth_grpc.pb.go Adds generated gRPC client/server interfaces for Auth service.
pkg/dshackle/auth.pb.go Adds generated protobuf messages for Auth request/response.
pkg/chains/chains.go Adds GrpcId to chain config and lookup map for resolving chains from gRPC enum IDs.
pkg/chains/chains_test.go Adds tests for GetChainByGrpcId behavior.
internal/server/grpc_server.go Wires up and runs a gRPC server (TLS optional), registers Auth/Blockchain services.
internal/server/grpc_blockchain.go Implements Blockchain streaming RPCs and subscription mapping/heartbeats.
internal/server/grpc_blockchain_test.go Adds tests for native call chunking, unauthenticated behavior, and subscribe mapping.
internal/server/grpc_auth.go Implements JWT-based auth exchange and session store/validation.
internal/server/grpc_auth_test.go Adds tests for auth success/disabled/invalid token cases and session TTL/auth.
internal/config/server_config.go Adds grpc-port and grpc-auth config + validation.
internal/config/defaults.go Adds defaults for GrpcAuthConfig.
internal/config/server_config_test.go Updates server config defaults test to include GrpcAuthConfig.
internal/config/config_test.go Updates full-config test to include GrpcAuthConfig.
internal/app/app.go Starts the gRPC server alongside the HTTP server.
Makefile Adds dshackle-proto-gen target to generate protobuf bindings from emerald-grpc.
.gitmodules Adds emerald-grpc submodule reference.
emerald-grpc Adds the emerald-grpc submodule pointer (commit ref).
go.mod Adds direct deps for grpc and protobuf, plus genproto rpc indirect.
go.sum Adds checksums for newly pulled deps.
Comments suppressed due to low confidence (1)

pkg/chains/chains.go:1

  • UnknownChaindoesn’t set a sentinel value forChain. With the new gRPC resolution flow, leaving Chainat its zero value risks mapping unknown gRPC IDs to a real chain (commonly index 0). SetUnknownChain.Chainto a negative sentinel (e.g., -1) and keep downstream checks consistent, or adjustGetChainByGrpcId`/resolution logic to make unknown unambiguously invalid.
package chains

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

specMethod = chainSupervisor.GetMethod(item.GetMethod())
}
requestID := strconv.FormatUint(uint64(item.GetId()), 10)
requests = append(requests, protocol.NewUpstreamJsonRpcRequest(
Copy link
Collaborator

Choose a reason for hiding this comment

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

It creates a non-streaming request, but it's a good idea to control it through the API params

Copy link
Author

Choose a reason for hiding this comment

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

Addressed in f568dc0.

What was added:

  • Streaming request mode is now selected for stream-capable methods in buildNativeCallRequests (protocol.NewStreamUpstreamJsonRpcRequest for eth_getLogs/getProgramAccounts): internal/server/grpc_blockchain.go.
  • Chunk size is controlled through API input (NativeCallRequest.ChunkSize) and passed into reply emission in NativeCall: sendNativeCallReplyItems(stream, wrapper, request.GetChunkSize()) in internal/server/grpc_blockchain.go.

return append([]byte(nil), response.ResponseResult()...), nil
}

rawStreamResponse, err := io.ReadAll(response.EncodeResponse([]byte("0")))
Copy link
Collaborator

Choose a reason for hiding this comment

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

However, even if we create a streaming request, we read all the data at once. It suppresses the streaming feature

Copy link
Author

Choose a reason for hiding this comment

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

Addressed in f568dc0.

It no longer reads the whole JSON-RPC body into memory for streaming path:

  • streamNativeCallPayload now processes an io.Reader and emits gRPC chunks incrementally.
  • streamJsonRPCResult extracts only the result field from the streaming JSON-RPC envelope token-by-token, then writes to chunk emitter.
  • Parser was moved into a dedicated file with dedicated tests:
    • internal/server/json_rpc_result_stream.go
    • internal/server/json_rpc_result_stream_test.go.

return nil, false, nil
}

var envelope struct {
Copy link
Collaborator

Choose a reason for hiding this comment

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

In SubscriptionRequestProcessor.ProcessRequest we already have two fields - the whole event and result, so I think it's possible to pass a special flag here to return in that case the result field only instead of the whole event

Copy link
Author

Choose a reason for hiding this comment

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

Addressed in f568dc0.

Implemented result-only subscription mode:

  • NativeSubscribe now sets WithSubscriptionResultOnly(true) when building upstream request (internal/server/grpc_blockchain.go).
  • SubscriptionRequestProcessor checks this flag and sends NewSubscriptionResultEventResponse (result-only payload) instead of full event frame (internal/upstreams/flow/sub_processor.go).
  • Flag plumbing is in UpstreamJsonRpcRequest (WithSubscriptionResultOnly / IsSubscriptionResultOnly) in internal/protocol/json_rpc_request.go.

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.

3 participants