github.com/adnan-c/fabric_e2e_couchdb@v0.6.1-preview.0.20170228180935-21ce6b23cf91/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  	"github.com/golang/protobuf/proto"
    28  	"github.com/hyperledger/fabric/core/chaincode/shim"
    29  	"github.com/hyperledger/fabric/core/peer"
    30  	pb "github.com/hyperledger/fabric/protos/peer"
    31  	"github.com/hyperledger/fabric/protos/utils"
    32  	"github.com/op/go-logging"
    33  )
    34  
    35  // PeerConfiger implements the configuration handler for the peer. For every
    36  // configuration transaction coming in from the ordering service, the
    37  // committer calls this system chaincode to process the transaction.
    38  type PeerConfiger struct {
    39  }
    40  
    41  var cnflogger = logging.MustGetLogger("chaincode")
    42  
    43  // These are function names from Invoke first parameter
    44  const (
    45  	JoinChain         string = "JoinChain"
    46  	UpdateConfigBlock string = "UpdateConfigBlock"
    47  	GetConfigBlock    string = "GetConfigBlock"
    48  	GetChannels       string = "GetChannels"
    49  )
    50  
    51  // Init is called once per chain when the chain is created.
    52  // This allows the chaincode to initialize any variables on the ledger prior
    53  // to any transaction execution on the chain.
    54  func (e *PeerConfiger) Init(stub shim.ChaincodeStubInterface) pb.Response {
    55  	cnflogger.Info("Init CSCC")
    56  	return shim.Success(nil)
    57  }
    58  
    59  // Invoke is called for the following:
    60  // # to process joining a chain (called by app as a transaction proposal)
    61  // # to get the current configuration block (called by app)
    62  // # to update the configuration block (called by commmitter)
    63  // Peer calls this function with 2 arguments:
    64  // # args[0] is the function name, which must be JoinChain, GetConfigBlock or
    65  // UpdateConfigBlock
    66  // # args[1] is a configuration Block if args[0] is JoinChain or
    67  // UpdateConfigBlock; otherwise it is the chain id
    68  // TODO: Improve the scc interface to avoid marshal/unmarshal args
    69  func (e *PeerConfiger) Invoke(stub shim.ChaincodeStubInterface) pb.Response {
    70  	args := stub.GetArgs()
    71  
    72  	if len(args) < 1 {
    73  		return shim.Error(fmt.Sprintf("Incorrect number of arguments, %d", len(args)))
    74  	}
    75  
    76  	fname := string(args[0])
    77  
    78  	if fname != GetChannels && len(args) < 2 {
    79  		return shim.Error(fmt.Sprintf("Incorrect number of arguments, %d", len(args)))
    80  	}
    81  
    82  	cnflogger.Debugf("Invoke function: %s", fname)
    83  
    84  	// TODO: Handle ACL
    85  
    86  	if fname == JoinChain {
    87  		return joinChain(args[1])
    88  	} else if fname == GetConfigBlock {
    89  		return getConfigBlock(args[1])
    90  	} else if fname == UpdateConfigBlock {
    91  		return updateConfigBlock(args[1])
    92  	} else if fname == GetChannels {
    93  		return getChannels()
    94  	}
    95  
    96  	return shim.Error(fmt.Sprintf("Requested function %s not found.", fname))
    97  }
    98  
    99  // joinChain will join the specified chain in the configuration block.
   100  // Since it is the first block, it is the genesis block containing configuration
   101  // for this chain, so we want to update the Chain object with this info
   102  func joinChain(blockBytes []byte) pb.Response {
   103  	if blockBytes == nil {
   104  		return shim.Error("Genesis block must not be nil.")
   105  	}
   106  
   107  	block, err := utils.GetBlockFromBlockBytes(blockBytes)
   108  	if err != nil {
   109  		return shim.Error(fmt.Sprintf("Failed to reconstruct the genesis block, %s", err))
   110  	}
   111  
   112  	if err = peer.CreateChainFromBlock(block); err != nil {
   113  		return shim.Error(err.Error())
   114  	}
   115  
   116  	chainID, err := utils.GetChainIDFromBlock(block)
   117  	if err != nil {
   118  		return shim.Error(fmt.Sprintf("Failed to get the chain ID from the configuration block, %s", err))
   119  	}
   120  
   121  	peer.InitChain(chainID)
   122  
   123  	return shim.Success(nil)
   124  }
   125  
   126  func updateConfigBlock(blockBytes []byte) pb.Response {
   127  	if blockBytes == nil {
   128  		return shim.Error("Configuration block must not be nil.")
   129  	}
   130  	block, err := utils.GetBlockFromBlockBytes(blockBytes)
   131  	if err != nil {
   132  		return shim.Error(fmt.Sprintf("Failed to reconstruct the configuration block, %s", err))
   133  	}
   134  	chainID, err := utils.GetChainIDFromBlock(block)
   135  	if err != nil {
   136  		return shim.Error(fmt.Sprintf("Failed to get the chain ID from the configuration block, %s", err))
   137  	}
   138  
   139  	if err := peer.SetCurrConfigBlock(block, chainID); err != nil {
   140  		return shim.Error(err.Error())
   141  	}
   142  
   143  	return shim.Success(nil)
   144  }
   145  
   146  // Return the current configuration block for the specified chainID. If the
   147  // peer doesn't belong to the chain, return error
   148  func getConfigBlock(chainID []byte) pb.Response {
   149  	if chainID == nil {
   150  		return shim.Error("ChainID must not be nil.")
   151  	}
   152  	block := peer.GetCurrConfigBlock(string(chainID))
   153  	if block == nil {
   154  		return shim.Error(fmt.Sprintf("Unknown chain ID, %s", string(chainID)))
   155  	}
   156  	blockBytes, err := utils.Marshal(block)
   157  	if err != nil {
   158  		return shim.Error(err.Error())
   159  	}
   160  
   161  	return shim.Success(blockBytes)
   162  }
   163  
   164  // getChannels returns information about all channels for this peer
   165  func getChannels() pb.Response {
   166  	channelInfoArray := peer.GetChannelsInfo()
   167  
   168  	// add array with info about all channels for this peer
   169  	cqr := &pb.ChannelQueryResponse{Channels: channelInfoArray}
   170  
   171  	cqrbytes, err := proto.Marshal(cqr)
   172  	if err != nil {
   173  		return shim.Error(err.Error())
   174  	}
   175  
   176  	return shim.Success(cqrbytes)
   177  }