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