Skip to content

Commit

Permalink
[FAB-8389] Refactor txn ID creation and config sigs
Browse files Browse the repository at this point in the history
This change moves the creation of transaction IDs
from prop utils into the txn package.

Utility method for extracting channel config is removed
from interface (and is instead a package method).

Change-Id: I4fc84713598d2d0f3279600b6eec67d9d816616e
Signed-off-by: Troy Ronda <troy@troyronda.com>
  • Loading branch information
troyronda committed Feb 20, 2018
1 parent 42a1d82 commit 75c84d2
Show file tree
Hide file tree
Showing 17 changed files with 178 additions and 135 deletions.
4 changes: 0 additions & 4 deletions api/apifabclient/resource.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,8 @@ type Resource interface {
InstallChaincode(request InstallChaincodeRequest) ([]*TransactionProposalResponse, string, error)
QueryInstalledChaincodes(peer ProposalProcessor) (*pb.ChaincodeQueryResponse, error)
QueryChannels(peer ProposalProcessor) (*pb.ChannelQueryResponse, error)

GenesisBlockFromOrderer(channelName string, orderer Orderer) (*common.Block, error)
JoinChannel(request JoinChannelRequest) error

// TODO - the following methods are utilities
ExtractChannelConfig(configEnvelope []byte) ([]byte, error)
SignChannelConfig(config []byte, signer IdentityContext) (*common.ConfigSignature, error)
}

Expand Down
2 changes: 1 addition & 1 deletion pkg/fabric-client/channel/proposal.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ type ChaincodeDeployRequest struct {
}

// CreateChaincodeDeployProposal creates an instantiate or upgrade chaincode proposal.
func CreateChaincodeDeployProposal(ctx fab.IdentityContext, deploy ChaincodeProposalType, channelID string, chaincode ChaincodeDeployRequest) (*fab.TransactionProposal, error) {
func CreateChaincodeDeployProposal(ctx fab.Context, deploy ChaincodeProposalType, channelID string, chaincode ChaincodeDeployRequest) (*fab.TransactionProposal, error) {

// Generate arguments for deploy (channel, marshaled CCDS, marshaled chaincode policy, marshaled collection policy)
args := [][]byte{}
Expand Down
7 changes: 2 additions & 5 deletions pkg/fabric-client/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -223,9 +223,7 @@ func (c *Client) LoadUserFromStateStore(name string) (fab.User, error) {
* @returns {byte[]} The bytes of the ConfigUpdate protobuf
*/
func (c *Client) ExtractChannelConfig(configEnvelope []byte) ([]byte, error) {
ctx := fabContext{ProviderContext: c, IdentityContext: c.signingIdentity}
rc := resource.New(ctx)
return rc.ExtractChannelConfig(configEnvelope)
return resource.ExtractChannelConfig(configEnvelope)
}

// SignChannelConfig ...
Expand All @@ -236,8 +234,7 @@ func (c *Client) ExtractChannelConfig(configEnvelope []byte) ([]byte, error) {
*/
func (c *Client) SignChannelConfig(config []byte, signer fab.IdentityContext) (*common.ConfigSignature, error) {
ctx := fabContext{ProviderContext: c, IdentityContext: c.signingIdentity}
rc := resource.New(ctx)
return rc.SignChannelConfig(config, signer)
return resource.CreateConfigSignature(ctx, config)
}

// CreateChannel ...
Expand Down
21 changes: 19 additions & 2 deletions pkg/fabric-client/mocks/mockcontext.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,13 @@ SPDX-License-Identifier: Apache-2.0
package mocks

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

config "github.com/hyperledger/fabric-sdk-go/api/apiconfig"
fab "github.com/hyperledger/fabric-sdk-go/api/apifabclient"
"github.com/hyperledger/fabric-sdk-go/internal/github.com/hyperledger/fabric/common/crypto"
protos_utils "github.com/hyperledger/fabric-sdk-go/third_party/github.com/hyperledger/fabric/protos/utils"

"github.com/hyperledger/fabric-sdk-go/api/apicryptosuite"
)
Expand Down Expand Up @@ -92,7 +95,8 @@ func NewMockTxnID() (fab.TransactionID, error) {
return fab.TransactionID{}, err
}

id, err := protos_utils.ComputeProposalTxID(nonce, creator)
h := sha256.New()
id, err := computeTxnID(nonce, creator, h)
if err != nil {
return fab.TransactionID{}, err
}
Expand All @@ -104,3 +108,16 @@ func NewMockTxnID() (fab.TransactionID, error) {

return txnID, nil
}

func computeTxnID(nonce, creator []byte, h hash.Hash) (string, error) {
b := append(nonce, creator...)

_, err := h.Write(b)
if err != nil {
return "", err
}
digest := h.Sum(nil)
id := hex.EncodeToString(digest)

return id, nil
}
5 changes: 3 additions & 2 deletions pkg/fabric-client/mocks/mockcryptosuite.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ SPDX-License-Identifier: Apache-2.0
package mocks

import (
"crypto/sha256"
"hash"

"github.com/hyperledger/fabric-sdk-go/api/apicryptosuite"
Expand Down Expand Up @@ -38,8 +39,8 @@ func (m *MockCryptoSuite) Hash(msg []byte, opts apicryptosuite.HashOpts) (hash [
}

// GetHash mock get hash
func (m *MockCryptoSuite) GetHash(opts apicryptosuite.HashOpts) (h hash.Hash, err error) {
return nil, nil
func (m *MockCryptoSuite) GetHash(opts apicryptosuite.HashOpts) (hash.Hash, error) {
return sha256.New(), nil
}

// Sign mock signing
Expand Down
9 changes: 0 additions & 9 deletions pkg/fabric-client/mocks/mockresource.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,15 +31,6 @@ func NewMockResource() *MockResource {
return &MockResource{}
}

// ExtractChannelConfig ...
func (c *MockResource) ExtractChannelConfig(configEnvelope []byte) ([]byte, error) {
if bytes.Compare(configEnvelope, []byte("ExtractChannelConfigError")) == 0 {
return nil, errors.New("Mock extract channel config error")
}

return configEnvelope, nil
}

// SignChannelConfig ...
func (c *MockResource) SignChannelConfig(config []byte, signer fab.IdentityContext) (*common.ConfigSignature, error) {
if bytes.Compare(config, []byte("SignChannelConfigError")) == 0 {
Expand Down
79 changes: 72 additions & 7 deletions pkg/fabric-client/resource/proposal.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,17 @@ package resource
import (
"time"

"github.com/golang/protobuf/proto"
"github.com/golang/protobuf/ptypes"
"github.com/hyperledger/fabric-sdk-go/pkg/fabric-client/txn"
"github.com/pkg/errors"

fab "github.com/hyperledger/fabric-sdk-go/api/apifabclient"
"github.com/hyperledger/fabric-sdk-go/internal/github.com/hyperledger/fabric/common/crypto"
fcutils "github.com/hyperledger/fabric-sdk-go/internal/github.com/hyperledger/fabric/common/util"
"github.com/hyperledger/fabric-sdk-go/pkg/fabric-client/txn"
"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"

fab "github.com/hyperledger/fabric-sdk-go/api/apifabclient"
)

// ChaincodeInstallRequest requests chaincode installation on the network
Expand All @@ -34,7 +37,7 @@ type ChaincodePackage struct {
}

// CreateChaincodeInstallProposal creates an install chaincode proposal.
func CreateChaincodeInstallProposal(ctx fab.IdentityContext, request ChaincodeInstallRequest) (*fab.TransactionProposal, error) {
func CreateChaincodeInstallProposal(ctx fab.Context, request ChaincodeInstallRequest) (*fab.TransactionProposal, error) {

// Generate arguments for install
args := [][]byte{}
Expand All @@ -53,13 +56,75 @@ func CreateChaincodeInstallProposal(ctx fab.IdentityContext, request ChaincodeIn
}
args = append(args, ccdsBytes)

args = append(args, []byte("escc"))
args = append(args, []byte("vscc"))

cir := fab.ChaincodeInvokeRequest{
ChaincodeID: "lscc",
Fcn: "install",
Args: args,
}
return txn.CreateChaincodeInvokeProposal(ctx, "", cir)
}

// CreateConfigSignature creates a ConfigSignature for the current context.
func CreateConfigSignature(ctx fab.Context, config []byte) (*common.ConfigSignature, error) {

creator, err := ctx.Identity()
if err != nil {
return nil, errors.WithMessage(err, "failed to get user context's identity")
}

// generate a random nonce
nonce, err := crypto.GetRandomNonce()
if err != nil {
return nil, errors.WithMessage(err, "nonce creation failed")
}

// signature is across a signature header and the config update
signatureHeader := &common.SignatureHeader{
Creator: creator,
Nonce: nonce,
}
signatureHeaderBytes, err := proto.Marshal(signatureHeader)
if err != nil {
return nil, errors.Wrap(err, "marshal signatureHeader failed")
}

// get all the bytes to be signed together, then sign
signingBytes := fcutils.ConcatenateBytes(signatureHeaderBytes, config)
signingMgr := ctx.SigningManager()
signature, err := signingMgr.Sign(signingBytes, ctx.PrivateKey())
if err != nil {
return nil, errors.WithMessage(err, "signing of channel config failed")
}

// build the return object
configSignature := common.ConfigSignature{
SignatureHeader: signatureHeaderBytes,
Signature: signature,
}
return &configSignature, nil
}

// ExtractChannelConfig extracts the protobuf 'ConfigUpdate' object out of the 'ConfigEnvelope'.
func ExtractChannelConfig(configEnvelope []byte) ([]byte, error) {
logger.Debug("extractConfigUpdate - start")

envelope := &common.Envelope{}
err := proto.Unmarshal(configEnvelope, envelope)
if err != nil {
return nil, errors.Wrap(err, "unmarshal config envelope failed")
}

payload := &common.Payload{}
err = proto.Unmarshal(envelope.Payload, payload)
if err != nil {
return nil, errors.Wrap(err, "unmarshal envelope payload failed")
}

configUpdateEnvelope := &common.ConfigUpdateEnvelope{}
err = proto.Unmarshal(payload.Data, configUpdateEnvelope)
if err != nil {
return nil, errors.Wrap(err, "unmarshal config update envelope")
}

return configUpdateEnvelope.ConfigUpdate, nil
}
29 changes: 29 additions & 0 deletions pkg/fabric-client/resource/proposal_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,13 @@ SPDX-License-Identifier: Apache-2.0
package resource

import (
"io/ioutil"
"path"
"testing"

fab "github.com/hyperledger/fabric-sdk-go/api/apifabclient"
"github.com/hyperledger/fabric-sdk-go/pkg/fabric-client/txn"
"github.com/hyperledger/fabric-sdk-go/test/metadata"

"github.com/hyperledger/fabric-sdk-go/pkg/fabric-client/mocks"
"github.com/stretchr/testify/assert"
Expand All @@ -33,3 +36,29 @@ func TestCreateChaincodeInstallProposal(t *testing.T) {
_, err = txn.SendProposal(c.clientContext, prop, []fab.ProposalProcessor{&peer})
assert.Nil(t, err, "sending mock proposal failed")
}

func TestExtractChannelConfig(t *testing.T) {
configTx, err := ioutil.ReadFile(path.Join("../../../", metadata.ChannelConfigPath, "mychannel.tx"))
if err != nil {
t.Fatalf(err.Error())
}

_, err = ExtractChannelConfig(configTx)
if err != nil {
t.Fatalf(err.Error())
}
}

func TestCreateConfigSignature(t *testing.T) {
client := setupTestClient()

configTx, err := ioutil.ReadFile(path.Join("../../../", metadata.ChannelConfigPath, "mychannel.tx"))
if err != nil {
t.Fatalf(err.Error())
}

_, err = CreateConfigSignature(client.clientContext, configTx)
if err != nil {
t.Fatalf("Expected 'channel configuration required %v", err)
}
}
66 changes: 7 additions & 59 deletions pkg/fabric-client/resource/resource.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ import (
"github.com/pkg/errors"

fab "github.com/hyperledger/fabric-sdk-go/api/apifabclient"
fcutils "github.com/hyperledger/fabric-sdk-go/internal/github.com/hyperledger/fabric/common/util"
ab "github.com/hyperledger/fabric-sdk-go/internal/github.com/hyperledger/fabric/protos/orderer"
ccomm "github.com/hyperledger/fabric-sdk-go/pkg/config/comm"
"github.com/hyperledger/fabric-sdk-go/pkg/errors/multi"
Expand All @@ -38,29 +37,9 @@ func New(ctx fab.Context) *Resource {
return &c
}

// ExtractChannelConfig extracts the protobuf 'ConfigUpdate' object out of the 'ConfigEnvelope'.
func (c *Resource) ExtractChannelConfig(configEnvelope []byte) ([]byte, error) {
logger.Debug("extractConfigUpdate - start")

envelope := &common.Envelope{}
err := proto.Unmarshal(configEnvelope, envelope)
if err != nil {
return nil, errors.Wrap(err, "unmarshal config envelope failed")
}

payload := &common.Payload{}
err = proto.Unmarshal(envelope.Payload, payload)
if err != nil {
return nil, errors.Wrap(err, "unmarshal envelope payload failed")
}

configUpdateEnvelope := &common.ConfigUpdateEnvelope{}
err = proto.Unmarshal(payload.Data, configUpdateEnvelope)
if err != nil {
return nil, errors.Wrap(err, "unmarshal config update envelope")
}

return configUpdateEnvelope.ConfigUpdate, nil
type fabCtx struct {
fab.ProviderContext
fab.IdentityContext
}

// SignChannelConfig signs a configuration.
Expand All @@ -81,43 +60,12 @@ func (c *Resource) SignChannelConfig(config []byte, signer fab.IdentityContext)
return nil, errors.New("user context required")
}

creator, err := signingUser.Identity()
if err != nil {
return nil, errors.WithMessage(err, "failed to get user context's identity")
}
txnID, err := txn.NewID(signingUser)
if err != nil {
return nil, errors.Wrap(err, "New Transaction ID failed")
}

// signature is across a signature header and the config update
signatureHeader := &common.SignatureHeader{
Creator: creator,
Nonce: txnID.Nonce,
}
signatureHeaderBytes, err := proto.Marshal(signatureHeader)
if err != nil {
return nil, errors.Wrap(err, "marshal signatureHeader failed")
ctx := fabCtx{
ProviderContext: c.clientContext,
IdentityContext: signingUser,
}

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

// get all the bytes to be signed together, then sign
signingBytes := fcutils.ConcatenateBytes(signatureHeaderBytes, config)
signature, err := signingMgr.Sign(signingBytes, signingUser.PrivateKey())
if err != nil {
return nil, errors.WithMessage(err, "signing of channel config failed")
}

// build the return object
configSignature := &common.ConfigSignature{
SignatureHeader: signatureHeaderBytes,
Signature: signature,
}
return configSignature, nil
return CreateConfigSignature(ctx, config)
}

// CreateChannel calls the orderer to start building the new channel.
Expand Down
14 changes: 0 additions & 14 deletions pkg/fabric-client/resource/resource_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,20 +24,6 @@ import (
"google.golang.org/grpc"
)

func TestExtractChannelConfig(t *testing.T) {
client := setupTestClient()

configTx, err := ioutil.ReadFile(path.Join("../../../", metadata.ChannelConfigPath, "mychannel.tx"))
if err != nil {
t.Fatalf(err.Error())
}

_, err = client.ExtractChannelConfig(configTx)
if err != nil {
t.Fatalf(err.Error())
}
}

func TestSignChannelConfig(t *testing.T) {
client := setupTestClient()

Expand Down
Loading

0 comments on commit 75c84d2

Please sign in to comment.