node: ZAP-native everywhere — kill every //go:build grpc path

The companion commit `7496606282` retired the gRPC fallback inside
vms/rpcchainvm/. This commit closes the loop by deleting every
remaining `//go:build grpc` file under node/, removing the dual-build
plumbing entirely. ZAP is the only wire protocol; there is no
`-tags=grpc` opt-in.

Per the "one and only one way to do everything" mandate, the
backwards-compat scaffolding (gRPC adapters, protoc stubs, connect-go
example handlers, OTLP gRPC exporter, x/sync gRPC sync engine,
keystore-over-gRPC client/server, rpcwarp gRPC signer, gRPC alias
reader) is removed forward-only — no aliases, no deprecation period.

Deletions (84 files):
  - proto/pb/{aliasreader,http,io,keystore,message,messenger,net,p2p,
    platformvm,rpcdb,sdk,sender,sharedmemory,signer,sync,
    validatorstate,vm,warp}/ — protoc stubs (entire tree)
  - proto/{p2p,platformvm,sync,vm}/*_grpc.go — gRPC type re-exports
  - db/rpcdb/{grpc_server,grpc_client,grpc_test}.go — rpcdb gRPC adapter
  - service/keystore/rpckeystore/ — keystore-over-gRPC (dead consumer)
  - x/sync/ — entire merkledb sync engine (100% gRPC-tagged)
  - internal/ids/rpcaliasreader/ — gRPC alias reader (dead consumer)
  - connectproto/ — connect-go XSVM ping handler scaffolding
  - vms/platformvm/warp/rpcwarp/{client,server}.go — gRPC warp signer
  - vms/platformvm/network/warp.go — protobuf-based warp justification
    handler (warp_zap.go retains the no-op verifier consumers expect)
  - vms/components/message/message_grpc.go + message_test.go
  - vms/example/xsvm/api/ping.go + vm_http_grpc.go + cmd/{run,xsvm}/
  - wallet/network/primary/examples/sign-l1-validator-* (5 dead
    example main packages)
  - trace/{exporter_grpc,exporter_type,exporter_type_test,noop,tracer}.go
    (OTLP gRPC exporter + duplicate Tracer types — trace_zap.go has
    the canonical Tracer interface + no-op tracer)
  - message/bft_grpc.go (Simplex BFT wrapper)

Edits (9 files): every surviving `_zap.go` drops its `//go:build !grpc`
constraint (the files are unconditional now) and drops stale
"ZAP version" / "ZAP mode" inline comments.

Doc updates:
  - LLM.md ZAP Transport section: remove the `-tags=grpc` opt-in
    language. Replace with "ZAP is the only wire protocol... there is
    one and only one way". Update Latest Tag to v1.26.31. Update the
    rpcdb topology section to reflect single-adapter state.

go.mod: connectrpc.com/connect, connectrpc.com/grpcreflect,
otlptracegrpc moved out of direct deps. google.golang.org/grpc +
protobuf demoted to indirect (still pulled transitively via luxfi/dex).

Verified:
  - `go build ./...` (default, no tags) clean
  - `go test ./db/rpcdb/... ./trace/... ./message/... ./vms/rpcchainvm/...
    ./vms/components/message/... ./vms/platformvm/network/...
    ./vms/example/xsvm/... ./service/keystore/... ./proto/...` clean
  - `grep -rln '//go:build grpc' --include='*.go' node/` returns zero
  - `grep -rln '//go:build !grpc' --include='*.go' node/` returns zero
  - `grep -rln 'google.golang.org/grpc' --include='*.go' node/` returns
    zero (only transitive deps remain in go.sum)

Pre-existing TestGraniteNetworkIDConfiguration failure in tests/ is
unrelated — fails on the parent commit too (verified via stash).
This commit is contained in:
Hanzo AI
2026-05-16 17:23:26 -07:00
parent 7496606282
commit 43f7aa2b03
95 changed files with 57 additions and 10480 deletions
-68
View File
@@ -1,68 +0,0 @@
//go:build grpc
// Copyright (C) 2019-2025, Lux Industries Inc. All rights reserved.
// See the file LICENSE for licensing terms.
package trace
import (
"context"
"time"
"go.opentelemetry.io/otel/exporters/otlp/otlptrace"
"go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc"
"go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp"
sdktrace "go.opentelemetry.io/otel/sdk/trace"
)
const tracerProviderExportCreationTimeout = 5 * time.Second
type ExporterConfig struct {
Type ExporterType `json:"type"`
// Endpoint to send metrics to. If empty, the default endpoint will be used.
Endpoint string `json:"endpoint"`
// Headers to send with metrics
Headers map[string]string `json:"headers"`
// If true, don't use TLS
Insecure bool `json:"insecure"`
}
func newExporter(config ExporterConfig) (sdktrace.SpanExporter, error) {
var client otlptrace.Client
switch config.Type {
case GRPC:
opts := []otlptracegrpc.Option{
otlptracegrpc.WithHeaders(config.Headers),
otlptracegrpc.WithTimeout(tracerExportTimeout),
}
if config.Endpoint != "" {
opts = append(opts, otlptracegrpc.WithEndpoint(config.Endpoint))
}
if config.Insecure {
opts = append(opts, otlptracegrpc.WithInsecure())
}
client = otlptracegrpc.NewClient(opts...)
case HTTP:
opts := []otlptracehttp.Option{
otlptracehttp.WithHeaders(config.Headers),
otlptracehttp.WithTimeout(tracerExportTimeout),
}
if config.Endpoint != "" {
opts = append(opts, otlptracehttp.WithEndpoint(config.Endpoint))
}
if config.Insecure {
opts = append(opts, otlptracehttp.WithInsecure())
}
client = otlptracehttp.NewClient(opts...)
default:
return nil, errUnknownExporterType
}
ctx, cancel := context.WithTimeout(context.Background(), tracerProviderExportCreationTimeout)
defer cancel()
return otlptrace.New(ctx, client)
}
-91
View File
@@ -1,91 +0,0 @@
//go:build grpc
// Copyright (C) 2019-2025, Lux Industries Inc. All rights reserved.
// See the file LICENSE for licensing terms.
package trace
import (
"errors"
"fmt"
"strings"
)
const (
Disabled ExporterType = iota
GRPC
HTTP
ZAP // ZAP-based OTLP transport (default, no gRPC dependency)
)
var (
errUnknownExporterType = errors.New("unknown exporter type")
errMissingQuotes = errors.New("first and last characters should be quotes")
)
func ExporterTypeFromString(exporterTypeStr string) (ExporterType, error) {
switch strings.ToLower(exporterTypeStr) {
case "disabled":
return Disabled, nil
case "grpc":
return GRPC, nil
case "http":
return HTTP, nil
case "zap":
return ZAP, nil
default:
return 0, fmt.Errorf("%w: %q", errUnknownExporterType, exporterTypeStr)
}
}
type ExporterType byte
func (t ExporterType) MarshalJSON() ([]byte, error) {
str, ok := t.toString()
if !ok {
return nil, fmt.Errorf("%w: %d", errUnknownExporterType, t)
}
return []byte(`"` + str + `"`), nil
}
func (t *ExporterType) UnmarshalJSON(b []byte) error {
str := string(b)
if str == "null" { // If "null", do nothing
return nil
}
if len(str) < 2 {
return errMissingQuotes
}
lastIndex := len(str) - 1
if str[0] != '"' || str[lastIndex] != '"' {
return errMissingQuotes
}
exporterType, err := ExporterTypeFromString(str[1:lastIndex])
if err != nil {
return err
}
*t = exporterType
return nil
}
func (t ExporterType) String() string {
str, _ := t.toString()
return str
}
func (t ExporterType) toString() (string, bool) {
switch t {
case Disabled:
return "disabled", true
case GRPC:
return "grpc", true
case HTTP:
return "http", true
case ZAP:
return "zap", true
default:
return "unknown", false
}
}
-132
View File
@@ -1,132 +0,0 @@
//go:build grpc
// Copyright (C) 2019-2025, Lux Industries Inc. All rights reserved.
// See the file LICENSE for licensing terms.
package trace
import (
"testing"
"github.com/stretchr/testify/require"
)
func TestMarshal(t *testing.T) {
tests := []struct {
name string
exporter ExporterType
expected string
expectedError error
}{
{
name: "unknown_type",
exporter: 255,
expectedError: errUnknownExporterType,
},
{
name: "disabled",
exporter: Disabled,
expected: `"disabled"`,
},
{
name: "grpc",
exporter: GRPC,
expected: `"grpc"`,
},
{
name: "http",
exporter: HTTP,
expected: `"http"`,
},
{
name: "zap",
exporter: ZAP,
expected: `"zap"`,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
require := require.New(t)
actual, err := tt.exporter.MarshalJSON()
require.ErrorIs(err, tt.expectedError)
require.Equal(tt.expected, string(actual))
})
}
}
func TestUnmarshal(t *testing.T) {
tests := []struct {
name string
json string
expected ExporterType
expectedError error
}{
{
name: "no_quotes",
json: "grpc",
expectedError: errMissingQuotes,
},
{
name: "single_left_quote",
json: `"grpc`,
expectedError: errMissingQuotes,
},
{
name: "single_right_quote",
json: `grpc"`,
expectedError: errMissingQuotes,
},
{
name: "only_one_quote",
json: `"`,
expectedError: errMissingQuotes,
},
{
name: "multiple_quotes",
json: `""grpc"""`,
expectedError: errUnknownExporterType,
},
{
name: "empty_string",
json: `""`,
expectedError: errUnknownExporterType,
},
{
name: "null",
json: `null`,
},
{
name: "disabled",
json: `"disabled"`,
expected: Disabled,
},
{
name: "grpc",
json: `"grpc"`,
expected: GRPC,
},
{
name: "http",
json: `"http"`,
expected: HTTP,
},
{
name: "zap",
json: `"zap"`,
expected: ZAP,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
require := require.New(t)
var actual ExporterType
err := actual.UnmarshalJSON([]byte(tt.json))
require.ErrorIs(err, tt.expectedError)
require.Equal(tt.expected, actual)
})
}
}
-19
View File
@@ -1,19 +0,0 @@
//go:build grpc
// Copyright (C) 2019-2025, Lux Industries Inc. All rights reserved.
// See the file LICENSE for licensing terms.
package trace
import "go.opentelemetry.io/otel/trace/noop"
var Noop Tracer = noOpTracer{}
// noOpTracer is an implementation of trace.Tracer that does nothing.
type noOpTracer struct {
noop.Tracer
}
func (noOpTracer) Close() error {
return nil
}
+10 -11
View File
@@ -1,11 +1,10 @@
//go:build !grpc
// Copyright (C) 2019-2025, Lux Industries Inc. All rights reserved.
// See the file LICENSE for licensing terms.
// Package trace provides tracing functionality.
// In ZAP mode (default), tracing is disabled - no OpenTelemetry dependencies.
// Use -tags=grpc to enable full OpenTelemetry tracing support.
// Package trace provides tracing primitives. The package ships a
// no-op tracer suitable for ZAP-native production builds; a real
// exporter implementation lives outside the node tree and plugs in
// via the Tracer interface.
package trace
import (
@@ -185,13 +184,13 @@ func (noopTracer) Start(ctx context.Context, _ string, _ ...SpanStartOption) (co
type noopSpan struct{}
func (noopSpan) End(...SpanEndOption) {}
func (noopSpan) SetStatus(StatusCode, string) {}
func (noopSpan) RecordError(error, ...EventOption) {}
func (noopSpan) AddEvent(string, ...EventOption) {}
func (noopSpan) SetAttributes(...KeyValue) {}
func (noopSpan) End(...SpanEndOption) {}
func (noopSpan) SetStatus(StatusCode, string) {}
func (noopSpan) RecordError(error, ...EventOption) {}
func (noopSpan) AddEvent(string, ...EventOption) {}
func (noopSpan) SetAttributes(...KeyValue) {}
// New creates a new tracer (returns Noop in ZAP mode)
// New creates a new tracer (returns Noop in the canonical ZAP build).
func New(Config) (Tracer, error) {
return Noop, nil
}
-134
View File
@@ -1,134 +0,0 @@
//go:build grpc
// Copyright (C) 2019-2025, Lux Industries Inc. All rights reserved.
// See the file LICENSE for licensing terms.
package trace
import (
"context"
"fmt"
"io"
"time"
"go.opentelemetry.io/otel/attribute"
"go.opentelemetry.io/otel/codes"
"go.opentelemetry.io/otel/sdk/resource"
oteltrace "go.opentelemetry.io/otel/trace"
sdktrace "go.opentelemetry.io/otel/sdk/trace"
semconv "go.opentelemetry.io/otel/semconv/v1.4.0"
)
// Type aliases for otel compatibility
type (
KeyValue = attribute.KeyValue
SpanStartOption = oteltrace.SpanStartOption
SpanEndOption = oteltrace.SpanEndOption
Span = oteltrace.Span
StatusCode = codes.Code
)
// Re-export otel status codes
const (
StatusUnset = codes.Unset
StatusOK = codes.Ok
StatusError = codes.Error
)
// EventOption is a type alias for span event options
type EventOption = oteltrace.EventOption
// Helper functions wrapping otel attribute constructors
// String creates a string attribute
func String(key, value string) KeyValue {
return attribute.String(key, value)
}
// Int creates an int attribute
func Int(key string, value int) KeyValue {
return attribute.Int(key, value)
}
// Int64 creates an int64 attribute
func Int64(key string, value int64) KeyValue {
return attribute.Int64(key, value)
}
// Bool creates a bool attribute
func Bool(key string, value bool) KeyValue {
return attribute.Bool(key, value)
}
// Stringer creates a string attribute from a fmt.Stringer
func Stringer(key string, value fmt.Stringer) KeyValue {
return attribute.Stringer(key, value)
}
// WithAttributes returns a SpanStartOption with the given attributes
func WithAttributes(kv ...KeyValue) SpanStartOption {
return oteltrace.WithAttributes(kv...)
}
const (
tracerExportTimeout = 10 * time.Second
// [tracerProviderShutdownTimeout] is longer than [tracerExportTimeout] so
// in-flight exports can finish before the tracer provider shuts down.
tracerProviderShutdownTimeout = 15 * time.Second
)
type Config struct {
ExporterConfig `json:"exporterConfig"`
// The fraction of traces to sample.
// If >= 1 always samples.
// If <= 0 never samples.
TraceSampleRate float64 `json:"traceSampleRate"`
AppName string `json:"appName"`
Version string `json:"version"`
}
type Tracer interface {
oteltrace.Tracer
io.Closer
}
type tracer struct {
oteltrace.Tracer
tp *sdktrace.TracerProvider
}
func (t *tracer) Close() error {
ctx, cancel := context.WithTimeout(context.Background(), tracerProviderShutdownTimeout)
defer cancel()
return t.tp.Shutdown(ctx)
}
func New(config Config) (Tracer, error) {
if config.ExporterConfig.Type == Disabled {
return Noop, nil
}
exporter, err := newExporter(config.ExporterConfig)
if err != nil {
return nil, err
}
tracerProviderOpts := []sdktrace.TracerProviderOption{
sdktrace.WithBatcher(exporter, sdktrace.WithExportTimeout(tracerExportTimeout)),
sdktrace.WithResource(resource.NewWithAttributes(semconv.SchemaURL,
attribute.String("version", config.Version),
semconv.ServiceNameKey.String(config.AppName),
)),
sdktrace.WithSampler(sdktrace.TraceIDRatioBased(config.TraceSampleRate)),
}
tracerProvider := sdktrace.NewTracerProvider(tracerProviderOpts...)
return &tracer{
Tracer: tracerProvider.Tracer(config.AppName),
tp: tracerProvider,
}, nil
}