1 Star 0 Fork 0

妥協/fabric

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
文件
克隆/下载
txutils.go 13.66 KB
一键复制 编辑 原始数据 按行查看 历史
Will Lahti 提交于 2018-07-19 16:36 . FAB-11123 Remove EventHub from peer
/*
Copyright IBM Corp. All Rights Reserved.
SPDX-License-Identifier: Apache-2.0
*/
package utils
import (
"fmt"
"bytes"
"github.com/golang/protobuf/proto"
"github.com/hyperledger/fabric/bccsp"
"github.com/hyperledger/fabric/bccsp/factory"
"github.com/hyperledger/fabric/common/crypto"
"github.com/hyperledger/fabric/msp"
"github.com/hyperledger/fabric/protos/common"
"github.com/hyperledger/fabric/protos/peer"
"github.com/pkg/errors"
)
// GetPayloads gets the underlying payload objects in a TransactionAction
func GetPayloads(txActions *peer.TransactionAction) (*peer.ChaincodeActionPayload, *peer.ChaincodeAction, error) {
// TODO: pass in the tx type (in what follows we're assuming the
// type is ENDORSER_TRANSACTION)
ccPayload, err := GetChaincodeActionPayload(txActions.Payload)
if err != nil {
return nil, nil, err
}
if ccPayload.Action == nil || ccPayload.Action.ProposalResponsePayload == nil {
return nil, nil, errors.New("no payload in ChaincodeActionPayload")
}
pRespPayload, err := GetProposalResponsePayload(ccPayload.Action.ProposalResponsePayload)
if err != nil {
return nil, nil, err
}
if pRespPayload.Extension == nil {
return nil, nil, errors.New("response payload is missing extension")
}
respPayload, err := GetChaincodeAction(pRespPayload.Extension)
if err != nil {
return ccPayload, nil, err
}
return ccPayload, respPayload, nil
}
// GetEnvelopeFromBlock gets an envelope from a block's Data field.
func GetEnvelopeFromBlock(data []byte) (*common.Envelope, error) {
// Block always begins with an envelope
var err error
env := &common.Envelope{}
if err = proto.Unmarshal(data, env); err != nil {
return nil, errors.Wrap(err, "error unmarshaling Envelope")
}
return env, nil
}
// CreateSignedEnvelope creates a signed envelope of the desired type, with
// marshaled dataMsg and signs it
func CreateSignedEnvelope(txType common.HeaderType, channelID string, signer crypto.LocalSigner, dataMsg proto.Message, msgVersion int32, epoch uint64) (*common.Envelope, error) {
return CreateSignedEnvelopeWithTLSBinding(txType, channelID, signer, dataMsg, msgVersion, epoch, nil)
}
// CreateSignedEnvelopeWithTLSBinding creates a signed envelope of the desired
// type, with marshaled dataMsg and signs it. It also includes a TLS cert hash
// into the channel header
func CreateSignedEnvelopeWithTLSBinding(txType common.HeaderType, channelID string, signer crypto.LocalSigner, dataMsg proto.Message, msgVersion int32, epoch uint64, tlsCertHash []byte) (*common.Envelope, error) {
payloadChannelHeader := MakeChannelHeader(txType, msgVersion, channelID, epoch)
payloadChannelHeader.TlsCertHash = tlsCertHash
var err error
payloadSignatureHeader := &common.SignatureHeader{}
if signer != nil {
payloadSignatureHeader, err = signer.NewSignatureHeader()
if err != nil {
return nil, err
}
}
data, err := proto.Marshal(dataMsg)
if err != nil {
return nil, errors.Wrap(err, "error marshaling")
}
paylBytes := MarshalOrPanic(
&common.Payload{
Header: MakePayloadHeader(payloadChannelHeader, payloadSignatureHeader),
Data: data,
},
)
var sig []byte
if signer != nil {
sig, err = signer.Sign(paylBytes)
if err != nil {
return nil, err
}
}
env := &common.Envelope{
Payload: paylBytes,
Signature: sig,
}
return env, nil
}
// CreateSignedTx assembles an Envelope message from proposal, endorsements,
// and a signer. This function should be called by a client when it has
// collected enough endorsements for a proposal to create a transaction and
// submit it to peers for ordering
func CreateSignedTx(proposal *peer.Proposal, signer msp.SigningIdentity, resps ...*peer.ProposalResponse) (*common.Envelope, error) {
if len(resps) == 0 {
return nil, errors.New("at least one proposal response is required")
}
// the original header
hdr, err := GetHeader(proposal.Header)
if err != nil {
return nil, err
}
// the original payload
pPayl, err := GetChaincodeProposalPayload(proposal.Payload)
if err != nil {
return nil, err
}
// check that the signer is the same that is referenced in the header
// TODO: maybe worth removing?
signerBytes, err := signer.Serialize()
if err != nil {
return nil, err
}
shdr, err := GetSignatureHeader(hdr.SignatureHeader)
if err != nil {
return nil, err
}
if bytes.Compare(signerBytes, shdr.Creator) != 0 {
return nil, errors.New("signer must be the same as the one referenced in the header")
}
// get header extensions so we have the visibility field
hdrExt, err := GetChaincodeHeaderExtension(hdr)
if err != nil {
return nil, err
}
// ensure that all actions are bitwise equal and that they are successful
var a1 []byte
for n, r := range resps {
if n == 0 {
a1 = r.Payload
if r.Response.Status != 200 {
return nil, errors.Errorf("proposal response was not successful, error code %d, msg %s", r.Response.Status, r.Response.Message)
}
continue
}
if bytes.Compare(a1, r.Payload) != 0 {
return nil, errors.New("ProposalResponsePayloads do not match")
}
}
// fill endorsements
endorsements := make([]*peer.Endorsement, len(resps))
for n, r := range resps {
endorsements[n] = r.Endorsement
}
// create ChaincodeEndorsedAction
cea := &peer.ChaincodeEndorsedAction{ProposalResponsePayload: resps[0].Payload, Endorsements: endorsements}
// obtain the bytes of the proposal payload that will go to the transaction
propPayloadBytes, err := GetBytesProposalPayloadForTx(pPayl, hdrExt.PayloadVisibility)
if err != nil {
return nil, err
}
// serialize the chaincode action payload
cap := &peer.ChaincodeActionPayload{ChaincodeProposalPayload: propPayloadBytes, Action: cea}
capBytes, err := GetBytesChaincodeActionPayload(cap)
if err != nil {
return nil, err
}
// create a transaction
taa := &peer.TransactionAction{Header: hdr.SignatureHeader, Payload: capBytes}
taas := make([]*peer.TransactionAction, 1)
taas[0] = taa
tx := &peer.Transaction{Actions: taas}
// serialize the tx
txBytes, err := GetBytesTransaction(tx)
if err != nil {
return nil, err
}
// create the payload
payl := &common.Payload{Header: hdr, Data: txBytes}
paylBytes, err := GetBytesPayload(payl)
if err != nil {
return nil, err
}
// sign the payload
sig, err := signer.Sign(paylBytes)
if err != nil {
return nil, err
}
// here's the envelope
return &common.Envelope{Payload: paylBytes, Signature: sig}, nil
}
// CreateProposalResponse creates a proposal response.
func CreateProposalResponse(hdrbytes []byte, payl []byte, response *peer.Response, results []byte, events []byte, ccid *peer.ChaincodeID, visibility []byte, signingEndorser msp.SigningIdentity) (*peer.ProposalResponse, error) {
hdr, err := GetHeader(hdrbytes)
if err != nil {
return nil, err
}
// obtain the proposal hash given proposal header, payload and the
// requested visibility
pHashBytes, err := GetProposalHash1(hdr, payl, visibility)
if err != nil {
return nil, errors.WithMessage(err, "error computing proposal hash")
}
// get the bytes of the proposal response payload - we need to sign them
prpBytes, err := GetBytesProposalResponsePayload(pHashBytes, response, results, events, ccid)
if err != nil {
return nil, err
}
// serialize the signing identity
endorser, err := signingEndorser.Serialize()
if err != nil {
return nil, errors.WithMessage(err, fmt.Sprintf("error serializing signing identity for %s", signingEndorser.GetIdentifier()))
}
// sign the concatenation of the proposal response and the serialized
// endorser identity with this endorser's key
signature, err := signingEndorser.Sign(append(prpBytes, endorser...))
if err != nil {
return nil, errors.WithMessage(err, "could not sign the proposal response payload")
}
resp := &peer.ProposalResponse{
// Timestamp: TODO!
Version: 1, // TODO: pick right version number
Endorsement: &peer.Endorsement{
Signature: signature,
Endorser: endorser,
},
Payload: prpBytes,
Response: &peer.Response{
Status: 200,
Message: "OK",
},
}
return resp, nil
}
// CreateProposalResponseFailure creates a proposal response for cases where
// endorsement proposal fails either due to a endorsement failure or a
// chaincode failure (chaincode response status >= shim.ERRORTHRESHOLD)
func CreateProposalResponseFailure(hdrbytes []byte, payl []byte, response *peer.Response, results []byte, events []byte, ccid *peer.ChaincodeID, visibility []byte) (*peer.ProposalResponse, error) {
hdr, err := GetHeader(hdrbytes)
if err != nil {
return nil, err
}
// obtain the proposal hash given proposal header, payload and the requested visibility
pHashBytes, err := GetProposalHash1(hdr, payl, visibility)
if err != nil {
return nil, errors.WithMessage(err, "error computing proposal hash")
}
// get the bytes of the proposal response payload
prpBytes, err := GetBytesProposalResponsePayload(pHashBytes, response, results, events, ccid)
if err != nil {
return nil, err
}
resp := &peer.ProposalResponse{
// Timestamp: TODO!
Payload: prpBytes,
Response: response,
}
return resp, nil
}
// GetSignedProposal returns a signed proposal given a Proposal message and a
// signing identity
func GetSignedProposal(prop *peer.Proposal, signer msp.SigningIdentity) (*peer.SignedProposal, error) {
// check for nil argument
if prop == nil || signer == nil {
return nil, errors.New("nil arguments")
}
propBytes, err := GetBytesProposal(prop)
if err != nil {
return nil, err
}
signature, err := signer.Sign(propBytes)
if err != nil {
return nil, err
}
return &peer.SignedProposal{ProposalBytes: propBytes, Signature: signature}, nil
}
// MockSignedEndorserProposalOrPanic creates a SignedProposal with the
// passed arguments
func MockSignedEndorserProposalOrPanic(chainID string, cs *peer.ChaincodeSpec, creator, signature []byte) (*peer.SignedProposal, *peer.Proposal) {
prop, _, err := CreateChaincodeProposal(
common.HeaderType_ENDORSER_TRANSACTION,
chainID,
&peer.ChaincodeInvocationSpec{ChaincodeSpec: cs},
creator)
if err != nil {
panic(err)
}
propBytes, err := GetBytesProposal(prop)
if err != nil {
panic(err)
}
return &peer.SignedProposal{ProposalBytes: propBytes, Signature: signature}, prop
}
func MockSignedEndorserProposal2OrPanic(chainID string, cs *peer.ChaincodeSpec, signer msp.SigningIdentity) (*peer.SignedProposal, *peer.Proposal) {
serializedSigner, err := signer.Serialize()
if err != nil {
panic(err)
}
prop, _, err := CreateChaincodeProposal(
common.HeaderType_ENDORSER_TRANSACTION,
chainID,
&peer.ChaincodeInvocationSpec{ChaincodeSpec: &peer.ChaincodeSpec{}},
serializedSigner)
if err != nil {
panic(err)
}
sProp, err := GetSignedProposal(prop, signer)
if err != nil {
panic(err)
}
return sProp, prop
}
// GetBytesProposalPayloadForTx takes a ChaincodeProposalPayload and returns
// its serialized version according to the visibility field
func GetBytesProposalPayloadForTx(payload *peer.ChaincodeProposalPayload, visibility []byte) ([]byte, error) {
// check for nil argument
if payload == nil {
return nil, errors.New("nil arguments")
}
// strip the transient bytes off the payload - this needs to be done no
// matter the visibility mode
cppNoTransient := &peer.ChaincodeProposalPayload{Input: payload.Input, TransientMap: nil}
cppBytes, err := GetBytesChaincodeProposalPayload(cppNoTransient)
if err != nil {
return nil, err
}
// currently the fabric only supports full visibility: this means that
// there are no restrictions on which parts of the proposal payload will
// be visible in the final transaction; this default approach requires
// no additional instructions in the PayloadVisibility field; however
// the fabric may be extended to encode more elaborate visibility
// mechanisms that shall be encoded in this field (and handled
// appropriately by the peer)
return cppBytes, nil
}
// GetProposalHash2 gets the proposal hash - this version
// is called by the committer where the visibility policy
// has already been enforced and so we already get what
// we have to get in ccPropPayl
func GetProposalHash2(header *common.Header, ccPropPayl []byte) ([]byte, error) {
// check for nil argument
if header == nil ||
header.ChannelHeader == nil ||
header.SignatureHeader == nil ||
ccPropPayl == nil {
return nil, errors.New("nil arguments")
}
hash, err := factory.GetDefault().GetHash(&bccsp.SHA256Opts{})
if err != nil {
return nil, errors.WithMessage(err, "error instantiating hash function")
}
// hash the serialized Channel Header object
hash.Write(header.ChannelHeader)
// hash the serialized Signature Header object
hash.Write(header.SignatureHeader)
// hash the bytes of the chaincode proposal payload that we are given
hash.Write(ccPropPayl)
return hash.Sum(nil), nil
}
// GetProposalHash1 gets the proposal hash bytes after sanitizing the
// chaincode proposal payload according to the rules of visibility
func GetProposalHash1(header *common.Header, ccPropPayl []byte, visibility []byte) ([]byte, error) {
// check for nil argument
if header == nil ||
header.ChannelHeader == nil ||
header.SignatureHeader == nil ||
ccPropPayl == nil {
return nil, errors.New("nil arguments")
}
// unmarshal the chaincode proposal payload
cpp, err := GetChaincodeProposalPayload(ccPropPayl)
if err != nil {
return nil, err
}
ppBytes, err := GetBytesProposalPayloadForTx(cpp, visibility)
if err != nil {
return nil, err
}
hash2, err := factory.GetDefault().GetHash(&bccsp.SHA256Opts{})
if err != nil {
return nil, errors.WithMessage(err, "error instantiating hash function")
}
// hash the serialized Channel Header object
hash2.Write(header.ChannelHeader)
// hash the serialized Signature Header object
hash2.Write(header.SignatureHeader)
// hash of the part of the chaincode proposal payload that will go to the tx
hash2.Write(ppBytes)
return hash2.Sum(nil), nil
}
Loading...
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
1
https://gitee.com/liurenhao/fabric.git
git@gitee.com:liurenhao/fabric.git
liurenhao
fabric
fabric
v1.3.0

搜索帮助