mirror of
https://github.com/luxfi/node.git
synced 2026-07-27 03:39:39 +00:00
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:
@@ -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)
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -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
@@ -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
@@ -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
|
||||
}
|
||||
Reference in New Issue
Block a user