Skip to content

Commit

Permalink
Refactor: remove fabric import "github.com/hyperledger/fabric/protout…
Browse files Browse the repository at this point in the history
…il".

Signed-off-by: yiwenlong <wlong.yi@gmail.com>
  • Loading branch information
yiwenlong authored and guoger committed Mar 27, 2021
1 parent fc69023 commit 052c718
Show file tree
Hide file tree
Showing 5 changed files with 725 additions and 1 deletion.
137 changes: 137 additions & 0 deletions fabric/protoutil/commonutils.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
/*
Copyright IBM Corp. All Rights Reserved.
SPDX-License-Identifier: Apache-2.0
*/

package protoutil

import (
"crypto/rand"
"time"

"github.com/golang/protobuf/proto"
"github.com/golang/protobuf/ptypes/timestamp"
cb "github.com/hyperledger/fabric-protos-go/common"
"github.com/pkg/errors"
)

// MarshalOrPanic serializes a protobuf message and panics if this
// operation fails
func MarshalOrPanic(pb proto.Message) []byte {
data, err := proto.Marshal(pb)
if err != nil {
panic(err)
}
return data
}

// Marshal serializes a protobuf message.
func Marshal(pb proto.Message) ([]byte, error) {
return proto.Marshal(pb)
}

// CreateNonce generates a nonce using the common/crypto package.
func CreateNonce() ([]byte, error) {
nonce, err := getRandomNonce()
return nonce, errors.WithMessage(err, "error generating random nonce")
}

// ExtractEnvelope retrieves the requested envelope from a given block and
// unmarshals it
func ExtractEnvelope(block *cb.Block, index int) (*cb.Envelope, error) {
if block.Data == nil {
return nil, errors.New("block data is nil")
}

envelopeCount := len(block.Data.Data)
if index < 0 || index >= envelopeCount {
return nil, errors.New("envelope index out of bounds")
}
marshaledEnvelope := block.Data.Data[index]
envelope, err := GetEnvelopeFromBlock(marshaledEnvelope)
err = errors.WithMessagef(err, "block data does not carry an envelope at index %d", index)
return envelope, err
}

// MakeChannelHeader creates a ChannelHeader.
func MakeChannelHeader(headerType cb.HeaderType, version int32, chainID string, epoch uint64) *cb.ChannelHeader {
return &cb.ChannelHeader{
Type: int32(headerType),
Version: version,
Timestamp: &timestamp.Timestamp{
Seconds: time.Now().Unix(),
Nanos: 0,
},
ChannelId: chainID,
Epoch: epoch,
}
}

// MakePayloadHeader creates a Payload Header.
func MakePayloadHeader(ch *cb.ChannelHeader, sh *cb.SignatureHeader) *cb.Header {
return &cb.Header{
ChannelHeader: MarshalOrPanic(ch),
SignatureHeader: MarshalOrPanic(sh),
}
}

// NewSignatureHeader returns a SignatureHeader with a valid nonce.
func NewSignatureHeader(id Signer) (*cb.SignatureHeader, error) {
creator, err := id.Serialize()
if err != nil {
return nil, err
}
nonce, err := CreateNonce()
if err != nil {
return nil, err
}

return &cb.SignatureHeader{
Creator: creator,
Nonce: nonce,
}, nil
}

// ChannelHeader returns the *cb.ChannelHeader for a given *cb.Envelope.
func ChannelHeader(env *cb.Envelope) (*cb.ChannelHeader, error) {
envPayload, err := UnmarshalPayload(env.Payload)
if err != nil {
return nil, err
}

if envPayload.Header == nil {
return nil, errors.New("header not set")
}

if envPayload.Header.ChannelHeader == nil {
return nil, errors.New("channel header not set")
}

chdr, err := UnmarshalChannelHeader(envPayload.Header.ChannelHeader)
if err != nil {
return nil, errors.WithMessage(err, "error unmarshaling channel header")
}

return chdr, nil
}

// ChannelID returns the Channel ID for a given *cb.Envelope.
func ChannelID(env *cb.Envelope) (string, error) {
chdr, err := ChannelHeader(env)
if err != nil {
return "", errors.WithMessage(err, "error retrieving channel header")
}

return chdr.ChannelId, nil
}

func getRandomNonce() ([]byte, error) {
key := make([]byte, 24)

_, err := rand.Read(key)
if err != nil {
return nil, errors.Wrap(err, "error getting random bytes")
}
return key, nil
}
162 changes: 162 additions & 0 deletions fabric/protoutil/proputils.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
/*
Copyright IBM Corp. All Rights Reserved.
SPDX-License-Identifier: Apache-2.0
*/

package protoutil

import (
"crypto/sha256"
"encoding/hex"
"time"

"github.com/golang/protobuf/proto"
"github.com/golang/protobuf/ptypes"
"github.com/hyperledger/fabric-protos-go/common"
"github.com/hyperledger/fabric-protos-go/peer"
"github.com/pkg/errors"
)

// CreateChaincodeProposal creates a proposal from given input.
// It returns the proposal and the transaction id associated to the proposal
func CreateChaincodeProposal(typ common.HeaderType, channelID string, cis *peer.ChaincodeInvocationSpec, creator []byte) (*peer.Proposal, string, error) {
return CreateChaincodeProposalWithTransient(typ, channelID, cis, creator, nil)
}

// CreateChaincodeProposalWithTransient creates a proposal from given input
// It returns the proposal and the transaction id associated to the proposal
func CreateChaincodeProposalWithTransient(typ common.HeaderType, channelID string, cis *peer.ChaincodeInvocationSpec, creator []byte, transientMap map[string][]byte) (*peer.Proposal, string, error) {
// generate a random nonce
nonce, err := getRandomNonce()
if err != nil {
return nil, "", err
}

// compute txid
txid := ComputeTxID(nonce, creator)

return CreateChaincodeProposalWithTxIDNonceAndTransient(txid, typ, channelID, cis, nonce, creator, transientMap)
}

// CreateChaincodeProposalWithTxIDNonceAndTransient creates a proposal from
// given input
func CreateChaincodeProposalWithTxIDNonceAndTransient(txid string, typ common.HeaderType, channelID string, cis *peer.ChaincodeInvocationSpec, nonce, creator []byte, transientMap map[string][]byte) (*peer.Proposal, string, error) {
ccHdrExt := &peer.ChaincodeHeaderExtension{ChaincodeId: cis.ChaincodeSpec.ChaincodeId}
ccHdrExtBytes, err := proto.Marshal(ccHdrExt)
if err != nil {
return nil, "", errors.Wrap(err, "error marshaling ChaincodeHeaderExtension")
}

cisBytes, err := proto.Marshal(cis)
if err != nil {
return nil, "", errors.Wrap(err, "error marshaling ChaincodeInvocationSpec")
}

ccPropPayload := &peer.ChaincodeProposalPayload{Input: cisBytes, TransientMap: transientMap}
ccPropPayloadBytes, err := proto.Marshal(ccPropPayload)
if err != nil {
return nil, "", errors.Wrap(err, "error marshaling ChaincodeProposalPayload")
}

// TODO: epoch is now set to zero. This must be changed once we
// get a more appropriate mechanism to handle it in.
var epoch uint64

timestamp, err := ptypes.TimestampProto(time.Now().UTC())
if err != nil {
return nil, "", errors.Wrap(err, "error validating Timestamp")
}

hdr := &common.Header{
ChannelHeader: MarshalOrPanic(
&common.ChannelHeader{
Type: int32(typ),
TxId: txid,
Timestamp: timestamp,
ChannelId: channelID,
Extension: ccHdrExtBytes,
Epoch: epoch,
},
),
SignatureHeader: MarshalOrPanic(
&common.SignatureHeader{
Nonce: nonce,
Creator: creator,
},
),
}

hdrBytes, err := proto.Marshal(hdr)
if err != nil {
return nil, "", err
}

prop := &peer.Proposal{
Header: hdrBytes,
Payload: ccPropPayloadBytes,
}
return prop, txid, nil
}

// GetBytesProposalResponsePayload gets proposal response payload
func GetBytesProposalResponsePayload(hash []byte, response *peer.Response, result []byte, event []byte, ccid *peer.ChaincodeID) ([]byte, error) {
cAct := &peer.ChaincodeAction{
Events: event, Results: result,
Response: response,
ChaincodeId: ccid,
}
cActBytes, err := proto.Marshal(cAct)
if err != nil {
return nil, errors.Wrap(err, "error marshaling ChaincodeAction")
}

prp := &peer.ProposalResponsePayload{
Extension: cActBytes,
ProposalHash: hash,
}
prpBytes, err := proto.Marshal(prp)
return prpBytes, errors.Wrap(err, "error marshaling ProposalResponsePayload")
}

// GetBytesChaincodeProposalPayload gets the chaincode proposal payload
func GetBytesChaincodeProposalPayload(cpp *peer.ChaincodeProposalPayload) ([]byte, error) {
cppBytes, err := proto.Marshal(cpp)
return cppBytes, errors.Wrap(err, "error marshaling ChaincodeProposalPayload")
}

// GetBytesChaincodeActionPayload get the bytes of ChaincodeActionPayload from
// the message
func GetBytesChaincodeActionPayload(cap *peer.ChaincodeActionPayload) ([]byte, error) {
capBytes, err := proto.Marshal(cap)
return capBytes, errors.Wrap(err, "error marshaling ChaincodeActionPayload")
}

// GetBytesTransaction get the bytes of Transaction from the message
func GetBytesTransaction(tx *peer.Transaction) ([]byte, error) {
bytes, err := proto.Marshal(tx)
return bytes, errors.Wrap(err, "error unmarshaling Transaction")
}

// GetBytesPayload get the bytes of Payload from the message
func GetBytesPayload(payl *common.Payload) ([]byte, error) {
bytes, err := proto.Marshal(payl)
return bytes, errors.Wrap(err, "error marshaling Payload")
}

// CreateProposalFromCIS returns a proposal given a serialized identity and a
// ChaincodeInvocationSpec
func CreateProposalFromCIS(typ common.HeaderType, channelID string, cis *peer.ChaincodeInvocationSpec, creator []byte) (*peer.Proposal, string, error) {
return CreateChaincodeProposal(typ, channelID, cis, creator)
}

// ComputeTxID computes TxID as the Hash computed
// over the concatenation of nonce and creator.
func ComputeTxID(nonce, creator []byte) string {
// TODO: Get the Hash function to be used from
// channel configuration
hasher := sha256.New()
hasher.Write(nonce)
hasher.Write(creator)
return hex.EncodeToString(hasher.Sum(nil))
}
Loading

0 comments on commit 052c718

Please sign in to comment.