github.com/leonlxy/hyperledger@v1.0.0-alpha.0.20170427033203-34922035d248/core/scc/cscc/configure.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 cscc chaincode configer provides functions to manage
    18  // configuration transactions as the network is being reconfigured. The
    19  // configuration transactions arrive from the ordering service to the committer
    20  // who calls this chaincode. The chaincode also provides peer configuration
    21  // services such as joining a chain or getting configuration data.
    22  package cscc
    23  
    24  import (
    25  	"fmt"
    26  
    27  	"errors"
    28  
    29  	"github.com/golang/protobuf/proto"
    30  	"github.com/hyperledger/fabric/common/flogging"
    31  	"github.com/hyperledger/fabric/common/policies"
    32  	"github.com/hyperledger/fabric/core/chaincode/shim"
    33  	"github.com/hyperledger/fabric/core/peer"
    34  	"github.com/hyperledger/fabric/core/policy"
    35  	"github.com/hyperledger/fabric/events/producer"
    36  	"github.com/hyperledger/fabric/msp/mgmt"
    37  	pb "github.com/hyperledger/fabric/protos/peer"
    38  	"github.com/hyperledger/fabric/protos/utils"
    39  )
    40  
    41  // PeerConfiger implements the configuration handler for the peer. For every
    42  // configuration transaction coming in from the ordering service, the
    43  // committer calls this system chaincode to process the transaction.
    44  type PeerConfiger struct {
    45  	policyChecker policy.PolicyChecker
    46  }
    47  
    48  var cnflogger = flogging.MustGetLogger("cscc")
    49  
    50  // These are function names from Invoke first parameter
    51  const (
    52  	JoinChain         string = "JoinChain"
    53  	UpdateConfigBlock string = "UpdateConfigBlock"
    54  	GetConfigBlock    string = "GetConfigBlock"
    55  	GetChannels       string = "GetChannels"
    56  )
    57  
    58  // Init is called once per chain when the chain is created.
    59  // This allows the chaincode to initialize any variables on the ledger prior
    60  // to any transaction execution on the chain.
    61  func (e *PeerConfiger) Init(stub shim.ChaincodeStubInterface) pb.Response {
    62  	cnflogger.Info("Init CSCC")
    63  
    64  	// Init policy checker for access control
    65  	e.policyChecker = policy.NewPolicyChecker(
    66  		peer.NewChannelPolicyManagerGetter(),
    67  		mgmt.GetLocalMSP(),
    68  		mgmt.NewLocalMSPPrincipalGetter(),
    69  	)
    70  
    71  	return shim.Success(nil)
    72  }
    73  
    74  // Invoke is called for the following:
    75  // # to process joining a chain (called by app as a transaction proposal)
    76  // # to get the current configuration block (called by app)
    77  // # to update the configuration block (called by commmitter)
    78  // Peer calls this function with 2 arguments:
    79  // # args[0] is the function name, which must be JoinChain, GetConfigBlock or
    80  // UpdateConfigBlock
    81  // # args[1] is a configuration Block if args[0] is JoinChain or
    82  // UpdateConfigBlock; otherwise it is the chain id
    83  // TODO: Improve the scc interface to avoid marshal/unmarshal args
    84  func (e *PeerConfiger) Invoke(stub shim.ChaincodeStubInterface) pb.Response {
    85  	args := stub.GetArgs()
    86  
    87  	if len(args) < 1 {
    88  		return shim.Error(fmt.Sprintf("Incorrect number of arguments, %d", len(args)))
    89  	}
    90  
    91  	fname := string(args[0])
    92  
    93  	if fname != GetChannels && len(args) < 2 {
    94  		return shim.Error(fmt.Sprintf("Incorrect number of arguments, %d", len(args)))
    95  	}
    96  
    97  	cnflogger.Debugf("Invoke function: %s", fname)
    98  
    99  	// Handle ACL:
   100  	// 1. get the signed proposal
   101  	sp, err := stub.GetSignedProposal()
   102  	if err != nil {
   103  		return shim.Error(fmt.Sprintf("Failed getting signed proposal from stub: [%s]", err))
   104  	}
   105  
   106  	switch fname {
   107  	case JoinChain:
   108  		// 2. check local MSP Admins policy
   109  		if err = e.policyChecker.CheckPolicyNoChannel(mgmt.Admins, sp); err != nil {
   110  			cid, e := utils.GetChainIDFromBlockBytes(args[1])
   111  			errorString := fmt.Sprintf("\"JoinChain\" request failed authorization check "+
   112  				"for channel [%s]: [%s]", cid, err)
   113  			if e != nil {
   114  				errorString = fmt.Sprintf("\"JoinChain\" request failed authorization [%s] and unable "+
   115  					"to extract channel id from the block due to [%s]", err, e)
   116  			}
   117  			return shim.Error(errorString)
   118  		}
   119  
   120  		return joinChain(args[1])
   121  	case GetConfigBlock:
   122  		// 2. check the channel reader policy
   123  		if err = e.policyChecker.CheckPolicy(string(args[1]), policies.ChannelApplicationReaders, sp); err != nil {
   124  			return shim.Error(fmt.Sprintf("\"GetConfigBlock\" request failed authorization check for channel [%s]: [%s]", args[1], err))
   125  		}
   126  		return getConfigBlock(args[1])
   127  	case UpdateConfigBlock:
   128  		// TODO: It needs to be clarified if this is a function invoked by a proposal or not.
   129  		// The issue is the following: ChannelApplicationAdmins might require multiple signatures
   130  		// but currently a proposal can be signed by a signle entity only. Therefore, the ChannelApplicationAdmins policy
   131  		// will be never satisfied.
   132  
   133  		return updateConfigBlock(args[1])
   134  	case GetChannels:
   135  		// 2. check local MSP Members policy
   136  		if err = e.policyChecker.CheckPolicyNoChannel(mgmt.Members, sp); err != nil {
   137  			return shim.Error(fmt.Sprintf("\"GetChannels\" request failed authorization check: [%s]", err))
   138  		}
   139  
   140  		return getChannels()
   141  
   142  	}
   143  	return shim.Error(fmt.Sprintf("Requested function %s not found.", fname))
   144  }
   145  
   146  // joinChain will join the specified chain in the configuration block.
   147  // Since it is the first block, it is the genesis block containing configuration
   148  // for this chain, so we want to update the Chain object with this info
   149  func joinChain(blockBytes []byte) pb.Response {
   150  	if blockBytes == nil {
   151  		return shim.Error("Genesis block must not be nil.")
   152  	}
   153  
   154  	block, err := utils.GetBlockFromBlockBytes(blockBytes)
   155  	if err != nil {
   156  		return shim.Error(fmt.Sprintf("Failed to reconstruct the genesis block, %s", err))
   157  	}
   158  
   159  	if err = peer.CreateChainFromBlock(block); err != nil {
   160  		return shim.Error(err.Error())
   161  	}
   162  
   163  	chainID, err := utils.GetChainIDFromBlock(block)
   164  	if err != nil {
   165  		return shim.Error(fmt.Sprintf("Failed to get the chain ID from the configuration block, %s", err))
   166  	}
   167  
   168  	peer.InitChain(chainID)
   169  
   170  	if err := producer.SendProducerBlockEvent(block); err != nil {
   171  		cnflogger.Errorf("Error sending block event %s", err)
   172  	}
   173  
   174  	return shim.Success(nil)
   175  }
   176  
   177  func getChannelFromConfigBlock(blockBytes []byte) (string, error) {
   178  	if blockBytes == nil {
   179  		return "", errors.New("Configuration block must not be nil.")
   180  	}
   181  	block, err := utils.GetBlockFromBlockBytes(blockBytes)
   182  	if err != nil {
   183  		return "", fmt.Errorf("Failed to reconstruct the configuration block, %s", err)
   184  	}
   185  	chainID, err := utils.GetChainIDFromBlock(block)
   186  	if err != nil {
   187  		return "", fmt.Errorf("Failed to get the chain ID from the configuration block, %s", err)
   188  	}
   189  	return chainID, nil
   190  }
   191  
   192  func updateConfigBlock(blockBytes []byte) pb.Response {
   193  	if blockBytes == nil {
   194  		return shim.Error("Configuration block must not be nil.")
   195  	}
   196  	block, err := utils.GetBlockFromBlockBytes(blockBytes)
   197  	if err != nil {
   198  		return shim.Error(fmt.Sprintf("Failed to reconstruct the configuration block, %s", err))
   199  	}
   200  	chainID, err := utils.GetChainIDFromBlock(block)
   201  	if err != nil {
   202  		return shim.Error(fmt.Sprintf("Failed to get the chain ID from the configuration block, %s", err))
   203  	}
   204  
   205  	if err := peer.SetCurrConfigBlock(block, chainID); err != nil {
   206  
   207  		return shim.Error(err.Error())
   208  	}
   209  
   210  	return shim.Success(nil)
   211  }
   212  
   213  // Return the current configuration block for the specified chainID. If the
   214  // peer doesn't belong to the chain, return error
   215  func getConfigBlock(chainID []byte) pb.Response {
   216  	if chainID == nil {
   217  		return shim.Error("ChainID must not be nil.")
   218  	}
   219  	block := peer.GetCurrConfigBlock(string(chainID))
   220  	if block == nil {
   221  		return shim.Error(fmt.Sprintf("Unknown chain ID, %s", string(chainID)))
   222  	}
   223  	blockBytes, err := utils.Marshal(block)
   224  	if err != nil {
   225  		return shim.Error(err.Error())
   226  	}
   227  
   228  	return shim.Success(blockBytes)
   229  }
   230  
   231  // getChannels returns information about all channels for this peer
   232  func getChannels() pb.Response {
   233  	channelInfoArray := peer.GetChannelsInfo()
   234  
   235  	// add array with info about all channels for this peer
   236  	cqr := &pb.ChannelQueryResponse{Channels: channelInfoArray}
   237  
   238  	cqrbytes, err := proto.Marshal(cqr)
   239  	if err != nil {
   240  		return shim.Error(err.Error())
   241  	}
   242  
   243  	return shim.Success(cqrbytes)
   244  }