Skip to content

Commit

Permalink
go/worker/consensusrpc: Add public consensus RPC services worker
Browse files Browse the repository at this point in the history
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.consensusrpc.enabled and is disabled
by default. Enabling the public consensus services worker exposes the light
consensus client interface over publicly accessible gRPC.
  • Loading branch information
kostko committed May 6, 2020
1 parent f3083ec commit 20107f5
Show file tree
Hide file tree
Showing 10 changed files with 173 additions and 14 deletions.
9 changes: 9 additions & 0 deletions .changelog/2440.feature.2.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
go/worker/consensusrpc: Add public consensus RPC 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.consensusrpc.enabled` and is
disabled by default. Enabling the public consensus services worker exposes
the light consensus client interface over publicly accessible gRPC.
1 change: 1 addition & 0 deletions .changelog/2881.breaking.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
go/common/node: Add RoleConsensusRPC role bit
17 changes: 11 additions & 6 deletions go/common/node/node.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,18 +69,20 @@ type Node struct {
type RolesMask uint32

const (
// RoleComputeWorker is Oasis compute worker role.
// RoleComputeWorker is the compute worker role.
RoleComputeWorker RolesMask = 1 << 0
// RoleStorageWorker is Oasis storage worker role.
// RoleStorageWorker is the storage worker role.
RoleStorageWorker RolesMask = 1 << 1
// RoleKeyManager is the Oasis key manager role.
// RoleKeyManager is the the key manager role.
RoleKeyManager RolesMask = 1 << 2
// RoleValidator is the Oasis validator role.
// RoleValidator is the validator role.
RoleValidator RolesMask = 1 << 3
// RoleConsensusRPC is the public consensus RPC services worker role.
RoleConsensusRPC RolesMask = 1 << 4

// RoleReserved are all the bits of the Oasis node roles bitmask
// that are reserved and must not be used.
RoleReserved RolesMask = ((1 << 32) - 1) & ^((RoleValidator << 1) - 1)
RoleReserved RolesMask = ((1 << 32) - 1) & ^((RoleConsensusRPC << 1) - 1)
)

// IsSingleRole returns true if RolesMask encodes a single valid role.
Expand All @@ -102,11 +104,14 @@ func (m RolesMask) String() string {
ret = append(ret, "storage")
}
if m&RoleKeyManager != 0 {
ret = append(ret, "key_manager")
ret = append(ret, "key-manager")
}
if m&RoleValidator != 0 {
ret = append(ret, "validator")
}
if m&RoleConsensusRPC != 0 {
ret = append(ret, "consensus-rpc")
}

return strings.Join(ret, ",")
}
Expand Down
5 changes: 2 additions & 3 deletions go/consensus/api/light.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,8 @@ type ValidatorSet struct {
type Parameters struct {
// Height contains the block height these consensus parameters are for.
Height int64 `json:"height"`

// TODO: Consider also including consensus/genesis.Parameters which are backend-agnostic.

// Meta contains the consensus backend specific consensus parameters.
Meta []byte `json:"meta"`

// TODO: Consider also including consensus/genesis.Parameters which are backend-agnostic.
}
22 changes: 21 additions & 1 deletion go/oasis-node/cmd/node/node.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,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"
workerConsensusRPC "github.com/oasislabs/oasis-core/go/worker/consensusrpc"
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"
Expand Down Expand Up @@ -126,6 +127,7 @@ type Node struct {
P2P *p2p.P2P
RegistrationWorker *registration.Worker
KeymanagerWorker *workerKeymanager.Worker
ConsensusWorker *workerConsensusRPC.Worker
}

// Cleanup cleans up after the node has terminated.
Expand Down Expand Up @@ -340,6 +342,13 @@ func (n *Node) initWorkers(logger *logging.Logger) error {
}
n.svcMgr.Register(n.TransactionSchedulerWorker)

// Initialize the public consensus services worker.
n.ConsensusWorker, err = workerConsensusRPC.New(n.CommonWorker, n.RegistrationWorker)
if err != nil {
return err
}
n.svcMgr.Register(n.ConsensusWorker)

return nil
}

Expand Down Expand Up @@ -384,8 +393,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,
Expand Down Expand Up @@ -793,6 +812,7 @@ func init() {
workerCommon.Flags,
workerStorage.Flags,
workerSentry.Flags,
workerConsensusRPC.Flags,
crash.InitFlags(),
} {
Flags.AddFlagSet(v)
Expand Down
6 changes: 6 additions & 0 deletions go/oasis-test-runner/oasis/args.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
workerConsensusRPC "github.com/oasislabs/oasis-core/go/worker/consensusrpc"
"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"
Expand Down Expand Up @@ -377,6 +378,11 @@ func (args *argBuilder) workerTxnschedulerCheckTxEnabled() *argBuilder {
return args
}

func (args *argBuilder) workerConsensusRPCEnabled() *argBuilder {
args.vec = append(args.vec, "--"+workerConsensusRPC.CfgWorkerEnabled)
return args
}

func (args *argBuilder) iasUseGenesis() *argBuilder {
args.vec = append(args.vec, "--ias.use_genesis")
return args
Expand Down
3 changes: 3 additions & 0 deletions go/oasis-test-runner/oasis/fixture.go
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,9 @@ type ConsensusFixture struct { // nolint: maligned

// TendermintRecoverCorruptedWAL enables automatic recovery of corrupted Tendermint's WAL.
TendermintRecoverCorruptedWAL bool `json:"tendermint_recover_corrupted_wal"`

// EnableConsensusRPCWorker enables the public consensus RPC services worker.
EnableConsensusRPCWorker bool `json:"enable_consensusrpc_worker,omitempty"`
}

// TEEFixture is a TEE configuration fixture.
Expand Down
13 changes: 12 additions & 1 deletion go/oasis-test-runner/oasis/validator.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ type Validator struct {

tmAddress string
consensusPort uint16
clientPort uint16
}

// ValidatorCfg is the Oasis validator provisioning configuration.
Expand Down Expand Up @@ -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()
Expand All @@ -91,6 +97,10 @@ func (val *Validator) startNode() error {
} else {
args = args.appendSeedNodes(val.net)
}
if val.consensus.EnableConsensusRPCWorker {
args = args.workerClientPort(val.clientPort).
workerConsensusRPCEnabled()
}

if len(val.net.validators) >= 1 && val == val.net.validators[0] {
args = args.supplementarysanityEnabled()
Expand Down Expand Up @@ -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

Expand Down Expand Up @@ -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",
Expand Down
6 changes: 3 additions & 3 deletions go/oasis-test-runner/scenario/e2e/runtime.go
Original file line number Diff line number Diff line change
Expand Up @@ -193,9 +193,9 @@ func (sc *runtimeImpl) Fixture() (*oasis.NetworkFixture, error) {
},
},
Validators: []oasis.ValidatorFixture{
oasis.ValidatorFixture{Entity: 1},
oasis.ValidatorFixture{Entity: 1},
oasis.ValidatorFixture{Entity: 1},
oasis.ValidatorFixture{Entity: 1, Consensus: oasis.ConsensusFixture{EnableConsensusRPCWorker: true}},
oasis.ValidatorFixture{Entity: 1, Consensus: oasis.ConsensusFixture{EnableConsensusRPCWorker: true}},
oasis.ValidatorFixture{Entity: 1, Consensus: oasis.ConsensusFixture{EnableConsensusRPCWorker: true}},
},
KeymanagerPolicies: []oasis.KeymanagerPolicyFixture{
oasis.KeymanagerPolicyFixture{Runtime: 0, Serial: 1},
Expand Down
105 changes: 105 additions & 0 deletions go/worker/consensusrpc/worker.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
// Package consensus implements publicly accessible consensus services.
package consensus

import (
"fmt"

flag "github.com/spf13/pflag"
"github.com/spf13/viper"

"github.com/oasislabs/oasis-core/go/common/logging"
"github.com/oasislabs/oasis-core/go/common/node"
consensus "github.com/oasislabs/oasis-core/go/consensus/api"
workerCommon "github.com/oasislabs/oasis-core/go/worker/common"
"github.com/oasislabs/oasis-core/go/worker/registration"
)

const (
// CfgWorkerEnabled enables the consensus RPC services worker.
CfgWorkerEnabled = "worker.consensusrpc.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 RPC 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 RPC 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, registration *registration.Worker) (*Worker, error) {
w := &Worker{
enabled: Enabled(),
commonWorker: commonWorker,
quitCh: make(chan struct{}),
logger: logging.GetLogger("worker/consensusrpc"),
}

if w.enabled {
// Register the consensus light client service.
consensus.RegisterLightService(commonWorker.Grpc.Server(), commonWorker.Consensus)

// Publish our role to ease discovery for clients.
rp, err := registration.NewRoleProvider(node.RoleConsensusRPC)
if err != nil {
return nil, fmt.Errorf("failed to create role provider: %w", err)
}

// The consensus RPC service is available immediately.
rp.SetAvailable(func(*node.Node) error { return nil })
}

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 RPC services worker")

_ = viper.BindPFlags(Flags)
}

0 comments on commit 20107f5

Please sign in to comment.