Skip to main content

Go Integration

This guide demonstrates how to interact with the Surflux gRPC API using Go. Go's strong concurrency support and performance make it an excellent choice for high-throughput blockchain applications.

Overview

Go provides excellent native support for gRPC through the google.golang.org/grpc package. This guide will walk you through setting up a complete Go project for Sui gRPC integration with proper authentication.

Prerequisites

  • Go 1.19 or later
  • The protoc compiler (Protocol Buffers compiler)

Step 1: Create a New Project

Create a dedicated directory for your Sui gRPC project:

mkdir sui-grpc-go
cd sui-grpc-go
go mod init sui-grpc-go

Step 2: Install Dependencies

Install the required gRPC and Protocol Buffer packages:

go get -u google.golang.org/grpc
go get -u google.golang.org/protobuf/cmd/protoc-gen-go
go get -u google.golang.org/grpc/cmd/protoc-gen-go-grpc

Step 3: Download and Generate Proto Files

Clone the official Sui proto definitions:

mkdir -p proto
cd proto
git clone https://github.com/MystenLabs/sui-apis.git

Generate Go code from the proto files:

# Inject go_package option (required for Go code generation)
for f in sui-apis/proto/sui/rpc/v2/*.proto; do
if ! grep -q "option go_package" "$f"; then
sed -i 's/package sui.rpc.v2;/package sui.rpc.v2;\noption go_package = "sui-grpc-go\/proto\/sui\/rpc\/v2";/' "$f"
fi
done

# Generate Go code
protoc --go_out=. --go_opt=module=sui-grpc-go \
--go-grpc_out=. --go-grpc_opt=module=sui-grpc-go \
sui-apis/proto/sui/rpc/v2/*.proto

Authentication

Surflux requires authentication via the x-api-key header. We'll implement a custom PerRPCCredentials to automatically inject this header.

Custom Auth Implementation

package main

import (
"context"
)

// apiKeyAuth implements credentials.PerRPCCredentials to inject the API key
type apiKeyAuth struct {
apiKey string
}

// GetRequestMetadata attaches the x-api-key header to every request
func (a *apiKeyAuth) GetRequestMetadata(ctx context.Context, uri ...string) (map[string]string, error) {
return map[string]string{
"x-api-key": a.apiKey,
}, nil
}

// RequireTransportSecurity indicates whether the credentials require TLS
func (a *apiKeyAuth) RequireTransportSecurity() bool {
return true
}

Complete Example

Here's a complete example showing how to connect to Surflux and fetch epoch information:

package main

import (
"context"
"crypto/tls"
"fmt"
"log"
"time"

"google.golang.org/grpc"
"google.golang.org/grpc/credentials"

// Import your generated proto package
// pb "sui-grpc-go/proto/sui/rpc/v2"
)

const (
serverAddr = "grpc.surflux.dev:443"
apiKey = "YOUR_API_KEY"
)

// apiKeyAuth implements credentials.PerRPCCredentials
type apiKeyAuth struct {
apiKey string
}

func (a *apiKeyAuth) GetRequestMetadata(ctx context.Context, uri ...string) (map[string]string, error) {
return map[string]string{
"x-api-key": a.apiKey,
}, nil
}

func (a *apiKeyAuth) RequireTransportSecurity() bool {
return true
}

func main() {
// Create TLS credentials
creds := credentials.NewTLS(&tls.Config{
MinVersion: tls.VersionTLS12,
})

// Create connection with TLS and API key auth
conn, err := grpc.Dial(
serverAddr,
grpc.WithTransportCredentials(creds),
grpc.WithPerRPCCredentials(&apiKeyAuth{apiKey: apiKey}),
)
if err != nil {
log.Fatalf("Failed to connect: %v", err)
}
defer conn.Close()

// Create the client (uncomment when using generated code)
// client := pb.NewLedgerServiceClient(conn)

// Create context with timeout
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()

// Make a request (uncomment when using generated code)
// req := &pb.GetEpochRequest{}
// resp, err := client.GetEpoch(ctx, req)
// if err != nil {
// log.Fatalf("Request failed: %v", err)
// }

fmt.Println("Connection successful! Uncomment the client code above to make requests.")

// Make a request (uncomment when using generated code)
// req := &pb.GetEpochRequest{}
// resp, err := client.GetEpoch(ctx, req)
// if err != nil {
// log.Fatalf("Request failed: %v", err)
// }

// fmt.Printf("Current Epoch: %v\n", resp.Epoch.GetEpoch())
}

Making Requests

Once your proto code is generated, you can make requests to any service:

// Example: Get a checkpoint
req := &pb.GetCheckpointRequest{
CheckpointId: &pb.GetCheckpointRequest_SequenceNumber{
SequenceNumber: 1000,
},
}

resp, err := client.GetCheckpoint(ctx, req)
if err != nil {
log.Fatalf("GetCheckpoint failed: %v", err)
}

fmt.Printf("Checkpoint Digest: %s\n", resp.Checkpoint.GetDigest())

Best Practices

  1. Connection Pooling: Reuse gRPC connections rather than creating new ones for each request.
  2. Context Timeouts: Always use context with timeouts to prevent hanging requests.
  3. Error Handling: Check for both network errors and gRPC status codes.
  4. Graceful Shutdown: Always close connections when done using defer conn.Close().

Next Steps

  • Explore the generated proto definitions to see all available services and methods
  • Implement retry logic for production applications
  • Consider using interceptors for logging and monitoring