node: add spy service
Change-Id: Ieb04e6d26c7778d8a8afbbeaee79d764d9f2cd31
This commit is contained in:
parent
2e0a225c23
commit
bc48b1b51d
10
DEVELOP.md
10
DEVELOP.md
|
@ -133,6 +133,16 @@ IntelliJ's [remote development backend](https://www.jetbrains.com/remote-develop
|
|||
|
||||
## Tips and tricks
|
||||
|
||||
### Call gRPC services
|
||||
|
||||
tools/bin/grpcurl -protoset <(tools/bin/buf build -o -) -plaintext localhost:7072 spy.v1.SpyRPCService/SubscribeSignedVAA
|
||||
|
||||
With parameters (using proto json encoding):
|
||||
|
||||
tools/bin/grpcurl -protoset <(tools/bin/buf build -o -) \
|
||||
-d '{"filters": [{"emitter_filter": {"emitter_address": "574108aed69daf7e625a361864b1f74d13702f2ca56de9660e566d1d8691848d", "chain_id": "CHAIN_ID_SOLANA"}}]}' \
|
||||
-plaintext localhost:7072 spy.v1.SpyRPCService/SubscribeSignedVAA
|
||||
|
||||
### Post messages
|
||||
|
||||
To Solana:
|
||||
|
|
25
Tiltfile
25
Tiltfile
|
@ -137,6 +137,14 @@ k8s_resource("guardian", resource_deps = ["proto-gen", "solana-devnet"], port_fo
|
|||
port_forward(2345, name = "Debugger [:2345]", host = webHost),
|
||||
])
|
||||
|
||||
# spy
|
||||
k8s_yaml_with_ns("devnet/spy.yaml")
|
||||
|
||||
k8s_resource("spy", resource_deps = ["proto-gen", "guardian"], port_forwards = [
|
||||
port_forward(6061, container_port = 6060, name = "Debug/Status Server [:6061]", host = webHost),
|
||||
port_forward(7072, name = "Spy gRPC [:7072]", host = webHost),
|
||||
])
|
||||
|
||||
# solana client cli (used for devnet setup)
|
||||
|
||||
docker_build(
|
||||
|
@ -228,7 +236,6 @@ k8s_resource("eth-devnet2", port_forwards = [
|
|||
])
|
||||
|
||||
if bridge_ui:
|
||||
|
||||
docker_build(
|
||||
ref = "bridge-ui",
|
||||
context = ".",
|
||||
|
@ -272,26 +279,27 @@ def build_cloud_function(container_name, go_func_name, path, builder):
|
|||
if ci:
|
||||
# inherit the DOCKER_HOST socket provided by custom_build.
|
||||
pack_build_cmd = pack_build_cmd + " --docker-host inherit"
|
||||
|
||||
# do not attempt to access Docker cache in CI
|
||||
# pack_build_cmd = pack_build_cmd + " --clear-cache"
|
||||
# don't try to pull previous container versions in CI
|
||||
pack_build_cmd = pack_build_cmd + " --pull-policy never"
|
||||
|
||||
# push to kubernetes registry
|
||||
disable_push = False
|
||||
skips_local_docker = False
|
||||
|
||||
docker_tag_cmd = "tilt docker -- tag " + caching_ref + " $EXPECTED_REF"
|
||||
docker_tag_cmd = "tilt docker -- tag " + caching_ref + " $EXPECTED_REF"
|
||||
custom_build(
|
||||
container_name,
|
||||
pack_build_cmd + " && " + docker_tag_cmd,
|
||||
[path],
|
||||
tag=tag,
|
||||
skips_local_docker=skips_local_docker,
|
||||
disable_push=disable_push,
|
||||
tag = tag,
|
||||
skips_local_docker = skips_local_docker,
|
||||
disable_push = disable_push,
|
||||
)
|
||||
|
||||
if explorer:
|
||||
|
||||
local_resource(
|
||||
name = "devnet-cloud-function",
|
||||
cmd = "tilt docker -- build -f ./event_database/cloud_functions/Dockerfile.run . -t devnet-cloud-function --label builtby=tilt",
|
||||
|
@ -308,7 +316,8 @@ if explorer:
|
|||
|
||||
k8s_yaml_with_ns("devnet/bigtable.yaml")
|
||||
|
||||
k8s_resource("bigtable-emulator",
|
||||
k8s_resource(
|
||||
"bigtable-emulator",
|
||||
port_forwards = [port_forward(8086, name = "BigTable clients [:8086]", host = webHost)],
|
||||
labels = ["explorer"],
|
||||
)
|
||||
|
@ -323,7 +332,7 @@ if explorer:
|
|||
"bigtable-functions",
|
||||
resource_deps = ["proto-gen", "bigtable-emulator"],
|
||||
port_forwards = [port_forward(8090, name = "BigTable Functions [:8090]", host = webHost)],
|
||||
labels = ["explorer"]
|
||||
labels = ["explorer"],
|
||||
)
|
||||
|
||||
# explorer web app
|
||||
|
|
5
buf.yaml
5
buf.yaml
|
@ -12,6 +12,11 @@ lint:
|
|||
- DEFAULT
|
||||
# https://github.com/twitchtv/twirp/issues/70#issuecomment-470367807
|
||||
- UNARY_RPC
|
||||
ignore_only:
|
||||
RPC_NO_SERVER_STREAMING:
|
||||
# Allow streamed RPC for the spy server, which is designed to run as a sidecar
|
||||
# and won't handle large amounts of connections.
|
||||
- spy/v1/spy.proto
|
||||
breaking:
|
||||
use:
|
||||
- WIRE_JSON
|
||||
|
|
|
@ -0,0 +1,60 @@
|
|||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: spy
|
||||
labels:
|
||||
app: spy
|
||||
spec:
|
||||
ports:
|
||||
- port: 7072
|
||||
name: spyrpc
|
||||
protocol: TCP
|
||||
- port: 6060
|
||||
name: status
|
||||
protocol: TCP
|
||||
clusterIP: None
|
||||
selector:
|
||||
app: spy
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: StatefulSet
|
||||
metadata:
|
||||
name: spy
|
||||
spec:
|
||||
selector:
|
||||
matchLabels:
|
||||
app: spy
|
||||
serviceName: spy
|
||||
replicas: 1
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: spy
|
||||
spec:
|
||||
terminationGracePeriodSeconds: 0
|
||||
containers:
|
||||
- name: spy
|
||||
image: guardiand-image
|
||||
command:
|
||||
- /guardiand
|
||||
- spy
|
||||
- --nodeKey
|
||||
- /tmp/node.key
|
||||
- --spyRPC
|
||||
- "[::]:7072"
|
||||
# Hardcoded devnet bootstrap (generated from deterministic key in guardiand)
|
||||
- --bootstrap
|
||||
- /dns4/guardian-0.guardian/udp/8999/quic/p2p/12D3KooWL3XJ9EMCyZvmmGXL2LMiVBtrVa2BuESsJiXkSj7333Jw
|
||||
# - --logLevel=debug
|
||||
ports:
|
||||
- containerPort: 7072
|
||||
name: spyrpc
|
||||
protocol: TCP
|
||||
- containerPort: 6060
|
||||
name: status
|
||||
protocol: TCP
|
||||
readinessProbe:
|
||||
httpGet:
|
||||
port: 6060
|
||||
path: /metrics
|
|
@ -9,12 +9,7 @@ import (
|
|||
publicrpcv1 "github.com/certusone/wormhole/node/pkg/proto/publicrpc/v1"
|
||||
"github.com/certusone/wormhole/node/pkg/publicrpc"
|
||||
ethcommon "github.com/ethereum/go-ethereum/common"
|
||||
grpc_middleware "github.com/grpc-ecosystem/go-grpc-middleware"
|
||||
grpc_zap "github.com/grpc-ecosystem/go-grpc-middleware/logging/zap"
|
||||
grpc_ctxtags "github.com/grpc-ecosystem/go-grpc-middleware/tags"
|
||||
grpc_prometheus "github.com/grpc-ecosystem/go-grpc-prometheus"
|
||||
"go.uber.org/zap"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/status"
|
||||
"math"
|
||||
|
@ -269,28 +264,8 @@ func adminServiceRunnable(logger *zap.Logger, socketPath string, injectC chan<-
|
|||
|
||||
publicrpcService := publicrpc.NewPublicrpcServer(logger, db, gst)
|
||||
|
||||
grpcServer := newGRPCServer(logger)
|
||||
grpcServer := common.NewInstrumentedGRPCServer(logger)
|
||||
nodev1.RegisterNodePrivilegedServiceServer(grpcServer, nodeService)
|
||||
publicrpcv1.RegisterPublicRPCServiceServer(grpcServer, publicrpcService)
|
||||
return supervisor.GRPCServer(grpcServer, l, false), nil
|
||||
}
|
||||
|
||||
func newGRPCServer(logger *zap.Logger) *grpc.Server {
|
||||
server := grpc.NewServer(
|
||||
grpc.StreamInterceptor(grpc_middleware.ChainStreamServer(
|
||||
grpc_ctxtags.StreamServerInterceptor(),
|
||||
grpc_prometheus.StreamServerInterceptor,
|
||||
grpc_zap.StreamServerInterceptor(logger),
|
||||
)),
|
||||
grpc.UnaryInterceptor(grpc_middleware.ChainUnaryServer(
|
||||
grpc_ctxtags.UnaryServerInterceptor(),
|
||||
grpc_prometheus.UnaryServerInterceptor,
|
||||
grpc_zap.UnaryServerInterceptor(logger),
|
||||
)),
|
||||
)
|
||||
|
||||
grpc_prometheus.EnableHandlingTimeHistogram()
|
||||
grpc_prometheus.Register(server)
|
||||
|
||||
return server
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@ import (
|
|||
"crypto/rand"
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/certusone/wormhole/node/pkg/common"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"os"
|
||||
|
@ -36,8 +37,8 @@ var KeygenCmd = &cobra.Command{
|
|||
}
|
||||
|
||||
func runKeygen(cmd *cobra.Command, args []string) {
|
||||
lockMemory()
|
||||
setRestrictiveUmask()
|
||||
common.LockMemory()
|
||||
common.SetRestrictiveUmask()
|
||||
|
||||
log.Print("Creating new key at ", args[0])
|
||||
|
||||
|
|
|
@ -3,30 +3,20 @@ package guardiand
|
|||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"github.com/certusone/wormhole/node/pkg/db"
|
||||
"github.com/certusone/wormhole/node/pkg/notify/discord"
|
||||
"github.com/gagliardetto/solana-go/rpc"
|
||||
"log"
|
||||
"net/http"
|
||||
_ "net/http/pprof"
|
||||
"os"
|
||||
"path"
|
||||
"strings"
|
||||
"syscall"
|
||||
|
||||
"github.com/certusone/wormhole/node/pkg/db"
|
||||
"github.com/gagliardetto/solana-go/rpc"
|
||||
|
||||
solana_types "github.com/gagliardetto/solana-go"
|
||||
"github.com/gorilla/mux"
|
||||
"github.com/prometheus/client_golang/prometheus/promhttp"
|
||||
|
||||
eth_common "github.com/ethereum/go-ethereum/common"
|
||||
ethcrypto "github.com/ethereum/go-ethereum/crypto"
|
||||
"github.com/libp2p/go-libp2p-core/crypto"
|
||||
"github.com/libp2p/go-libp2p-core/peer"
|
||||
"github.com/spf13/cobra"
|
||||
"go.uber.org/zap"
|
||||
"golang.org/x/sys/unix"
|
||||
|
||||
"github.com/certusone/wormhole/node/pkg/common"
|
||||
"github.com/certusone/wormhole/node/pkg/devnet"
|
||||
"github.com/certusone/wormhole/node/pkg/ethereum"
|
||||
|
@ -38,6 +28,12 @@ import (
|
|||
solana "github.com/certusone/wormhole/node/pkg/solana"
|
||||
"github.com/certusone/wormhole/node/pkg/supervisor"
|
||||
"github.com/certusone/wormhole/node/pkg/vaa"
|
||||
eth_common "github.com/ethereum/go-ethereum/common"
|
||||
ethcrypto "github.com/ethereum/go-ethereum/crypto"
|
||||
"github.com/libp2p/go-libp2p-core/crypto"
|
||||
"github.com/libp2p/go-libp2p-core/peer"
|
||||
"github.com/spf13/cobra"
|
||||
"go.uber.org/zap"
|
||||
|
||||
"github.com/certusone/wormhole/node/pkg/terra"
|
||||
|
||||
|
@ -199,23 +195,6 @@ func rootLoggerName() string {
|
|||
}
|
||||
}
|
||||
|
||||
// lockMemory locks current and future pages in memory to protect secret keys from being swapped out to disk.
|
||||
// It's possible (and strongly recommended) to deploy Wormhole such that keys are only ever
|
||||
// stored in memory and never touch the disk. This is a privileged operation and requires CAP_IPC_LOCK.
|
||||
func lockMemory() {
|
||||
err := unix.Mlockall(syscall.MCL_CURRENT | syscall.MCL_FUTURE)
|
||||
if err != nil {
|
||||
fmt.Printf("Failed to lock memory: %v (CAP_IPC_LOCK missing?)\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
// setRestrictiveUmask masks the group and world bits. This ensures that key material
|
||||
// and sockets we create aren't accidentally group- or world-readable.
|
||||
func setRestrictiveUmask() {
|
||||
syscall.Umask(0077) // cannot fail
|
||||
}
|
||||
|
||||
// NodeCmd represents the node command
|
||||
var NodeCmd = &cobra.Command{
|
||||
Use: "node",
|
||||
|
@ -228,8 +207,8 @@ func runNode(cmd *cobra.Command, args []string) {
|
|||
fmt.Print(devwarning)
|
||||
}
|
||||
|
||||
lockMemory()
|
||||
setRestrictiveUmask()
|
||||
common.LockMemory()
|
||||
common.SetRestrictiveUmask()
|
||||
|
||||
// Refuse to run as root in production mode.
|
||||
if !*unsafeDevMode && os.Geteuid() == 0 {
|
||||
|
@ -506,7 +485,7 @@ func runNode(cmd *cobra.Command, args []string) {
|
|||
}
|
||||
priv = devnet.DeterministicP2PPrivKeyByIndex(int64(idx))
|
||||
} else {
|
||||
priv, err = getOrCreateNodeKey(logger, *nodeKeyPath)
|
||||
priv, err = common.GetOrCreateNodeKey(logger, *nodeKeyPath)
|
||||
if err != nil {
|
||||
logger.Fatal("Failed to load node key", zap.Error(err))
|
||||
}
|
||||
|
|
|
@ -21,7 +21,7 @@ func publicrpcServiceRunnable(logger *zap.Logger, listenAddr string, db *db.Data
|
|||
logger.Info("publicrpc server listening", zap.String("addr", l.Addr().String()))
|
||||
|
||||
rpcServer := publicrpc.NewPublicrpcServer(logger, db, gst)
|
||||
grpcServer := newGRPCServer(logger)
|
||||
grpcServer := common.NewInstrumentedGRPCServer(logger)
|
||||
publicrpcv1.RegisterPublicRPCServiceServer(grpcServer, rpcServer)
|
||||
|
||||
return supervisor.GRPCServer(grpcServer, l, false), grpcServer, nil
|
||||
|
|
|
@ -3,6 +3,7 @@ package cmd
|
|||
import (
|
||||
"fmt"
|
||||
"github.com/certusone/wormhole/node/cmd/debug"
|
||||
"github.com/certusone/wormhole/node/cmd/spy"
|
||||
"github.com/certusone/wormhole/node/pkg/version"
|
||||
"os"
|
||||
|
||||
|
@ -45,6 +46,7 @@ func init() {
|
|||
|
||||
rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.guardiand.yaml)")
|
||||
rootCmd.AddCommand(guardiand.NodeCmd)
|
||||
rootCmd.AddCommand(spy.SpyCmd)
|
||||
rootCmd.AddCommand(guardiand.KeygenCmd)
|
||||
rootCmd.AddCommand(guardiand.AdminCmd)
|
||||
rootCmd.AddCommand(guardiand.TemplateCmd)
|
||||
|
|
|
@ -0,0 +1,322 @@
|
|||
package spy
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"github.com/certusone/wormhole/node/pkg/common"
|
||||
"github.com/certusone/wormhole/node/pkg/p2p"
|
||||
gossipv1 "github.com/certusone/wormhole/node/pkg/proto/gossip/v1"
|
||||
"github.com/certusone/wormhole/node/pkg/proto/spy/v1"
|
||||
"github.com/certusone/wormhole/node/pkg/supervisor"
|
||||
"github.com/certusone/wormhole/node/pkg/vaa"
|
||||
"github.com/google/uuid"
|
||||
"github.com/gorilla/mux"
|
||||
ipfslog "github.com/ipfs/go-log/v2"
|
||||
"github.com/libp2p/go-libp2p-core/crypto"
|
||||
"github.com/prometheus/client_golang/prometheus/promhttp"
|
||||
"github.com/spf13/cobra"
|
||||
"go.uber.org/zap"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/status"
|
||||
"net"
|
||||
"net/http"
|
||||
"os"
|
||||
"sync"
|
||||
)
|
||||
|
||||
var (
|
||||
rootCtx context.Context
|
||||
rootCtxCancel context.CancelFunc
|
||||
)
|
||||
|
||||
var (
|
||||
p2pNetworkID *string
|
||||
p2pPort *uint
|
||||
p2pBootstrap *string
|
||||
|
||||
statusAddr *string
|
||||
|
||||
nodeKeyPath *string
|
||||
|
||||
logLevel *string
|
||||
|
||||
spyRPC *string
|
||||
)
|
||||
|
||||
func init() {
|
||||
p2pNetworkID = SpyCmd.Flags().String("network", "/wormhole/dev", "P2P network identifier")
|
||||
p2pPort = SpyCmd.Flags().Uint("port", 8999, "P2P UDP listener port")
|
||||
p2pBootstrap = SpyCmd.Flags().String("bootstrap", "", "P2P bootstrap peers (comma-separated)")
|
||||
|
||||
statusAddr = SpyCmd.Flags().String("statusAddr", "[::]:6060", "Listen address for status server (disabled if blank)")
|
||||
|
||||
nodeKeyPath = SpyCmd.Flags().String("nodeKey", "", "Path to node key (will be generated if it doesn't exist)")
|
||||
|
||||
logLevel = SpyCmd.Flags().String("logLevel", "info", "Logging level (debug, info, warn, error, dpanic, panic, fatal)")
|
||||
|
||||
spyRPC = SpyCmd.Flags().String("spyRPC", "", "Listen address for gRPC interface")
|
||||
}
|
||||
|
||||
// SpyCmd represents the node command
|
||||
var SpyCmd = &cobra.Command{
|
||||
Use: "spy",
|
||||
Short: "Run gossip spy client",
|
||||
Run: runSpy,
|
||||
}
|
||||
|
||||
type spyServer struct {
|
||||
spyv1.UnimplementedSpyRPCServiceServer
|
||||
logger *zap.Logger
|
||||
subs map[string]*subscription
|
||||
subsMu sync.Mutex
|
||||
}
|
||||
|
||||
type message struct {
|
||||
vaaBytes []byte
|
||||
}
|
||||
|
||||
type filter struct {
|
||||
chainId vaa.ChainID
|
||||
emitterAddr vaa.Address
|
||||
}
|
||||
|
||||
type subscription struct {
|
||||
filters []filter
|
||||
ch chan message
|
||||
}
|
||||
|
||||
func subscriptionId() string {
|
||||
return uuid.New().String()
|
||||
}
|
||||
|
||||
func decodeEmitterAddr(hexAddr string) (vaa.Address, error) {
|
||||
address, err := hex.DecodeString(hexAddr)
|
||||
if err != nil {
|
||||
return vaa.Address{}, status.Error(codes.InvalidArgument, fmt.Sprintf("failed to decode address: %v", err))
|
||||
}
|
||||
if len(address) != 32 {
|
||||
return vaa.Address{}, status.Error(codes.InvalidArgument, "address must be 32 bytes")
|
||||
}
|
||||
|
||||
addr := vaa.Address{}
|
||||
copy(addr[:], address)
|
||||
|
||||
return addr, nil
|
||||
}
|
||||
|
||||
func (s *spyServer) Publish(vaaBytes []byte) error {
|
||||
s.subsMu.Lock()
|
||||
defer s.subsMu.Unlock()
|
||||
|
||||
var v *vaa.VAA
|
||||
|
||||
for _, sub := range s.subs {
|
||||
if len(sub.filters) == 0 {
|
||||
sub.ch <- message{vaaBytes: vaaBytes}
|
||||
} else {
|
||||
if v == nil {
|
||||
var err error
|
||||
v, err = vaa.Unmarshal(vaaBytes)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
for _, fi := range sub.filters {
|
||||
if fi.chainId == v.EmitterChain && fi.emitterAddr == v.EmitterAddress {
|
||||
sub.ch <- message{vaaBytes: vaaBytes}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *spyServer) SubscribeSignedVAA(req *spyv1.SubscribeSignedVAARequest, resp spyv1.SpyRPCService_SubscribeSignedVAAServer) error {
|
||||
var fi []filter
|
||||
if req.Filters != nil {
|
||||
for _, f := range req.Filters {
|
||||
switch t := f.Filter.(type) {
|
||||
case *spyv1.FilterEntry_EmitterFilter:
|
||||
addr, err := decodeEmitterAddr(t.EmitterFilter.EmitterAddress)
|
||||
if err != nil {
|
||||
return status.Error(codes.InvalidArgument, fmt.Sprintf("failed to decode emitter address: %v", err))
|
||||
}
|
||||
fi = append(fi, filter{
|
||||
chainId: vaa.ChainID(t.EmitterFilter.ChainId),
|
||||
emitterAddr: addr,
|
||||
})
|
||||
default:
|
||||
return status.Error(codes.InvalidArgument, "unsupported filter type")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
s.subsMu.Lock()
|
||||
id := subscriptionId()
|
||||
sub := &subscription{
|
||||
ch: make(chan message, 1),
|
||||
filters: fi,
|
||||
}
|
||||
s.subs[id] = sub
|
||||
s.subsMu.Unlock()
|
||||
|
||||
defer func() {
|
||||
s.subsMu.Lock()
|
||||
defer s.subsMu.Unlock()
|
||||
delete(s.subs, id)
|
||||
}()
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-resp.Context().Done():
|
||||
return resp.Context().Err()
|
||||
case msg := <-sub.ch:
|
||||
if err := resp.Send(&spyv1.SubscribeSignedVAAResponse{
|
||||
VaaBytes: msg.vaaBytes,
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func newSpyServer(logger *zap.Logger) *spyServer {
|
||||
return &spyServer{
|
||||
logger: logger.Named("spyserver"),
|
||||
subs: make(map[string]*subscription),
|
||||
}
|
||||
}
|
||||
|
||||
func spyServerRunnable(s *spyServer, logger *zap.Logger, listenAddr string) (supervisor.Runnable, *grpc.Server, error) {
|
||||
l, err := net.Listen("tcp", listenAddr)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("failed to listen: %w", err)
|
||||
}
|
||||
|
||||
logger.Info("publicrpc server listening", zap.String("addr", l.Addr().String()))
|
||||
|
||||
grpcServer := common.NewInstrumentedGRPCServer(logger)
|
||||
spyv1.RegisterSpyRPCServiceServer(grpcServer, s)
|
||||
|
||||
return supervisor.GRPCServer(grpcServer, l, false), grpcServer, nil
|
||||
}
|
||||
|
||||
func runSpy(cmd *cobra.Command, args []string) {
|
||||
common.SetRestrictiveUmask()
|
||||
|
||||
lvl, err := ipfslog.LevelFromString(*logLevel)
|
||||
if err != nil {
|
||||
fmt.Println("Invalid log level")
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
logger := ipfslog.Logger("wormhole-spy").Desugar()
|
||||
|
||||
ipfslog.SetAllLoggers(lvl)
|
||||
|
||||
// Status server
|
||||
if *statusAddr != "" {
|
||||
router := mux.NewRouter()
|
||||
|
||||
router.Handle("/metrics", promhttp.Handler())
|
||||
|
||||
go func() {
|
||||
logger.Info("status server listening on [::]:6060")
|
||||
logger.Error("status server crashed", zap.Error(http.ListenAndServe(*statusAddr, router)))
|
||||
}()
|
||||
}
|
||||
|
||||
// Verify flags
|
||||
|
||||
if *nodeKeyPath == "" {
|
||||
logger.Fatal("Please specify --nodeKey")
|
||||
}
|
||||
if *p2pBootstrap == "" {
|
||||
logger.Fatal("Please specify --bootstrap")
|
||||
}
|
||||
|
||||
// Node's main lifecycle context.
|
||||
rootCtx, rootCtxCancel = context.WithCancel(context.Background())
|
||||
defer rootCtxCancel()
|
||||
|
||||
// Outbound gossip message queue
|
||||
sendC := make(chan []byte)
|
||||
|
||||
// Inbound observations
|
||||
obsvC := make(chan *gossipv1.SignedObservation, 50)
|
||||
|
||||
// Inbound signed VAAs
|
||||
signedInC := make(chan *gossipv1.SignedVAAWithQuorum, 50)
|
||||
|
||||
// Guardian set state managed by processor
|
||||
gst := common.NewGuardianSetState()
|
||||
|
||||
// RPC server
|
||||
s := newSpyServer(logger)
|
||||
rpcSvc, _, err := spyServerRunnable(s, logger, *spyRPC)
|
||||
if err != nil {
|
||||
logger.Fatal("failed to start RPC server", zap.Error(err))
|
||||
}
|
||||
|
||||
// Ignore observations
|
||||
go func() {
|
||||
for {
|
||||
select {
|
||||
case <-rootCtx.Done():
|
||||
return
|
||||
case <-obsvC:
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
// Log signed VAAs
|
||||
go func() {
|
||||
for {
|
||||
select {
|
||||
case <-rootCtx.Done():
|
||||
return
|
||||
case v := <-signedInC:
|
||||
logger.Info("Received signed VAA",
|
||||
zap.Any("vaa", v.Vaa))
|
||||
if err := s.Publish(v.Vaa); err != nil {
|
||||
logger.Error("failed to publish signed VAA", zap.Error(err))
|
||||
}
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
// Load p2p private key
|
||||
var priv crypto.PrivKey
|
||||
priv, err = common.GetOrCreateNodeKey(logger, *nodeKeyPath)
|
||||
if err != nil {
|
||||
logger.Fatal("Failed to load node key", zap.Error(err))
|
||||
}
|
||||
|
||||
// Run supervisor.
|
||||
supervisor.New(rootCtx, logger, func(ctx context.Context) error {
|
||||
if err := supervisor.Run(ctx, "p2p", p2p.Run(
|
||||
obsvC, sendC, signedInC, priv, nil, gst, *p2pPort, *p2pNetworkID, *p2pBootstrap, "", false, rootCtxCancel)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := supervisor.Run(ctx, "spyrpc", rpcSvc); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
logger.Info("Started internal services")
|
||||
|
||||
<-ctx.Done()
|
||||
return nil
|
||||
},
|
||||
// It's safer to crash and restart the process in case we encounter a panic,
|
||||
// rather than attempting to reschedule the runnable.
|
||||
supervisor.WithPropagatePanic)
|
||||
|
||||
<-rootCtx.Done()
|
||||
logger.Info("root context cancelled, exiting...")
|
||||
// TODO: wait for things to shut down gracefully
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
package common
|
||||
|
||||
import (
|
||||
"github.com/grpc-ecosystem/go-grpc-middleware"
|
||||
"github.com/grpc-ecosystem/go-grpc-middleware/logging/zap"
|
||||
"github.com/grpc-ecosystem/go-grpc-middleware/tags"
|
||||
"github.com/grpc-ecosystem/go-grpc-prometheus"
|
||||
"go.uber.org/zap"
|
||||
"google.golang.org/grpc"
|
||||
)
|
||||
|
||||
func NewInstrumentedGRPCServer(logger *zap.Logger) *grpc.Server {
|
||||
server := grpc.NewServer(
|
||||
grpc.StreamInterceptor(grpc_middleware.ChainStreamServer(
|
||||
grpc_ctxtags.StreamServerInterceptor(),
|
||||
grpc_prometheus.StreamServerInterceptor,
|
||||
grpc_zap.StreamServerInterceptor(logger),
|
||||
)),
|
||||
grpc.UnaryInterceptor(grpc_middleware.ChainUnaryServer(
|
||||
grpc_ctxtags.UnaryServerInterceptor(),
|
||||
grpc_prometheus.UnaryServerInterceptor,
|
||||
grpc_zap.UnaryServerInterceptor(logger),
|
||||
)),
|
||||
)
|
||||
|
||||
grpc_prometheus.EnableHandlingTimeHistogram()
|
||||
grpc_prometheus.Register(server)
|
||||
|
||||
return server
|
||||
}
|
|
@ -1,27 +1,26 @@
|
|||
package guardiand
|
||||
package common
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
|
||||
p2pcrypto "github.com/libp2p/go-libp2p-core/crypto"
|
||||
"github.com/libp2p/go-libp2p-core/crypto"
|
||||
"github.com/libp2p/go-libp2p-core/peer"
|
||||
"go.uber.org/zap"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
)
|
||||
|
||||
func getOrCreateNodeKey(logger *zap.Logger, path string) (p2pcrypto.PrivKey, error) {
|
||||
func GetOrCreateNodeKey(logger *zap.Logger, path string) (crypto.PrivKey, error) {
|
||||
b, err := ioutil.ReadFile(path)
|
||||
if err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
logger.Info("No node key found, generating a new one...", zap.String("path", path))
|
||||
|
||||
priv, _, err := p2pcrypto.GenerateKeyPair(p2pcrypto.Ed25519, -1)
|
||||
priv, _, err := crypto.GenerateKeyPair(crypto.Ed25519, -1)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
s, err := p2pcrypto.MarshalPrivateKey(priv)
|
||||
s, err := crypto.MarshalPrivateKey(priv)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
@ -37,7 +36,7 @@ func getOrCreateNodeKey(logger *zap.Logger, path string) (p2pcrypto.PrivKey, err
|
|||
}
|
||||
}
|
||||
|
||||
priv, err := p2pcrypto.UnmarshalPrivateKey(b)
|
||||
priv, err := crypto.UnmarshalPrivateKey(b)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to unmarshal node key: %w", err)
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
package common
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"golang.org/x/sys/unix"
|
||||
"os"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
// LockMemory locks current and future pages in memory to protect secret keys from being swapped out to disk.
|
||||
// It's possible (and strongly recommended) to deploy Wormhole such that keys are only ever
|
||||
// stored in memory and never touch the disk. This is a privileged operation and requires CAP_IPC_LOCK.
|
||||
func LockMemory() {
|
||||
err := unix.Mlockall(syscall.MCL_CURRENT | syscall.MCL_FUTURE)
|
||||
if err != nil {
|
||||
fmt.Printf("Failed to lock memory: %v (CAP_IPC_LOCK missing?)\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
// SetRestrictiveUmask masks the group and world bits. This ensures that key material
|
||||
// and sockets we create aren't accidentally group- or world-readable.
|
||||
func SetRestrictiveUmask() {
|
||||
syscall.Umask(0077) // cannot fail
|
||||
}
|
|
@ -193,6 +193,11 @@ func Run(obsvC chan *gossipv1.SignedObservation, sendC chan []byte, signedInC ch
|
|||
}()
|
||||
|
||||
go func() {
|
||||
// Disable heartbeat when no node name is provided (spy mode)
|
||||
if nodeName == "" {
|
||||
return
|
||||
}
|
||||
|
||||
ctr := int64(0)
|
||||
tick := time.NewTicker(15 * time.Second)
|
||||
defer tick.Stop()
|
||||
|
|
|
@ -6,8 +6,6 @@ option go_package = "github.com/certusone/wormhole/node/pkg/proto/gossip/v1;goss
|
|||
|
||||
message GossipMessage {
|
||||
oneof message {
|
||||
// Deprecated: use SignedHeartbeat.
|
||||
Heartbeat heartbeat = 1;
|
||||
SignedObservation signed_observation = 2;
|
||||
SignedHeartbeat signed_heartbeat = 3;
|
||||
SignedVAAWithQuorum signed_vaa_with_quorum = 4;
|
||||
|
|
|
@ -0,0 +1,44 @@
|
|||
syntax = "proto3";
|
||||
|
||||
package spy.v1;
|
||||
|
||||
option go_package = "github.com/certusone/wormhole/node/pkg/proto/spy/v1;spyv1";
|
||||
|
||||
import "google/api/annotations.proto";
|
||||
import "publicrpc/v1/publicrpc.proto";
|
||||
|
||||
// SpyRPCService exposes a gossip introspection service, allowing sniffing of gossip messages.
|
||||
service SpyRPCService {
|
||||
// SubscribeSignedVAA returns a stream of signed VAA messages received on the network.
|
||||
rpc SubscribeSignedVAA (SubscribeSignedVAARequest) returns (stream SubscribeSignedVAAResponse) {
|
||||
option (google.api.http) = {
|
||||
post: "/v1:subscribe_signed_vaa"
|
||||
body: "*"
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// A MessageFilter represents an exact match for an emitter.
|
||||
message EmitterFilter {
|
||||
// Source chain
|
||||
publicrpc.v1.ChainID chain_id = 1;
|
||||
// Hex-encoded (without leading 0x) emitter address.
|
||||
string emitter_address = 2;
|
||||
}
|
||||
|
||||
message FilterEntry {
|
||||
oneof filter {
|
||||
EmitterFilter emitter_filter = 1;
|
||||
}
|
||||
}
|
||||
|
||||
message SubscribeSignedVAARequest {
|
||||
// List of filters to apply to the stream (OR).
|
||||
// If empty, all messages are streamed.
|
||||
repeated FilterEntry filters = 1;
|
||||
}
|
||||
|
||||
message SubscribeSignedVAAResponse {
|
||||
// Raw VAA bytes
|
||||
bytes vaa_bytes = 1;
|
||||
}
|
|
@ -7,3 +7,4 @@ go build -mod=readonly -o bin/protoc-gen-openapiv2 github.com/grpc-ecosystem/grp
|
|||
go build -mod=readonly -o bin/protoc-gen-go-grpc google.golang.org/grpc/cmd/protoc-gen-go-grpc
|
||||
go build -mod=readonly -o bin/buf github.com/bufbuild/buf/cmd/buf
|
||||
go build -mod=readonly -o bin/cobra github.com/spf13/cobra/cobra
|
||||
go build -mod=readonly -o bin/grpcurl github.com/fullstorydev/grpcurl/cmd/grpcurl
|
||||
|
|
99
tools/go.mod
99
tools/go.mod
|
@ -5,8 +5,107 @@ go 1.17
|
|||
require (
|
||||
github.com/bufbuild/buf v0.48.2
|
||||
github.com/buildpacks/pack v0.20.0
|
||||
github.com/fullstorydev/grpcurl v1.8.5
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.5.0
|
||||
github.com/spf13/cobra v1.2.1
|
||||
google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0
|
||||
google.golang.org/protobuf v1.27.1
|
||||
)
|
||||
|
||||
require (
|
||||
cloud.google.com/go v0.81.0 // indirect
|
||||
github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78 // indirect
|
||||
github.com/BurntSushi/toml v0.3.1 // indirect
|
||||
github.com/Masterminds/semver v1.5.0 // indirect
|
||||
github.com/Microsoft/go-winio v0.4.15-0.20200908182639-5b44b70ab3ab // indirect
|
||||
github.com/Microsoft/hcsshim v0.8.10 // indirect
|
||||
github.com/apex/log v1.9.0 // indirect
|
||||
github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d // indirect
|
||||
github.com/buildpacks/imgutil v0.0.0-20210510154637-009f91f52918 // indirect
|
||||
github.com/buildpacks/lifecycle v0.11.3 // indirect
|
||||
github.com/census-instrumentation/opencensus-proto v0.2.1 // indirect
|
||||
github.com/cespare/xxhash v1.1.0 // indirect
|
||||
github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403 // indirect
|
||||
github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed // indirect
|
||||
github.com/containerd/containerd v1.4.1 // indirect
|
||||
github.com/containerd/stargz-snapshotter/estargz v0.4.1 // indirect
|
||||
github.com/docker/cli v0.0.0-20200312141509-ef2f64abbd37 // indirect
|
||||
github.com/docker/distribution v2.7.1+incompatible // indirect
|
||||
github.com/docker/docker v20.10.7+incompatible // indirect
|
||||
github.com/docker/docker-credential-helpers v0.6.3 // indirect
|
||||
github.com/docker/go-connections v0.4.0 // indirect
|
||||
github.com/docker/go-units v0.4.0 // indirect
|
||||
github.com/emirpasic/gods v1.12.0 // indirect
|
||||
github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0 // indirect
|
||||
github.com/envoyproxy/protoc-gen-validate v0.1.0 // indirect
|
||||
github.com/fsnotify/fsnotify v1.4.9 // indirect
|
||||
github.com/ghodss/yaml v1.0.0 // indirect
|
||||
github.com/gofrs/flock v0.8.1 // indirect
|
||||
github.com/gofrs/uuid v4.0.0+incompatible // indirect
|
||||
github.com/gogo/protobuf v1.3.2 // indirect
|
||||
github.com/golang/glog v0.0.0-20210429001901-424d2337a529 // indirect
|
||||
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e // indirect
|
||||
github.com/golang/mock v1.6.0 // indirect
|
||||
github.com/golang/protobuf v1.5.2 // indirect
|
||||
github.com/golang/snappy v0.0.3 // indirect
|
||||
github.com/google/go-containerregistry v0.5.1 // indirect
|
||||
github.com/hashicorp/hcl v1.0.0 // indirect
|
||||
github.com/heroku/color v0.0.6 // indirect
|
||||
github.com/inconshreveable/mousetrap v1.0.0 // indirect
|
||||
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect
|
||||
github.com/jhump/protoreflect v1.10.1 // indirect
|
||||
github.com/kevinburke/ssh_config v0.0.0-20190725054713-01f96b0aa0cd // indirect
|
||||
github.com/klauspost/compress v1.13.1 // indirect
|
||||
github.com/klauspost/pgzip v1.2.5 // indirect
|
||||
github.com/magiconair/properties v1.8.5 // indirect
|
||||
github.com/mattn/go-colorable v0.1.8 // indirect
|
||||
github.com/mattn/go-isatty v0.0.12 // indirect
|
||||
github.com/mitchellh/go-homedir v1.1.0 // indirect
|
||||
github.com/mitchellh/ioprogress v0.0.0-20180201004757-6a23b12fa88e // indirect
|
||||
github.com/mitchellh/mapstructure v1.4.1 // indirect
|
||||
github.com/moby/sys/mount v0.2.0 // indirect
|
||||
github.com/moby/sys/mountinfo v0.4.0 // indirect
|
||||
github.com/moby/term v0.0.0-20201110203204-bea5bbe245bf // indirect
|
||||
github.com/morikuni/aec v1.0.0 // indirect
|
||||
github.com/opencontainers/go-digest v1.0.0 // indirect
|
||||
github.com/opencontainers/image-spec v1.0.1 // indirect
|
||||
github.com/opencontainers/runc v0.1.1 // indirect
|
||||
github.com/opencontainers/selinux v1.6.0 // indirect
|
||||
github.com/pelletier/go-toml v1.9.3 // indirect
|
||||
github.com/pkg/errors v0.9.1 // indirect
|
||||
github.com/pkg/profile v1.6.0 // indirect
|
||||
github.com/sabhiram/go-gitignore v0.0.0-20201211074657-223ce5d391b0 // indirect
|
||||
github.com/sergi/go-diff v1.1.0 // indirect
|
||||
github.com/sirupsen/logrus v1.7.0 // indirect
|
||||
github.com/spf13/afero v1.6.0 // indirect
|
||||
github.com/spf13/cast v1.3.1 // indirect
|
||||
github.com/spf13/jwalterweatherman v1.1.0 // indirect
|
||||
github.com/spf13/pflag v1.0.5 // indirect
|
||||
github.com/spf13/viper v1.8.1 // indirect
|
||||
github.com/src-d/gcfg v1.4.0 // indirect
|
||||
github.com/subosito/gotenv v1.2.0 // indirect
|
||||
github.com/twitchtv/twirp v8.1.0+incompatible // indirect
|
||||
github.com/willf/bitset v1.1.11 // indirect
|
||||
github.com/xanzy/ssh-agent v0.3.0 // indirect
|
||||
go.opencensus.io v0.23.0 // indirect
|
||||
go.uber.org/atomic v1.7.0 // indirect
|
||||
go.uber.org/multierr v1.7.0 // indirect
|
||||
go.uber.org/zap v1.18.1 // indirect
|
||||
golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897 // indirect
|
||||
golang.org/x/mod v0.4.2 // indirect
|
||||
golang.org/x/net v0.0.0-20210726213435-c6fcb2dbf985 // indirect
|
||||
golang.org/x/oauth2 v0.0.0-20210615190721-d04028783cf1 // indirect
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c // indirect
|
||||
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c // indirect
|
||||
golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b // indirect
|
||||
golang.org/x/text v0.3.6 // indirect
|
||||
google.golang.org/appengine v1.6.7 // indirect
|
||||
google.golang.org/genproto v0.0.0-20210729151513-df9385d47c1b // indirect
|
||||
google.golang.org/grpc v1.40.0-dev.0.20210708170655-30dfb4b933a5 // indirect
|
||||
gopkg.in/ini.v1 v1.62.0 // indirect
|
||||
gopkg.in/src-d/go-billy.v4 v4.3.2 // indirect
|
||||
gopkg.in/src-d/go-git.v4 v4.13.1 // indirect
|
||||
gopkg.in/warnings.v0 v0.1.2 // indirect
|
||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect
|
||||
)
|
||||
|
|
18
tools/go.sum
18
tools/go.sum
|
@ -18,6 +18,7 @@ cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKP
|
|||
cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk=
|
||||
cloud.google.com/go v0.78.0/go.mod h1:QjdrLG0uq+YwhjoVOLsS1t7TW8fs36kLs4XO5R5ECHg=
|
||||
cloud.google.com/go v0.79.0/go.mod h1:3bzgcEeQlzbuEAYu4mrWhKqWjmpprinYgKJLgKHnbb8=
|
||||
cloud.google.com/go v0.81.0 h1:at8Tk2zUz63cLPR0JPWm5vp77pEZmzxEQBEfRKn1VV8=
|
||||
cloud.google.com/go v0.81.0/go.mod h1:mk/AM35KwGk/Nm2YSeZbxXdrNK3KZOYHmLkOqC2V6E0=
|
||||
cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=
|
||||
cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE=
|
||||
|
@ -52,6 +53,7 @@ github.com/Microsoft/go-winio v0.4.15-0.20200908182639-5b44b70ab3ab/go.mod h1:tT
|
|||
github.com/Microsoft/hcsshim v0.8.10 h1:k5wTrpnVU2/xv8ZuzGkbXVd3js5zJ8RnumPo5RxiIxU=
|
||||
github.com/Microsoft/hcsshim v0.8.10/go.mod h1:g5uw8EV2mAlzqe94tfNBNdr89fnbD/n3HV0OhsddkmM=
|
||||
github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ=
|
||||
github.com/OneOfOne/xxhash v1.2.2 h1:KMrpdQIwFcEqXDklaen+P1axHaj9BSKzvpUUfnHldSE=
|
||||
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
|
||||
github.com/PuerkitoBio/purell v1.0.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
|
||||
github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
|
||||
|
@ -93,7 +95,9 @@ github.com/buildpacks/lifecycle v0.11.3 h1:FyvtzNxNjnBAdujzUiSpiCap3x+NzrqokGj69
|
|||
github.com/buildpacks/lifecycle v0.11.3/go.mod h1:4anPUHYqREC3oh3qqKZwt7wqWR866E7BvtIxRE8xGLE=
|
||||
github.com/buildpacks/pack v0.20.0 h1:MkMkfnMcuk1eIBU9qqd3JCAMdB1BqcjMzb/YQf7vB38=
|
||||
github.com/buildpacks/pack v0.20.0/go.mod h1:VmSAGBQ1jO8Ht+SO5GWwsh501ZerxrgJN0fVt1wZM3U=
|
||||
github.com/census-instrumentation/opencensus-proto v0.2.1 h1:glEXhBS5PSLLv4IXzLA5yPRVX4bilULVyxxbrfOtDAk=
|
||||
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||
github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko=
|
||||
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
|
||||
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
|
||||
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
|
||||
|
@ -102,7 +106,9 @@ github.com/cilium/ebpf v0.0.0-20200110133405-4032b1d8aae3/go.mod h1:MA5e5Lr8slmE
|
|||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
|
||||
github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
|
||||
github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403 h1:cqQfy1jclcSy/FwLjemeg3SR1yaINm74aQyupQ0Bl8M=
|
||||
github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
|
||||
github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed h1:OZmjad4L3H8ncOIR8rnb5MREYqG8ixi5+WbeUsquF0c=
|
||||
github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
||||
github.com/containerd/cgroups v0.0.0-20200531161412-0dbf7f05ba59/go.mod h1:pA0z1pT8KYB3TCXK/ocprsh7MAkoW8bZVzPdih9snmM=
|
||||
github.com/containerd/console v0.0.0-20180822173158-c12b1e7919c1/go.mod h1:Tj/on1eG8kiEhd0+fhSDzsPAFESxzBBvdyEgyryXffw=
|
||||
|
@ -165,13 +171,17 @@ github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1m
|
|||
github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po=
|
||||
github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
|
||||
github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
|
||||
github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0 h1:dulLQAYQFYtG5MTplgNGHWuV2D+OBD+Z8lmDBmbLg+s=
|
||||
github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ=
|
||||
github.com/envoyproxy/protoc-gen-validate v0.1.0 h1:EQciDnbrYxy13PgWoY8AqoxGiPrpgBZ1R8UNe3ddc+A=
|
||||
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
||||
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
|
||||
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc=
|
||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||
github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
|
||||
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
|
||||
github.com/fullstorydev/grpcurl v1.8.5 h1:xYZBGwhLFuHx6VZLdANGx7Ffb/dlY8JZlJz76/TxclM=
|
||||
github.com/fullstorydev/grpcurl v1.8.5/go.mod h1:hmAJ/1FHD4xEdiTQS4Byb5NHVVGZr9iGy8CnX0t6ftA=
|
||||
github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
||||
github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk=
|
||||
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
||||
|
@ -285,6 +295,7 @@ github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLe
|
|||
github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
|
||||
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/google/uuid v1.1.2 h1:EVhdT+1Kseyi1/pUmXKaFxYsDNy9RQYkMWRH68J/W7Y=
|
||||
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
|
||||
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
|
||||
|
@ -333,8 +344,9 @@ github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANyt
|
|||
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A=
|
||||
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo=
|
||||
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
|
||||
github.com/jhump/protoreflect v1.9.0 h1:npqHz788dryJiR/l6K/RUQAyh2SwV91+d1dnh4RjO9w=
|
||||
github.com/jhump/protoreflect v1.9.0/go.mod h1:7GcYQDdMU/O/BBrl/cX6PNHpXh6cenjd8pneu5yW7Tg=
|
||||
github.com/jhump/protoreflect v1.10.1 h1:iH+UZfsbRE6vpyZH7asAjTPWJf7RJbpZ9j/N3lDlKs0=
|
||||
github.com/jhump/protoreflect v1.10.1/go.mod h1:7GcYQDdMU/O/BBrl/cX6PNHpXh6cenjd8pneu5yW7Tg=
|
||||
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
|
||||
github.com/joefitzgerald/rainbow-reporter v0.1.0/go.mod h1:481CNgqmVHQZzdIbN52CupLJyoVwB10FQ/IQlF1pdL8=
|
||||
github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
|
||||
|
@ -509,6 +521,7 @@ github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIK
|
|||
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
|
||||
github.com/smartystreets/gunit v1.0.0/go.mod h1:qwPWnhz6pn0NnRBP++URONOVyNkPyr4SauJk4cUOwJs=
|
||||
github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
|
||||
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72 h1:qLC7fQah7D6K1B0ujays3HV9gkFtllcxhzImRR7ArPQ=
|
||||
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
|
||||
github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
|
||||
github.com/spf13/afero v1.6.0 h1:xoax2sJ2DT8S8xA2paPFjDCScCNeWsg75VG0DLRreiY=
|
||||
|
@ -707,6 +720,7 @@ golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ
|
|||
golang.org/x/oauth2 v0.0.0-20210220000619-9bb904979d93/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/oauth2 v0.0.0-20210313182246-cd4f82c27b84/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/oauth2 v0.0.0-20210402161424-2e8d93401602/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/oauth2 v0.0.0-20210615190721-d04028783cf1 h1:x622Z2o4hgCr/4CiKWc51jHVKaWdtVpBNmEI8wI9Qns=
|
||||
golang.org/x/oauth2 v0.0.0-20210615190721-d04028783cf1/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
|
@ -906,6 +920,7 @@ google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7
|
|||
google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
|
||||
google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
|
||||
google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
|
||||
google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c=
|
||||
google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
|
||||
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||
google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
|
@ -973,6 +988,7 @@ google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA5
|
|||
google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
|
||||
google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
|
||||
google.golang.org/grpc v1.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
|
||||
google.golang.org/grpc v1.37.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM=
|
||||
google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM=
|
||||
google.golang.org/grpc v1.39.0/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE=
|
||||
google.golang.org/grpc v1.40.0-dev.0.20210708170655-30dfb4b933a5 h1:jeEzNnOogdiVxvaPNbt/QFOggkBTaUPBkQ2/NIngeyk=
|
||||
|
|
|
@ -9,6 +9,7 @@ package main
|
|||
import (
|
||||
_ "github.com/bufbuild/buf/cmd/buf"
|
||||
_ "github.com/buildpacks/pack/cmd/pack"
|
||||
_ "github.com/fullstorydev/grpcurl/cmd/grpcurl"
|
||||
_ "github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-grpc-gateway"
|
||||
_ "github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-openapiv2"
|
||||
_ "github.com/spf13/cobra/cobra"
|
||||
|
|
Loading…
Reference in New Issue