diff --git a/gossip/integration/integration.go b/gossip/integration/integration.go new file mode 100644 index 00000000000..0f5b91b212e --- /dev/null +++ b/gossip/integration/integration.go @@ -0,0 +1,126 @@ +/* +Copyright IBM Corp. 2016 All Rights Reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package integration + +import ( + "bytes" + "fmt" + "strconv" + "strings" + "time" + + "github.com/hyperledger/fabric/gossip/comm" + "github.com/hyperledger/fabric/gossip/gossip" + "github.com/hyperledger/fabric/gossip/proto" + "google.golang.org/grpc" +) + +// This file is used to bootstrap a gossip instance for integration/demo purposes ONLY + +func newConfig(selfEndpoint string, bootPeers ...string) *gossip.Config { + port, err := strconv.ParseInt(strings.Split(selfEndpoint, ":")[1], 10, 64) + if err != nil { + panic(err) + } + return &gossip.Config{ + BindPort: int(port), + BootstrapPeers: bootPeers, + ID: selfEndpoint, + MaxMessageCountToStore: 100, + MaxPropagationBurstLatency: time.Millisecond * 50, + MaxPropagationBurstSize: 3, + PropagateIterations: 1, + PropagatePeerNum: 3, + PullInterval: time.Second * 5, + PullPeerNum: 3, + SelfEndpoint: selfEndpoint, + } +} + +func newComm(selfEndpoint string, s *grpc.Server, dialOpts ...grpc.DialOption) comm.Comm { + comm, err := comm.NewCommInstance(s, NewGossipCryptoService(), []byte(selfEndpoint), dialOpts...) + if err != nil { + panic(err) + } + return comm +} + +// NewGossipComponent creates a gossip component that attaches itself to the given gRPC server +func NewGossipComponent(endpoint string, s *grpc.Server, bootPeers ...string) (gossip.Gossip, comm.Comm) { + conf := newConfig(endpoint, bootPeers...) + comm := newComm(endpoint, s, grpc.WithInsecure()) + return gossip.NewGossipService(conf, comm, NewGossipCryptoService()), comm +} + +// GossipCryptoService is an interface that conforms to both +// the comm.SecurityProvider and to discovery.CryptoService +type GossipCryptoService interface { + + // isEnabled returns whether authentication is enabled + IsEnabled() bool + + // Sign signs msg with this peers signing key and outputs + // the signature if no error occurred. + Sign(msg []byte) ([]byte, error) + + // Verify checks that signature if a valid signature of message under vkID's verification key. + // If the verification succeeded, Verify returns nil meaning no error occurred. + // If vkID is nil, then the signature is verified against this validator's verification key. + Verify(vkID, signature, message []byte) error + + // validateAliveMsg validates that an Alive message is authentic + ValidateAliveMsg(*proto.AliveMessage) bool + + // SignMessage signs an AliveMessage and updates its signature field + SignMessage(*proto.AliveMessage) *proto.AliveMessage +} + +// NewGossipCryptoService returns an instance that implements naively every security +// interface that the gossip layer needs +func NewGossipCryptoService() GossipCryptoService { + return &naiveCryptoServiceImpl{} +} + +type naiveCryptoServiceImpl struct { +} + +func (cs *naiveCryptoServiceImpl) ValidateAliveMsg(*proto.AliveMessage) bool { + return true +} + +// SignMessage signs an AliveMessage and updates its signature field +func (cs *naiveCryptoServiceImpl) SignMessage(msg *proto.AliveMessage) *proto.AliveMessage { + return msg +} + +// IsEnabled returns true whether authentication is enabled +func (cs *naiveCryptoServiceImpl) IsEnabled() bool { + return false +} + +// Sign signs a message with the local peer's private key +func (cs *naiveCryptoServiceImpl) Sign(msg []byte) ([]byte, error) { + return msg, nil +} + +// Verify verifies a signature on a message that came from a peer with a certain vkID +func (cs *naiveCryptoServiceImpl) Verify(vkID, signature, message []byte) error { + if !bytes.Equal(signature, message) { + return fmt.Errorf("Invalid signature!") + } + return nil +} diff --git a/gossip/integration/integration_test.go b/gossip/integration/integration_test.go new file mode 100644 index 00000000000..7d4b6799fde --- /dev/null +++ b/gossip/integration/integration_test.go @@ -0,0 +1,54 @@ +/* +Copyright IBM Corp. 2016 All Rights Reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package integration + +import ( + "fmt" + "net" + "testing" + "time" + + "google.golang.org/grpc" +) + +// This is just a test that shows how to instantiate a gossip component +func TestNewGossipCryptoService(t *testing.T) { + s1 := grpc.NewServer() + s2 := grpc.NewServer() + s3 := grpc.NewServer() + + ll1, _ := net.Listen("tcp", fmt.Sprintf("%s:%d", "", 5611)) + ll2, _ := net.Listen("tcp", fmt.Sprintf("%s:%d", "", 5612)) + ll3, _ := net.Listen("tcp", fmt.Sprintf("%s:%d", "", 5613)) + + endpoint1 := "localhost:5611" + endpoint2 := "localhost:5612" + endpoint3 := "localhost:5613" + + g1, _ := NewGossipComponent(endpoint1, s1) + g2, _ := NewGossipComponent(endpoint2, s2, "localhost:5611") + g3, _ := NewGossipComponent(endpoint3, s3, "localhost:5611") + go s1.Serve(ll1) + go s2.Serve(ll2) + go s2.Serve(ll3) + + time.Sleep(time.Second * 5) + fmt.Println(g1.GetPeers()) + fmt.Println(g2.GetPeers()) + fmt.Println(g3.GetPeers()) + time.Sleep(time.Second) +}