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