github.com/leonlxy/hyperledger@v1.0.0-alpha.0.20170427033203-34922035d248/core/peer/peer.go (about)

     1  /*
     2  Copyright IBM Corp. 2016 All Rights Reserved.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8  		 http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package peer
    18  
    19  import (
    20  	"errors"
    21  	"fmt"
    22  	"math"
    23  	"net"
    24  	"sync"
    25  
    26  	"github.com/golang/protobuf/proto"
    27  	"github.com/hyperledger/fabric/common/config"
    28  	"github.com/hyperledger/fabric/common/configtx"
    29  	configtxapi "github.com/hyperledger/fabric/common/configtx/api"
    30  	configtxtest "github.com/hyperledger/fabric/common/configtx/test"
    31  	"github.com/hyperledger/fabric/common/flogging"
    32  	mockconfigtx "github.com/hyperledger/fabric/common/mocks/configtx"
    33  	mockpolicies "github.com/hyperledger/fabric/common/mocks/policies"
    34  	"github.com/hyperledger/fabric/common/policies"
    35  	"github.com/hyperledger/fabric/core/comm"
    36  	"github.com/hyperledger/fabric/core/committer"
    37  	"github.com/hyperledger/fabric/core/committer/txvalidator"
    38  	"github.com/hyperledger/fabric/core/ledger"
    39  	"github.com/hyperledger/fabric/core/ledger/ledgermgmt"
    40  	"github.com/hyperledger/fabric/gossip/api"
    41  	"github.com/hyperledger/fabric/gossip/service"
    42  	"github.com/hyperledger/fabric/msp"
    43  	mspmgmt "github.com/hyperledger/fabric/msp/mgmt"
    44  	"github.com/hyperledger/fabric/protos/common"
    45  	mspprotos "github.com/hyperledger/fabric/protos/msp"
    46  	pb "github.com/hyperledger/fabric/protos/peer"
    47  	"github.com/hyperledger/fabric/protos/utils"
    48  	"github.com/spf13/viper"
    49  	"google.golang.org/grpc"
    50  )
    51  
    52  var peerLogger = flogging.MustGetLogger("peer")
    53  
    54  var peerServer comm.GRPCServer
    55  
    56  // singleton instance to manage CAs for the peer across channel config changes
    57  var rootCASupport = comm.GetCASupport()
    58  
    59  type chainSupport struct {
    60  	configtxapi.Manager
    61  	config.Application
    62  	ledger ledger.PeerLedger
    63  }
    64  
    65  func (cs *chainSupport) Ledger() ledger.PeerLedger {
    66  	return cs.ledger
    67  }
    68  
    69  func (cs *chainSupport) GetMSPIDs(cid string) []string {
    70  	return GetMSPIDs(cid)
    71  }
    72  
    73  // chain is a local struct to manage objects in a chain
    74  type chain struct {
    75  	cs        *chainSupport
    76  	cb        *common.Block
    77  	committer committer.Committer
    78  }
    79  
    80  // chains is a local map of chainID->chainObject
    81  var chains = struct {
    82  	sync.RWMutex
    83  	list map[string]*chain
    84  }{list: make(map[string]*chain)}
    85  
    86  //MockInitialize resets chains for test env
    87  func MockInitialize() {
    88  	ledgermgmt.InitializeTestEnv()
    89  	chains.list = nil
    90  	chains.list = make(map[string]*chain)
    91  	chainInitializer = func(string) { return }
    92  }
    93  
    94  var chainInitializer func(string)
    95  
    96  // Initialize sets up any chains that the peer has from the persistence. This
    97  // function should be called at the start up when the ledger and gossip
    98  // ready
    99  func Initialize(init func(string)) {
   100  	chainInitializer = init
   101  
   102  	var cb *common.Block
   103  	var ledger ledger.PeerLedger
   104  	ledgermgmt.Initialize()
   105  	ledgerIds, err := ledgermgmt.GetLedgerIDs()
   106  	if err != nil {
   107  		panic(fmt.Errorf("Error in initializing ledgermgmt: %s", err))
   108  	}
   109  	for _, cid := range ledgerIds {
   110  		peerLogger.Infof("Loading chain %s", cid)
   111  		if ledger, err = ledgermgmt.OpenLedger(cid); err != nil {
   112  			peerLogger.Warningf("Failed to load ledger %s(%s)", cid, err)
   113  			peerLogger.Debugf("Error while loading ledger %s with message %s. We continue to the next ledger rather than abort.", cid, err)
   114  			continue
   115  		}
   116  		if cb, err = getCurrConfigBlockFromLedger(ledger); err != nil {
   117  			peerLogger.Warningf("Failed to find config block on ledger %s(%s)", cid, err)
   118  			peerLogger.Debugf("Error while looking for config block on ledger %s with message %s. We continue to the next ledger rather than abort.", cid, err)
   119  			continue
   120  		}
   121  		// Create a chain if we get a valid ledger with config block
   122  		if err = createChain(cid, ledger, cb); err != nil {
   123  			peerLogger.Warningf("Failed to load chain %s(%s)", cid, err)
   124  			peerLogger.Debugf("Error reloading chain %s with message %s. We continue to the next chain rather than abort.", cid, err)
   125  			continue
   126  		}
   127  
   128  		InitChain(cid)
   129  	}
   130  }
   131  
   132  // Take care to initialize chain after peer joined, for example deploys system CCs
   133  func InitChain(cid string) {
   134  	if chainInitializer != nil {
   135  		// Initialize chaincode, namely deploy system CC
   136  		peerLogger.Debugf("Init chain %s", cid)
   137  		chainInitializer(cid)
   138  	}
   139  }
   140  
   141  func getCurrConfigBlockFromLedger(ledger ledger.PeerLedger) (*common.Block, error) {
   142  	// Config blocks contain only 1 transaction, so we look for 1-tx
   143  	// blocks and check the transaction type
   144  	var envelope *common.Envelope
   145  	var tx *common.Payload
   146  	var block *common.Block
   147  	var err error
   148  	var currBlockNumber uint64 = math.MaxUint64
   149  	for currBlockNumber >= 0 {
   150  		if block, err = ledger.GetBlockByNumber(currBlockNumber); err != nil {
   151  			return nil, err
   152  		}
   153  		if block.Data != nil && len(block.Data.Data) == 1 {
   154  			if envelope, err = utils.ExtractEnvelope(block, 0); err != nil {
   155  				peerLogger.Warning("Failed to get Envelope from Block %d.", block.Header.Number)
   156  				currBlockNumber = block.Header.Number - 1
   157  				continue
   158  			}
   159  			if tx, err = utils.ExtractPayload(envelope); err != nil {
   160  				peerLogger.Warning("Failed to get Payload from Block %d.", block.Header.Number)
   161  				currBlockNumber = block.Header.Number - 1
   162  				continue
   163  			}
   164  			chdr, err := utils.UnmarshalChannelHeader(tx.Header.ChannelHeader)
   165  			if err != nil {
   166  				peerLogger.Warning("Failed to get ChannelHeader from Block %d, error %s.", block.Header.Number, err)
   167  				currBlockNumber = block.Header.Number - 1
   168  				continue
   169  			}
   170  			if chdr.Type == int32(common.HeaderType_CONFIG) {
   171  				return block, nil
   172  			}
   173  		}
   174  		currBlockNumber = block.Header.Number - 1
   175  	}
   176  	return nil, fmt.Errorf("Failed to find config block.")
   177  }
   178  
   179  // createChain creates a new chain object and insert it into the chains
   180  func createChain(cid string, ledger ledger.PeerLedger, cb *common.Block) error {
   181  
   182  	envelopeConfig, err := utils.ExtractEnvelope(cb, 0)
   183  	if err != nil {
   184  		return err
   185  	}
   186  
   187  	configtxInitializer := configtx.NewInitializer()
   188  
   189  	gossipEventer := service.GetGossipService().NewConfigEventer()
   190  
   191  	gossipCallbackWrapper := func(cm configtxapi.Manager) {
   192  		gossipEventer.ProcessConfigUpdate(&chainSupport{
   193  			Manager:     cm,
   194  			Application: configtxInitializer.ApplicationConfig(),
   195  		})
   196  		service.GetGossipService().SuspectPeers(func(identity api.PeerIdentityType) bool {
   197  			// TODO: this is a place-holder that would somehow make the MSP layer suspect
   198  			// that a given certificate is revoked, or its intermediate CA is revoked.
   199  			// In the meantime, before we have such an ability, we return true in order
   200  			// to suspect ALL identities in order to validate all of them.
   201  			return true
   202  		})
   203  	}
   204  
   205  	trustedRootsCallbackWrapper := func(cm configtxapi.Manager) {
   206  		updateTrustedRoots(cm)
   207  	}
   208  
   209  	configtxManager, err := configtx.NewManagerImpl(
   210  		envelopeConfig,
   211  		configtxInitializer,
   212  		[]func(cm configtxapi.Manager){gossipCallbackWrapper, trustedRootsCallbackWrapper},
   213  	)
   214  	if err != nil {
   215  		return err
   216  	}
   217  
   218  	// TODO remove once all references to mspmgmt are gone from peer code
   219  	mspmgmt.XXXSetMSPManager(cid, configtxManager.MSPManager())
   220  
   221  	cs := &chainSupport{
   222  		Manager:     configtxManager,
   223  		Application: configtxManager.ApplicationConfig(), // TODO, refactor as this is accessible through Manager
   224  		ledger:      ledger,
   225  	}
   226  
   227  	c := committer.NewLedgerCommitter(ledger, txvalidator.NewTxValidator(cs))
   228  	ordererAddresses := configtxManager.ChannelConfig().OrdererAddresses()
   229  	if len(ordererAddresses) == 0 {
   230  		return errors.New("No orderering service endpoint provided in configuration block")
   231  	}
   232  	service.GetGossipService().InitializeChannel(cs.ChainID(), c, ordererAddresses)
   233  
   234  	chains.Lock()
   235  	defer chains.Unlock()
   236  	chains.list[cid] = &chain{
   237  		cs:        cs,
   238  		cb:        cb,
   239  		committer: c,
   240  	}
   241  	return nil
   242  }
   243  
   244  // CreateChainFromBlock creates a new chain from config block
   245  func CreateChainFromBlock(cb *common.Block) error {
   246  	cid, err := utils.GetChainIDFromBlock(cb)
   247  	if err != nil {
   248  		return err
   249  	}
   250  
   251  	var l ledger.PeerLedger
   252  	if l, err = ledgermgmt.CreateLedger(cb); err != nil {
   253  		return fmt.Errorf("Cannot create ledger from genesis block, due to %s", err)
   254  	}
   255  
   256  	return createChain(cid, l, cb)
   257  }
   258  
   259  // MockCreateChain used for creating a ledger for a chain for tests
   260  // without havin to join
   261  func MockCreateChain(cid string) error {
   262  	var ledger ledger.PeerLedger
   263  	var err error
   264  	if ledger, err = createLedger(cid); err != nil {
   265  		return err
   266  	}
   267  
   268  	// Here we need to mock also the policy manager
   269  	// in order for the ACL to be checked
   270  	initializer := mockconfigtx.Initializer{
   271  		Resources: mockconfigtx.Resources{
   272  			PolicyManagerVal: &mockpolicies.Manager{
   273  				Policy: &mockpolicies.Policy{},
   274  			},
   275  		},
   276  		PolicyProposerVal: &mockconfigtx.PolicyProposer{
   277  			Transactional: mockconfigtx.Transactional{},
   278  		},
   279  		ValueProposerVal: &mockconfigtx.ValueProposer{
   280  			Transactional: mockconfigtx.Transactional{},
   281  		},
   282  	}
   283  	manager := &mockconfigtx.Manager{
   284  		Initializer: initializer,
   285  	}
   286  
   287  	chains.Lock()
   288  	defer chains.Unlock()
   289  
   290  	chains.list[cid] = &chain{
   291  		cs: &chainSupport{
   292  			Manager: manager,
   293  			ledger:  ledger},
   294  	}
   295  
   296  	return nil
   297  }
   298  
   299  // GetLedger returns the ledger of the chain with chain ID. Note that this
   300  // call returns nil if chain cid has not been created.
   301  func GetLedger(cid string) ledger.PeerLedger {
   302  	chains.RLock()
   303  	defer chains.RUnlock()
   304  	if c, ok := chains.list[cid]; ok {
   305  		return c.cs.ledger
   306  	}
   307  	return nil
   308  }
   309  
   310  // GetPolicyManager returns the policy manager of the chain with chain ID. Note that this
   311  // call returns nil if chain cid has not been created.
   312  func GetPolicyManager(cid string) policies.Manager {
   313  	chains.RLock()
   314  	defer chains.RUnlock()
   315  	if c, ok := chains.list[cid]; ok {
   316  		return c.cs.PolicyManager()
   317  	}
   318  	return nil
   319  }
   320  
   321  // GetCurrConfigBlock returns the cached config block of the specified chain.
   322  // Note that this call returns nil if chain cid has not been created.
   323  func GetCurrConfigBlock(cid string) *common.Block {
   324  	chains.RLock()
   325  	defer chains.RUnlock()
   326  	if c, ok := chains.list[cid]; ok {
   327  		return c.cb
   328  	}
   329  	return nil
   330  }
   331  
   332  // updates the trusted roots for the peer based on updates to channels
   333  func updateTrustedRoots(cm configtxapi.Manager) {
   334  	// this is triggered on per channel basis so first update the roots for the channel
   335  	peerLogger.Debugf("Updating trusted root authorities for channel %s", cm.ChainID())
   336  	var secureConfig comm.SecureServerConfig
   337  	var err error
   338  	// only run is TLS is enabled
   339  	secureConfig, err = GetSecureConfig()
   340  	if err == nil && secureConfig.UseTLS {
   341  		buildTrustedRootsForChain(cm)
   342  
   343  		// now iterate over all roots for all app and orderer chains
   344  		trustedRoots := [][]byte{}
   345  		rootCASupport.RLock()
   346  		defer rootCASupport.RUnlock()
   347  		for _, roots := range rootCASupport.AppRootCAsByChain {
   348  			trustedRoots = append(trustedRoots, roots...)
   349  		}
   350  		// also need to append statically configured root certs
   351  		if len(secureConfig.ClientRootCAs) > 0 {
   352  			trustedRoots = append(trustedRoots, secureConfig.ClientRootCAs...)
   353  		}
   354  		if len(secureConfig.ServerRootCAs) > 0 {
   355  			trustedRoots = append(trustedRoots, secureConfig.ServerRootCAs...)
   356  		}
   357  
   358  		server := GetPeerServer()
   359  		// now update the client roots for the peerServer
   360  		if server != nil {
   361  			err := server.SetClientRootCAs(trustedRoots)
   362  			if err != nil {
   363  				msg := "Failed to update trusted roots for peer from latest config " +
   364  					"block.  This peer may not be able to communicate " +
   365  					"with members of channel %s (%s)"
   366  				peerLogger.Warningf(msg, cm.ChainID(), err)
   367  			}
   368  		}
   369  	}
   370  }
   371  
   372  // populates the appRootCAs and orderRootCAs maps by getting the
   373  // root and intermediate certs for all msps assocaited with the MSPManager
   374  func buildTrustedRootsForChain(cm configtxapi.Manager) {
   375  	rootCASupport.Lock()
   376  	defer rootCASupport.Unlock()
   377  
   378  	appRootCAs := [][]byte{}
   379  	ordererRootCAs := [][]byte{}
   380  	cid := cm.ChainID()
   381  	msps, err := cm.MSPManager().GetMSPs()
   382  	if err != nil {
   383  		peerLogger.Errorf("Error getting getting root CA for channel %s (%s)", cid, err)
   384  	}
   385  	if err == nil {
   386  		for _, v := range msps {
   387  			// check to see if this is a FABRIC MSP
   388  			if v.GetType() == msp.FABRIC {
   389  				for _, root := range v.GetRootCerts() {
   390  					sid, err := root.Serialize()
   391  					if err == nil {
   392  						id := &mspprotos.SerializedIdentity{}
   393  						err = proto.Unmarshal(sid, id)
   394  						if err == nil {
   395  							appRootCAs = append(appRootCAs, id.IdBytes)
   396  						}
   397  					}
   398  				}
   399  				for _, intermediate := range v.GetIntermediateCerts() {
   400  					sid, err := intermediate.Serialize()
   401  					if err == nil {
   402  						id := &mspprotos.SerializedIdentity{}
   403  						err = proto.Unmarshal(sid, id)
   404  						if err == nil {
   405  							appRootCAs = append(appRootCAs, id.IdBytes)
   406  						}
   407  					}
   408  				}
   409  			}
   410  		}
   411  		// TODO: separate app and orderer CAs
   412  		ordererRootCAs = appRootCAs
   413  		rootCASupport.AppRootCAsByChain[cid] = appRootCAs
   414  		rootCASupport.OrdererRootCAsByChain[cid] = ordererRootCAs
   415  	}
   416  }
   417  
   418  // GetMSPIDs returns the ID of each application MSP defined on this chain
   419  func GetMSPIDs(cid string) []string {
   420  	chains.RLock()
   421  	defer chains.RUnlock()
   422  	if c, ok := chains.list[cid]; ok {
   423  		if c == nil || c.cs == nil ||
   424  			c.cs.ApplicationConfig() == nil ||
   425  			c.cs.ApplicationConfig().Organizations() == nil {
   426  			return nil
   427  		}
   428  
   429  		orgs := c.cs.ApplicationConfig().Organizations()
   430  		toret := make([]string, len(orgs))
   431  		i := 0
   432  		for _, org := range orgs {
   433  			toret[i] = org.MSPID()
   434  			i++
   435  		}
   436  
   437  		return toret
   438  	}
   439  	return nil
   440  }
   441  
   442  // SetCurrConfigBlock sets the current config block of the specified chain
   443  func SetCurrConfigBlock(block *common.Block, cid string) error {
   444  	chains.Lock()
   445  	defer chains.Unlock()
   446  	if c, ok := chains.list[cid]; ok {
   447  		c.cb = block
   448  		// TODO: Change MSP config
   449  		// c.mspmgr.Reconfig(block)
   450  
   451  		// TODO: Change gossip configs
   452  		return nil
   453  	}
   454  	return fmt.Errorf("Chain %s doesn't exist on the peer", cid)
   455  }
   456  
   457  // createLedger function is used only for the testing (see function 'MockCreateChain').
   458  // TODO - this function should not be in this file which contains production code
   459  func createLedger(cid string) (ledger.PeerLedger, error) {
   460  	var ledger ledger.PeerLedger
   461  	if ledger = GetLedger(cid); ledger != nil {
   462  		return ledger, nil
   463  	}
   464  	gb, _ := configtxtest.MakeGenesisBlock(cid)
   465  	return ledgermgmt.CreateLedger(gb)
   466  }
   467  
   468  // NewPeerClientConnection Returns a new grpc.ClientConn to the configured local PEER.
   469  func NewPeerClientConnection() (*grpc.ClientConn, error) {
   470  	return NewPeerClientConnectionWithAddress(viper.GetString("peer.address"))
   471  }
   472  
   473  // GetLocalIP returns the non loopback local IP of the host
   474  func GetLocalIP() string {
   475  	addrs, err := net.InterfaceAddrs()
   476  	if err != nil {
   477  		return ""
   478  	}
   479  	for _, address := range addrs {
   480  		// check the address type and if it is not a loopback then display it
   481  		if ipnet, ok := address.(*net.IPNet); ok && !ipnet.IP.IsLoopback() {
   482  			if ipnet.IP.To4() != nil {
   483  				return ipnet.IP.String()
   484  			}
   485  		}
   486  	}
   487  	return ""
   488  }
   489  
   490  // NewPeerClientConnectionWithAddress Returns a new grpc.ClientConn to the configured local PEER.
   491  func NewPeerClientConnectionWithAddress(peerAddress string) (*grpc.ClientConn, error) {
   492  	if comm.TLSEnabled() {
   493  		return comm.NewClientConnectionWithAddress(peerAddress, true, true, comm.InitTLSForPeer())
   494  	}
   495  	return comm.NewClientConnectionWithAddress(peerAddress, true, false, nil)
   496  }
   497  
   498  // GetChannelsInfo returns an array with information about all channels for
   499  // this peer
   500  func GetChannelsInfo() []*pb.ChannelInfo {
   501  	// array to store metadata for all channels
   502  	var channelInfoArray []*pb.ChannelInfo
   503  
   504  	chains.RLock()
   505  	defer chains.RUnlock()
   506  	for key := range chains.list {
   507  		channelInfo := &pb.ChannelInfo{ChannelId: key}
   508  
   509  		// add this specific chaincode's metadata to the array of all chaincodes
   510  		channelInfoArray = append(channelInfoArray, channelInfo)
   511  	}
   512  
   513  	return channelInfoArray
   514  }
   515  
   516  // NewChannelPolicyManagerGetter returns a new instance of ChannelPolicyManagerGetter
   517  func NewChannelPolicyManagerGetter() policies.ChannelPolicyManagerGetter {
   518  	return &channelPolicyManagerGetter{}
   519  }
   520  
   521  type channelPolicyManagerGetter struct{}
   522  
   523  func (c *channelPolicyManagerGetter) Manager(channelID string) (policies.Manager, bool) {
   524  	policyManager := GetPolicyManager(channelID)
   525  	return policyManager, policyManager != nil
   526  }
   527  
   528  // CreatePeerServer creates an instance of comm.GRPCServer
   529  // This server is used for peer communications
   530  func CreatePeerServer(listenAddress string,
   531  	secureConfig comm.SecureServerConfig) (comm.GRPCServer, error) {
   532  
   533  	var err error
   534  	peerServer, err = comm.NewGRPCServer(listenAddress, secureConfig)
   535  	if err != nil {
   536  		peerLogger.Errorf("Failed to create peer server (%s)", err)
   537  		return nil, err
   538  	}
   539  	return peerServer, nil
   540  }
   541  
   542  // GetPeerServer returns the peer server instance
   543  func GetPeerServer() comm.GRPCServer {
   544  	return peerServer
   545  }