github.com/adnan-c/fabric_e2e_couchdb@v0.6.1-preview.0.20170228180935-21ce6b23cf91/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  	"fmt"
    21  	"math"
    22  	"net"
    23  	"sync"
    24  
    25  	"github.com/hyperledger/fabric/common/configtx"
    26  	configtxapi "github.com/hyperledger/fabric/common/configtx/api"
    27  	configvaluesapi "github.com/hyperledger/fabric/common/configvalues"
    28  	mockconfigtx "github.com/hyperledger/fabric/common/mocks/configtx"
    29  	mockpolicies "github.com/hyperledger/fabric/common/mocks/policies"
    30  	"github.com/hyperledger/fabric/common/policies"
    31  	"github.com/hyperledger/fabric/core/comm"
    32  	"github.com/hyperledger/fabric/core/committer"
    33  	"github.com/hyperledger/fabric/core/committer/txvalidator"
    34  	"github.com/hyperledger/fabric/core/ledger"
    35  	"github.com/hyperledger/fabric/core/ledger/ledgermgmt"
    36  	"github.com/hyperledger/fabric/gossip/service"
    37  	mspmgmt "github.com/hyperledger/fabric/msp/mgmt"
    38  	"github.com/hyperledger/fabric/protos/common"
    39  	pb "github.com/hyperledger/fabric/protos/peer"
    40  	"github.com/hyperledger/fabric/protos/utils"
    41  	"github.com/op/go-logging"
    42  	"github.com/spf13/viper"
    43  	"google.golang.org/grpc"
    44  )
    45  
    46  var peerLogger = logging.MustGetLogger("peer")
    47  
    48  type chainSupport struct {
    49  	configtxapi.Manager
    50  	configvaluesapi.Application
    51  	ledger ledger.PeerLedger
    52  }
    53  
    54  func (cs *chainSupport) Ledger() ledger.PeerLedger {
    55  	return cs.ledger
    56  }
    57  
    58  // chain is a local struct to manage objects in a chain
    59  type chain struct {
    60  	cs        *chainSupport
    61  	cb        *common.Block
    62  	committer committer.Committer
    63  }
    64  
    65  // chains is a local map of chainID->chainObject
    66  var chains = struct {
    67  	sync.RWMutex
    68  	list map[string]*chain
    69  }{list: make(map[string]*chain)}
    70  
    71  //MockInitialize resets chains for test env
    72  func MockInitialize() {
    73  	ledgermgmt.InitializeTestEnv()
    74  	chains.list = nil
    75  	chains.list = make(map[string]*chain)
    76  	chainInitializer = func(string) { return }
    77  }
    78  
    79  var chainInitializer func(string)
    80  
    81  // Initialize sets up any chains that the peer has from the persistence. This
    82  // function should be called at the start up when the ledger and gossip
    83  // ready
    84  func Initialize(init func(string)) {
    85  	chainInitializer = init
    86  
    87  	var cb *common.Block
    88  	var ledger ledger.PeerLedger
    89  	ledgermgmt.Initialize()
    90  	ledgerIds, err := ledgermgmt.GetLedgerIDs()
    91  	if err != nil {
    92  		panic(fmt.Errorf("Error in initializing ledgermgmt: %s", err))
    93  	}
    94  	for _, cid := range ledgerIds {
    95  		peerLogger.Infof("Loading chain %s", cid)
    96  		if ledger, err = ledgermgmt.OpenLedger(cid); err != nil {
    97  			peerLogger.Warningf("Failed to load ledger %s(%s)", cid, err)
    98  			peerLogger.Debugf("Error while loading ledger %s with message %s. We continue to the next ledger rather than abort.", cid, err)
    99  			continue
   100  		}
   101  		if cb, err = getCurrConfigBlockFromLedger(ledger); err != nil {
   102  			peerLogger.Warningf("Failed to find config block on ledger %s(%s)", cid, err)
   103  			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)
   104  			continue
   105  		}
   106  		// Create a chain if we get a valid ledger with config block
   107  		if err = createChain(cid, ledger, cb); err != nil {
   108  			peerLogger.Warningf("Failed to load chain %s(%s)", cid, err)
   109  			peerLogger.Debugf("Error reloading chain %s with message %s. We continue to the next chain rather than abort.", cid, err)
   110  			continue
   111  		}
   112  
   113  		InitChain(cid)
   114  	}
   115  }
   116  
   117  // Take care to initialize chain after peer joined, for example deploys system CCs
   118  func InitChain(cid string) {
   119  	if chainInitializer != nil {
   120  		// Initialize chaincode, namely deploy system CC
   121  		peerLogger.Debugf("Init chain %s", cid)
   122  		chainInitializer(cid)
   123  	}
   124  }
   125  
   126  func getCurrConfigBlockFromLedger(ledger ledger.PeerLedger) (*common.Block, error) {
   127  	// Config blocks contain only 1 transaction, so we look for 1-tx
   128  	// blocks and check the transaction type
   129  	var envelope *common.Envelope
   130  	var tx *common.Payload
   131  	var block *common.Block
   132  	var err error
   133  	var currBlockNumber uint64 = math.MaxUint64
   134  	for currBlockNumber >= 0 {
   135  		if block, err = ledger.GetBlockByNumber(currBlockNumber); err != nil {
   136  			return nil, err
   137  		}
   138  		if block.Data != nil && len(block.Data.Data) == 1 {
   139  			if envelope, err = utils.ExtractEnvelope(block, 0); err != nil {
   140  				peerLogger.Warning("Failed to get Envelope from Block %d.", block.Header.Number)
   141  				currBlockNumber = block.Header.Number - 1
   142  				continue
   143  			}
   144  			if tx, err = utils.ExtractPayload(envelope); err != nil {
   145  				peerLogger.Warning("Failed to get Payload from Block %d.", block.Header.Number)
   146  				currBlockNumber = block.Header.Number - 1
   147  				continue
   148  			}
   149  			chdr, err := utils.UnmarshalChannelHeader(tx.Header.ChannelHeader)
   150  			if err != nil {
   151  				peerLogger.Warning("Failed to get ChannelHeader from Block %d, error %s.", block.Header.Number, err)
   152  				currBlockNumber = block.Header.Number - 1
   153  				continue
   154  			}
   155  			if chdr.Type == int32(common.HeaderType_CONFIG) {
   156  				return block, nil
   157  			}
   158  		}
   159  		currBlockNumber = block.Header.Number - 1
   160  	}
   161  	return nil, fmt.Errorf("Failed to find config block.")
   162  }
   163  
   164  // createChain creates a new chain object and insert it into the chains
   165  func createChain(cid string, ledger ledger.PeerLedger, cb *common.Block) error {
   166  
   167  	configEnvelope, err := configtx.ConfigEnvelopeFromBlock(cb)
   168  	if err != nil {
   169  		return err
   170  	}
   171  
   172  	configtxInitializer := configtx.NewInitializer()
   173  
   174  	gossipEventer := service.GetGossipService().NewConfigEventer()
   175  
   176  	gossipCallbackWrapper := func(cm configtxapi.Manager) {
   177  		gossipEventer.ProcessConfigUpdate(&chainSupport{
   178  			Manager:     cm,
   179  			Application: configtxInitializer.ApplicationConfig(),
   180  		})
   181  	}
   182  
   183  	configtxManager, err := configtx.NewManagerImpl(
   184  		configEnvelope,
   185  		configtxInitializer,
   186  		[]func(cm configtxapi.Manager){gossipCallbackWrapper},
   187  	)
   188  	if err != nil {
   189  		return err
   190  	}
   191  
   192  	// TODO remove once all references to mspmgmt are gone from peer code
   193  	mspmgmt.XXXSetMSPManager(cid, configtxManager.MSPManager())
   194  
   195  	cs := &chainSupport{
   196  		Manager:     configtxManager,
   197  		Application: configtxManager.ApplicationConfig(), // TODO, refactor as this is accessible through Manager
   198  		ledger:      ledger,
   199  	}
   200  
   201  	c := committer.NewLedgerCommitter(ledger, txvalidator.NewTxValidator(cs))
   202  	service.GetGossipService().InitializeChannel(cs.ChainID(), c)
   203  
   204  	chains.Lock()
   205  	defer chains.Unlock()
   206  	chains.list[cid] = &chain{
   207  		cs:        cs,
   208  		cb:        cb,
   209  		committer: c,
   210  	}
   211  	return nil
   212  }
   213  
   214  // CreateChainFromBlock creates a new chain from config block
   215  func CreateChainFromBlock(cb *common.Block) error {
   216  	cid, err := utils.GetChainIDFromBlock(cb)
   217  	if err != nil {
   218  		return err
   219  	}
   220  	var ledger ledger.PeerLedger
   221  	if ledger, err = createLedger(cid); err != nil {
   222  		return err
   223  	}
   224  
   225  	if err := ledger.Commit(cb); err != nil {
   226  		peerLogger.Errorf("Unable to get genesis block committed into the ledger, chainID %v", cid)
   227  		return err
   228  	}
   229  	return createChain(cid, ledger, cb)
   230  }
   231  
   232  // MockCreateChain used for creating a ledger for a chain for tests
   233  // without havin to join
   234  func MockCreateChain(cid string) error {
   235  	var ledger ledger.PeerLedger
   236  	var err error
   237  	if ledger, err = createLedger(cid); err != nil {
   238  		return err
   239  	}
   240  
   241  	i := mockconfigtx.Initializer{
   242  		Resources: mockconfigtx.Resources{
   243  			PolicyManagerVal: &mockpolicies.Manager{
   244  				Policy: &mockpolicies.Policy{},
   245  			},
   246  		},
   247  	}
   248  
   249  	chains.Lock()
   250  	defer chains.Unlock()
   251  	chains.list[cid] = &chain{
   252  		cs: &chainSupport{
   253  			ledger:  ledger,
   254  			Manager: &mockconfigtx.Manager{Initializer: i},
   255  		},
   256  	}
   257  
   258  	return nil
   259  }
   260  
   261  // GetLedger returns the ledger of the chain with chain ID. Note that this
   262  // call returns nil if chain cid has not been created.
   263  func GetLedger(cid string) ledger.PeerLedger {
   264  	chains.RLock()
   265  	defer chains.RUnlock()
   266  	if c, ok := chains.list[cid]; ok {
   267  		return c.cs.ledger
   268  	}
   269  	return nil
   270  }
   271  
   272  // GetPolicyManager returns the policy manager of the chain with chain ID. Note that this
   273  // call returns nil if chain cid has not been created.
   274  func GetPolicyManager(cid string) policies.Manager {
   275  	chains.RLock()
   276  	defer chains.RUnlock()
   277  	if c, ok := chains.list[cid]; ok {
   278  		return c.cs.PolicyManager()
   279  	}
   280  	return nil
   281  }
   282  
   283  // GetCurrConfigBlock returns the cached config block of the specified chain.
   284  // Note that this call returns nil if chain cid has not been created.
   285  func GetCurrConfigBlock(cid string) *common.Block {
   286  	chains.RLock()
   287  	defer chains.RUnlock()
   288  	if c, ok := chains.list[cid]; ok {
   289  		return c.cb
   290  	}
   291  	return nil
   292  }
   293  
   294  // SetCurrConfigBlock sets the current config block of the specified chain
   295  func SetCurrConfigBlock(block *common.Block, cid string) error {
   296  	chains.Lock()
   297  	defer chains.Unlock()
   298  	if c, ok := chains.list[cid]; ok {
   299  		c.cb = block
   300  		// TODO: Change MSP config
   301  		// c.mspmgr.Reconfig(block)
   302  
   303  		// TODO: Change gossip configs
   304  		return nil
   305  	}
   306  	return fmt.Errorf("Chain %s doesn't exist on the peer", cid)
   307  }
   308  
   309  // All ledgers are located under `peer.fileSystemPath`
   310  func createLedger(cid string) (ledger.PeerLedger, error) {
   311  	var ledger ledger.PeerLedger
   312  	if ledger = GetLedger(cid); ledger != nil {
   313  		return ledger, nil
   314  	}
   315  	return ledgermgmt.CreateLedger(cid)
   316  }
   317  
   318  // NewPeerClientConnection Returns a new grpc.ClientConn to the configured local PEER.
   319  func NewPeerClientConnection() (*grpc.ClientConn, error) {
   320  	return NewPeerClientConnectionWithAddress(viper.GetString("peer.address"))
   321  }
   322  
   323  // GetLocalIP returns the non loopback local IP of the host
   324  func GetLocalIP() string {
   325  	addrs, err := net.InterfaceAddrs()
   326  	if err != nil {
   327  		return ""
   328  	}
   329  	for _, address := range addrs {
   330  		// check the address type and if it is not a loopback then display it
   331  		if ipnet, ok := address.(*net.IPNet); ok && !ipnet.IP.IsLoopback() {
   332  			if ipnet.IP.To4() != nil {
   333  				return ipnet.IP.String()
   334  			}
   335  		}
   336  	}
   337  	return ""
   338  }
   339  
   340  // NewPeerClientConnectionWithAddress Returns a new grpc.ClientConn to the configured local PEER.
   341  func NewPeerClientConnectionWithAddress(peerAddress string) (*grpc.ClientConn, error) {
   342  	if comm.TLSEnabled() {
   343  		return comm.NewClientConnectionWithAddress(peerAddress, true, true, comm.InitTLSForPeer())
   344  	}
   345  	return comm.NewClientConnectionWithAddress(peerAddress, true, false, nil)
   346  }
   347  
   348  // GetChannelsInfo returns an array with information about all channels for
   349  // this peer
   350  func GetChannelsInfo() []*pb.ChannelInfo {
   351  	// array to store metadata for all channels
   352  	var channelInfoArray []*pb.ChannelInfo
   353  
   354  	chains.RLock()
   355  	defer chains.RUnlock()
   356  	for key := range chains.list {
   357  		channelInfo := &pb.ChannelInfo{ChannelId: key}
   358  
   359  		// add this specific chaincode's metadata to the array of all chaincodes
   360  		channelInfoArray = append(channelInfoArray, channelInfo)
   361  	}
   362  
   363  	return channelInfoArray
   364  }
   365  
   366  // GetPolicyManagerMgmt returns a special PolicyManager whose
   367  // only function is to give access to the policy manager of
   368  // a given channel. If the channel does not exists then,
   369  // it returns nil.
   370  // The only method implemented is therefore 'Manager'.
   371  func GetPolicyManagerMgmt() policies.Manager {
   372  	return &policyManagerMgmt{}
   373  }
   374  
   375  type policyManagerMgmt struct{}
   376  
   377  func (c *policyManagerMgmt) GetPolicy(id string) (policies.Policy, bool) {
   378  	panic("implement me")
   379  }
   380  
   381  // Manager returns the policy manager associated to a channel
   382  // specified by a path of length 1 that has the name of the channel as the only
   383  // coordinate available.
   384  // If the path has length different from 1, then the method returns (nil, false).
   385  // If the channel does not exists, then the method returns (nil, false)
   386  // Nothing is created.
   387  func (c *policyManagerMgmt) Manager(path []string) (policies.Manager, bool) {
   388  	if len(path) != 1 {
   389  		return nil, false
   390  	}
   391  
   392  	policyManager := GetPolicyManager(path[0])
   393  	return policyManager, policyManager != nil
   394  }
   395  
   396  func (c *policyManagerMgmt) BasePath() string {
   397  	panic("implement me")
   398  }
   399  
   400  func (c *policyManagerMgmt) PolicyNames() []string {
   401  	panic("implement me")
   402  }