github.com/lzy4123/fabric@v2.1.1+incompatible/protoutil/proputils.go (about) 1 /* 2 Copyright IBM Corp. All Rights Reserved. 3 4 SPDX-License-Identifier: Apache-2.0 5 */ 6 7 package protoutil 8 9 import ( 10 "crypto/sha256" 11 "encoding/hex" 12 "time" 13 14 "github.com/golang/protobuf/proto" 15 "github.com/golang/protobuf/ptypes" 16 "github.com/hyperledger/fabric-protos-go/common" 17 "github.com/hyperledger/fabric-protos-go/peer" 18 "github.com/pkg/errors" 19 ) 20 21 // CreateChaincodeProposal creates a proposal from given input. 22 // It returns the proposal and the transaction id associated to the proposal 23 func CreateChaincodeProposal(typ common.HeaderType, channelID string, cis *peer.ChaincodeInvocationSpec, creator []byte) (*peer.Proposal, string, error) { 24 return CreateChaincodeProposalWithTransient(typ, channelID, cis, creator, nil) 25 } 26 27 // CreateChaincodeProposalWithTransient creates a proposal from given input 28 // It returns the proposal and the transaction id associated to the proposal 29 func CreateChaincodeProposalWithTransient(typ common.HeaderType, channelID string, cis *peer.ChaincodeInvocationSpec, creator []byte, transientMap map[string][]byte) (*peer.Proposal, string, error) { 30 // generate a random nonce 31 nonce, err := getRandomNonce() 32 if err != nil { 33 return nil, "", err 34 } 35 36 // compute txid 37 txid := ComputeTxID(nonce, creator) 38 39 return CreateChaincodeProposalWithTxIDNonceAndTransient(txid, typ, channelID, cis, nonce, creator, transientMap) 40 } 41 42 // CreateChaincodeProposalWithTxIDAndTransient creates a proposal from given 43 // input. It returns the proposal and the transaction id associated with the 44 // proposal 45 func CreateChaincodeProposalWithTxIDAndTransient(typ common.HeaderType, channelID string, cis *peer.ChaincodeInvocationSpec, creator []byte, txid string, transientMap map[string][]byte) (*peer.Proposal, string, error) { 46 // generate a random nonce 47 nonce, err := getRandomNonce() 48 if err != nil { 49 return nil, "", err 50 } 51 52 // compute txid unless provided by tests 53 if txid == "" { 54 txid = ComputeTxID(nonce, creator) 55 } 56 57 return CreateChaincodeProposalWithTxIDNonceAndTransient(txid, typ, channelID, cis, nonce, creator, transientMap) 58 } 59 60 // CreateChaincodeProposalWithTxIDNonceAndTransient creates a proposal from 61 // given input 62 func CreateChaincodeProposalWithTxIDNonceAndTransient(txid string, typ common.HeaderType, channelID string, cis *peer.ChaincodeInvocationSpec, nonce, creator []byte, transientMap map[string][]byte) (*peer.Proposal, string, error) { 63 ccHdrExt := &peer.ChaincodeHeaderExtension{ChaincodeId: cis.ChaincodeSpec.ChaincodeId} 64 ccHdrExtBytes, err := proto.Marshal(ccHdrExt) 65 if err != nil { 66 return nil, "", errors.Wrap(err, "error marshaling ChaincodeHeaderExtension") 67 } 68 69 cisBytes, err := proto.Marshal(cis) 70 if err != nil { 71 return nil, "", errors.Wrap(err, "error marshaling ChaincodeInvocationSpec") 72 } 73 74 ccPropPayload := &peer.ChaincodeProposalPayload{Input: cisBytes, TransientMap: transientMap} 75 ccPropPayloadBytes, err := proto.Marshal(ccPropPayload) 76 if err != nil { 77 return nil, "", errors.Wrap(err, "error marshaling ChaincodeProposalPayload") 78 } 79 80 // TODO: epoch is now set to zero. This must be changed once we 81 // get a more appropriate mechanism to handle it in. 82 var epoch uint64 83 84 timestamp, err := ptypes.TimestampProto(time.Now().UTC()) 85 if err != nil { 86 return nil, "", errors.Wrap(err, "error validating Timestamp") 87 } 88 89 hdr := &common.Header{ 90 ChannelHeader: MarshalOrPanic( 91 &common.ChannelHeader{ 92 Type: int32(typ), 93 TxId: txid, 94 Timestamp: timestamp, 95 ChannelId: channelID, 96 Extension: ccHdrExtBytes, 97 Epoch: epoch, 98 }, 99 ), 100 SignatureHeader: MarshalOrPanic( 101 &common.SignatureHeader{ 102 Nonce: nonce, 103 Creator: creator, 104 }, 105 ), 106 } 107 108 hdrBytes, err := proto.Marshal(hdr) 109 if err != nil { 110 return nil, "", err 111 } 112 113 prop := &peer.Proposal{ 114 Header: hdrBytes, 115 Payload: ccPropPayloadBytes, 116 } 117 return prop, txid, nil 118 } 119 120 // GetBytesProposalResponsePayload gets proposal response payload 121 func GetBytesProposalResponsePayload(hash []byte, response *peer.Response, result []byte, event []byte, ccid *peer.ChaincodeID) ([]byte, error) { 122 cAct := &peer.ChaincodeAction{ 123 Events: event, Results: result, 124 Response: response, 125 ChaincodeId: ccid, 126 } 127 cActBytes, err := proto.Marshal(cAct) 128 if err != nil { 129 return nil, errors.Wrap(err, "error marshaling ChaincodeAction") 130 } 131 132 prp := &peer.ProposalResponsePayload{ 133 Extension: cActBytes, 134 ProposalHash: hash, 135 } 136 prpBytes, err := proto.Marshal(prp) 137 return prpBytes, errors.Wrap(err, "error marshaling ProposalResponsePayload") 138 } 139 140 // GetBytesChaincodeProposalPayload gets the chaincode proposal payload 141 func GetBytesChaincodeProposalPayload(cpp *peer.ChaincodeProposalPayload) ([]byte, error) { 142 cppBytes, err := proto.Marshal(cpp) 143 return cppBytes, errors.Wrap(err, "error marshaling ChaincodeProposalPayload") 144 } 145 146 // GetBytesResponse gets the bytes of Response 147 func GetBytesResponse(res *peer.Response) ([]byte, error) { 148 resBytes, err := proto.Marshal(res) 149 return resBytes, errors.Wrap(err, "error marshaling Response") 150 } 151 152 // GetBytesChaincodeEvent gets the bytes of ChaincodeEvent 153 func GetBytesChaincodeEvent(event *peer.ChaincodeEvent) ([]byte, error) { 154 eventBytes, err := proto.Marshal(event) 155 return eventBytes, errors.Wrap(err, "error marshaling ChaincodeEvent") 156 } 157 158 // GetBytesChaincodeActionPayload get the bytes of ChaincodeActionPayload from 159 // the message 160 func GetBytesChaincodeActionPayload(cap *peer.ChaincodeActionPayload) ([]byte, error) { 161 capBytes, err := proto.Marshal(cap) 162 return capBytes, errors.Wrap(err, "error marshaling ChaincodeActionPayload") 163 } 164 165 // GetBytesProposalResponse gets proposal bytes response 166 func GetBytesProposalResponse(pr *peer.ProposalResponse) ([]byte, error) { 167 respBytes, err := proto.Marshal(pr) 168 return respBytes, errors.Wrap(err, "error marshaling ProposalResponse") 169 } 170 171 // GetBytesHeader get the bytes of Header from the message 172 func GetBytesHeader(hdr *common.Header) ([]byte, error) { 173 bytes, err := proto.Marshal(hdr) 174 return bytes, errors.Wrap(err, "error marshaling Header") 175 } 176 177 // GetBytesSignatureHeader get the bytes of SignatureHeader from the message 178 func GetBytesSignatureHeader(hdr *common.SignatureHeader) ([]byte, error) { 179 bytes, err := proto.Marshal(hdr) 180 return bytes, errors.Wrap(err, "error marshaling SignatureHeader") 181 } 182 183 // GetBytesTransaction get the bytes of Transaction from the message 184 func GetBytesTransaction(tx *peer.Transaction) ([]byte, error) { 185 bytes, err := proto.Marshal(tx) 186 return bytes, errors.Wrap(err, "error unmarshaling Transaction") 187 } 188 189 // GetBytesPayload get the bytes of Payload from the message 190 func GetBytesPayload(payl *common.Payload) ([]byte, error) { 191 bytes, err := proto.Marshal(payl) 192 return bytes, errors.Wrap(err, "error marshaling Payload") 193 } 194 195 // GetBytesEnvelope get the bytes of Envelope from the message 196 func GetBytesEnvelope(env *common.Envelope) ([]byte, error) { 197 bytes, err := proto.Marshal(env) 198 return bytes, errors.Wrap(err, "error marshaling Envelope") 199 } 200 201 // GetActionFromEnvelope extracts a ChaincodeAction message from a 202 // serialized Envelope 203 // TODO: fix function name as per FAB-11831 204 func GetActionFromEnvelope(envBytes []byte) (*peer.ChaincodeAction, error) { 205 env, err := GetEnvelopeFromBlock(envBytes) 206 if err != nil { 207 return nil, err 208 } 209 return GetActionFromEnvelopeMsg(env) 210 } 211 212 func GetActionFromEnvelopeMsg(env *common.Envelope) (*peer.ChaincodeAction, error) { 213 payl, err := UnmarshalPayload(env.Payload) 214 if err != nil { 215 return nil, err 216 } 217 218 tx, err := UnmarshalTransaction(payl.Data) 219 if err != nil { 220 return nil, err 221 } 222 223 if len(tx.Actions) == 0 { 224 return nil, errors.New("at least one TransactionAction required") 225 } 226 227 _, respPayload, err := GetPayloads(tx.Actions[0]) 228 return respPayload, err 229 } 230 231 // CreateProposalFromCISAndTxid returns a proposal given a serialized identity 232 // and a ChaincodeInvocationSpec 233 func CreateProposalFromCISAndTxid(txid string, typ common.HeaderType, channelID string, cis *peer.ChaincodeInvocationSpec, creator []byte) (*peer.Proposal, string, error) { 234 nonce, err := getRandomNonce() 235 if err != nil { 236 return nil, "", err 237 } 238 return CreateChaincodeProposalWithTxIDNonceAndTransient(txid, typ, channelID, cis, nonce, creator, nil) 239 } 240 241 // CreateProposalFromCIS returns a proposal given a serialized identity and a 242 // ChaincodeInvocationSpec 243 func CreateProposalFromCIS(typ common.HeaderType, channelID string, cis *peer.ChaincodeInvocationSpec, creator []byte) (*peer.Proposal, string, error) { 244 return CreateChaincodeProposal(typ, channelID, cis, creator) 245 } 246 247 // CreateGetChaincodesProposal returns a GETCHAINCODES proposal given a 248 // serialized identity 249 func CreateGetChaincodesProposal(channelID string, creator []byte) (*peer.Proposal, string, error) { 250 ccinp := &peer.ChaincodeInput{Args: [][]byte{[]byte("getchaincodes")}} 251 lsccSpec := &peer.ChaincodeInvocationSpec{ 252 ChaincodeSpec: &peer.ChaincodeSpec{ 253 Type: peer.ChaincodeSpec_GOLANG, 254 ChaincodeId: &peer.ChaincodeID{Name: "lscc"}, 255 Input: ccinp, 256 }, 257 } 258 return CreateProposalFromCIS(common.HeaderType_ENDORSER_TRANSACTION, channelID, lsccSpec, creator) 259 } 260 261 // CreateGetInstalledChaincodesProposal returns a GETINSTALLEDCHAINCODES 262 // proposal given a serialized identity 263 func CreateGetInstalledChaincodesProposal(creator []byte) (*peer.Proposal, string, error) { 264 ccinp := &peer.ChaincodeInput{Args: [][]byte{[]byte("getinstalledchaincodes")}} 265 lsccSpec := &peer.ChaincodeInvocationSpec{ 266 ChaincodeSpec: &peer.ChaincodeSpec{ 267 Type: peer.ChaincodeSpec_GOLANG, 268 ChaincodeId: &peer.ChaincodeID{Name: "lscc"}, 269 Input: ccinp, 270 }, 271 } 272 return CreateProposalFromCIS(common.HeaderType_ENDORSER_TRANSACTION, "", lsccSpec, creator) 273 } 274 275 // CreateInstallProposalFromCDS returns a install proposal given a serialized 276 // identity and a ChaincodeDeploymentSpec 277 func CreateInstallProposalFromCDS(ccpack proto.Message, creator []byte) (*peer.Proposal, string, error) { 278 return createProposalFromCDS("", ccpack, creator, "install") 279 } 280 281 // CreateDeployProposalFromCDS returns a deploy proposal given a serialized 282 // identity and a ChaincodeDeploymentSpec 283 func CreateDeployProposalFromCDS( 284 channelID string, 285 cds *peer.ChaincodeDeploymentSpec, 286 creator []byte, 287 policy []byte, 288 escc []byte, 289 vscc []byte, 290 collectionConfig []byte) (*peer.Proposal, string, error) { 291 if collectionConfig == nil { 292 return createProposalFromCDS(channelID, cds, creator, "deploy", policy, escc, vscc) 293 } 294 return createProposalFromCDS(channelID, cds, creator, "deploy", policy, escc, vscc, collectionConfig) 295 } 296 297 // CreateUpgradeProposalFromCDS returns a upgrade proposal given a serialized 298 // identity and a ChaincodeDeploymentSpec 299 func CreateUpgradeProposalFromCDS( 300 channelID string, 301 cds *peer.ChaincodeDeploymentSpec, 302 creator []byte, 303 policy []byte, 304 escc []byte, 305 vscc []byte, 306 collectionConfig []byte) (*peer.Proposal, string, error) { 307 if collectionConfig == nil { 308 return createProposalFromCDS(channelID, cds, creator, "upgrade", policy, escc, vscc) 309 } 310 return createProposalFromCDS(channelID, cds, creator, "upgrade", policy, escc, vscc, collectionConfig) 311 } 312 313 // createProposalFromCDS returns a deploy or upgrade proposal given a 314 // serialized identity and a ChaincodeDeploymentSpec 315 func createProposalFromCDS(channelID string, msg proto.Message, creator []byte, propType string, args ...[]byte) (*peer.Proposal, string, error) { 316 // in the new mode, cds will be nil, "deploy" and "upgrade" are instantiates. 317 var ccinp *peer.ChaincodeInput 318 var b []byte 319 var err error 320 if msg != nil { 321 b, err = proto.Marshal(msg) 322 if err != nil { 323 return nil, "", err 324 } 325 } 326 switch propType { 327 case "deploy": 328 fallthrough 329 case "upgrade": 330 cds, ok := msg.(*peer.ChaincodeDeploymentSpec) 331 if !ok || cds == nil { 332 return nil, "", errors.New("invalid message for creating lifecycle chaincode proposal") 333 } 334 Args := [][]byte{[]byte(propType), []byte(channelID), b} 335 Args = append(Args, args...) 336 337 ccinp = &peer.ChaincodeInput{Args: Args} 338 case "install": 339 ccinp = &peer.ChaincodeInput{Args: [][]byte{[]byte(propType), b}} 340 } 341 342 // wrap the deployment in an invocation spec to lscc... 343 lsccSpec := &peer.ChaincodeInvocationSpec{ 344 ChaincodeSpec: &peer.ChaincodeSpec{ 345 Type: peer.ChaincodeSpec_GOLANG, 346 ChaincodeId: &peer.ChaincodeID{Name: "lscc"}, 347 Input: ccinp, 348 }, 349 } 350 351 // ...and get the proposal for it 352 return CreateProposalFromCIS(common.HeaderType_ENDORSER_TRANSACTION, channelID, lsccSpec, creator) 353 } 354 355 // ComputeTxID computes TxID as the Hash computed 356 // over the concatenation of nonce and creator. 357 func ComputeTxID(nonce, creator []byte) string { 358 // TODO: Get the Hash function to be used from 359 // channel configuration 360 hasher := sha256.New() 361 hasher.Write(nonce) 362 hasher.Write(creator) 363 return hex.EncodeToString(hasher.Sum(nil)) 364 } 365 366 // CheckTxID checks that txid is equal to the Hash computed 367 // over the concatenation of nonce and creator. 368 func CheckTxID(txid string, nonce, creator []byte) error { 369 computedTxID := ComputeTxID(nonce, creator) 370 371 if txid != computedTxID { 372 return errors.Errorf("invalid txid. got [%s], expected [%s]", txid, computedTxID) 373 } 374 375 return nil 376 } 377 378 // InvokedChaincodeName takes the proposal bytes of a SignedProposal, and unpacks it all the way down, 379 // until either an error is encountered, or the chaincode name is found. This is useful primarily 380 // for chaincodes which wish to know the chaincode name originally invoked, in order to deny cc2cc 381 // invocations (or, perhaps to deny direct invocations and require cc2cc). 382 func InvokedChaincodeName(proposalBytes []byte) (string, error) { 383 proposal := &peer.Proposal{} 384 err := proto.Unmarshal(proposalBytes, proposal) 385 if err != nil { 386 return "", errors.WithMessage(err, "could not unmarshal proposal") 387 } 388 389 proposalPayload := &peer.ChaincodeProposalPayload{} 390 err = proto.Unmarshal(proposal.Payload, proposalPayload) 391 if err != nil { 392 return "", errors.WithMessage(err, "could not unmarshal chaincode proposal payload") 393 } 394 395 cis := &peer.ChaincodeInvocationSpec{} 396 err = proto.Unmarshal(proposalPayload.Input, cis) 397 if err != nil { 398 return "", errors.WithMessage(err, "could not unmarshal chaincode invocation spec") 399 } 400 401 if cis.ChaincodeSpec == nil { 402 return "", errors.Errorf("chaincode spec is nil") 403 } 404 405 if cis.ChaincodeSpec.ChaincodeId == nil { 406 return "", errors.Errorf("chaincode id is nil") 407 } 408 409 return cis.ChaincodeSpec.ChaincodeId.Name, nil 410 }