234 lines
6.5 KiB
Go
234 lines
6.5 KiB
Go
/*
|
|
Copyright IBM Corp. All Rights Reserved.
|
|
|
|
SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
package chaincode
|
|
|
|
import (
|
|
"crypto/tls"
|
|
|
|
pb "github.com/hyperledger/fabric-protos-go/peer"
|
|
"github.com/hyperledger/fabric/bccsp"
|
|
"github.com/hyperledger/fabric/internal/peer/common"
|
|
"github.com/hyperledger/fabric/internal/pkg/identity"
|
|
"github.com/pkg/errors"
|
|
"github.com/spf13/viper"
|
|
)
|
|
|
|
// ClientConnections holds the clients for connecting to the various
|
|
// endpoints in a Fabric network.
|
|
type ClientConnections struct {
|
|
BroadcastClient common.BroadcastClient
|
|
DeliverClients []pb.DeliverClient
|
|
EndorserClients []pb.EndorserClient
|
|
Certificate tls.Certificate
|
|
Signer identity.SignerSerializer
|
|
CryptoProvider bccsp.BCCSP
|
|
}
|
|
|
|
// ClientConnectionsInput holds the input parameters for creating
|
|
// client connections.
|
|
type ClientConnectionsInput struct {
|
|
CommandName string
|
|
EndorserRequired bool
|
|
OrdererRequired bool
|
|
OrderingEndpoint string
|
|
ChannelID string
|
|
PeerAddresses []string
|
|
TLSRootCertFiles []string
|
|
ConnectionProfilePath string
|
|
TargetPeer string
|
|
TLSEnabled bool
|
|
}
|
|
|
|
// NewClientConnections creates a new set of client connections based on the
|
|
// input parameters.
|
|
func NewClientConnections(input *ClientConnectionsInput, cryptoProvider bccsp.BCCSP) (*ClientConnections, error) {
|
|
signer, err := common.GetDefaultSigner()
|
|
if err != nil {
|
|
return nil, errors.WithMessage(err, "failed to retrieve default signer")
|
|
}
|
|
|
|
c := &ClientConnections{
|
|
Signer: signer,
|
|
CryptoProvider: cryptoProvider,
|
|
}
|
|
|
|
if input.EndorserRequired {
|
|
err := c.setPeerClients(input)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
}
|
|
|
|
if input.OrdererRequired {
|
|
err := c.setOrdererClient()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
}
|
|
|
|
return c, nil
|
|
}
|
|
|
|
func (c *ClientConnections) setPeerClients(input *ClientConnectionsInput) error {
|
|
var endorserClients []pb.EndorserClient
|
|
var deliverClients []pb.DeliverClient
|
|
|
|
if err := c.validatePeerConnectionParameters(input); err != nil {
|
|
return errors.WithMessage(err, "failed to validate peer connection parameters")
|
|
}
|
|
|
|
for i, address := range input.PeerAddresses {
|
|
var tlsRootCertFile string
|
|
if input.TLSRootCertFiles != nil {
|
|
tlsRootCertFile = input.TLSRootCertFiles[i]
|
|
}
|
|
endorserClient, err := common.GetEndorserClient(address, tlsRootCertFile)
|
|
if err != nil {
|
|
return errors.WithMessagef(err, "failed to retrieve endorser client for %s", input.CommandName)
|
|
}
|
|
endorserClients = append(endorserClients, endorserClient)
|
|
deliverClient, err := common.GetPeerDeliverClient(address, tlsRootCertFile)
|
|
if err != nil {
|
|
return errors.WithMessagef(err, "failed to retrieve deliver client for %s", input.CommandName)
|
|
}
|
|
deliverClients = append(deliverClients, deliverClient)
|
|
}
|
|
if len(endorserClients) == 0 {
|
|
// this should only be empty due to a programming bug
|
|
return errors.New("no endorser clients retrieved")
|
|
}
|
|
|
|
err := c.setCertificate()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
c.EndorserClients = endorserClients
|
|
c.DeliverClients = deliverClients
|
|
|
|
return nil
|
|
}
|
|
|
|
func (c *ClientConnections) validatePeerConnectionParameters(input *ClientConnectionsInput) error {
|
|
if input.ConnectionProfilePath != "" {
|
|
err := input.parseConnectionProfile()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
// currently only support multiple peer addresses for _lifecycle
|
|
// for approveformyorg and commit
|
|
multiplePeersAllowed := map[string]bool{
|
|
"approveformyorg": true,
|
|
"commit": true,
|
|
}
|
|
if !multiplePeersAllowed[input.CommandName] && len(input.PeerAddresses) > 1 {
|
|
return errors.Errorf("'%s' command supports one peer. %d peers provided", input.CommandName, len(input.PeerAddresses))
|
|
}
|
|
|
|
if !input.TLSEnabled {
|
|
input.TLSRootCertFiles = nil
|
|
return nil
|
|
}
|
|
if len(input.TLSRootCertFiles) != len(input.PeerAddresses) {
|
|
return errors.Errorf("number of peer addresses (%d) does not match the number of TLS root cert files (%d)", len(input.PeerAddresses), len(input.TLSRootCertFiles))
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (c *ClientConnectionsInput) parseConnectionProfile() error {
|
|
networkConfig, err := common.GetConfig(c.ConnectionProfilePath)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
c.PeerAddresses = []string{}
|
|
c.TLSRootCertFiles = []string{}
|
|
|
|
if c.ChannelID == "" {
|
|
if c.TargetPeer == "" {
|
|
return errors.New("--targetPeer must be specified for channel-less operation using connection profile")
|
|
}
|
|
return c.appendPeerConfig(networkConfig, c.TargetPeer)
|
|
}
|
|
|
|
if len(networkConfig.Channels[c.ChannelID].Peers) == 0 {
|
|
return nil
|
|
}
|
|
|
|
for peer, peerChannelConfig := range networkConfig.Channels[c.ChannelID].Peers {
|
|
if peerChannelConfig.EndorsingPeer {
|
|
err := c.appendPeerConfig(networkConfig, peer)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (c *ClientConnectionsInput) appendPeerConfig(n *common.NetworkConfig, peer string) error {
|
|
peerConfig, ok := n.Peers[peer]
|
|
if !ok {
|
|
return errors.Errorf("peer '%s' doesn't have associated peer config", peer)
|
|
}
|
|
c.PeerAddresses = append(c.PeerAddresses, peerConfig.URL)
|
|
c.TLSRootCertFiles = append(c.TLSRootCertFiles, peerConfig.TLSCACerts.Path)
|
|
|
|
return nil
|
|
}
|
|
|
|
func (c *ClientConnections) setCertificate() error {
|
|
certificate, err := common.GetClientCertificate()
|
|
if err != nil {
|
|
return errors.WithMessage(err, "failed to retrieve client cerificate")
|
|
}
|
|
|
|
c.Certificate = certificate
|
|
|
|
return nil
|
|
}
|
|
|
|
func (c *ClientConnections) setOrdererClient() error {
|
|
oe := viper.GetString("orderer.address")
|
|
if oe == "" {
|
|
// if we're here we didn't get an orderer endpoint from the command line
|
|
// so we'll attempt to get one from cscc - bless it
|
|
if c.Signer == nil {
|
|
return errors.New("cannot obtain orderer endpoint, no signer was configured")
|
|
}
|
|
|
|
if len(c.EndorserClients) == 0 {
|
|
return errors.New("cannot obtain orderer endpoint, empty endorser list")
|
|
}
|
|
|
|
orderingEndpoints, err := common.GetOrdererEndpointOfChainFnc(channelID, c.Signer, c.EndorserClients[0], c.CryptoProvider)
|
|
if err != nil {
|
|
return errors.WithMessagef(err, "error getting channel (%s) orderer endpoint", channelID)
|
|
}
|
|
if len(orderingEndpoints) == 0 {
|
|
return errors.Errorf("no orderer endpoints retrieved for channel %s, pass orderer endpoint with -o flag instead", channelID)
|
|
}
|
|
|
|
logger.Infof("Retrieved channel (%s) orderer endpoint: %s", channelID, orderingEndpoints[0])
|
|
// override viper env
|
|
viper.Set("orderer.address", orderingEndpoints[0])
|
|
}
|
|
|
|
broadcastClient, err := common.GetBroadcastClient()
|
|
if err != nil {
|
|
return errors.WithMessage(err, "failed to retrieve broadcast client")
|
|
}
|
|
|
|
c.BroadcastClient = broadcastClient
|
|
|
|
return nil
|
|
}
|