diff --git a/README.md b/README.md index a2269de11b75c28de5da068eef61e313fc7366bd..0fa75799f1fe7a64ac712daa25bdf82e2a9a68de 100644 --- a/README.md +++ b/README.md @@ -4,6 +4,7 @@ [](https://gitlab.com/xx_network/comms/commits/master) ``` +protoc -I interconnect/ interconnect/interconnect.proto -I /path/to/gitlab.com/ --go_out=plugins=grpc:interconnect protoc -I messages/ messages/messages.proto --go_out=plugins=grpc:messages protoc -I gossip/ gossip/messages.proto --go_out=plugins=grpc:gossip ``` diff --git a/connect/comms_test.go b/connect/comms_test.go index ee1eb5fcd495d9cb8f86bd2da4da7ec44d9bf98d..95f543f6fd7744bf2f33bfa35cba2e912ee93ab1 100644 --- a/connect/comms_test.go +++ b/connect/comms_test.go @@ -34,4 +34,4 @@ func TestSendNoAddressFails(t *testing.T) { if err.Error() != "Host address is blank, host might be receive only." { t.Errorf("Send function should have errored with address error.") } -} \ No newline at end of file +} diff --git a/go.mod b/go.mod index 15b8bcf0722d8df9a4e7e919cd500b4a4288e6ea..0ecd723e5994f651d553509ff6aa1af569679699 100644 --- a/go.mod +++ b/go.mod @@ -8,7 +8,7 @@ require ( github.com/spf13/jwalterweatherman v1.1.0 github.com/zeebo/blake3 v0.0.4 gitlab.com/elixxir/comms v0.0.0-20200707210150-b8ebd0951d23 - gitlab.com/elixxir/crypto v0.0.0-20200707005343-97f868cbd930 + gitlab.com/elixxir/crypto v0.0.0-20200803223738-661ca14b6470 gitlab.com/elixxir/primitives v0.0.0-20200731184040-494269b53b4d golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 golang.org/x/net v0.0.0-20200707034311-ab3426394381 diff --git a/go.sum b/go.sum index 9304ebd5a8821a8f8e0a59514a7010715b430bd2..6e81c6e37e5374d945667b27974e2ffe880416e6 100644 --- a/go.sum +++ b/go.sum @@ -61,6 +61,8 @@ gitlab.com/elixxir/comms v0.0.0-20200707210150-b8ebd0951d23 h1:ikyf3DPibZq+SsVUe gitlab.com/elixxir/comms v0.0.0-20200707210150-b8ebd0951d23/go.mod h1:OsWMZ1O/R9fOkm+PoHnR3rkXfFtipGoPs73FuKuurHY= gitlab.com/elixxir/crypto v0.0.0-20200707005343-97f868cbd930 h1:9qzfwyR12OYgn3j30qcHZHHVfWshWnH54lcAHppEROQ= gitlab.com/elixxir/crypto v0.0.0-20200707005343-97f868cbd930/go.mod h1:LHBAaEf48a0/AjU118rjoworH0LgXifhAqmNX3ZRvME= +gitlab.com/elixxir/crypto v0.0.0-20200803223738-661ca14b6470 h1:WGECBA9PtyUk9RfkpHjcbySoXfByEBTaD5IUHmjGem4= +gitlab.com/elixxir/crypto v0.0.0-20200803223738-661ca14b6470/go.mod h1:LHBAaEf48a0/AjU118rjoworH0LgXifhAqmNX3ZRvME= gitlab.com/elixxir/primitives v0.0.0-20200706165052-9fe7a4fb99a3 h1:GTfflZBNLeBq3UApYog0J3+hytdkoRsDduGQji2wyEU= gitlab.com/elixxir/primitives v0.0.0-20200706165052-9fe7a4fb99a3/go.mod h1:OQgUZq7SjnE0b+8+iIAT2eqQF+2IFHn73tOo+aV11mg= gitlab.com/elixxir/primitives v0.0.0-20200731184040-494269b53b4d h1:OKWTmYN5q8XVHo8JXThIH0TCuvl/fLXR7MGVacpqfRg= diff --git a/interconnect/consensusClient.go b/interconnect/consensusClient.go new file mode 100644 index 0000000000000000000000000000000000000000..ef735a322b9e85efbd20bff9d63c6e3be6e27720 --- /dev/null +++ b/interconnect/consensusClient.go @@ -0,0 +1,48 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright © 2020 xx network SEZC // +// // +// Use of this source code is governed by a license that can be found in the // +// LICENSE file // +/////////////////////////////////////////////////////////////////////////////// +package interconnect + +import ( + "errors" + "github.com/golang/protobuf/ptypes" + "github.com/golang/protobuf/ptypes/any" + jww "github.com/spf13/jwalterweatherman" + "gitlab.com/xx_network/comms/connect" + "gitlab.com/xx_network/comms/messages" + "google.golang.org/grpc" +) + +// consensus Server -> cmix Server Send Function +func (s *Comms) SendGetNDF(host *connect.Host, + message *messages.Ping) (*NDF, error) { + + // Create the Send Function + f := func(conn *grpc.ClientConn) (*any.Any, error) { + // Set up the context + ctx, cancel := connect.MessagingContext() + defer cancel() + //Format to authenticated message type + // Send the message + + resultMsg, err := NewInterconnectClient(conn).GetNDF(ctx, message) + if err != nil { + return nil, errors.New(err.Error()) + } + return ptypes.MarshalAny(resultMsg) + } + + // Execute the Send function + jww.DEBUG.Printf("Sending Post Phase message: %+v", message) + resultMsg, err := s.Send(host, f) + if err != nil { + return nil, err + } + + // Marshall the result + result := &NDF{} + return result, ptypes.UnmarshalAny(resultMsg, result) +} diff --git a/interconnect/consensusClient_test.go b/interconnect/consensusClient_test.go new file mode 100644 index 0000000000000000000000000000000000000000..3728c1cdc075d806a6fffcf53296af9fbc644fa8 --- /dev/null +++ b/interconnect/consensusClient_test.go @@ -0,0 +1,38 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright © 2020 xx network SEZC // +// // +// Use of this source code is governed by a license that can be found in the // +// LICENSE file // +/////////////////////////////////////////////////////////////////////////////// +package interconnect + +import ( + "bytes" + "context" + "gitlab.com/elixxir/primitives/id" + "gitlab.com/xx_network/comms/messages" + "gitlab.com/xx_network/comms/testkeys" + "testing" +) + +func TestComms_SendGetNDF(t *testing.T) { + testNodeID := id.NewIdFromString("test", id.Node, t) + testPort := "5959" + + certPEM := testkeys.LoadFromPath(testkeys.GetNodeCertPath()) + keyPEM := testkeys.LoadFromPath(testkeys.GetNodeKeyPath()) + + ic := StartCMixInterconnect(testNodeID, testPort, NewImplementation(), certPEM, keyPEM) + + expectedMessage := []byte("hello world") + + resultMsg, err := ic.GetNDF(context.Background(), &messages.Ping{}) + if err != nil { + t.Errorf("Failed to send message: %v", err) + } + if !bytes.Equal(expectedMessage, resultMsg.Ndf) { + t.Errorf("Unexpected message. "+ + "\nReceived: %v"+ + "\nExpected: %v", resultMsg.Ndf, expectedMessage) + } +} diff --git a/interconnect/endpoints.go b/interconnect/endpoints.go new file mode 100644 index 0000000000000000000000000000000000000000..df8bc60c497578a040f99785d826537a4942f5a0 --- /dev/null +++ b/interconnect/endpoints.go @@ -0,0 +1,19 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright © 2020 xx network SEZC // +// // +// Use of this source code is governed by a license that can be found in the // +// LICENSE file // +/////////////////////////////////////////////////////////////////////////////// + +// Endpoints for the interconnect service + +package interconnect + +import ( + "context" + "gitlab.com/xx_network/comms/messages" +) + +func (c *Comms) GetNDF(ctx context.Context, ping *messages.Ping) (*NDF, error) { + return c.handler.GetNDF() +} diff --git a/interconnect/handler.go b/interconnect/handler.go new file mode 100644 index 0000000000000000000000000000000000000000..e29965bc06deaa2d6590040bd12c295389e70e14 --- /dev/null +++ b/interconnect/handler.go @@ -0,0 +1,103 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright © 2020 xx network SEZC // +// // +// Use of this source code is governed by a license that can be found in the // +// LICENSE file // +/////////////////////////////////////////////////////////////////////////////// +package interconnect + +import ( + "errors" + jww "github.com/spf13/jwalterweatherman" + "gitlab.com/elixxir/primitives/id" + "gitlab.com/xx_network/comms/connect" + "google.golang.org/grpc/reflection" + "net" + "runtime/debug" +) + +// Starts a new server on the localHost:port specified by port +// and a callback interface for interconnect operations +// with given path to public and private key for TLS connection +func StartCMixInterconnect(id *id.ID, port string, handler Handler, + certPEMblock, keyPEMblock []byte) *Comms { + + addr := net.JoinHostPort("0.0.0.0", port) + + pc, lis, err := connect.StartCommServer(id, addr, + certPEMblock, keyPEMblock) + if err != nil { + jww.FATAL.Panicf("Unable to start comms server: %+v", err) + } + + CMixInterconnect := Comms{ + ProtoComms: pc, + handler: handler, + } + + go func() { + // Register GRPC services to the listening address + RegisterInterconnectServer(CMixInterconnect.LocalServer, &CMixInterconnect) + //messages.RegisterGenericServer(CMixInterconnect.LocalServer, &CMixInterconnect) + + // Register reflection service on gRPC server. + reflection.Register(CMixInterconnect.LocalServer) + if err := CMixInterconnect.LocalServer.Serve(lis); err != nil { + jww.FATAL.Panicf("Failed to serve: %+v", + errors.New(err.Error())) + } + jww.INFO.Printf("Shutting down node server listener: %s", lis) + }() + + return &CMixInterconnect + +} + +// Server object used to implement endpoints and top-level comms functionality +type Comms struct { + *connect.ProtoComms + handler Handler +} + +type Handler interface { + // Interconnect interface for getting the NDF + GetNDF() (*NDF, error) +} + +type implementationFunctions struct { + GetNDF func() (*NDF, error) +} + +// Implementation allows users of the client library to set the +// functions that implement the node functions +type Implementation struct { + Functions implementationFunctions +} + +// Below is the Implementation implementation, which calls the +// function matching the variable in the structure. + +// NewImplementation returns a Implementation struct with all of the +// function pointers returning nothing and printing an error. +func NewImplementation() *Implementation { + um := "UNIMPLEMENTED FUNCTION!" + warn := func(msg string) { + jww.WARN.Printf(msg) + jww.WARN.Printf("%s", debug.Stack()) + } + return &Implementation{ + Functions: implementationFunctions{ + GetNDF: func() (*NDF, error) { + warn(um) + return &NDF{ + Ndf: []byte("hello world"), + }, nil + }, + }, + } +} + +// Interconnect Interface for getting an NDF +func (s *Implementation) GetNDF() (*NDF, error) { + return s.Functions.GetNDF() +} diff --git a/interconnect/interconnect.pb.go b/interconnect/interconnect.pb.go new file mode 100644 index 0000000000000000000000000000000000000000..0ff2fc4d19ae97628f4db41e7f31608d976f98aa --- /dev/null +++ b/interconnect/interconnect.pb.go @@ -0,0 +1,167 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// source: interconnect.proto + +package interconnect + +import ( + context "context" + fmt "fmt" + proto "github.com/golang/protobuf/proto" + messages "gitlab.com/xx_network/comms/messages" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" + math "math" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package + +// The Network Definition File is defined as a +// JSON structure in primitives/ndf. +type NDF struct { + Ndf []byte `protobuf:"bytes,1,opt,name=Ndf,proto3" json:"Ndf,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *NDF) Reset() { *m = NDF{} } +func (m *NDF) String() string { return proto.CompactTextString(m) } +func (*NDF) ProtoMessage() {} +func (*NDF) Descriptor() ([]byte, []int) { + return fileDescriptor_076c6e9f11b66192, []int{0} +} + +func (m *NDF) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_NDF.Unmarshal(m, b) +} +func (m *NDF) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_NDF.Marshal(b, m, deterministic) +} +func (m *NDF) XXX_Merge(src proto.Message) { + xxx_messageInfo_NDF.Merge(m, src) +} +func (m *NDF) XXX_Size() int { + return xxx_messageInfo_NDF.Size(m) +} +func (m *NDF) XXX_DiscardUnknown() { + xxx_messageInfo_NDF.DiscardUnknown(m) +} + +var xxx_messageInfo_NDF proto.InternalMessageInfo + +func (m *NDF) GetNdf() []byte { + if m != nil { + return m.Ndf + } + return nil +} + +func init() { + proto.RegisterType((*NDF)(nil), "interconnect.NDF") +} + +func init() { proto.RegisterFile("interconnect.proto", fileDescriptor_076c6e9f11b66192) } + +var fileDescriptor_076c6e9f11b66192 = []byte{ + // 150 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x12, 0xca, 0xcc, 0x2b, 0x49, + 0x2d, 0x4a, 0xce, 0xcf, 0xcb, 0x4b, 0x4d, 0x2e, 0xd1, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0xe2, + 0x41, 0x16, 0x93, 0x32, 0x4e, 0xcf, 0x2c, 0xc9, 0x49, 0x4c, 0xd2, 0x4b, 0xce, 0xcf, 0xd5, 0xaf, + 0xa8, 0x88, 0xcf, 0x4b, 0x2d, 0x29, 0xcf, 0x2f, 0xca, 0xd6, 0x4f, 0xce, 0xcf, 0xcd, 0x2d, 0xd6, + 0xcf, 0x4d, 0x2d, 0x2e, 0x4e, 0x4c, 0x4f, 0x45, 0x30, 0x20, 0x46, 0x28, 0x89, 0x73, 0x31, 0xfb, + 0xb9, 0xb8, 0x09, 0x09, 0x70, 0x31, 0xfb, 0xa5, 0xa4, 0x49, 0x30, 0x2a, 0x30, 0x6a, 0xf0, 0x04, + 0x81, 0x98, 0x46, 0xd6, 0x5c, 0x3c, 0x9e, 0x48, 0xa6, 0x0b, 0x69, 0x73, 0xb1, 0xb9, 0xa7, 0x96, + 0x80, 0xd4, 0xf2, 0xe9, 0xc1, 0xcd, 0x08, 0xc8, 0xcc, 0x4b, 0x97, 0x12, 0xd4, 0x43, 0x71, 0x9a, + 0x9f, 0x8b, 0x5b, 0x12, 0x1b, 0xd8, 0x70, 0x63, 0x40, 0x00, 0x00, 0x00, 0xff, 0xff, 0x1b, 0x2e, + 0x36, 0xe8, 0xb5, 0x00, 0x00, 0x00, +} + +// Reference imports to suppress errors if they are not otherwise used. +var _ context.Context +var _ grpc.ClientConn + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +const _ = grpc.SupportPackageIsVersion4 + +// InterconnectClient is the client API for Interconnect service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream. +type InterconnectClient interface { + GetNDF(ctx context.Context, in *messages.Ping, opts ...grpc.CallOption) (*NDF, error) +} + +type interconnectClient struct { + cc *grpc.ClientConn +} + +func NewInterconnectClient(cc *grpc.ClientConn) InterconnectClient { + return &interconnectClient{cc} +} + +func (c *interconnectClient) GetNDF(ctx context.Context, in *messages.Ping, opts ...grpc.CallOption) (*NDF, error) { + out := new(NDF) + err := c.cc.Invoke(ctx, "/interconnect.Interconnect/GetNDF", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// InterconnectServer is the server API for Interconnect service. +type InterconnectServer interface { + GetNDF(context.Context, *messages.Ping) (*NDF, error) +} + +// UnimplementedInterconnectServer can be embedded to have forward compatible implementations. +type UnimplementedInterconnectServer struct { +} + +func (*UnimplementedInterconnectServer) GetNDF(ctx context.Context, req *messages.Ping) (*NDF, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetNDF not implemented") +} + +func RegisterInterconnectServer(s *grpc.Server, srv InterconnectServer) { + s.RegisterService(&_Interconnect_serviceDesc, srv) +} + +func _Interconnect_GetNDF_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(messages.Ping) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(InterconnectServer).GetNDF(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/interconnect.Interconnect/GetNDF", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(InterconnectServer).GetNDF(ctx, req.(*messages.Ping)) + } + return interceptor(ctx, in, info, handler) +} + +var _Interconnect_serviceDesc = grpc.ServiceDesc{ + ServiceName: "interconnect.Interconnect", + HandlerType: (*InterconnectServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "GetNDF", + Handler: _Interconnect_GetNDF_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "interconnect.proto", +} diff --git a/interconnect/interconnect.proto b/interconnect/interconnect.proto new file mode 100644 index 0000000000000000000000000000000000000000..3488d81722949c7dbf76050b71efc7ee266b3e07 --- /dev/null +++ b/interconnect/interconnect.proto @@ -0,0 +1,22 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright © 2020 xx network SEZC // +// // +// Use of this source code is governed by a license that can be found in the // +// LICENSE file // +/////////////////////////////////////////////////////////////////////////////// + +syntax = "proto3"; +import "gitlab.com/xx_network/comms/messages/messages.proto"; + +package interconnect; + +// RPC for handling communication between cmix nodes and consensus nodes +service Interconnect { + rpc GetNDF (messages.Ping) returns (NDF); +} + +// The Network Definition File is defined as a +// JSON structure in primitives/ndf. +message NDF { + bytes Ndf = 1; +}