From 3ac68c115bce104daf0ccbb7c3d33353c0c32aff Mon Sep 17 00:00:00 2001 From: Yawning Angel Date: Fri, 4 Jun 2021 09:18:35 +0000 Subject: [PATCH 1/3] build: Add a workaround for invalid cached copies of flatbuffers Badger pulls in Google's flatbuffers package as a dependency, and some go module caches have a screwed up copy which causes build failures. The maintainer re-tagged a new minor version to allow workarounds for this issue, so use the new tag. --- go/go.mod | 5 +++++ go/go.sum | 4 ++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/go/go.mod b/go/go.mod index 8bd9d892296..be7ab7ef371 100644 --- a/go/go.mod +++ b/go/go.mod @@ -5,6 +5,11 @@ replace ( // Can be removed once there is a spf13/viper release with updated etcd. // https://github.com/spf13/viper/issues/956 github.com/coreos/etcd => github.com/coreos/etcd v3.3.25+incompatible + // Updates the version used by badgerdb, because some of the Go + // module caches apparently have a messed up copy that causes + // build failures. + // https://github.com/google/flatbuffers/issues/6466 + github.com/google/flatbuffers => github.com/google/flatbuffers v1.12.1 // Updates the version used in spf13/cobra (dependency via tendermint) as // there is no release yet with the fix. Remove once an updated release of // spf13/cobra exists and tendermint is updated to include it. diff --git a/go/go.sum b/go/go.sum index bf756784cc7..8df9df94208 100644 --- a/go/go.sum +++ b/go/go.sum @@ -297,8 +297,8 @@ github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Z github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.1 h1:gK4Kx5IaGY9CD5sPJ36FHiBJ6ZXl0kilRiiCj+jdYp4= github.com/google/btree v1.0.1/go.mod h1:xXMiIv4Fb/0kKde4SpL7qlzvu5cMJDRkFDxJfI9uaxA= -github.com/google/flatbuffers v1.12.0 h1:/PtAHvnBY4Kqnx/xCQ3OIV9uYcSFGScBsWI3Oogeh6w= -github.com/google/flatbuffers v1.12.0/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8= +github.com/google/flatbuffers v1.12.1 h1:MVlul7pQNoDzWRLTw5imwYsl+usrS1TXG2H4jg6ImGw= +github.com/google/flatbuffers v1.12.1/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= From ae99fb329d8d9fd413934f0ef7c5d91c0a78ce43 Mon Sep 17 00:00:00 2001 From: Yawning Angel Date: Fri, 4 Jun 2021 09:24:35 +0000 Subject: [PATCH 2/3] go/beacon/api: Expose the PVSS calls via gRPC --- go/beacon/api/grpc.go | 47 +++++++++++++++++++++ go/beacon/api/pvss.go | 2 +- go/consensus/tendermint/beacon/beacon.go | 4 +- go/oasis-node/cmd/debug/byzantine/beacon.go | 5 ++- go/worker/beacon/worker.go | 8 +++- 5 files changed, 61 insertions(+), 5 deletions(-) diff --git a/go/beacon/api/grpc.go b/go/beacon/api/grpc.go index 0f7a5c73730..f0ee1b46c4d 100644 --- a/go/beacon/api/grpc.go +++ b/go/beacon/api/grpc.go @@ -30,6 +30,8 @@ var ( methodStateToGenesis = serviceName.NewMethod("StateToGenesis", int64(0)) // methodConsensusParameters is the ConsensusParameters method. methodConsensusParameters = serviceName.NewMethod("ConsensusParameters", int64(0)) + // methodGetPVSSState is the GetPVSSState method. + methodGetPVSSState = serviceName.NewMethod("GetPVSSState", nil) // methodWatchEpochs is the WatchEpochs method. methodWatchEpochs = serviceName.NewMethod("WatchEpochs", nil) @@ -71,6 +73,10 @@ var ( MethodName: methodConsensusParameters.ShortName(), Handler: handlerConsensusParameters, }, + { + MethodName: methodGetPVSSState.ShortName(), + Handler: handlerGetPVSSState, + }, }, Streams: []grpc.StreamDesc{ { @@ -262,6 +268,33 @@ func handlerConsensusParameters( //nolint:golint return interceptor(ctx, height, info, handler) } +func handlerGetPVSSState( //nolint:golint + srv interface{}, + ctx context.Context, + dec func(interface{}) error, + interceptor grpc.UnaryServerInterceptor, +) (interface{}, error) { + pvssBackend, ok := srv.(PVSSBackend) + if !ok { + return nil, fmt.Errorf("beacon: not using PVSS backend") + } + var height int64 + if err := dec(&height); err != nil { + return nil, err + } + if interceptor == nil { + return pvssBackend.GetPVSSState(ctx, height) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: methodGetPVSSState.FullName(), + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return pvssBackend.GetPVSSState(ctx, req.(int64)) + } + return interceptor(ctx, height, info, handler) +} + func handlerWatchEpochs(srv interface{}, stream grpc.ServerStream) error { if err := stream.RecvMsg(nil); err != nil { return err @@ -400,6 +433,20 @@ func (c *beaconClient) ConsensusParameters(ctx context.Context, height int64) (* return &rsp, nil } +func (c *beaconClient) GetPVSSState(ctx context.Context, height int64) (*PVSSState, error) { + var rsp PVSSState + if err := c.conn.Invoke(ctx, methodGetPVSSState.FullName(), height, &rsp); err != nil { + return nil, err + } + return &rsp, nil +} + +func (c *beaconClient) WatchLatestPVSSEvent(ctx context.Context) (<-chan *PVSSEvent, *pubsub.Subscription, error) { + // The only thing that uses this is the beacon worker, and it is not + // over gRPC. + return nil, nil, fmt.Errorf("beacon: gRPC method not implemented") +} + func (c *beaconClient) Cleanup() { } diff --git a/go/beacon/api/pvss.go b/go/beacon/api/pvss.go index 160fd5f9fab..78466a532c9 100644 --- a/go/beacon/api/pvss.go +++ b/go/beacon/api/pvss.go @@ -145,5 +145,5 @@ type PVSSBackend interface { // from the channel, old events are overwritten. // // Upon subscription the current round event is sent immediately. - WatchLatestPVSSEvent() (<-chan *PVSSEvent, *pubsub.Subscription) + WatchLatestPVSSEvent(ctx context.Context) (<-chan *PVSSEvent, *pubsub.Subscription, error) } diff --git a/go/consensus/tendermint/beacon/beacon.go b/go/consensus/tendermint/beacon/beacon.go index e7ad5602fcc..fbf5a7893cf 100644 --- a/go/consensus/tendermint/beacon/beacon.go +++ b/go/consensus/tendermint/beacon/beacon.go @@ -202,12 +202,12 @@ func (sc *serviceClient) GetPVSSState(ctx context.Context, height int64) (*beaco return q.PVSSState(ctx) } -func (sc *serviceClient) WatchLatestPVSSEvent() (<-chan *beaconAPI.PVSSEvent, *pubsub.Subscription) { +func (sc *serviceClient) WatchLatestPVSSEvent(ctx context.Context) (<-chan *beaconAPI.PVSSEvent, *pubsub.Subscription, error) { typedCh := make(chan *beaconAPI.PVSSEvent) sub := sc.pvssNotifier.Subscribe() sub.Unwrap(typedCh) - return typedCh, sub + return typedCh, sub, nil } func (sc *serviceClient) SetEpoch(ctx context.Context, epoch beaconAPI.EpochTime) error { diff --git a/go/oasis-node/cmd/debug/byzantine/beacon.go b/go/oasis-node/cmd/debug/byzantine/beacon.go index d0be69124c4..91e9c38d68c 100644 --- a/go/oasis-node/cmd/debug/byzantine/beacon.go +++ b/go/oasis-node/cmd/debug/byzantine/beacon.go @@ -94,7 +94,10 @@ func doBeaconScenario(cmd *cobra.Command, args []string) { } // Start watching for PVSS events - ch, sub := backend.WatchLatestPVSSEvent() + ch, sub, err := backend.WatchLatestPVSSEvent(ctx) + if err != nil { + panic(fmt.Sprintf("failed to subscribe to PVSS events: %+v", err)) + } defer sub.Close() var iter int diff --git a/go/worker/beacon/worker.go b/go/worker/beacon/worker.go index 30634580c58..7dbed613e66 100644 --- a/go/worker/beacon/worker.go +++ b/go/worker/beacon/worker.go @@ -102,7 +102,13 @@ func (w *Worker) worker() { w.recoverPersistedState() // Subscribe to PVSS events. - eventCh, eventSub := w.backend.WatchLatestPVSSEvent() + eventCh, eventSub, err := w.backend.WatchLatestPVSSEvent(w.ctx) + if err != nil { + w.logger.Error("failed to subscribe to PVSS events", + "err", err, + ) + return + } defer eventSub.Close() for { From 26cad5b2a7732ce83549a66e6317fe34801e471f Mon Sep 17 00:00:00 2001 From: Yawning Angel Date: Fri, 4 Jun 2021 09:47:23 +0000 Subject: [PATCH 3/3] go/oasis-node/cmd/debug/beacon: Initial import --- .changelog/3897.feature.md | 4 + go/oasis-node/cmd/debug/beacon/beacon.go | 102 +++++++++++++++++++++++ go/oasis-node/cmd/debug/debug.go | 2 + 3 files changed, 108 insertions(+) create mode 100644 .changelog/3897.feature.md create mode 100644 go/oasis-node/cmd/debug/beacon/beacon.go diff --git a/.changelog/3897.feature.md b/.changelog/3897.feature.md new file mode 100644 index 00000000000..cd26ee0ba5c --- /dev/null +++ b/.changelog/3897.feature.md @@ -0,0 +1,4 @@ +go/oasis-node/cmd/debug/beacon: Initial import + +Add a `debug beacon status` command which queries the current beacon and +PVSS backend state. diff --git a/go/oasis-node/cmd/debug/beacon/beacon.go b/go/oasis-node/cmd/debug/beacon/beacon.go new file mode 100644 index 00000000000..5b6b6cc02ed --- /dev/null +++ b/go/oasis-node/cmd/debug/beacon/beacon.go @@ -0,0 +1,102 @@ +// Package beacon implements the beacon introspection debug sub-commands. +package beacon + +import ( + "context" + "encoding/json" + "fmt" + "os" + + "github.com/spf13/cobra" + "google.golang.org/grpc" + + beacon "github.com/oasisprotocol/oasis-core/go/beacon/api" + "github.com/oasisprotocol/oasis-core/go/common/logging" + consensus "github.com/oasisprotocol/oasis-core/go/consensus/api" + cmdCommon "github.com/oasisprotocol/oasis-core/go/oasis-node/cmd/common" + cmdGrpc "github.com/oasisprotocol/oasis-core/go/oasis-node/cmd/common/grpc" +) + +var ( + beaconCmd = &cobra.Command{ + Use: "beacon", + Short: "debug the random beacon", + } + + beaconStatusCmd = &cobra.Command{ + Use: "status", + Short: "query beacon status", + Run: doBeaconStatus, + } + + logger = logging.GetLogger("cmd/debug/beacon") +) + +func doConnect(cmd *cobra.Command) (*grpc.ClientConn, beacon.Backend) { + if err := cmdCommon.Init(); err != nil { + cmdCommon.EarlyLogAndExit(err) + } + + conn, err := cmdGrpc.NewClient(cmd) + if err != nil { + logger.Error("failed to establish connection with node", + "err", err, + ) + os.Exit(1) + } + + client := beacon.NewBeaconClient(conn) + + return conn, client +} + +func doBeaconStatus(cmd *cobra.Command, args []string) { + conn, client := doConnect(cmd) + defer conn.Close() + + logger.Info("querying latest beacon") + + b, err := client.GetBeacon(context.Background(), consensus.HeightLatest) + if err != nil { + logger.Error("failed to query beacon", + "err", err, + ) + os.Exit(1) + } + + // I'm going to be sad if people use this as a way to programatically + // scrape the beacon. Oh well. + prettyOut := struct { + Beacon []byte + State *beacon.PVSSState + }{ + Beacon: b, + } + + pvssClient, ok := client.(beacon.PVSSBackend) + if ok { + prettyOut.State, err = pvssClient.GetPVSSState(context.Background(), consensus.HeightLatest) + if err != nil { + logger.Error("failed to query PVSS backend state", + "err", err, + ) + os.Exit(1) + } + } + + formatted, err := json.MarshalIndent(prettyOut, "", " ") + if err != nil { + logger.Error("failed to format state", + "err", err, + ) + os.Exit(1) + } + fmt.Println(string(formatted)) +} + +// Register registers the beacon sub-command and all of it's children. +func Register(parentCmd *cobra.Command) { + beaconCmd.PersistentFlags().AddFlagSet(cmdGrpc.ClientFlags) + + beaconCmd.AddCommand(beaconStatusCmd) +} diff --git a/go/oasis-node/cmd/debug/debug.go b/go/oasis-node/cmd/debug/debug.go index 67249a2ce3a..d58239d7c61 100644 --- a/go/oasis-node/cmd/debug/debug.go +++ b/go/oasis-node/cmd/debug/debug.go @@ -4,6 +4,7 @@ package debug import ( "github.com/spf13/cobra" + "github.com/oasisprotocol/oasis-core/go/oasis-node/cmd/debug/beacon" "github.com/oasisprotocol/oasis-core/go/oasis-node/cmd/debug/byzantine" "github.com/oasisprotocol/oasis-core/go/oasis-node/cmd/debug/consim" "github.com/oasisprotocol/oasis-core/go/oasis-node/cmd/debug/control" @@ -27,6 +28,7 @@ func Register(parentCmd *cobra.Command) { control.Register(debugCmd) consim.Register(debugCmd) dumpdb.Register(debugCmd) + beacon.Register(debugCmd) parentCmd.AddCommand(debugCmd) }