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 }