github.com/myafeier/fabric@v1.0.1-0.20170722181825-3a4b1f2bce86/core/scc/qscc/query.go (about)

     1  /*
     2  Copyright IBM Corp. 2017 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 qscc
    18  
    19  import (
    20  	"fmt"
    21  	"strconv"
    22  
    23  	"github.com/hyperledger/fabric/common/flogging"
    24  
    25  	"github.com/hyperledger/fabric/common/policies"
    26  	"github.com/hyperledger/fabric/core/chaincode/shim"
    27  	"github.com/hyperledger/fabric/core/ledger"
    28  	"github.com/hyperledger/fabric/core/peer"
    29  	"github.com/hyperledger/fabric/core/policy"
    30  	"github.com/hyperledger/fabric/msp/mgmt"
    31  	pb "github.com/hyperledger/fabric/protos/peer"
    32  	"github.com/hyperledger/fabric/protos/utils"
    33  )
    34  
    35  // LedgerQuerier implements the ledger query functions, including:
    36  // - GetChainInfo returns BlockchainInfo
    37  // - GetBlockByNumber returns a block
    38  // - GetBlockByHash returns a block
    39  // - GetTransactionByID returns a transaction
    40  type LedgerQuerier struct {
    41  	policyChecker policy.PolicyChecker
    42  }
    43  
    44  var qscclogger = flogging.MustGetLogger("qscc")
    45  
    46  // These are function names from Invoke first parameter
    47  const (
    48  	GetChainInfo       string = "GetChainInfo"
    49  	GetBlockByNumber   string = "GetBlockByNumber"
    50  	GetBlockByHash     string = "GetBlockByHash"
    51  	GetTransactionByID string = "GetTransactionByID"
    52  	GetBlockByTxID     string = "GetBlockByTxID"
    53  )
    54  
    55  // Init is called once per chain when the chain is created.
    56  // This allows the chaincode to initialize any variables on the ledger prior
    57  // to any transaction execution on the chain.
    58  func (e *LedgerQuerier) Init(stub shim.ChaincodeStubInterface) pb.Response {
    59  	qscclogger.Info("Init QSCC")
    60  
    61  	// Init policy checker for access control
    62  	e.policyChecker = policy.NewPolicyChecker(
    63  		peer.NewChannelPolicyManagerGetter(),
    64  		mgmt.GetLocalMSP(),
    65  		mgmt.NewLocalMSPPrincipalGetter(),
    66  	)
    67  
    68  	return shim.Success(nil)
    69  }
    70  
    71  // Invoke is called with args[0] contains the query function name, args[1]
    72  // contains the chain ID, which is temporary for now until it is part of stub.
    73  // Each function requires additional parameters as described below:
    74  // # GetChainInfo: Return a BlockchainInfo object marshalled in bytes
    75  // # GetBlockByNumber: Return the block specified by block number in args[2]
    76  // # GetBlockByHash: Return the block specified by block hash in args[2]
    77  // # GetTransactionByID: Return the transaction specified by ID in args[2]
    78  func (e *LedgerQuerier) Invoke(stub shim.ChaincodeStubInterface) pb.Response {
    79  	args := stub.GetArgs()
    80  
    81  	if len(args) < 2 {
    82  		return shim.Error(fmt.Sprintf("Incorrect number of arguments, %d", len(args)))
    83  	}
    84  	fname := string(args[0])
    85  	cid := string(args[1])
    86  
    87  	if fname != GetChainInfo && len(args) < 3 {
    88  		return shim.Error(fmt.Sprintf("missing 3rd argument for %s", fname))
    89  	}
    90  
    91  	targetLedger := peer.GetLedger(cid)
    92  	if targetLedger == nil {
    93  		return shim.Error(fmt.Sprintf("Invalid chain ID, %s", cid))
    94  	}
    95  
    96  	qscclogger.Debugf("Invoke function: %s on chain: %s", fname, cid)
    97  
    98  	// Handle ACL:
    99  	// 1. get the signed proposal
   100  	sp, err := stub.GetSignedProposal()
   101  	if err != nil {
   102  		return shim.Error(fmt.Sprintf("Failed getting signed proposal from stub, %s: %s", cid, err))
   103  	}
   104  
   105  	// 2. check the channel reader policy
   106  	if err = e.policyChecker.CheckPolicy(cid, policies.ChannelApplicationReaders, sp); err != nil {
   107  		return shim.Error(fmt.Sprintf("Authorization request failed %s: %s", cid, err))
   108  	}
   109  
   110  	switch fname {
   111  	case GetTransactionByID:
   112  		return getTransactionByID(targetLedger, args[2])
   113  	case GetBlockByNumber:
   114  		return getBlockByNumber(targetLedger, args[2])
   115  	case GetBlockByHash:
   116  		return getBlockByHash(targetLedger, args[2])
   117  	case GetChainInfo:
   118  		return getChainInfo(targetLedger)
   119  	case GetBlockByTxID:
   120  		return getBlockByTxID(targetLedger, args[2])
   121  	}
   122  
   123  	return shim.Error(fmt.Sprintf("Requested function %s not found.", fname))
   124  }
   125  
   126  func getTransactionByID(vledger ledger.PeerLedger, tid []byte) pb.Response {
   127  	if tid == nil {
   128  		return shim.Error("Transaction ID must not be nil.")
   129  	}
   130  
   131  	processedTran, err := vledger.GetTransactionByID(string(tid))
   132  	if err != nil {
   133  		return shim.Error(fmt.Sprintf("Failed to get transaction with id %s, error %s", string(tid), err))
   134  	}
   135  
   136  	bytes, err := utils.Marshal(processedTran)
   137  	if err != nil {
   138  		return shim.Error(err.Error())
   139  	}
   140  
   141  	return shim.Success(bytes)
   142  }
   143  
   144  func getBlockByNumber(vledger ledger.PeerLedger, number []byte) pb.Response {
   145  	if number == nil {
   146  		return shim.Error("Block number must not be nil.")
   147  	}
   148  	bnum, err := strconv.ParseUint(string(number), 10, 64)
   149  	if err != nil {
   150  		return shim.Error(fmt.Sprintf("Failed to parse block number with error %s", err))
   151  	}
   152  	block, err := vledger.GetBlockByNumber(bnum)
   153  	if err != nil {
   154  		return shim.Error(fmt.Sprintf("Failed to get block number %d, error %s", bnum, err))
   155  	}
   156  	// TODO: consider trim block content before returning
   157  	//  Specifically, trim transaction 'data' out of the transaction array Payloads
   158  	//  This will preserve the transaction Payload header,
   159  	//  and client can do GetTransactionByID() if they want the full transaction details
   160  
   161  	bytes, err := utils.Marshal(block)
   162  	if err != nil {
   163  		return shim.Error(err.Error())
   164  	}
   165  
   166  	return shim.Success(bytes)
   167  }
   168  
   169  func getBlockByHash(vledger ledger.PeerLedger, hash []byte) pb.Response {
   170  	if hash == nil {
   171  		return shim.Error("Block hash must not be nil.")
   172  	}
   173  	block, err := vledger.GetBlockByHash(hash)
   174  	if err != nil {
   175  		return shim.Error(fmt.Sprintf("Failed to get block hash %s, error %s", string(hash), err))
   176  	}
   177  	// TODO: consider trim block content before returning
   178  	//  Specifically, trim transaction 'data' out of the transaction array Payloads
   179  	//  This will preserve the transaction Payload header,
   180  	//  and client can do GetTransactionByID() if they want the full transaction details
   181  
   182  	bytes, err := utils.Marshal(block)
   183  	if err != nil {
   184  		return shim.Error(err.Error())
   185  	}
   186  
   187  	return shim.Success(bytes)
   188  }
   189  
   190  func getChainInfo(vledger ledger.PeerLedger) pb.Response {
   191  	binfo, err := vledger.GetBlockchainInfo()
   192  	if err != nil {
   193  		return shim.Error(fmt.Sprintf("Failed to get block info with error %s", err))
   194  	}
   195  	bytes, err := utils.Marshal(binfo)
   196  	if err != nil {
   197  		return shim.Error(err.Error())
   198  	}
   199  
   200  	return shim.Success(bytes)
   201  }
   202  
   203  func getBlockByTxID(vledger ledger.PeerLedger, rawTxID []byte) pb.Response {
   204  	txID := string(rawTxID)
   205  	block, err := vledger.GetBlockByTxID(txID)
   206  
   207  	if err != nil {
   208  		return shim.Error(fmt.Sprintf("Failed to get block for txID %s, error %s", txID, err))
   209  	}
   210  
   211  	bytes, err := utils.Marshal(block)
   212  
   213  	if err != nil {
   214  		return shim.Error(err.Error())
   215  	}
   216  
   217  	return shim.Success(bytes)
   218  }