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 }