github.com/inklabsfoundation/inkchain@v0.17.1-0.20181025012015-c3cef8062f19/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/inklabsfoundation/inkchain/bccsp" 29 "github.com/inklabsfoundation/inkchain/bccsp/factory" 30 "github.com/inklabsfoundation/inkchain/common/crypto" 31 "github.com/inklabsfoundation/inkchain/common/util" 32 "github.com/inklabsfoundation/inkchain/core/chaincode/platforms" 33 "github.com/inklabsfoundation/inkchain/protos/common" 34 "github.com/inklabsfoundation/inkchain/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.ChaincodeInvocationSpec, *peer.ChaincodeAction, error) { 395 env, err := GetEnvelopeFromBlock(envBytes) 396 if err != nil { 397 return nil, nil, err 398 } 399 400 payl, err := GetPayload(env) 401 if err != nil { 402 return nil, nil, err 403 } 404 405 tx, err := GetTransaction(payl.Data) 406 if err != nil { 407 return nil, nil, err 408 } 409 410 if len(tx.Actions) == 0 { 411 return nil, nil, fmt.Errorf("At least one TransactionAction is required") 412 } 413 ccPayload, respPayload, err := GetPayloads(tx.Actions[0]) 414 415 cpp, err := GetChaincodeProposalPayload(ccPayload.ChaincodeProposalPayload) 416 if err != nil { 417 return nil, nil, fmt.Errorf("GetChaincodeProposalPayload failed") 418 } 419 420 cis := &peer.ChaincodeInvocationSpec{} 421 err = proto.Unmarshal(cpp.Input, cis) 422 if err != nil { 423 return nil, nil, fmt.Errorf("Unmarshal ChaincodeInvocationSpec failed") 424 } 425 return cis, respPayload, err 426 } 427 428 func GetActionFromEnvelopeProp(env *common.Envelope) (*peer.ChaincodeInvocationSpec, *peer.ChaincodeAction, error) { 429 430 payl, err := GetPayload(env) 431 if err != nil { 432 return nil, nil, err 433 } 434 435 tx, err := GetTransaction(payl.Data) 436 if err != nil { 437 return nil, nil, err 438 } 439 440 if len(tx.Actions) == 0 { 441 return nil, nil, fmt.Errorf("At least one TransactionAction is required") 442 } 443 ccPayload, respPayload, err := GetPayloads(tx.Actions[0]) 444 445 cpp, err := GetChaincodeProposalPayload(ccPayload.ChaincodeProposalPayload) 446 if err != nil { 447 return nil, nil, fmt.Errorf("GetChaincodeProposalPayload failed") 448 } 449 450 cis := &peer.ChaincodeInvocationSpec{} 451 err = proto.Unmarshal(cpp.Input, cis) 452 if err != nil { 453 return nil, nil, fmt.Errorf("Unmarshal ChaincodeInvocationSpec failed") 454 } 455 return cis, respPayload, err 456 } 457 458 func GetActionFromEnvelopePayload(payloadBytes []byte) (*peer.ChaincodeInvocationSpec, *peer.ChaincodeAction, error) { 459 payl := &common.Payload{} 460 err := proto.Unmarshal(payloadBytes, payl) 461 if err != nil { 462 return nil, nil, err 463 } 464 465 tx, err := GetTransaction(payl.Data) 466 if err != nil { 467 return nil, nil, err 468 } 469 470 if len(tx.Actions) == 0 { 471 return nil, nil, fmt.Errorf("At least one TransactionAction is required") 472 } 473 ccPayload, respPayload, err := GetPayloads(tx.Actions[0]) 474 if ccPayload == nil { 475 return nil, nil, fmt.Errorf("nil ChaincodeProposalPayload") 476 } 477 cpp, err := GetChaincodeProposalPayload(ccPayload.ChaincodeProposalPayload) 478 if err != nil { 479 return nil, nil, fmt.Errorf("GetChaincodeProposalPayload failed") 480 } 481 482 cis := &peer.ChaincodeInvocationSpec{} 483 err = proto.Unmarshal(cpp.Input, cis) 484 if err != nil { 485 return nil, nil, fmt.Errorf("Unmarshal ChaincodeInvocationSpec failed") 486 } 487 return cis, respPayload, err 488 } 489 490 func GetChaincodeInvocationSpecFromSignedProposal(proposal *peer.Proposal) (*peer.ChaincodeInvocationSpec, error) { 491 cpp, err := GetChaincodeProposalPayload(proposal.Payload) 492 if err != nil { 493 return nil, fmt.Errorf("GetChaincodeInvocationSpecFromProposal failed") 494 } 495 cis := &peer.ChaincodeInvocationSpec{} 496 err = proto.Unmarshal(cpp.Input, cis) 497 if err != nil { 498 return nil, fmt.Errorf("GetChaincodeInvocationSpecFromProposal failed") 499 } 500 return cis, nil 501 } 502 503 // CreateProposalFromCIS returns a proposal given a serialized identity and a ChaincodeInvocationSpec 504 func CreateProposalFromCIS(typ common.HeaderType, chainID string, cis *peer.ChaincodeInvocationSpec, creator []byte) (*peer.Proposal, string, error) { 505 return CreateChaincodeProposal(typ, chainID, cis, creator) 506 } 507 508 // CreateInstallProposalFromCDS returns a install proposal given a serialized identity and a ChaincodeDeploymentSpec 509 func CreateInstallProposalFromCDS(ccpack proto.Message, creator []byte) (*peer.Proposal, string, error) { 510 return createProposalFromCDS("", ccpack, creator, nil, nil, nil, "install") 511 } 512 513 // CreateDeployProposalFromCDS returns a deploy proposal given a serialized identity and a ChaincodeDeploymentSpec 514 func CreateDeployProposalFromCDS(chainID string, cds *peer.ChaincodeDeploymentSpec, creator []byte, policy []byte, escc []byte, vscc []byte) (*peer.Proposal, string, error) { 515 return createProposalFromCDS(chainID, cds, creator, policy, escc, vscc, "deploy") 516 } 517 518 // CreateUpgradeProposalFromCDS returns a upgrade proposal given a serialized identity and a ChaincodeDeploymentSpec 519 func CreateUpgradeProposalFromCDS(chainID string, cds *peer.ChaincodeDeploymentSpec, creator []byte, policy []byte, escc []byte, vscc []byte) (*peer.Proposal, string, error) { 520 return createProposalFromCDS(chainID, cds, creator, policy, escc, vscc, "upgrade") 521 } 522 523 // createProposalFromCDS returns a deploy or upgrade proposal given a serialized identity and a ChaincodeDeploymentSpec 524 func createProposalFromCDS(chainID string, msg proto.Message, creator []byte, policy []byte, escc []byte, vscc []byte, propType string) (*peer.Proposal, string, error) { 525 //in the new mode, cds will be nil, "deploy" and "upgrade" are instantiates. 526 var ccinp *peer.ChaincodeInput 527 var b []byte 528 var err error 529 if msg != nil { 530 b, err = proto.Marshal(msg) 531 if err != nil { 532 return nil, "", err 533 } 534 } 535 switch propType { 536 case "deploy": 537 fallthrough 538 case "upgrade": 539 cds, ok := msg.(*peer.ChaincodeDeploymentSpec) 540 if !ok || cds == nil { 541 return nil, "", fmt.Errorf("invalid message for creating lifecycle chaincode proposal from") 542 } 543 ccinp = &peer.ChaincodeInput{Args: [][]byte{[]byte(propType), []byte(chainID), b, policy, escc, vscc}} 544 case "install": 545 ccinp = &peer.ChaincodeInput{Args: [][]byte{[]byte(propType), b}} 546 } 547 548 //wrap the deployment in an invocation spec to lscc... 549 lsccSpec := &peer.ChaincodeInvocationSpec{ 550 ChaincodeSpec: &peer.ChaincodeSpec{ 551 Type: peer.ChaincodeSpec_GOLANG, 552 ChaincodeId: &peer.ChaincodeID{Name: "lscc"}, 553 Input: ccinp}} 554 555 //...and get the proposal for it 556 return CreateProposalFromCIS(common.HeaderType_ENDORSER_TRANSACTION, chainID, lsccSpec, creator) 557 } 558 559 // ComputeProposalTxID computes TxID as the Hash computed 560 // over the concatenation of nonce and creator. 561 func ComputeProposalTxID(nonce, creator []byte) (string, error) { 562 // TODO: Get the Hash function to be used from 563 // channel configuration 564 digest, err := factory.GetDefault().Hash( 565 append(nonce, creator...), 566 &bccsp.SHA256Opts{}) 567 if err != nil { 568 return "", err 569 } 570 return hex.EncodeToString(digest), nil 571 } 572 573 // CheckProposalTxID checks that txid is equal to the Hash computed 574 // over the concatenation of nonce and creator. 575 func CheckProposalTxID(txid string, nonce, creator []byte) error { 576 computedTxID, err := ComputeProposalTxID(nonce, creator) 577 if err != nil { 578 return fmt.Errorf("Failed computing target TXID for comparison [%s]", err) 579 } 580 581 if txid != computedTxID { 582 return fmt.Errorf("Transaction is not valid. Got [%s], expected [%s]", txid, computedTxID) 583 } 584 585 return nil 586 } 587 588 // ComputeProposalBinding computes the binding of a proposal 589 func ComputeProposalBinding(proposal *peer.Proposal) ([]byte, error) { 590 if proposal == nil { 591 return nil, fmt.Errorf("Porposal is nil") 592 } 593 if len(proposal.Header) == 0 { 594 return nil, fmt.Errorf("Proposal's Header is nil") 595 } 596 597 h, err := GetHeader(proposal.Header) 598 if err != nil { 599 return nil, err 600 } 601 602 chdr, err := UnmarshalChannelHeader(h.ChannelHeader) 603 if err != nil { 604 return nil, err 605 } 606 shdr, err := GetSignatureHeader(h.SignatureHeader) 607 if err != nil { 608 return nil, err 609 } 610 611 return computeProposalBindingInternal(shdr.Nonce, shdr.Creator, chdr.Epoch) 612 } 613 614 func computeProposalBindingInternal(nonce, creator []byte, epoch uint64) ([]byte, error) { 615 epochBytes := make([]byte, 8) 616 binary.LittleEndian.PutUint64(epochBytes, epoch) 617 618 // TODO: add to genesis block the hash function used for the binding computation. 619 return factory.GetDefault().Hash( 620 append(append(nonce, creator...), epochBytes...), 621 &bccsp.SHA256Opts{}) 622 }