Skip to content

Commit

Permalink
go/consensus: Add basic API for supporting light consensus clients
Browse files Browse the repository at this point in the history
  • Loading branch information
kostko committed May 5, 2020
1 parent 8c828c2 commit a2f59b9
Show file tree
Hide file tree
Showing 9 changed files with 356 additions and 34 deletions.
1 change: 1 addition & 0 deletions .changelog/2440.feature.1.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
go/consensus: Add basic API for supporting light consensus clients
10 changes: 8 additions & 2 deletions go/consensus/api/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ package api

import (
"context"
"time"

beacon "github.com/oasislabs/oasis-core/go/beacon/api"
"github.com/oasislabs/oasis-core/go/common/cbor"
Expand Down Expand Up @@ -42,9 +43,10 @@ var (
ErrVersionNotFound = errors.New(moduleName, 3, "consensus: version not found")
)

// ClientBackend is a limited consensus interface used by clients that
// connect to the local node.
// ClientBackend is a limited consensus interface used by clients that connect to the local full
// node. This is separate from light clients which use the LightClientBackend interface.
type ClientBackend interface {
LightClientBackend
TransactionAuthHandler

// SubmitTx submits a signed consensus transaction.
Expand Down Expand Up @@ -87,6 +89,10 @@ type ClientBackend interface {
type Block struct {
// Height contains the block height.
Height int64 `json:"height"`
// Hash contains the block header hash.
Hash []byte `json:"hash"`
// Time is the second-granular consensus time.
Time time.Time `json:"time"`
// Meta contains the consensus backend specific block metadata.
Meta cbor.RawMessage `json:"meta"`
}
Expand Down
188 changes: 166 additions & 22 deletions go/consensus/api/grpc.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ import (
var (
// serviceName is the gRPC service name.
serviceName = cmnGrpc.NewServiceName("Consensus")
// lightServiceName is the gRPC service name for the light consensus interface.
lightServiceName = cmnGrpc.NewServiceName("ConsensusLight")

// methodSubmitTx is the SubmitTx method.
methodSubmitTx = serviceName.NewMethod("SubmitTx", transaction.SignedTransaction{})
Expand All @@ -36,10 +38,17 @@ var (
// methodWatchBlocks is the WatchBlocks method.
methodWatchBlocks = serviceName.NewMethod("WatchBlocks", nil)

// methodGetSignedHeader is the GetSignedHeader method.
methodGetSignedHeader = lightServiceName.NewMethod("GetSignedHeader", int64(0))
// methodGetValidatorSet is the GetValidatorSet method.
methodGetValidatorSet = lightServiceName.NewMethod("GetValidatorSet", int64(0))
// methodGetParameters is the GetParameters method.
methodGetParameters = lightServiceName.NewMethod("GetParameters", int64(0))

// serviceDesc is the gRPC service descriptor.
serviceDesc = grpc.ServiceDesc{
ServiceName: string(serviceName),
HandlerType: (*Backend)(nil),
HandlerType: (*ClientBackend)(nil),
Methods: []grpc.MethodDesc{
{
MethodName: methodSubmitTx.ShortName(),
Expand Down Expand Up @@ -82,6 +91,26 @@ var (
},
},
}

// lightServiceDesc is the gRPC service descriptor for the light consensus service.
lightServiceDesc = grpc.ServiceDesc{
ServiceName: string(lightServiceName),
HandlerType: (*LightClientBackend)(nil),
Methods: []grpc.MethodDesc{
{
MethodName: methodGetSignedHeader.ShortName(),
Handler: handlerGetSignedHeader,
},
{
MethodName: methodGetValidatorSet.ShortName(),
Handler: handlerGetValidatorSet,
},
{
MethodName: methodGetParameters.ShortName(),
Handler: handlerGetParameters,
},
},
}
)

func handlerSubmitTx( // nolint: golint
Expand All @@ -95,14 +124,14 @@ func handlerSubmitTx( // nolint: golint
return nil, err
}
if interceptor == nil {
return nil, srv.(Backend).SubmitTx(ctx, rq)
return nil, srv.(ClientBackend).SubmitTx(ctx, rq)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: methodSubmitTx.FullName(),
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return nil, srv.(Backend).SubmitTx(ctx, req.(*transaction.SignedTransaction))
return nil, srv.(ClientBackend).SubmitTx(ctx, req.(*transaction.SignedTransaction))
}
return interceptor(ctx, rq, info, handler)
}
Expand All @@ -118,14 +147,14 @@ func handlerStateToGenesis( // nolint: golint
return nil, err
}
if interceptor == nil {
return srv.(Backend).StateToGenesis(ctx, height)
return srv.(ClientBackend).StateToGenesis(ctx, height)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: methodStateToGenesis.FullName(),
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(Backend).StateToGenesis(ctx, req.(int64))
return srv.(ClientBackend).StateToGenesis(ctx, req.(int64))
}
return interceptor(ctx, height, info, handler)
}
Expand All @@ -141,14 +170,14 @@ func handlerEstimateGas( // nolint: golint
return nil, err
}
if interceptor == nil {
return srv.(Backend).EstimateGas(ctx, rq)
return srv.(ClientBackend).EstimateGas(ctx, rq)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: methodEstimateGas.FullName(),
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(Backend).EstimateGas(ctx, req.(*EstimateGasRequest))
return srv.(ClientBackend).EstimateGas(ctx, req.(*EstimateGasRequest))
}
return interceptor(ctx, rq, info, handler)
}
Expand All @@ -164,14 +193,14 @@ func handlerGetSignerNonce( // nolint: golint
return nil, err
}
if interceptor == nil {
return srv.(Backend).GetSignerNonce(ctx, rq)
return srv.(ClientBackend).GetSignerNonce(ctx, rq)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: methodGetSignerNonce.FullName(),
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(Backend).GetSignerNonce(ctx, req.(*GetSignerNonceRequest))
return srv.(ClientBackend).GetSignerNonce(ctx, req.(*GetSignerNonceRequest))
}
return interceptor(ctx, rq, info, handler)
}
Expand All @@ -187,14 +216,14 @@ func handlerGetEpoch( // nolint: golint
return nil, err
}
if interceptor == nil {
return srv.(Backend).GetEpoch(ctx, height)
return srv.(ClientBackend).GetEpoch(ctx, height)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: methodGetEpoch.FullName(),
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(Backend).GetEpoch(ctx, req.(int64))
return srv.(ClientBackend).GetEpoch(ctx, req.(int64))
}
return interceptor(ctx, height, info, handler)
}
Expand All @@ -210,14 +239,14 @@ func handlerWaitEpoch( // nolint: golint
return nil, err
}
if interceptor == nil {
return nil, srv.(Backend).WaitEpoch(ctx, epoch)
return nil, srv.(ClientBackend).WaitEpoch(ctx, epoch)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: methodWaitEpoch.FullName(),
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return nil, srv.(Backend).WaitEpoch(ctx, req.(epochtime.EpochTime))
return nil, srv.(ClientBackend).WaitEpoch(ctx, req.(epochtime.EpochTime))
}
return interceptor(ctx, epoch, info, handler)
}
Expand All @@ -233,14 +262,14 @@ func handlerGetBlock( // nolint: golint
return nil, err
}
if interceptor == nil {
return srv.(Backend).GetBlock(ctx, height)
return srv.(ClientBackend).GetBlock(ctx, height)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: methodGetBlock.FullName(),
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(Backend).GetBlock(ctx, req.(int64))
return srv.(ClientBackend).GetBlock(ctx, req.(int64))
}
return interceptor(ctx, height, info, handler)
}
Expand All @@ -256,14 +285,14 @@ func handlerGetTransactions( // nolint: golint
return nil, err
}
if interceptor == nil {
return srv.(Backend).GetTransactions(ctx, height)
return srv.(ClientBackend).GetTransactions(ctx, height)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: methodGetTransactions.FullName(),
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(Backend).GetTransactions(ctx, req.(int64))
return srv.(ClientBackend).GetTransactions(ctx, req.(int64))
}
return interceptor(ctx, height, info, handler)
}
Expand All @@ -274,7 +303,7 @@ func handlerWatchBlocks(srv interface{}, stream grpc.ServerStream) error {
}

ctx := stream.Context()
ch, sub, err := srv.(Backend).WatchBlocks(ctx)
ch, sub, err := srv.(ClientBackend).WatchBlocks(ctx)
if err != nil {
return err
}
Expand All @@ -296,13 +325,120 @@ func handlerWatchBlocks(srv interface{}, stream grpc.ServerStream) error {
}
}

// RegisterService registers a new consensus backend service with the
// given gRPC server.
func RegisterService(server *grpc.Server, service Backend) {
func handlerGetSignedHeader( // nolint: golint
srv interface{},
ctx context.Context,
dec func(interface{}) error,
interceptor grpc.UnaryServerInterceptor,
) (interface{}, error) {
var height int64
if err := dec(&height); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(LightClientBackend).GetSignedHeader(ctx, height)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: methodGetSignedHeader.FullName(),
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(LightClientBackend).GetSignedHeader(ctx, req.(int64))
}
return interceptor(ctx, height, info, handler)
}

func handlerGetValidatorSet( // nolint: golint
srv interface{},
ctx context.Context,
dec func(interface{}) error,
interceptor grpc.UnaryServerInterceptor,
) (interface{}, error) {
var height int64
if err := dec(&height); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(LightClientBackend).GetValidatorSet(ctx, height)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: methodGetValidatorSet.FullName(),
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(LightClientBackend).GetValidatorSet(ctx, req.(int64))
}
return interceptor(ctx, height, info, handler)
}

func handlerGetParameters( // nolint: golint
srv interface{},
ctx context.Context,
dec func(interface{}) error,
interceptor grpc.UnaryServerInterceptor,
) (interface{}, error) {
var height int64
if err := dec(&height); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(LightClientBackend).GetParameters(ctx, height)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: methodGetParameters.FullName(),
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(LightClientBackend).GetParameters(ctx, req.(int64))
}
return interceptor(ctx, height, info, handler)
}

// RegisterService registers a new client backend service with the given gRPC server.
func RegisterService(server *grpc.Server, service ClientBackend) {
server.RegisterService(&serviceDesc, service)
RegisterLightService(server, service)
}

// RegisterLightService registers a new light client backend service with the given gRPC server.
func RegisterLightService(server *grpc.Server, service LightClientBackend) {
server.RegisterService(&lightServiceDesc, service)
}

type consensusLightClient struct {
conn *grpc.ClientConn
}

// Implements LightClientBackend.
func (c *consensusLightClient) GetSignedHeader(ctx context.Context, height int64) (*SignedHeader, error) {
var rsp SignedHeader
if err := c.conn.Invoke(ctx, methodGetSignedHeader.FullName(), height, &rsp); err != nil {
return nil, err
}
return &rsp, nil
}

// Implements LightClientBackend.
func (c *consensusLightClient) GetValidatorSet(ctx context.Context, height int64) (*ValidatorSet, error) {
var rsp ValidatorSet
if err := c.conn.Invoke(ctx, methodGetValidatorSet.FullName(), height, &rsp); err != nil {
return nil, err
}
return &rsp, nil
}

// Implements LightClientBackend.
func (c *consensusLightClient) GetParameters(ctx context.Context, height int64) (*Parameters, error) {
var rsp Parameters
if err := c.conn.Invoke(ctx, methodGetParameters.FullName(), height, &rsp); err != nil {
return nil, err
}
return &rsp, nil
}

type consensusClient struct {
consensusLightClient

conn *grpc.ClientConn
}

Expand Down Expand Up @@ -399,5 +535,13 @@ func (c *consensusClient) WatchBlocks(ctx context.Context) (<-chan *Block, pubsu

// NewConsensusClient creates a new gRPC consensus client service.
func NewConsensusClient(c *grpc.ClientConn) ClientBackend {
return &consensusClient{c}
return &consensusClient{
consensusLightClient: consensusLightClient{c},
conn: c,
}
}

// NewConsensusLightClient creates a new gRPC consensus light client service.
func NewConsensusLightClient(c *grpc.ClientConn) LightClientBackend {
return &consensusLightClient{c}
}
Loading

0 comments on commit a2f59b9

Please sign in to comment.