Skip to content

Commit

Permalink
Connect MSP-components-for gossip with gossip
Browse files Browse the repository at this point in the history
The gossip layer uses 2 interfaces for identity
and cryptographic capabilities, which are implemented
using the various MSP managers (either local or channel-based).

The 2 interfaces are found under gossip/api
and they are called MessageCryptoService and SecurityAdvisor.

They were implemented using the MSP, and this commit
connects their implementation to the gossip layer,
and removes the fake/dummy implementations that were
used as placeholders.

- This test also fixes a bug that is related to parsing
the certificate of anchor peers.

- It also now makes the default anchor peer (if non specified) to be
peer0 with the certificate of msp/sampleconfig

- And it also fixes a small bug was introduced by a commit a few days ago
  that was caused by passing a certificate instead of a PKI-ID
  into the gossip identity mapper, when validating
  a channel state-info message.

How was this tested?
I ran 4 instances of peers, in 2 different orgs, but with rootCAs
of all orgs in all peer local MSP configurations, and with peer0
as a bootstrap peer for the rest 3 peers, and made sure that the gossip
communication logs in all 4 peers send messages to 3 other peers.
This proves that they are able to authenticate and exchange membership
information about each other.
Then I created a channel, and made peers join it, and saw that they send
one another channel related messages and no warnings/errors were seen
in the logs.

Signed-off-by: Yacov Manevich <yacovm@il.ibm.com>
Change-Id: Id8b5e7e9400b7c58302e4396c04209f917bbde70
  • Loading branch information
yacovm committed Jan 30, 2017
1 parent 886f6bc commit 15c301b
Show file tree
Hide file tree
Showing 10 changed files with 85 additions and 97 deletions.
7 changes: 6 additions & 1 deletion core/peer/peer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import (
ccp "github.com/hyperledger/fabric/core/common/ccprovider"
"github.com/hyperledger/fabric/core/mocks/ccprovider"
"github.com/hyperledger/fabric/gossip/service"
"github.com/hyperledger/fabric/msp/mgmt"
)

func TestInitialize(t *testing.T) {
Expand Down Expand Up @@ -57,7 +58,11 @@ func TestCreateChainFromBlock(t *testing.T) {
assert.NoError(t, err)
go grpcServer.Serve(socket)
defer grpcServer.Stop()
service.InitGossipService("localhost:13611", grpcServer)

mgmt.LoadFakeSetupWithLocalMspAndTestChainMsp("../../msp/sampleconfig")

identity, _ := mgmt.GetLocalSigningIdentityOrPanic().Serialize()
service.InitGossipService(identity, "localhost:13611", grpcServer)

err = CreateChainFromBlock(block)
if err != nil {
Expand Down
7 changes: 6 additions & 1 deletion core/scc/cscc/configer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ import (
"github.com/hyperledger/fabric/core/ledger/ledgermgmt"
"github.com/hyperledger/fabric/core/peer"
"github.com/hyperledger/fabric/gossip/service"
"github.com/hyperledger/fabric/msp/mgmt"
"github.com/hyperledger/fabric/protos/common"
pb "github.com/hyperledger/fabric/protos/peer"
"github.com/hyperledger/fabric/protos/utils"
Expand Down Expand Up @@ -116,7 +117,11 @@ func TestConfigerInvokeJoinChainCorrectParams(t *testing.T) {
assert.NoError(t, err)
go grpcServer.Serve(socket)
defer grpcServer.Stop()
service.InitGossipService("localhost:13611", grpcServer)

mgmt.LoadFakeSetupWithLocalMspAndTestChainMsp("../../../msp/sampleconfig")
identity, _ := mgmt.GetLocalSigningIdentityOrPanic().Serialize()

service.InitGossipService(identity, "localhost:13611", grpcServer)

// Successful path for JoinChain
blockBytes := mockConfigBlock()
Expand Down
6 changes: 5 additions & 1 deletion gossip/gossip/gossip_impl.go
Original file line number Diff line number Diff line change
Expand Up @@ -869,7 +869,11 @@ func (g *gossipServiceImpl) getOrgOfPeer(PKIID common.PKIidType) api.OrgIdentity

func (g *gossipServiceImpl) validateStateInfoMsg(msg *proto.GossipMessage) error {
verifier := func(identity []byte, signature, message []byte) error {
return g.idMapper.Verify(identity, signature, message)
pkiID := g.idMapper.GetPKIidOfCert(api.PeerIdentityType(identity))
if pkiID == nil {
return fmt.Errorf("PKI-ID not found in identity mapper")
}
return g.idMapper.Verify(pkiID, signature, message)
}
identity, err := g.idMapper.Get(msg.GetStateInfo().PkiID)
if err != nil {
Expand Down
72 changes: 6 additions & 66 deletions gossip/integration/integration.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,25 +17,18 @@ limitations under the License.
package integration

import (
"bytes"
"fmt"
"strconv"
"strings"
"time"

"github.com/hyperledger/fabric/gossip/api"
"github.com/hyperledger/fabric/gossip/common"
"github.com/hyperledger/fabric/gossip/gossip"
"github.com/hyperledger/fabric/peer/gossip/mcs"
"github.com/hyperledger/fabric/peer/gossip/sa"
"google.golang.org/grpc"
)

// This file is used to bootstrap a gossip instance for integration/demo purposes ONLY

// TODO: This is a temporary fix to make gossip multi-channel work
// because we don't support cross-organization gossip yet.
// this will be removed once we support gossip across orgs.
var orgId = []byte("ORG1")

func newConfig(selfEndpoint string, bootPeers ...string) *gossip.Config {
port, err := strconv.ParseInt(strings.Split(selfEndpoint, ":")[1], 10, 64)
if err != nil {
Expand All @@ -61,62 +54,9 @@ func newConfig(selfEndpoint string, bootPeers ...string) *gossip.Config {
}

// NewGossipComponent creates a gossip component that attaches itself to the given gRPC server
func NewGossipComponent(endpoint string, s *grpc.Server, dialOpts []grpc.DialOption, bootPeers ...string) gossip.Gossip {
func NewGossipComponent(identity []byte, endpoint string, s *grpc.Server, dialOpts []grpc.DialOption, bootPeers ...string) gossip.Gossip {
conf := newConfig(endpoint, bootPeers...)
return gossip.NewGossipService(conf, s, &orgCryptoService{}, &naiveCryptoService{}, []byte(endpoint), dialOpts...)
}

type naiveCryptoService struct {
}

// ValidateIdentity validates the given identity.
// Returns error on failure, nil on success
func (*naiveCryptoService) ValidateIdentity(peerIdentity api.PeerIdentityType) error {
return nil
}

// GetPKIidOfCert returns the PKI-ID of a peer's identity
func (*naiveCryptoService) GetPKIidOfCert(peerIdentity api.PeerIdentityType) common.PKIidType {
return common.PKIidType(peerIdentity)
}

// VerifyBlock returns nil if the block is properly signed,
// else returns error
func (*naiveCryptoService) VerifyBlock(chainID common.ChainID, signedBlock api.SignedBlock) error {
return nil
}

// Sign signs msg with this peer's signing key and outputs
// the signature if no error occurred.
func (*naiveCryptoService) Sign(msg []byte) ([]byte, error) {
return msg, nil
}

// VerifyByChannel verifies a peer's signature on a message in the context
// of a specific channel
func (*naiveCryptoService) VerifyByChannel(_ common.ChainID, _ api.PeerIdentityType, _, _ []byte) error {
return nil
}

// Verify verifies a signature on a message that came from a peer with a certain vkID
func (cs *naiveCryptoService) Verify(vkID api.PeerIdentityType, signature, message []byte) error {
if !bytes.Equal(signature, message) {
return fmt.Errorf("Invalid signature")
}
return nil
}

type orgCryptoService struct {
}

// OrgByPeerIdentity returns the OrgIdentityType
// of a given peer identity
func (*orgCryptoService) OrgByPeerIdentity(identity api.PeerIdentityType) api.OrgIdentityType {
return orgId
}

// Verify verifies a JoinChannelMessage, returns nil on success,
// and an error on failure
func (*orgCryptoService) Verify(joinChanMsg api.JoinChannelMessage) error {
return nil
cryptSvc := mcs.NewMessageCryptoService()
secAdv := sa.NewSecurityAdvisor()
return gossip.NewGossipService(conf, s, secAdv, cryptSvc, identity, dialOpts...)
}
10 changes: 7 additions & 3 deletions gossip/integration/integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import (
"testing"
"time"

"github.com/hyperledger/fabric/msp/mgmt"
"google.golang.org/grpc"
)

Expand All @@ -39,9 +40,12 @@ func TestNewGossipCryptoService(t *testing.T) {
endpoint2 := "localhost:5612"
endpoint3 := "localhost:5613"

g1 := NewGossipComponent(endpoint1, s1, []grpc.DialOption{grpc.WithInsecure()})
g2 := NewGossipComponent(endpoint2, s2, []grpc.DialOption{grpc.WithInsecure()}, endpoint1)
g3 := NewGossipComponent(endpoint3, s3, []grpc.DialOption{grpc.WithInsecure()}, endpoint1)
mgmt.LoadFakeSetupWithLocalMspAndTestChainMsp("../../msp/sampleconfig")
identity, _ := mgmt.GetLocalSigningIdentityOrPanic().Serialize()

g1 := NewGossipComponent(identity, endpoint1, s1, []grpc.DialOption{grpc.WithInsecure()})
g2 := NewGossipComponent(identity, endpoint2, s2, []grpc.DialOption{grpc.WithInsecure()}, endpoint1)
g3 := NewGossipComponent(identity, endpoint3, s3, []grpc.DialOption{grpc.WithInsecure()}, endpoint1)
go s1.Serve(ll1)
go s2.Serve(ll2)
go s3.Serve(ll3)
Expand Down
4 changes: 2 additions & 2 deletions gossip/service/gossip_service.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ func (jcm *joinChannelMessage) AnchorPeers() []api.AnchorPeer {
var logger = logging.MustGetLogger("gossipService")

// InitGossipService initialize gossip service
func InitGossipService(endpoint string, s *grpc.Server, bootPeers ...string) {
func InitGossipService(identity []byte, endpoint string, s *grpc.Server, bootPeers ...string) {
once.Do(func() {
logger.Info("Initialize gossip with endpoint", endpoint, "and bootstrap set", bootPeers)
dialOpts := []grpc.DialOption{}
Expand All @@ -86,7 +86,7 @@ func InitGossipService(endpoint string, s *grpc.Server, bootPeers ...string) {
dialOpts = append(dialOpts, grpc.WithInsecure())
}

gossip := integration.NewGossipComponent(endpoint, s, dialOpts, bootPeers...)
gossip := integration.NewGossipComponent(identity, endpoint, s, dialOpts, bootPeers...)
gossipServiceInstance = &gossipServiceImpl{
gossipSvc: gossip,
chains: make(map[string]state.GossipStateProvider),
Expand Down
6 changes: 5 additions & 1 deletion gossip/service/gossip_service_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import (
"testing"

"github.com/hyperledger/fabric/gossip/api"
"github.com/hyperledger/fabric/msp/mgmt"
"github.com/stretchr/testify/assert"
"google.golang.org/grpc"
)
Expand All @@ -36,11 +37,14 @@ func TestInitGossipService(t *testing.T) {
go grpcServer.Serve(socket)
defer grpcServer.Stop()

mgmt.LoadFakeSetupWithLocalMspAndTestChainMsp("../../msp/sampleconfig")
identity, _ := mgmt.GetLocalSigningIdentityOrPanic().Serialize()

wg := sync.WaitGroup{}
wg.Add(10)
for i := 0; i < 10; i++ {
go func() {
InitGossipService("localhost:5611", grpcServer)
InitGossipService(identity, "localhost:5611", grpcServer)
wg.Done()
}()
}
Expand Down
15 changes: 15 additions & 0 deletions msp/identities.go
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,21 @@ func (id *identity) GetOrganizationUnits() string {
return "dunno"
}

// NewSerializedIdentity returns a serialized identity
// having as content the passed mspID and x509 certificate in PEM format.
// This method does not check the validity of certificate nor
// any consistency of the mspID with it.
func NewSerializedIdentity(mspID string, certPEM []byte) ([]byte, error) {
// We serialize identities by prepending the MSPID
// and appending the x509 cert in PEM format
sId := &SerializedIdentity{Mspid: mspID, IdBytes: certPEM}
raw, err := proto.Marshal(sId)
if err != nil {
return nil, fmt.Errorf("Failed serializing identity [%s][% X]: [%s]", mspID, certPEM, err)
}
return raw, nil
}

// Verify checks against a signature and a message
// to determine whether this identity produced the
// signature; it returns nil if so or an error otherwise
Expand Down
46 changes: 25 additions & 21 deletions peer/common/anchors.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import (
"strconv"
"strings"

"github.com/hyperledger/fabric/msp"
"github.com/hyperledger/fabric/protos/peer"
)

Expand Down Expand Up @@ -112,34 +113,37 @@ func anchorPeerFromFile(filename string) (*peer.AnchorPeer, error) {
if err != nil {
return nil, fmt.Errorf("Anchor peer certificate is not a valid PEM certificate: %v", err)
}

// TODO: this MSP-ID isn't going to stay like that in the future,
// but right now, it's the same for everyone.
identity, err := msp.NewSerializedIdentity("DEFAULT", rawPEM)
if err != nil {
return nil, err
}

ap := &peer.AnchorPeer{
Host: hostname,
Port: int32(port),
Cert: block.Bytes,
Cert: identity,
}
return ap, nil
}

const defaultAnchorPeerFile = `anchorpeer
const defaultAnchorPeerFile = `peer0
7051
-----BEGIN CERTIFICATE-----
MIIDZzCCAk+gAwIBAgIJAKSntkwsYDPhMA0GCSqGSIb3DQEBCwUAMEoxCzAJBgNV
BAYTAklMMQ8wDQYDVQQIDAZJc3JhZWwxDjAMBgNVBAcMBUhhaWZhMQwwCgYDVQQK
DANJQk0xDDAKBgNVBAsMA0lCTTAeFw0xNzAxMjcwMzUzMjdaFw0xODAxMjcwMzUz
MjdaMEoxCzAJBgNVBAYTAklMMQ8wDQYDVQQIDAZJc3JhZWwxDjAMBgNVBAcMBUhh
aWZhMQwwCgYDVQQKDANJQk0xDDAKBgNVBAsMA0lCTTCCASIwDQYJKoZIhvcNAQEB
BQADggEPADCCAQoCggEBAL0KUiuuZFfs+BN7+FnDKoeiVGCkayQVrPrdeO8Mwu/n
928T9lhmBI6wFnmkdeEjYTi1M5dks8hEal2AP8ykREc+LTmMH5JAJ8kktnoNQteO
rdFqnBpzA0IdiDnaLLLU3QD22VT47TPxWnfqZ3Z+fEJkmxc+tNmJJ5/0eCxXC4v4
875wQZP8CEeI1EpkljL6AILLNCUN4qpug2R2CCBRvGaqA81TM8NKxvWgN90iSAiv
vrQIc3/aelIpaJN457JEqLWgAcWw982rFUn5+D3u63pUq99lWH16VU4vRdUFzqi1
E3mBbGNTcNBzrBYswj5KhMFHLBpzIwQQX+Tvjh70cwkCAwEAAaNQME4wHQYDVR0O
BBYEFNHpTtXPDggAIavkdxLh+ttFH+HCMB8GA1UdIwQYMBaAFNHpTtXPDggAIavk
dxLh+ttFH+HCMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBADuYrb0h
eXepdpkUSZ6t5mk6R4vyaGDQAHCUltL5Q2qhL8f5sWxMBqke/JhbB02+pQCsvj8P
SIVSXuCXgFbzP0O3gNWqGhGn9atgN/j81hGyXtpAl5U5hyqcaFATX++Rdv58TKty
WnjzYUtnrG2W6c5uK/XPmoUHoNHxkgj1HrlmuahdrxzFXkdcND7UIfW8U2K0Cz4V
gJyAC5yIOs+kakE2gwjJI8SqREgegfO1JIbBfnUCkDJj1TLu2eUkBgnVLeJrcbXq
AbiMV4MFfj5KFA51Tp8QltKbsPPm1Vx3+CRVWNnMgqVWygIQF+8h4H/CcETU4XCV
4LqJvYfKwy27YUA=
MIICjDCCAjKgAwIBAgIUBEVwsSx0TmqdbzNwleNBBzoIT0wwCgYIKoZIzj0EAwIw
fzELMAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExFjAUBgNVBAcTDVNh
biBGcmFuY2lzY28xHzAdBgNVBAoTFkludGVybmV0IFdpZGdldHMsIEluYy4xDDAK
BgNVBAsTA1dXVzEUMBIGA1UEAxMLZXhhbXBsZS5jb20wHhcNMTYxMTExMTcwNzAw
WhcNMTcxMTExMTcwNzAwWjBjMQswCQYDVQQGEwJVUzEXMBUGA1UECBMOTm9ydGgg
Q2Fyb2xpbmExEDAOBgNVBAcTB1JhbGVpZ2gxGzAZBgNVBAoTEkh5cGVybGVkZ2Vy
IEZhYnJpYzEMMAoGA1UECxMDQ09QMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE
HBuKsAO43hs4JGpFfiGMkB/xsILTsOvmN2WmwpsPHZNL6w8HWe3xCPQtdG/XJJvZ
+C756KEsUBM3yw5PTfku8qOBpzCBpDAOBgNVHQ8BAf8EBAMCBaAwHQYDVR0lBBYw
FAYIKwYBBQUHAwEGCCsGAQUFBwMCMAwGA1UdEwEB/wQCMAAwHQYDVR0OBBYEFOFC
dcUZ4es3ltiCgAVDoyLfVpPIMB8GA1UdIwQYMBaAFBdnQj2qnoI/xMUdn1vDmdG1
nEgQMCUGA1UdEQQeMByCCm15aG9zdC5jb22CDnd3dy5teWhvc3QuY29tMAoGCCqG
SM49BAMCA0gAMEUCIDf9Hbl4xn3z4EwNKmilM9lX2Fq4jWpAaRVB97OmVEeyAiEA
25aDPQHGGq2AvhKT0wvt08cX1GTGCIbfmuLpMwKQj38=
-----END CERTIFICATE-----`
9 changes: 8 additions & 1 deletion peer/node/start.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ import (
"github.com/hyperledger/fabric/core/scc"
"github.com/hyperledger/fabric/events/producer"
"github.com/hyperledger/fabric/gossip/service"
"github.com/hyperledger/fabric/msp/mgmt"
"github.com/hyperledger/fabric/peer/common"
pb "github.com/hyperledger/fabric/protos/peer"
"github.com/spf13/cobra"
Expand Down Expand Up @@ -169,7 +170,13 @@ func serve(args []string) error {

// Initialize gossip component
bootstrap := viper.GetStringSlice("peer.gossip.bootstrap")
service.InitGossipService(peerEndpoint.Address, grpcServer, bootstrap...)

serializedIdentity, err := mgmt.GetLocalSigningIdentityOrPanic().Serialize()
if err != nil {
panic(fmt.Sprintf("Failed serializing self identity: %v", err))
}

service.InitGossipService(serializedIdentity, peerEndpoint.Address, grpcServer, bootstrap...)
defer service.GetGossipService().Stop()

//initialize the env for chainless startup
Expand Down

0 comments on commit 15c301b

Please sign in to comment.