From c33045c444afe0e776f42d0fe07bd1f9d8028423 Mon Sep 17 00:00:00 2001 From: Jernej Kos Date: Sun, 3 May 2020 21:18:53 +0200 Subject: [PATCH] go/worker/consensus: Add public consensus services worker A public consensus services worker enables any full consensus node to expose light client services to other nodes that may need them (e.g., they are needed to support light clients). The worker can be enabled using --worker.consensus.enabled and is disabled by default. Enabling the public consensus services worker exposes the light consensus client interface over publicly accessible gRPC. --- .changelog/2440.feature.2.md | 9 +++ go/oasis-node/cmd/node/node.go | 22 +++++- go/oasis-test-runner/oasis/args.go | 6 ++ go/oasis-test-runner/oasis/fixture.go | 3 + go/oasis-test-runner/oasis/validator.go | 13 +++- go/worker/consensus/worker.go | 95 +++++++++++++++++++++++++ 6 files changed, 146 insertions(+), 2 deletions(-) create mode 100644 .changelog/2440.feature.2.md create mode 100644 go/worker/consensus/worker.go diff --git a/.changelog/2440.feature.2.md b/.changelog/2440.feature.2.md new file mode 100644 index 00000000000..da2b5e72b27 --- /dev/null +++ b/.changelog/2440.feature.2.md @@ -0,0 +1,9 @@ +go/worker/consensus: Add public consensus services worker + +A public consensus services worker enables any full consensus node to expose +light client services to other nodes that may need them (e.g., they are needed +to support light clients). + +The worker can be enabled using --worker.consensus.enabled and is disabled by +default. Enabling the public consensus services worker exposes the light +consensus client interface over publicly accessible gRPC. diff --git a/go/oasis-node/cmd/node/node.go b/go/oasis-node/cmd/node/node.go index fce8f7b27ff..078c1d163df 100644 --- a/go/oasis-node/cmd/node/node.go +++ b/go/oasis-node/cmd/node/node.go @@ -60,6 +60,7 @@ import ( "github.com/oasislabs/oasis-core/go/worker/compute/executor" "github.com/oasislabs/oasis-core/go/worker/compute/merge" "github.com/oasislabs/oasis-core/go/worker/compute/txnscheduler" + workerConsensus "github.com/oasislabs/oasis-core/go/worker/consensus" workerKeymanager "github.com/oasislabs/oasis-core/go/worker/keymanager" "github.com/oasislabs/oasis-core/go/worker/registration" workerSentry "github.com/oasislabs/oasis-core/go/worker/sentry" @@ -125,6 +126,7 @@ type Node struct { P2P *p2p.P2P RegistrationWorker *registration.Worker KeymanagerWorker *workerKeymanager.Worker + ConsensusWorker *workerConsensus.Worker } // Cleanup cleans up after the node has terminated. @@ -338,6 +340,13 @@ func (n *Node) initWorkers(logger *logging.Logger) error { } n.svcMgr.Register(n.TransactionSchedulerWorker) + // Initialize the public consensus services worker. + n.ConsensusWorker, err = workerConsensus.New(n.CommonWorker) + if err != nil { + return err + } + n.svcMgr.Register(n.ConsensusWorker) + return nil } @@ -382,8 +391,18 @@ func (n *Node) startWorkers(logger *logging.Logger) error { return err } + // Start the public consensus services worker. + if err := n.ConsensusWorker.Start(); err != nil { + return fmt.Errorf("consensus worker: %w", err) + } + // Only start the external gRPC server if any workers are enabled. - if n.StorageWorker.Enabled() || n.TransactionSchedulerWorker.Enabled() || n.MergeWorker.Enabled() || n.KeymanagerWorker.Enabled() { + if n.StorageWorker.Enabled() || + n.TransactionSchedulerWorker.Enabled() || + n.MergeWorker.Enabled() || + n.KeymanagerWorker.Enabled() || + n.ConsensusWorker.Enabled() { + if err := n.CommonWorker.Grpc.Start(); err != nil { logger.Error("failed to start external gRPC server", "err", err, @@ -791,6 +810,7 @@ func init() { workerCommon.Flags, workerStorage.Flags, workerSentry.Flags, + workerConsensus.Flags, crash.InitFlags(), } { Flags.AddFlagSet(v) diff --git a/go/oasis-test-runner/oasis/args.go b/go/oasis-test-runner/oasis/args.go index 0ee717542df..70784076d6c 100644 --- a/go/oasis-test-runner/oasis/args.go +++ b/go/oasis-test-runner/oasis/args.go @@ -30,6 +30,7 @@ import ( "github.com/oasislabs/oasis-core/go/worker/common/p2p" "github.com/oasislabs/oasis-core/go/worker/compute" "github.com/oasislabs/oasis-core/go/worker/compute/txnscheduler" + workerConsensus "github.com/oasislabs/oasis-core/go/worker/consensus" "github.com/oasislabs/oasis-core/go/worker/keymanager" "github.com/oasislabs/oasis-core/go/worker/registration" workerSentry "github.com/oasislabs/oasis-core/go/worker/sentry" @@ -377,6 +378,11 @@ func (args *argBuilder) workerTxnschedulerCheckTxEnabled() *argBuilder { return args } +func (args *argBuilder) workerConsensusEnabled() *argBuilder { + args.vec = append(args.vec, "--"+workerConsensus.CfgWorkerEnabled) + return args +} + func (args *argBuilder) iasUseGenesis() *argBuilder { args.vec = append(args.vec, "--ias.use_genesis") return args diff --git a/go/oasis-test-runner/oasis/fixture.go b/go/oasis-test-runner/oasis/fixture.go index 2c272876a30..2e2ed770129 100644 --- a/go/oasis-test-runner/oasis/fixture.go +++ b/go/oasis-test-runner/oasis/fixture.go @@ -125,6 +125,9 @@ type ConsensusFixture struct { // nolint: maligned // TendermintRecoverCorruptedWAL enables automatic recovery of corrupted Tendermint's WAL. TendermintRecoverCorruptedWAL bool `json:"tendermint_recover_corrupted_wal"` + + // EnableConsensusWorker enables the public consensus services worker. + EnableConsensusWorker bool `json:"enable_consensus_worker,omitempty"` } // TEEFixture is a TEE configuration fixture. diff --git a/go/oasis-test-runner/oasis/validator.go b/go/oasis-test-runner/oasis/validator.go index 67b2a2abe0c..90a7aa97698 100644 --- a/go/oasis-test-runner/oasis/validator.go +++ b/go/oasis-test-runner/oasis/validator.go @@ -25,6 +25,7 @@ type Validator struct { tmAddress string consensusPort uint16 + clientPort uint16 } // ValidatorCfg is the Oasis validator provisioning configuration. @@ -66,6 +67,11 @@ func (val *Validator) ExportsPath() string { return nodeExportsPath(val.dir) } +// ExternalGRPCAddress returns the address of the node's external gRPC server. +func (val *Validator) ExternalGRPCAddress() string { + return fmt.Sprintf("127.0.0.1:%d", val.clientPort) +} + // Start starts an Oasis node. func (val *Validator) Start() error { return val.startNode() @@ -91,6 +97,10 @@ func (val *Validator) startNode() error { } else { args = args.appendSeedNodes(val.net) } + if val.consensus.EnableConsensusWorker { + args = args.workerClientPort(val.clientPort). + workerConsensusEnabled() + } if len(val.net.validators) >= 1 && val == val.net.validators[0] { args = args.supplementarysanityEnabled() @@ -130,6 +140,7 @@ func (net *Network) NewValidator(cfg *ValidatorCfg) (*Validator, error) { entity: cfg.Entity, sentries: cfg.Sentries, consensusPort: net.nextNodePort, + clientPort: net.nextNodePort + 1, } val.doStartNode = val.startNode @@ -191,7 +202,7 @@ func (net *Network) NewValidator(cfg *ValidatorCfg) (*Validator, error) { } net.validators = append(net.validators, val) - net.nextNodePort++ + net.nextNodePort += 2 if err := net.AddLogWatcher(&val.Node); err != nil { net.logger.Error("failed to add log watcher", diff --git a/go/worker/consensus/worker.go b/go/worker/consensus/worker.go new file mode 100644 index 00000000000..1d2c88a64fb --- /dev/null +++ b/go/worker/consensus/worker.go @@ -0,0 +1,95 @@ +// Package consensus implements publicly accessible consensus services. +package consensus + +import ( + flag "github.com/spf13/pflag" + "github.com/spf13/viper" + + "github.com/oasislabs/oasis-core/go/common/logging" + consensus "github.com/oasislabs/oasis-core/go/consensus/api" + workerCommon "github.com/oasislabs/oasis-core/go/worker/common" +) + +const ( + // CfgWorkerEnabled enables the consensus services worker. + CfgWorkerEnabled = "worker.consensus.enabled" +) + +// Flags has the configuration flags. +var Flags = flag.NewFlagSet("", flag.ContinueOnError) + +// Worker is a worker providing publicly accessible consensus services. +// +// Currently this only exposes the consensus light client service. +type Worker struct { + enabled bool + + commonWorker *workerCommon.Worker + + quitCh chan struct{} + + logger *logging.Logger +} + +// Name returns the service name. +func (w *Worker) Name() string { + return "public consensus services worker" +} + +// Enabled returns if worker is enabled. +func (w *Worker) Enabled() bool { + return w.enabled +} + +// Start starts the worker. +func (w *Worker) Start() error { + if w.enabled { + w.logger.Info("starting public consensus services worker") + } + return nil +} + +// Stop halts the service. +func (w *Worker) Stop() { + close(w.quitCh) +} + +// Quit returns a channel that will be closed when the service terminates. +func (w *Worker) Quit() <-chan struct{} { + return w.quitCh +} + +// Cleanup performs the service specific post-termination cleanup. +func (w *Worker) Cleanup() { +} + +// New creates a new public consensus services worker. +func New(commonWorker *workerCommon.Worker) (*Worker, error) { + w := &Worker{ + enabled: Enabled(), + commonWorker: commonWorker, + quitCh: make(chan struct{}), + logger: logging.GetLogger("worker/consensus"), + } + + if w.enabled { + // Register the consensus light client service. + consensus.RegisterLightService(commonWorker.Grpc.Server(), commonWorker.Consensus) + + // TODO: We could introduce a role bit for nodes providing these public services so that you + // could easily discover suitable nodes to use. + } + + return w, nil +} + +// Enabled reads our enabled flag from viper. +func Enabled() bool { + return viper.GetBool(CfgWorkerEnabled) +} + +func init() { + Flags.Bool(CfgWorkerEnabled, false, "Enable public consensus services worker") + + _ = viper.BindPFlags(Flags) +}