Skip to content

Commit

Permalink
Merge "FAB-2417 create channel from provided config tx"
Browse files Browse the repository at this point in the history
  • Loading branch information
Jason Yellick authored and Gerrit Code Review committed Feb 23, 2017
2 parents a086639 + 215126c commit f145efe
Show file tree
Hide file tree
Showing 3 changed files with 232 additions and 6 deletions.
4 changes: 3 additions & 1 deletion peer/channel/channel.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ var (
// create related variables
chainID string
anchorPeerList string
channelTxFile string
)

// Cmd returns the cobra command for Node
Expand All @@ -64,8 +65,9 @@ func AddFlags(cmd *cobra.Command) {
flags := cmd.PersistentFlags()

flags.StringVarP(&genesisBlockPath, "blockpath", "b", common.UndefinedParamValue, "Path to file containing genesis block")
flags.StringVarP(&chainID, "chain", "c", "mychain", "In case of a newChain command, the chain ID to create.")
flags.StringVarP(&chainID, "chain", "c", common.UndefinedParamValue, "In case of a newChain command, the chain ID to create.")
flags.StringVarP(&anchorPeerList, "anchors", "a", "", anchorPeerUsage)
flags.StringVarP(&channelTxFile, "file", "f", "", "Configuration transaction file generated by a tool such as configtxgen for submitting to orderer")
}

var channelCmd = &cobra.Command{
Expand Down
83 changes: 78 additions & 5 deletions peer/channel/create.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ limitations under the License.
package channel

import (
"fmt"
"io/ioutil"
"time"

Expand All @@ -28,9 +29,24 @@ import (
mspmgmt "github.com/hyperledger/fabric/msp/mgmt"
"github.com/hyperledger/fabric/peer/common"
cb "github.com/hyperledger/fabric/protos/common"
"github.com/hyperledger/fabric/protos/utils"
"github.com/spf13/cobra"
)

//ConfigTxFileNotFound channel create configuration tx file not found
type ConfigTxFileNotFound string

func (e ConfigTxFileNotFound) Error() string {
return fmt.Sprintf("channel create configuration tx file not found %s", string(e))
}

//InvalidCreateTx invalid channel create transaction
type InvalidCreateTx string

func (e InvalidCreateTx) Error() string {
return fmt.Sprintf("Invalid channel create transaction : %s", string(e))
}

func createCmd(cf *ChannelCmdFactory) *cobra.Command {
createCmd := &cobra.Command{
Use: "create",
Expand All @@ -44,15 +60,16 @@ func createCmd(cf *ChannelCmdFactory) *cobra.Command {
return createCmd
}

func sendCreateChainTransaction(cf *ChannelCmdFactory) error {
func createChannelFromDefaults(cf *ChannelCmdFactory) (*cb.Envelope, error) {
if cf.AnchorPeerParser == nil {
cf.AnchorPeerParser = common.GetDefaultAnchorPeerParser()
}

anchorPeers, err := cf.AnchorPeerParser.Parse()
if err != nil {
return err
return nil, err
}
//TODO this is a temporary hack until `orderer.template` and 'msp.template' is supplied from the CLI

oTemplate := configtxtest.OrdererTemplate()
oOrgTemplate := configtxtest.OrdererOrgTemplate()
appOrgTemplate := configtxtest.ApplicationOrgTemplate()
Expand All @@ -61,13 +78,64 @@ func sendCreateChainTransaction(cf *ChannelCmdFactory) error {

signer, err := mspmgmt.GetLocalMSP().GetDefaultSigningIdentity()
if err != nil {
return err
return nil, err
}

chCrtEnv, err := configtx.MakeChainCreationTransaction(provisional.AcceptAllPolicyKey, chainID, signer, chCrtTemp)

if err != nil {
return err
return nil, err
}

return chCrtEnv, nil
}

func createChannelFromConfigTx(configTxFileName string) (*cb.Envelope, error) {
cftx, err := ioutil.ReadFile(configTxFileName)
if err != nil {
return nil, ConfigTxFileNotFound(err.Error())
}

env := utils.UnmarshalEnvelopeOrPanic(cftx)

payload := utils.ExtractPayloadOrPanic(env)

if payload.Header == nil || payload.Header.ChannelHeader == nil {
return nil, InvalidCreateTx("bad header")
}

ch, err := utils.UnmarshalChannelHeader(payload.Header.ChannelHeader)
if err != nil {
return nil, InvalidCreateTx("could not unmarshall channel header")
}

if ch.Type != int32(cb.HeaderType_CONFIG_UPDATE) {
return nil, InvalidCreateTx("bad type")
}

if ch.ChannelId == "" {
return nil, InvalidCreateTx("empty channel id")
}

if ch.ChannelId != chainID {
return nil, InvalidCreateTx(fmt.Sprintf("mismatched channel ID %s != %s", ch.ChannelId, chainID))
}

return env, nil
}

func sendCreateChainTransaction(cf *ChannelCmdFactory) error {
var err error
var chCrtEnv *cb.Envelope

if channelTxFile != "" {
if chCrtEnv, err = createChannelFromConfigTx(channelTxFile); err != nil {
return err
}
} else {
if chCrtEnv, err = createChannelFromDefaults(cf); err != nil {
return err
}
}

err = cf.BroadcastClient.Send(chCrtEnv)
Expand Down Expand Up @@ -105,6 +173,11 @@ func executeCreate(cf *ChannelCmdFactory) error {
}

func create(cmd *cobra.Command, args []string, cf *ChannelCmdFactory) error {
//the global chainID filled by the "-c" command
if chainID == common.UndefinedParamValue {
return fmt.Errorf("Must supply channel ID .\n")
}

var err error
if cf == nil {
cf, err = InitCmdFactory(false)
Expand Down
151 changes: 151 additions & 0 deletions peer/channel/create_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,14 @@ package channel

import (
"fmt"
"io/ioutil"
"os"
"path/filepath"
"sync"
"testing"

"github.com/golang/protobuf/proto"

"github.com/hyperledger/fabric/msp/mgmt/testtools"
"github.com/hyperledger/fabric/peer/common"
cb "github.com/hyperledger/fabric/protos/common"
Expand Down Expand Up @@ -251,3 +255,150 @@ func TestCreateChainDeliverFail(t *testing.T) {
}
}
}

func createTxFile(filename string, typ cb.HeaderType, channelID string) (*cb.Envelope, error) {
ch := &cb.ChannelHeader{Type: int32(typ), ChannelId: channelID}
data, err := proto.Marshal(ch)
if err != nil {
return nil, err
}

p := &cb.Payload{Header: &cb.Header{ChannelHeader: data}}
data, err = proto.Marshal(p)
if err != nil {
return nil, err
}

env := &cb.Envelope{Payload: data}
data, err = proto.Marshal(env)
if err != nil {
return nil, err
}

if err = ioutil.WriteFile(filename, data, 0644); err != nil {
return nil, err
}

return env, nil
}

func TestCreateChainFromTx(t *testing.T) {
InitMSP()

mockchannel := "mockchannel"

dir, err := ioutil.TempDir("/tmp", "createtestfromtx-")
if err != nil {
t.Fatalf("couldn't create temp dir")
}

defer os.RemoveAll(dir) // clean up

//this could be created by the create command
defer os.Remove(mockchannel + ".block")

file := filepath.Join(dir, mockchannel)

signer, err := common.GetDefaultSigner()
if err != nil {
t.Fatalf("Get default signer error: %v", err)
}

mockBroadcastClient := common.GetMockBroadcastClient(nil)

mockCF := &ChannelCmdFactory{
BroadcastClient: mockBroadcastClient,
Signer: signer,
DeliverClient: &mockDeliverClient{},
AnchorPeerParser: common.GetAnchorPeersParser("../common/testdata/anchorPeersOrg1.txt"),
}

cmd := createCmd(mockCF)

AddFlags(cmd)

args := []string{"-c", mockchannel, "-f", file, "-a", "../common/testdata/anchorPeersOrg1.txt"}
cmd.SetArgs(args)

if _, err = createTxFile(file, cb.HeaderType_CONFIG_UPDATE, mockchannel); err != nil {
t.Fatalf("couldn't create tx file")
}

if err := cmd.Execute(); err != nil {
t.Errorf("create chain failed")
}
}

func TestCreateChainInvalidTx(t *testing.T) {
InitMSP()

mockchannel := "mockchannel"

dir, err := ioutil.TempDir("/tmp", "createinvaltest-")
if err != nil {
t.Fatalf("couldn't create temp dir")
}

defer os.RemoveAll(dir) // clean up

//this is created by create command
defer os.Remove(mockchannel + ".block")

file := filepath.Join(dir, mockchannel)

signer, err := common.GetDefaultSigner()
if err != nil {
t.Fatalf("Get default signer error: %v", err)
}

mockBroadcastClient := common.GetMockBroadcastClient(nil)

mockCF := &ChannelCmdFactory{
BroadcastClient: mockBroadcastClient,
Signer: signer,
DeliverClient: &mockDeliverClient{},
AnchorPeerParser: common.GetAnchorPeersParser("../common/testdata/anchorPeersOrg1.txt"),
}

cmd := createCmd(mockCF)

AddFlags(cmd)

args := []string{"-c", mockchannel, "-f", file, "-a", "../common/testdata/anchorPeersOrg1.txt"}
cmd.SetArgs(args)

//bad type CONFIG
if _, err = createTxFile(file, cb.HeaderType_CONFIG, mockchannel); err != nil {
t.Fatalf("couldn't create tx file")
}

defer os.Remove(file)

if err := cmd.Execute(); err == nil {
t.Errorf("expected error")
} else if _, ok := err.(InvalidCreateTx); !ok {
t.Errorf("invalid error")
}

//bad channel name - does not match one specified in command
if _, err = createTxFile(file, cb.HeaderType_CONFIG_UPDATE, "different_channel"); err != nil {
t.Fatalf("couldn't create tx file")
}

if err := cmd.Execute(); err == nil {
t.Errorf("expected error")
} else if _, ok := err.(InvalidCreateTx); !ok {
t.Errorf("invalid error")
}

//empty channel
if _, err = createTxFile(file, cb.HeaderType_CONFIG_UPDATE, ""); err != nil {
t.Fatalf("couldn't create tx file")
}

if err := cmd.Execute(); err == nil {
t.Errorf("expected error")
} else if _, ok := err.(InvalidCreateTx); !ok {
t.Errorf("invalid error")
}
}

0 comments on commit f145efe

Please sign in to comment.