Skip to content

Commit

Permalink
[FAB-8422] Refactor broadcast to sign proposal
Browse files Browse the repository at this point in the history
This change moves signing of broadcasts to the
broadcast method.

Change-Id: I0af49bcce888c8213baeb372fa0f6444c3baf6c5
Signed-off-by: Troy Ronda <troy@troyronda.com>
  • Loading branch information
troyronda committed Feb 21, 2018
1 parent ef2097c commit eb9db60
Show file tree
Hide file tree
Showing 6 changed files with 146 additions and 155 deletions.
4 changes: 0 additions & 4 deletions api/apifabclient/resource.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,10 +40,6 @@ type CreateChannelRequest struct {
// required by the channel create policy when using the `config` parameter.
// see signChannelConfig() method of this package
Signatures []*common.ConfigSignature

// TODO: InvokeChannelRequest allows the TransactionID to be passed in.
// This request struct also has the field for consistency but perhaps it should be removed.
TxnID TransactionID
}

// InstallChaincodeRequest requests chaincode installation on the network
Expand Down
14 changes: 2 additions & 12 deletions pkg/fabric-client/channel/block.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,22 +71,12 @@ func (c *Channel) block(pos *ab.SeekPosition) (*common.Block, error) {
return nil, errors.Wrap(err, "marshal seek info failed")
}

seekPayload := &common.Payload{
payload := common.Payload{
Header: seekHeader,
Data: seekInfoBytes,
}

seekPayloadBytes, err := proto.Marshal(seekPayload)
if err != nil {
return nil, err
}

signedEnvelope, err := txn.SignPayload(c.clientContext, seekPayloadBytes)
if err != nil {
return nil, errors.WithMessage(err, "SignPayload failed")
}

return txn.SendEnvelope(c.clientContext, signedEnvelope, c.Orderers())
return txn.SendPayload(c.clientContext, &payload, c.Orderers())
}

// newNewestSeekPosition returns a SeekPosition that requests the newest block
Expand Down
181 changes: 75 additions & 106 deletions pkg/fabric-client/resource/resource.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ import (
"github.com/hyperledger/fabric-sdk-go/pkg/logging"
"github.com/hyperledger/fabric-sdk-go/third_party/github.com/hyperledger/fabric/protos/common"
pb "github.com/hyperledger/fabric-sdk-go/third_party/github.com/hyperledger/fabric/protos/peer"
protos_utils "github.com/hyperledger/fabric-sdk-go/third_party/github.com/hyperledger/fabric/protos/utils"
)

var logger = logging.NewLogger("fabric_sdk_go")
Expand Down Expand Up @@ -70,21 +69,47 @@ func (c *Resource) SignChannelConfig(config []byte, signer fab.IdentityContext)

// CreateChannel calls the orderer to start building the new channel.
func (c *Resource) CreateChannel(request fab.CreateChannelRequest) (fab.TransactionID, error) {
haveEnvelope := false
if request.Orderer == nil {
return fab.TransactionID{}, errors.New("missing orderer request parameter for the initialize channel")
}

if request.Name == "" {
return fab.TransactionID{}, errors.New("missing name request parameter for the new channel")
}

if request.Envelope != nil {
logger.Debug("createChannel - have envelope")
haveEnvelope = true
return c.createChannelFromEnvelope(request)
}

if !haveEnvelope && request.TxnID.ID == "" {
txnID, err := txn.NewID(c.clientContext)
if err != nil {
return txnID, err
}
request.TxnID = txnID
if request.Config == nil {
return fab.TransactionID{}, errors.New("missing envelope request parameter containing the configuration of the new channel")
}

return request.TxnID, c.createOrUpdateChannel(request, haveEnvelope)
if request.Signatures == nil {
return fab.TransactionID{}, errors.New("missing signatures request parameter for the new channel")
}

txnID, err := txn.NewID(c.clientContext)
if err != nil {
return txnID, err
}

return txnID, c.createOrUpdateChannel(txnID, request)
}

// TODO: this function was extracted from createOrUpdateChannel, but needs a closer examination.
func (c *Resource) createChannelFromEnvelope(request fab.CreateChannelRequest) (fab.TransactionID, error) {
env, err := c.extractSignedEnvelope(request.Envelope)
if err != nil {
return fab.TransactionID{}, errors.WithMessage(err, "signed envelope not valid")
}

// Send request
_, err = request.Orderer.SendBroadcast(env)
if err != nil {
return fab.TransactionID{}, errors.WithMessage(err, "failed broadcast to orderer")
}
return fab.TransactionID{}, nil
}

// GenesisBlockFromOrderer returns the genesis block from the defined orderer that may be
Expand All @@ -107,6 +132,10 @@ func (c *Resource) GenesisBlockFromOrderer(channelName string, orderer fab.Order
Stop: seekStop,
Behavior: ab.SeekInfo_BLOCK_UNTIL_READY,
}
seekInfoBytes, err := proto.Marshal(seekInfo)
if err != nil {
return nil, errors.Wrap(err, "marshaling of seek info header failed")
}

tlsCertHash := ccomm.TLSCertHash(c.clientContext.Config())
channelHeaderOpts := txn.ChannelHeaderOpts{
Expand All @@ -116,24 +145,15 @@ func (c *Resource) GenesisBlockFromOrderer(channelName string, orderer fab.Order
}
seekInfoHeader, err := txn.CreateChannelHeader(common.HeaderType_DELIVER_SEEK_INFO, channelHeaderOpts)
if err != nil {
return nil, errors.Wrap(err, "BuildChannelHeader failed")
}
seekHeader, err := txn.CreateHeader(c.clientContext, seekInfoHeader, txnID)
if err != nil {
return nil, errors.Wrap(err, "BuildHeader failed")
}
seekPayload := &common.Payload{
Header: seekHeader,
Data: protos_utils.MarshalOrPanic(seekInfo),
return nil, errors.Wrap(err, "CreateChannelHeader failed")
}
seekPayloadBytes := protos_utils.MarshalOrPanic(seekPayload)

signedEnvelope, err := txn.SignPayload(c.clientContext, seekPayloadBytes)
payload, err := txn.CreatePayload(txnID, seekInfoHeader, seekInfoBytes)
if err != nil {
return nil, errors.WithMessage(err, "SignPayload failed")
return nil, errors.Wrap(err, "CreatePayload failed")
}

block, err := txn.SendEnvelope(c.clientContext, signedEnvelope, orderers)
block, err := txn.SendPayload(c.clientContext, payload, orderers)
if err != nil {
return nil, errors.WithMessage(err, "SendEnvelope failed")
}
Expand Down Expand Up @@ -168,101 +188,50 @@ func (c *Resource) JoinChannel(request fab.JoinChannelRequest) error {
return err
}

// createOrUpdateChannel creates a new channel or updates an existing channel.
func (c *Resource) createOrUpdateChannel(request fab.CreateChannelRequest, haveEnvelope bool) error {
// Validate request
if request.Config == nil && !haveEnvelope {
return errors.New("missing envelope request parameter containing the configuration of the new channel")
func (c *Resource) extractSignedEnvelope(reqEnvelope []byte) (*fab.SignedEnvelope, error) {
envelope := &common.Envelope{}
err := proto.Unmarshal(reqEnvelope, envelope)
if err != nil {
return nil, errors.Wrap(err, "unmarshal request envelope failed")
}

if request.Signatures == nil && !haveEnvelope {
return errors.New("missing signatures request parameter for the new channel")
se := fab.SignedEnvelope{
Signature: envelope.Signature,
Payload: envelope.Payload,
}
return &se, nil
}

if request.TxnID.ID == "" && !haveEnvelope {
return errors.New("txId required")
}
// createOrUpdateChannel creates a new channel or updates an existing channel.
func (c *Resource) createOrUpdateChannel(txnID fab.TransactionID, request fab.CreateChannelRequest) error {

if request.TxnID.Nonce == nil && !haveEnvelope {
return errors.New("nonce required")
configUpdateEnvelope := &common.ConfigUpdateEnvelope{
ConfigUpdate: request.Config,
Signatures: request.Signatures,
}

if request.Orderer == nil {
return errors.New("missing orderer request parameter for the initialize channel")
configUpdateEnvelopeBytes, err := proto.Marshal(configUpdateEnvelope)
if err != nil {
return errors.Wrap(err, "marshal configUpdateEnvelope failed")
}

if request.Name == "" {
return errors.New("missing name request parameter for the new channel")
channelHeaderOpts := txn.ChannelHeaderOpts{
ChannelID: request.Name,
TxnID: txnID,
TLSCertHash: ccomm.TLSCertHash(c.clientContext.Config()),
}

// channel = null;
var signature []byte
var payloadBytes []byte

if haveEnvelope {
logger.Debug("createOrUpdateChannel - have envelope")
envelope := &common.Envelope{}
err := proto.Unmarshal(request.Envelope, envelope)
if err != nil {
return errors.Wrap(err, "unmarshal request envelope failed")
}
signature = envelope.Signature
payloadBytes = envelope.Payload
} else {
logger.Debug("createOrUpdateChannel - have config_update")
configUpdateEnvelope := &common.ConfigUpdateEnvelope{
ConfigUpdate: request.Config,
Signatures: request.Signatures,
}

// TODO: Move
channelHeaderOpts := txn.ChannelHeaderOpts{
ChannelID: request.Name,
TxnID: request.TxnID,
TLSCertHash: ccomm.TLSCertHash(c.clientContext.Config()),
}
channelHeader, err := txn.CreateChannelHeader(common.HeaderType_CONFIG_UPDATE, channelHeaderOpts)
if err != nil {
return errors.WithMessage(err, "BuildChannelHeader failed")
}

header, err := txn.CreateHeader(c.clientContext, channelHeader, request.TxnID)
if err != nil {
return errors.Wrap(err, "BuildHeader failed")
}
configUpdateEnvelopeBytes, err := proto.Marshal(configUpdateEnvelope)
if err != nil {
return errors.Wrap(err, "marshal configUpdateEnvelope failed")
}
payload := &common.Payload{
Header: header,
Data: configUpdateEnvelopeBytes,
}
payloadBytes, err = proto.Marshal(payload)
if err != nil {
return errors.Wrap(err, "marshal payload failed")
}

signingMgr := c.clientContext.SigningManager()
if signingMgr == nil {
return errors.New("signing manager is nil")
}

signature, err = signingMgr.Sign(payloadBytes, c.clientContext.PrivateKey())
if err != nil {
return errors.WithMessage(err, "signing payload failed")
}
channelHeader, err := txn.CreateChannelHeader(common.HeaderType_CONFIG_UPDATE, channelHeaderOpts)
if err != nil {
return errors.WithMessage(err, "CreateChannelHeader failed")
}

// Send request
_, err := request.Orderer.SendBroadcast(&fab.SignedEnvelope{
Signature: signature,
Payload: payloadBytes,
})
payload, err := txn.CreatePayload(txnID, channelHeader, configUpdateEnvelopeBytes)
if err != nil {
return errors.WithMessage(err, "failed broadcast to orderer")
return errors.WithMessage(err, "CreatePayload failed")
}

_, err = txn.BroadcastPayload(c.clientContext, payload, []fab.Orderer{request.Orderer})
if err != nil {
return errors.WithMessage(err, "SendEnvelope failed")
}
return nil
}

Expand Down
46 changes: 30 additions & 16 deletions pkg/fabric-client/txn/env.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,16 +72,19 @@ func computeTxnID(nonce, creator []byte, h hash.Hash) (string, error) {
return id, nil
}

// SignPayload signs payload
//
// TODO: Determine if this function should be exported after refactoring is completed.
func SignPayload(ctx context, payload []byte) (*fab.SignedEnvelope, error) {
// signPayload signs payload
func signPayload(ctx context, payload *common.Payload) (*fab.SignedEnvelope, error) {
payloadBytes, err := proto.Marshal(payload)
if err != nil {
return nil, errors.WithMessage(err, "marshaling of payload failed")
}

signingMgr := ctx.SigningManager()
signature, err := signingMgr.Sign(payload, ctx.PrivateKey())
signature, err := signingMgr.Sign(payloadBytes, ctx.PrivateKey())
if err != nil {
return nil, err
return nil, errors.WithMessage(err, "signing of payload failed")
}
return &fab.SignedEnvelope{Payload: payload, Signature: signature}, nil
return &fab.SignedEnvelope{Payload: payloadBytes, Signature: signature}, nil
}

// ChannelHeaderOpts holds the parameters to create a ChannelHeader.
Expand Down Expand Up @@ -133,15 +136,11 @@ func CreateChannelHeader(headerType common.HeaderType, opts ChannelHeaderOpts) (
return channelHeader, nil
}

// CreateHeader creates a Header from a ChannelHeader.
func CreateHeader(ctx fab.IdentityContext, channelHeader *common.ChannelHeader, txnID fab.TransactionID) (*common.Header, error) {
creator, err := ctx.Identity()
if err != nil {
return nil, errors.WithMessage(err, "extracting creator from identity context failed")
}
// createHeader creates a Header from a ChannelHeader.
func createHeader(txnID fab.TransactionID, channelHeader *common.ChannelHeader) (*common.Header, error) {

signatureHeader := &common.SignatureHeader{
Creator: creator,
Creator: txnID.Creator,
Nonce: txnID.Nonce,
}
sh, err := proto.Marshal(signatureHeader)
Expand All @@ -152,9 +151,24 @@ func CreateHeader(ctx fab.IdentityContext, channelHeader *common.ChannelHeader,
if err != nil {
return nil, errors.Wrap(err, "marshal channelHeader failed")
}
header := &common.Header{
header := common.Header{
SignatureHeader: sh,
ChannelHeader: ch,
}
return header, nil
return &header, nil
}

// CreatePayload creates a slice of payload bytes from a ChannelHeader and a data slice.
func CreatePayload(txnID fab.TransactionID, channelHeader *common.ChannelHeader, data []byte) (*common.Payload, error) {
header, err := createHeader(txnID, channelHeader)
if err != nil {
return nil, errors.Wrap(err, "header creation failed")
}

payload := common.Payload{
Header: header,
Data: data,
}

return &payload, nil
}
Loading

0 comments on commit eb9db60

Please sign in to comment.