github.com/darrenli6/fabric-sdk-example@v0.0.0-20220109053535-94b13b56df8c/protos/utils/proputils.go (about) 1 /* 2 Copyright IBM Corp. 2016 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 utils 18 19 import ( 20 "errors" 21 "fmt" 22 23 "encoding/binary" 24 25 "encoding/hex" 26 27 "github.com/golang/protobuf/proto" 28 "github.com/hyperledger/fabric/bccsp" 29 "github.com/hyperledger/fabric/bccsp/factory" 30 "github.com/hyperledger/fabric/common/crypto" 31 "github.com/hyperledger/fabric/common/util" 32 "github.com/hyperledger/fabric/core/chaincode/platforms" 33 "github.com/hyperledger/fabric/protos/common" 34 "github.com/hyperledger/fabric/protos/peer" 35 ) 36 37 // GetChaincodeInvocationSpec get the ChaincodeInvocationSpec from the proposal 38 func GetChaincodeInvocationSpec(prop *peer.Proposal) (*peer.ChaincodeInvocationSpec, error) { 39 if prop == nil { 40 return nil, fmt.Errorf("Proposal is nil") 41 } 42 _, err := GetHeader(prop.Header) 43 if err != nil { 44 return nil, err 45 } 46 ccPropPayload := &peer.ChaincodeProposalPayload{} 47 err = proto.Unmarshal(prop.Payload, ccPropPayload) 48 if err != nil { 49 return nil, err 50 } 51 cis := &peer.ChaincodeInvocationSpec{} 52 err = proto.Unmarshal(ccPropPayload.Input, cis) 53 return cis, err 54 } 55 56 // GetChaincodeProposalContext returns creator and transient 57 func GetChaincodeProposalContext(prop *peer.Proposal) ([]byte, map[string][]byte, error) { 58 if prop == nil { 59 return nil, nil, fmt.Errorf("Proposal is nil") 60 } 61 if len(prop.Header) == 0 { 62 return nil, nil, fmt.Errorf("Proposal's header is nil") 63 } 64 if len(prop.Payload) == 0 { 65 return nil, nil, fmt.Errorf("Proposal's payload is nil") 66 } 67 68 //// get back the header 69 hdr, err := GetHeader(prop.Header) 70 if err != nil { 71 return nil, nil, fmt.Errorf("Could not extract the header from the proposal: %s", err) 72 } 73 if hdr == nil { 74 return nil, nil, fmt.Errorf("Unmarshalled header is nil") 75 } 76 77 chdr, err := UnmarshalChannelHeader(hdr.ChannelHeader) 78 if err != nil { 79 return nil, nil, fmt.Errorf("Could not extract the channel header from the proposal: %s", err) 80 } 81 82 if common.HeaderType(chdr.Type) != common.HeaderType_ENDORSER_TRANSACTION && 83 common.HeaderType(chdr.Type) != common.HeaderType_CONFIG { 84 return nil, nil, fmt.Errorf("Invalid proposal type expected ENDORSER_TRANSACTION or CONFIG. Was: %d", chdr.Type) 85 } 86 87 shdr, err := GetSignatureHeader(hdr.SignatureHeader) 88 if err != nil { 89 return nil, nil, fmt.Errorf("Could not extract the signature header from the proposal: %s", err) 90 } 91 92 ccPropPayload := &peer.ChaincodeProposalPayload{} 93 err = proto.Unmarshal(prop.Payload, ccPropPayload) 94 if err != nil { 95 return nil, nil, err 96 } 97 98 return shdr.Creator, ccPropPayload.TransientMap, nil 99 } 100 101 // GetHeader Get Header from bytes 102 func GetHeader(bytes []byte) (*common.Header, error) { 103 hdr := &common.Header{} 104 err := proto.Unmarshal(bytes, hdr) 105 return hdr, err 106 } 107 108 // GetNonce returns the nonce used in Proposal 109 func GetNonce(prop *peer.Proposal) ([]byte, error) { 110 if prop == nil { 111 return nil, fmt.Errorf("Proposal is nil") 112 } 113 // get back the header 114 hdr, err := GetHeader(prop.Header) 115 if err != nil { 116 return nil, fmt.Errorf("Could not extract the header from the proposal: %s", err) 117 } 118 119 chdr, err := UnmarshalChannelHeader(hdr.ChannelHeader) 120 if err != nil { 121 return nil, fmt.Errorf("Could not extract the channel header from the proposal: %s", err) 122 } 123 124 if common.HeaderType(chdr.Type) != common.HeaderType_ENDORSER_TRANSACTION && 125 common.HeaderType(chdr.Type) != common.HeaderType_CONFIG { 126 return nil, fmt.Errorf("Invalid proposal type expected ENDORSER_TRANSACTION or CONFIG. Was: %d", chdr.Type) 127 } 128 129 shdr, err := GetSignatureHeader(hdr.SignatureHeader) 130 if err != nil { 131 return nil, fmt.Errorf("Could not extract the signature header from the proposal: %s", err) 132 } 133 134 if hdr.SignatureHeader == nil { 135 return nil, errors.New("Invalid signature header. It must be different from nil.") 136 } 137 138 return shdr.Nonce, nil 139 } 140 141 // GetChaincodeHeaderExtension get chaincode header extension given header 142 func GetChaincodeHeaderExtension(hdr *common.Header) (*peer.ChaincodeHeaderExtension, error) { 143 chdr, err := UnmarshalChannelHeader(hdr.ChannelHeader) 144 if err != nil { 145 return nil, err 146 } 147 148 chaincodeHdrExt := &peer.ChaincodeHeaderExtension{} 149 err = proto.Unmarshal(chdr.Extension, chaincodeHdrExt) 150 return chaincodeHdrExt, err 151 } 152 153 // GetProposalResponse given proposal in bytes 154 func GetProposalResponse(prBytes []byte) (*peer.ProposalResponse, error) { 155 proposalResponse := &peer.ProposalResponse{} 156 err := proto.Unmarshal(prBytes, proposalResponse) 157 return proposalResponse, err 158 } 159 160 // GetChaincodeDeploymentSpec returns a ChaincodeDeploymentSpec given args 161 func GetChaincodeDeploymentSpec(code []byte) (*peer.ChaincodeDeploymentSpec, error) { 162 cds := &peer.ChaincodeDeploymentSpec{} 163 err := proto.Unmarshal(code, cds) 164 if err != nil { 165 return nil, err 166 } 167 168 // FAB-2122: Validate the CDS according to platform specific requirements 169 platform, err := platforms.Find(cds.ChaincodeSpec.Type) 170 if err != nil { 171 return nil, err 172 } 173 174 err = platform.ValidateDeploymentSpec(cds) 175 return cds, err 176 } 177 178 // GetChaincodeAction gets the ChaincodeAction given chaicnode action bytes 179 func GetChaincodeAction(caBytes []byte) (*peer.ChaincodeAction, error) { 180 chaincodeAction := &peer.ChaincodeAction{} 181 err := proto.Unmarshal(caBytes, chaincodeAction) 182 return chaincodeAction, err 183 } 184 185 // GetResponse gets the Response given response bytes 186 func GetResponse(resBytes []byte) (*peer.Response, error) { 187 response := &peer.Response{} 188 err := proto.Unmarshal(resBytes, response) 189 return response, err 190 } 191 192 // GetChaincodeEvents gets the ChaincodeEvents given chaicnode event bytes 193 func GetChaincodeEvents(eBytes []byte) (*peer.ChaincodeEvent, error) { 194 chaincodeEvent := &peer.ChaincodeEvent{} 195 err := proto.Unmarshal(eBytes, chaincodeEvent) 196 return chaincodeEvent, err 197 } 198 199 // GetProposalResponsePayload gets the proposal response payload 200 func GetProposalResponsePayload(prpBytes []byte) (*peer.ProposalResponsePayload, error) { 201 prp := &peer.ProposalResponsePayload{} 202 err := proto.Unmarshal(prpBytes, prp) 203 return prp, err 204 } 205 206 // GetProposal returns a Proposal message from its bytes 207 func GetProposal(propBytes []byte) (*peer.Proposal, error) { 208 prop := &peer.Proposal{} 209 err := proto.Unmarshal(propBytes, prop) 210 return prop, err 211 } 212 213 // GetPayload Get Payload from Envelope message 214 func GetPayload(e *common.Envelope) (*common.Payload, error) { 215 payload := &common.Payload{} 216 err := proto.Unmarshal(e.Payload, payload) 217 return payload, err 218 } 219 220 // GetTransaction Get Transaction from bytes 221 func GetTransaction(txBytes []byte) (*peer.Transaction, error) { 222 tx := &peer.Transaction{} 223 err := proto.Unmarshal(txBytes, tx) 224 return tx, err 225 } 226 227 // GetChaincodeActionPayload Get ChaincodeActionPayload from bytes 228 func GetChaincodeActionPayload(capBytes []byte) (*peer.ChaincodeActionPayload, error) { 229 cap := &peer.ChaincodeActionPayload{} 230 err := proto.Unmarshal(capBytes, cap) 231 return cap, err 232 } 233 234 // GetChaincodeProposalPayload Get ChaincodeProposalPayload from bytes 235 func GetChaincodeProposalPayload(bytes []byte) (*peer.ChaincodeProposalPayload, error) { 236 cpp := &peer.ChaincodeProposalPayload{} 237 err := proto.Unmarshal(bytes, cpp) 238 return cpp, err 239 } 240 241 // GetSignatureHeader Get SignatureHeader from bytes 242 func GetSignatureHeader(bytes []byte) (*common.SignatureHeader, error) { 243 sh := &common.SignatureHeader{} 244 err := proto.Unmarshal(bytes, sh) 245 return sh, err 246 } 247 248 // CreateChaincodeProposal creates a proposal from given input. 249 // It returns the proposal and the transaction id associated to the proposal 250 func CreateChaincodeProposal(typ common.HeaderType, chainID string, cis *peer.ChaincodeInvocationSpec, creator []byte) (*peer.Proposal, string, error) { 251 return CreateChaincodeProposalWithTransient(typ, chainID, cis, creator, nil) 252 } 253 254 // CreateChaincodeProposalWithTransient creates a proposal from given input 255 // It returns the proposal and the transaction id associated to the proposal 256 func CreateChaincodeProposalWithTransient(typ common.HeaderType, chainID string, cis *peer.ChaincodeInvocationSpec, creator []byte, transientMap map[string][]byte) (*peer.Proposal, string, error) { 257 // generate a random nonce 258 nonce, err := crypto.GetRandomNonce() 259 if err != nil { 260 return nil, "", err 261 } 262 263 // compute txid 264 txid, err := ComputeProposalTxID(nonce, creator) 265 if err != nil { 266 return nil, "", err 267 } 268 269 return CreateChaincodeProposalWithTxIDNonceAndTransient(txid, typ, chainID, cis, nonce, creator, transientMap) 270 } 271 272 // CreateChaincodeProposalWithTxIDNonceAndTransient creates a proposal from given input 273 func CreateChaincodeProposalWithTxIDNonceAndTransient(txid string, typ common.HeaderType, chainID string, cis *peer.ChaincodeInvocationSpec, nonce, creator []byte, transientMap map[string][]byte) (*peer.Proposal, string, error) { 274 ccHdrExt := &peer.ChaincodeHeaderExtension{ChaincodeId: cis.ChaincodeSpec.ChaincodeId} 275 ccHdrExtBytes, err := proto.Marshal(ccHdrExt) 276 if err != nil { 277 return nil, "", err 278 } 279 280 cisBytes, err := proto.Marshal(cis) 281 if err != nil { 282 return nil, "", err 283 } 284 285 ccPropPayload := &peer.ChaincodeProposalPayload{Input: cisBytes, TransientMap: transientMap} 286 ccPropPayloadBytes, err := proto.Marshal(ccPropPayload) 287 if err != nil { 288 return nil, "", err 289 } 290 291 // TODO: epoch is now set to zero. This must be changed once we 292 // get a more appropriate mechanism to handle it in. 293 var epoch uint64 = 0 294 295 timestamp := util.CreateUtcTimestamp() 296 297 hdr := &common.Header{ChannelHeader: MarshalOrPanic(&common.ChannelHeader{ 298 Type: int32(typ), 299 TxId: txid, 300 Timestamp: timestamp, 301 ChannelId: chainID, 302 Extension: ccHdrExtBytes, 303 Epoch: epoch}), 304 SignatureHeader: MarshalOrPanic(&common.SignatureHeader{Nonce: nonce, Creator: creator})} 305 306 hdrBytes, err := proto.Marshal(hdr) 307 if err != nil { 308 return nil, "", err 309 } 310 311 return &peer.Proposal{Header: hdrBytes, Payload: ccPropPayloadBytes}, txid, nil 312 } 313 314 // GetBytesProposalResponsePayload gets proposal response payload 315 func GetBytesProposalResponsePayload(hash []byte, response *peer.Response, result []byte, event []byte, ccid *peer.ChaincodeID) ([]byte, error) { 316 cAct := &peer.ChaincodeAction{Events: event, Results: result, Response: response, ChaincodeId: ccid} 317 cActBytes, err := proto.Marshal(cAct) 318 if err != nil { 319 return nil, err 320 } 321 322 prp := &peer.ProposalResponsePayload{Extension: cActBytes, ProposalHash: hash} 323 prpBytes, err := proto.Marshal(prp) 324 return prpBytes, err 325 } 326 327 // GetBytesChaincodeProposalPayload gets the chaincode proposal payload 328 func GetBytesChaincodeProposalPayload(cpp *peer.ChaincodeProposalPayload) ([]byte, error) { 329 cppBytes, err := proto.Marshal(cpp) 330 return cppBytes, err 331 } 332 333 // GetBytesResponse gets the bytes of Response 334 func GetBytesResponse(res *peer.Response) ([]byte, error) { 335 resBytes, err := proto.Marshal(res) 336 return resBytes, err 337 } 338 339 // GetBytesChaincodeEvent gets the bytes of ChaincodeEvent 340 func GetBytesChaincodeEvent(event *peer.ChaincodeEvent) ([]byte, error) { 341 eventBytes, err := proto.Marshal(event) 342 return eventBytes, err 343 } 344 345 // GetBytesChaincodeActionPayload get the bytes of ChaincodeActionPayload from the message 346 func GetBytesChaincodeActionPayload(cap *peer.ChaincodeActionPayload) ([]byte, error) { 347 capBytes, err := proto.Marshal(cap) 348 return capBytes, err 349 } 350 351 // GetBytesProposalResponse gets propoal bytes response 352 func GetBytesProposalResponse(pr *peer.ProposalResponse) ([]byte, error) { 353 respBytes, err := proto.Marshal(pr) 354 return respBytes, err 355 } 356 357 // GetBytesProposal returns the bytes of a proposal message 358 func GetBytesProposal(prop *peer.Proposal) ([]byte, error) { 359 propBytes, err := proto.Marshal(prop) 360 return propBytes, err 361 } 362 363 // GetBytesHeader get the bytes of Header from the message 364 func GetBytesHeader(hdr *common.Header) ([]byte, error) { 365 bytes, err := proto.Marshal(hdr) 366 return bytes, err 367 } 368 369 // GetBytesSignatureHeader get the bytes of SignatureHeader from the message 370 func GetBytesSignatureHeader(hdr *common.SignatureHeader) ([]byte, error) { 371 bytes, err := proto.Marshal(hdr) 372 return bytes, err 373 } 374 375 // GetBytesTransaction get the bytes of Transaction from the message 376 func GetBytesTransaction(tx *peer.Transaction) ([]byte, error) { 377 bytes, err := proto.Marshal(tx) 378 return bytes, err 379 } 380 381 // GetBytesPayload get the bytes of Payload from the message 382 func GetBytesPayload(payl *common.Payload) ([]byte, error) { 383 bytes, err := proto.Marshal(payl) 384 return bytes, err 385 } 386 387 // GetBytesEnvelope get the bytes of Envelope from the message 388 func GetBytesEnvelope(env *common.Envelope) ([]byte, error) { 389 bytes, err := proto.Marshal(env) 390 return bytes, err 391 } 392 393 // GetActionFromEnvelope extracts a ChaincodeAction message from a serialized Envelope 394 func GetActionFromEnvelope(envBytes []byte) (*peer.ChaincodeAction, error) { 395 env, err := GetEnvelopeFromBlock(envBytes) 396 if err != nil { 397 return nil, err 398 } 399 400 payl, err := GetPayload(env) 401 if err != nil { 402 return nil, err 403 } 404 405 tx, err := GetTransaction(payl.Data) 406 if err != nil { 407 return nil, err 408 } 409 410 if len(tx.Actions) == 0 { 411 return nil, fmt.Errorf("At least one TransactionAction is required") 412 } 413 414 _, respPayload, err := GetPayloads(tx.Actions[0]) 415 return respPayload, err 416 } 417 418 // CreateProposalFromCIS returns a proposal given a serialized identity and a ChaincodeInvocationSpec 419 func CreateProposalFromCIS(typ common.HeaderType, chainID string, cis *peer.ChaincodeInvocationSpec, creator []byte) (*peer.Proposal, string, error) { 420 return CreateChaincodeProposal(typ, chainID, cis, creator) 421 } 422 423 // CreateInstallProposalFromCDS returns a install proposal given a serialized identity and a ChaincodeDeploymentSpec 424 func CreateInstallProposalFromCDS(ccpack proto.Message, creator []byte) (*peer.Proposal, string, error) { 425 return createProposalFromCDS("", ccpack, creator, nil, nil, nil, "install") 426 } 427 428 // CreateDeployProposalFromCDS returns a deploy proposal given a serialized identity and a ChaincodeDeploymentSpec 429 func CreateDeployProposalFromCDS(chainID string, cds *peer.ChaincodeDeploymentSpec, creator []byte, policy []byte, escc []byte, vscc []byte) (*peer.Proposal, string, error) { 430 return createProposalFromCDS(chainID, cds, creator, policy, escc, vscc, "deploy") 431 } 432 433 // CreateUpgradeProposalFromCDS returns a upgrade proposal given a serialized identity and a ChaincodeDeploymentSpec 434 func CreateUpgradeProposalFromCDS(chainID string, cds *peer.ChaincodeDeploymentSpec, creator []byte, policy []byte, escc []byte, vscc []byte) (*peer.Proposal, string, error) { 435 return createProposalFromCDS(chainID, cds, creator, policy, escc, vscc, "upgrade") 436 } 437 438 // createProposalFromCDS returns a deploy or upgrade proposal given a serialized identity and a ChaincodeDeploymentSpec 439 func createProposalFromCDS(chainID string, msg proto.Message, creator []byte, policy []byte, escc []byte, vscc []byte, propType string) (*peer.Proposal, string, error) { 440 //in the new mode, cds will be nil, "deploy" and "upgrade" are instantiates. 441 var ccinp *peer.ChaincodeInput 442 var b []byte 443 var err error 444 if msg != nil { 445 b, err = proto.Marshal(msg) 446 if err != nil { 447 return nil, "", err 448 } 449 } 450 switch propType { 451 case "deploy": 452 fallthrough 453 case "upgrade": 454 cds, ok := msg.(*peer.ChaincodeDeploymentSpec) 455 if !ok || cds == nil { 456 return nil, "", fmt.Errorf("invalid message for creating lifecycle chaincode proposal from") 457 } 458 ccinp = &peer.ChaincodeInput{Args: [][]byte{[]byte(propType), []byte(chainID), b, policy, escc, vscc}} 459 case "install": 460 ccinp = &peer.ChaincodeInput{Args: [][]byte{[]byte(propType), b}} 461 } 462 463 //wrap the deployment in an invocation spec to lscc... 464 lsccSpec := &peer.ChaincodeInvocationSpec{ 465 ChaincodeSpec: &peer.ChaincodeSpec{ 466 Type: peer.ChaincodeSpec_GOLANG, 467 ChaincodeId: &peer.ChaincodeID{Name: "lscc"}, 468 Input: ccinp}} 469 470 //...and get the proposal for it 471 return CreateProposalFromCIS(common.HeaderType_ENDORSER_TRANSACTION, chainID, lsccSpec, creator) 472 } 473 474 // ComputeProposalTxID computes TxID as the Hash computed 475 // over the concatenation of nonce and creator. 476 func ComputeProposalTxID(nonce, creator []byte) (string, error) { 477 // TODO: Get the Hash function to be used from 478 // channel configuration 479 digest, err := factory.GetDefault().Hash( 480 append(nonce, creator...), 481 &bccsp.SHA256Opts{}) 482 if err != nil { 483 return "", err 484 } 485 return hex.EncodeToString(digest), nil 486 } 487 488 // CheckProposalTxID checks that txid is equal to the Hash computed 489 // over the concatenation of nonce and creator. 490 func CheckProposalTxID(txid string, nonce, creator []byte) error { 491 computedTxID, err := ComputeProposalTxID(nonce, creator) 492 if err != nil { 493 return fmt.Errorf("Failed computing target TXID for comparison [%s]", err) 494 } 495 496 if txid != computedTxID { 497 return fmt.Errorf("Transaction is not valid. Got [%s], expected [%s]", txid, computedTxID) 498 } 499 500 return nil 501 } 502 503 // ComputeProposalBinding computes the binding of a proposal 504 func ComputeProposalBinding(proposal *peer.Proposal) ([]byte, error) { 505 if proposal == nil { 506 return nil, fmt.Errorf("Porposal is nil") 507 } 508 if len(proposal.Header) == 0 { 509 return nil, fmt.Errorf("Proposal's Header is nil") 510 } 511 512 h, err := GetHeader(proposal.Header) 513 if err != nil { 514 return nil, err 515 } 516 517 chdr, err := UnmarshalChannelHeader(h.ChannelHeader) 518 if err != nil { 519 return nil, err 520 } 521 shdr, err := GetSignatureHeader(h.SignatureHeader) 522 if err != nil { 523 return nil, err 524 } 525 526 return computeProposalBindingInternal(shdr.Nonce, shdr.Creator, chdr.Epoch) 527 } 528 529 func computeProposalBindingInternal(nonce, creator []byte, epoch uint64) ([]byte, error) { 530 epochBytes := make([]byte, 8) 531 binary.LittleEndian.PutUint64(epochBytes, epoch) 532 533 // TODO: add to genesis block the hash function used for the binding computation. 534 return factory.GetDefault().Hash( 535 append(append(nonce, creator...), epochBytes...), 536 &bccsp.SHA256Opts{}) 537 }