From cdb34d50f9b7d89494c4c745de3170ea4fc4503c Mon Sep 17 00:00:00 2001 From: Sandra Vrtikapa Date: Wed, 31 Jan 2018 17:41:56 -0500 Subject: [PATCH] [FAB-8023] Channel Config from orderer Change-Id: I64c32e4921452a301749e1ae947e362c326238df Signed-off-by: Sandra Vrtikapa --- api/apifabclient/channel.go | 3 - api/apifabclient/chconfig.go | 13 +- pkg/fabric-client/channel/channel.go | 44 +- pkg/fabric-client/channel/channel_test.go | 134 +----- pkg/fabric-client/channel/config.go | 419 +------------------ pkg/fabric-client/channel/config_test.go | 164 +------- pkg/fabric-client/channel/query.go | 22 +- pkg/fabric-client/channel/txnsender_test.go | 4 +- pkg/fabric-client/chconfig/chconfig.go | 98 ++++- pkg/fabric-client/chconfig/chconfig_test.go | 128 ++++++ pkg/fabric-client/client.go | 3 +- pkg/fabric-client/mocks/mockchconfig.go | 51 +++ pkg/fabric-client/orderer/deprecated_test.go | 95 ----- pkg/fabric-client/orderer/orderer_test.go | 96 ----- pkg/fabric-txn/chclient/chclient_test.go | 2 +- pkg/fabric-txn/resmgmtclient/resmgmt_test.go | 6 +- pkg/fabric-txn/txnhandler/txnhandler_test.go | 2 +- pkg/fabsdk/provider/fabpvdr/fabpvdr.go | 2 +- test/integration/base_test_setup.go | 4 - test/integration/sdk/channel_config_test.go | 94 ++++- 20 files changed, 428 insertions(+), 956 deletions(-) create mode 100644 pkg/fabric-client/chconfig/chconfig_test.go create mode 100644 pkg/fabric-client/mocks/mockchconfig.go diff --git a/api/apifabclient/channel.go b/api/apifabclient/channel.go index 0391b16076..95fedf25a2 100644 --- a/api/apifabclient/channel.go +++ b/api/apifabclient/channel.go @@ -28,9 +28,6 @@ type Channel interface { txn.ProposalSender Name() string - Initialize(data []byte) error - IsInitialized() bool - LoadConfigUpdateEnvelope(data []byte) error ChannelConfig() (*common.ConfigEnvelope, error) SendInstantiateProposal(chaincodeName string, args [][]byte, chaincodePath string, chaincodeVersion string, chaincodePolicy *common.SignaturePolicyEnvelope, collConfig []*common.CollectionConfig, targets []txn.ProposalProcessor) ([]*txn.TransactionProposalResponse, txn.TransactionID, error) diff --git a/api/apifabclient/chconfig.go b/api/apifabclient/chconfig.go index 616fc102f7..8c4dd04270 100644 --- a/api/apifabclient/chconfig.go +++ b/api/apifabclient/chconfig.go @@ -15,15 +15,16 @@ import ( type ChannelConfig interface { // Query channel configuration - Query() (*ChannelCfg, error) + Query() (ChannelCfg, error) } // ChannelCfg contains channel configuration -type ChannelCfg struct { - Msps []*msp.MSPConfig - AnchorPeers []*OrgAnchorPeer - Orderers []string - Versions *Versions +type ChannelCfg interface { + Name() string + Msps() []*msp.MSPConfig + AnchorPeers() []*OrgAnchorPeer + Orderers() []string + Versions() *Versions } // Versions ... diff --git a/pkg/fabric-client/channel/channel.go b/pkg/fabric-client/channel/channel.go index fa9eac2db9..179f4a25bb 100644 --- a/pkg/fabric-client/channel/channel.go +++ b/pkg/fabric-client/channel/channel.go @@ -11,6 +11,7 @@ import ( "github.com/hyperledger/fabric-sdk-go/internal/github.com/hyperledger/fabric/msp" "github.com/hyperledger/fabric-sdk-go/pkg/errors" + "github.com/hyperledger/fabric-sdk-go/pkg/fabric-client/orderer" "github.com/hyperledger/fabric-sdk-go/pkg/logging" ) @@ -33,8 +34,8 @@ type Channel struct { // name: used to identify different channel instances. The naming of channel instances // is enforced by the ordering service and must be unique within the blockchain network. // client: Provides operational context such as submitting User etc. -func New(ctx fab.Context, name string) (*Channel, error) { - if name == "" { +func New(ctx fab.Context, cfg fab.ChannelCfg) (*Channel, error) { + if cfg.Name() == "" { return nil, errors.Errorf("name is required") } if ctx == nil { @@ -42,13 +43,48 @@ func New(ctx fab.Context, name string) (*Channel, error) { } p := make(map[string]fab.Peer) o := make(map[string]fab.Orderer) + c := Channel{ - name: name, + name: cfg.Name(), peers: p, orderers: o, clientContext: ctx, - mspManager: msp.NewMSPManager(), } + + mspManager := msp.NewMSPManager() + if len(cfg.Msps()) > 0 { + msps, err := loadMSPs(cfg.Msps(), ctx.CryptoSuite()) + if err != nil { + return nil, errors.WithMessage(err, "load MSPs from config failed") + } + + if err := mspManager.Setup(msps); err != nil { + return nil, errors.WithMessage(err, "MSPManager Setup failed") + } + } + + c.mspManager = mspManager + c.anchorPeers = cfg.AnchorPeers() + + // Add orderer if specified in config + for _, name := range cfg.Orderers() { + + // Figure out orderer configuration + oCfg, err := ctx.Config().OrdererConfig(name) + + // Check if retrieving orderer configuration went ok + if err != nil || oCfg == nil { + return nil, errors.Errorf("failed to retrieve orderer config: %s", err) + } + + o, err := orderer.New(ctx.Config(), orderer.FromOrdererConfig(oCfg)) + if err != nil { + return nil, errors.WithMessage(err, "failed to create new orderer from config") + } + + c.orderers[o.URL()] = o + } + logger.Debugf("Constructed channel instance for channel %s: %v", c.name, c) return &c, nil diff --git a/pkg/fabric-client/channel/channel_test.go b/pkg/fabric-client/channel/channel_test.go index fe6401c7d2..b7c0a628e4 100644 --- a/pkg/fabric-client/channel/channel_test.go +++ b/pkg/fabric-client/channel/channel_test.go @@ -36,7 +36,7 @@ oG5kQQIgQAe4OOKYhJdh3f7URaKfGTf492/nmRmtK+ySKjpHSrU= func TestChannelMethods(t *testing.T) { user := mocks.NewMockUser("test") ctx := mocks.NewMockContext(user) - channel, err := New(ctx, "testChannel") + channel, err := New(ctx, mocks.NewMockChannelCfg("testChannel")) if err != nil { t.Fatalf("New return error[%s]", err) } @@ -44,7 +44,7 @@ func TestChannelMethods(t *testing.T) { t.Fatalf("New create wrong channel") } - _, err = New(ctx, "") + _, err = New(ctx, mocks.NewMockChannelCfg("")) if err == nil { t.Fatalf("New didn't return error") } @@ -52,7 +52,7 @@ func TestChannelMethods(t *testing.T) { t.Fatalf("New didn't return right error") } - _, err = New(nil, "testChannel") + _, err = New(nil, mocks.NewMockChannelCfg("testChannel")) if err == nil { t.Fatalf("NewChannel didn't return error") } @@ -97,7 +97,7 @@ func TestAddRemoveOrderer(t *testing.T) { } } -func TestAnchorAndRemovePeers(t *testing.T) { +func TestAddAndRemovePeers(t *testing.T) { //Setup channel channel, _ := setupTestChannel() @@ -113,12 +113,10 @@ func TestAnchorAndRemovePeers(t *testing.T) { //Add the Peer again channel.AddPeer(&peer) - - channel.Initialize(nil) - if len(channel.AnchorPeers()) != 0 { - //Currently testing only for empty anchor list - t.Fatal("Anchor peer list is incorrect") + if len(channel.Peers()) != 1 { + t.Fatal("Add Peer failed") } + } func TestPrimaryPeer(t *testing.T) { @@ -170,122 +168,6 @@ func TestPrimaryPeer(t *testing.T) { } -func TestChannelInitializeFromOrderer(t *testing.T) { - org1MSPID := "ORG1MSP" - org2MSPID := "ORG2MSP" - - channel, _ := setupTestChannel() - builder := &mocks.MockConfigBlockBuilder{ - MockConfigGroupBuilder: mocks.MockConfigGroupBuilder{ - ModPolicy: "Admins", - MSPNames: []string{ - org1MSPID, - org2MSPID, - }, - OrdererAddress: "localhost:7054", - RootCA: validRootCA, - }, - Index: 0, - LastConfigIndex: 0, - } - orderer := mocks.NewMockOrderer("", nil) - orderer.(mocks.MockOrderer).EnqueueForSendDeliver(builder.Build()) - orderer.(mocks.MockOrderer).EnqueueForSendDeliver(builder.Build()) - err := channel.AddOrderer(orderer) - if err != nil { - t.Fatalf("Error adding orderer: %v", err) - } - - err = channel.Initialize(nil) - if err != nil { - t.Fatalf("channel Initialize failed : %v", err) - } - if !channel.IsInitialized() { - t.Fatalf("channel Initialize failed : channel initialized flag not set") - } - - mspManager := channel.MSPManager() - if mspManager == nil { - t.Fatalf("nil MSPManager on new channel") - } - msps, err := mspManager.GetMSPs() - if err != nil || len(msps) == 0 { - t.Fatalf("At least one MSP expected in MSPManager") - } - msp, ok := msps[org1MSPID] - if !ok { - t.Fatalf("Could not find %s", org1MSPID) - } - if identifier, _ := msp.GetIdentifier(); identifier != org1MSPID { - t.Fatalf("Expecting MSP identifier to be %s but got %s", org1MSPID, identifier) - } - msp, ok = msps[org2MSPID] - if !ok { - t.Fatalf("Could not find %s", org2MSPID) - } - if identifier, _ := msp.GetIdentifier(); identifier != org2MSPID { - t.Fatalf("Expecting MSP identifier to be %s but got %s", org2MSPID, identifier) - } - - channel.SetMSPManager(nil) - if channel.MSPManager() != nil { - t.Fatal("Set MSPManager is not working as expected") - } - -} - -func TestOrganizationUnits(t *testing.T) { - org1MSPID := "ORG1MSP" - org2MSPID := "ORG2MSP" - - channel, _ := setupTestChannel() - orgUnits, err := channel.OrganizationUnits() - - if len(orgUnits) > 0 { - t.Fatalf("Returned non configured organizational unit : %v", err) - } - builder := &mocks.MockConfigBlockBuilder{ - MockConfigGroupBuilder: mocks.MockConfigGroupBuilder{ - ModPolicy: "Admins", - MSPNames: []string{ - channel.Name(), - org1MSPID, - org2MSPID, - }, - OrdererAddress: "localhost:7054", - RootCA: validRootCA, - }, - Index: 0, - LastConfigIndex: 0, - } - orderer := mocks.NewMockOrderer("", nil) - orderer.(mocks.MockOrderer).EnqueueForSendDeliver(builder.Build()) - orderer.(mocks.MockOrderer).EnqueueForSendDeliver(builder.Build()) - err = channel.AddOrderer(orderer) - if err != nil { - t.Fatalf("Error adding orderer: %v", err) - } - - err = channel.Initialize(nil) - if err != nil { - t.Fatalf("channel Initialize failed : %v", err) - } - orgUnits, err = channel.OrganizationUnits() - if err != nil { - t.Fatalf("CANNOT retrieve organizational units : %v", err) - } - if !isValueInList(channel.Name(), orgUnits) { - t.Fatalf("Could not find %s in the list of organizations", channel.Name()) - } - if !isValueInList(org1MSPID, orgUnits) { - t.Fatalf("Could not find %s in the list of organizations", org1MSPID) - } - if !isValueInList(org2MSPID, orgUnits) { - t.Fatalf("Could not find %s in the list of organizations", org2MSPID) - } - -} - func isValueInList(value string, list []string) bool { for _, v := range list { if v == value { @@ -298,7 +180,7 @@ func isValueInList(value string, list []string) bool { func setupTestChannel() (*Channel, error) { user := mocks.NewMockUser("test") ctx := mocks.NewMockContext(user) - return New(ctx, "testChannel") + return New(ctx, mocks.NewMockChannelCfg("testChannel")) } func setupMassiveTestChannel(numberOfPeers int, numberOfOrderers int) (*Channel, error) { diff --git a/pkg/fabric-client/channel/config.go b/pkg/fabric-client/channel/config.go index 5f0361294b..18d817195b 100644 --- a/pkg/fabric-client/channel/config.go +++ b/pkg/fabric-client/channel/config.go @@ -9,116 +9,15 @@ package channel import ( "github.com/golang/protobuf/proto" - fab "github.com/hyperledger/fabric-sdk-go/api/apifabclient" + "github.com/hyperledger/fabric-sdk-go/api/apicryptosuite" "github.com/hyperledger/fabric-sdk-go/third_party/github.com/hyperledger/fabric/protos/common" mb "github.com/hyperledger/fabric-sdk-go/third_party/github.com/hyperledger/fabric/protos/msp" - ab "github.com/hyperledger/fabric-sdk-go/third_party/github.com/hyperledger/fabric/protos/orderer" - 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" - channelConfig "github.com/hyperledger/fabric-sdk-go/internal/github.com/hyperledger/fabric/common/channelconfig" "github.com/hyperledger/fabric-sdk-go/internal/github.com/hyperledger/fabric/msp" "github.com/hyperledger/fabric-sdk-go/pkg/errors" fc "github.com/hyperledger/fabric-sdk-go/pkg/fabric-client/internal" ) -// configItems contains the configuration values retrieved from the Orderer Service -type configItems struct { - msps []*mb.MSPConfig - anchorPeers []*fab.OrgAnchorPeer - orderers []string - versions *versions -} - -// versions ... -type versions struct { - ReadSet *common.ConfigGroup - WriteSet *common.ConfigGroup - Channel *common.ConfigGroup -} - -// Initialize initializes the channel. -// Retrieves the configuration from the primary orderer and initializes this channel -// with those values. Optionally a configuration may be passed in to initialize this channel -// without making the call to the orderer. -// config_update: Optional - A serialized form of the protobuf configuration update. -func (c *Channel) Initialize(configUpdate []byte) error { - - if len(configUpdate) > 0 { - var err error - if _, err = c.loadConfigUpdate(configUpdate); err != nil { - return errors.WithMessage(err, "config update envelope load failed") - } - return nil - } - - configEnvelope, err := c.ChannelConfig() - if err != nil { - return errors.WithMessage(err, "channel configuration retrieval from orderer failed") - } - - _, err = c.loadConfigEnvelope(configEnvelope) - if err != nil { - return errors.WithMessage(err, "load config envelope failed") - } - c.initialized = true - return nil -} - -// LoadConfigUpdateEnvelope is a utility method to load this channel with configuration information -// from an Envelope that contains a Configuration. -// data: the envelope with the configuration update items. -// See /protos/common/configtx.proto -func (c *Channel) LoadConfigUpdateEnvelope(data []byte) error { - logger.Debugf("loadConfigUpdateEnvelope - start") - - envelope := &common.Envelope{} - err := proto.Unmarshal(data, envelope) - if err != nil { - return errors.Wrap(err, "unmarshal envelope failed") - } - - payload, err := protos_utils.ExtractPayload(envelope) - if err != nil { - return errors.Wrap(err, "extract payload from config update envelope failed") - } - - channelHeader, err := protos_utils.UnmarshalChannelHeader(payload.Header.ChannelHeader) - if err != nil { - return errors.Wrap(err, "extract channel header from config update payload failed") - } - - if common.HeaderType(channelHeader.Type) != common.HeaderType_CONFIG_UPDATE { - return errors.New("block must be of type 'CONFIG_UPDATE'") - } - - configUpdateEnvelope := &common.ConfigUpdateEnvelope{} - if err := proto.Unmarshal(payload.Data, configUpdateEnvelope); err != nil { - return errors.Wrap(err, "unmarshal config update envelope failed") - } - - _, err = c.loadConfigUpdate(configUpdateEnvelope.ConfigUpdate) - return err -} - -func (c *Channel) initializeFromConfig(configItems *configItems) error { - // TODO revisit this if - if len(configItems.msps) > 0 { - msps, err := c.loadMSPs(configItems.msps) - if err != nil { - return errors.WithMessage(err, "load MSPs from config failed") - } - - if err := c.mspManager.Setup(msps); err != nil { - return errors.WithMessage(err, "MSPManager Setup failed") - } - } - c.anchorPeers = configItems.anchorPeers - - // TODO should we create orderers and endorsing peers - return nil -} - // ChannelConfig queries for the current config block for this channel. // This transaction will be made to the orderer. // @returns {ConfigEnvelope} Object containing the configuration items. @@ -153,8 +52,14 @@ func (c *Channel) ChannelConfig() (*common.ConfigEnvelope, error) { return nil, errors.New("config block must contain one transaction") } + return createConfigEnvelope(block.Data.Data[0]) + +} + +func createConfigEnvelope(data []byte) (*common.ConfigEnvelope, error) { + envelope := &common.Envelope{} - if err = proto.Unmarshal(block.Data.Data[0], envelope); err != nil { + if err := proto.Unmarshal(data, envelope); err != nil { return nil, errors.Wrap(err, "unmarshal envelope from config block failed") } payload := &common.Payload{} @@ -172,10 +77,11 @@ func (c *Channel) ChannelConfig() (*common.ConfigEnvelope, error) { if err := proto.Unmarshal(payload.Data, configEnvelope); err != nil { return nil, errors.Wrap(err, "unmarshal config envelope failed") } + return configEnvelope, nil } -func (c *Channel) loadMSPs(mspConfigs []*mb.MSPConfig) ([]msp.MSP, error) { +func loadMSPs(mspConfigs []*mb.MSPConfig, cs apicryptosuite.CryptoSuite) ([]msp.MSP, error) { logger.Debugf("loadMSPs - start number of msps=%d", len(mspConfigs)) msps := []msp.MSP{} @@ -215,7 +121,7 @@ func (c *Channel) loadMSPs(mspConfigs []*mb.MSPConfig) ([]msp.MSP, error) { // TODO: Do something with orgs // TODO: Configure MSP version (rather than MSP 1.0) - newMSP, err := msp.NewBccspMsp(msp.MSPv1_0, c.clientContext.CryptoSuite()) + newMSP, err := msp.NewBccspMsp(msp.MSPv1_0, cs) if err != nil { return nil, errors.Wrap(err, "instantiate MSP failed") } @@ -233,306 +139,3 @@ func (c *Channel) loadMSPs(mspConfigs []*mb.MSPConfig) ([]msp.MSP, error) { logger.Debugf("loadMSPs - loaded %d MSPs", len(msps)) return msps, nil } - -func loadConfigPolicy(configItems *configItems, key string, versionsPolicy *common.ConfigPolicy, configPolicy *common.ConfigPolicy, groupName string, org string) error { - logger.Debugf("loadConfigPolicy - %s - name: %s", groupName, key) - logger.Debugf("loadConfigPolicy - %s - version: %d", groupName, configPolicy.Version) - logger.Debugf("loadConfigPolicy - %s - mod_policy: %s", groupName, configPolicy.ModPolicy) - - versionsPolicy.Version = configPolicy.Version - return loadPolicy(configItems, versionsPolicy, key, configPolicy.Policy, groupName, org) -} - -func loadConfigGroup(configItems *configItems, versionsGroup *common.ConfigGroup, group *common.ConfigGroup, name string, org string, top bool) error { - logger.Debugf("loadConfigGroup - %s - START groups Org: %s", name, org) - if group == nil { - return nil - } - - logger.Debugf("loadConfigGroup - %s - version %v", name, group.Version) - logger.Debugf("loadConfigGroup - %s - mod policy %s", name, group.ModPolicy) - logger.Debugf("loadConfigGroup - %s - >> groups", name) - - groups := group.GetGroups() - if groups != nil { - versionsGroup.Groups = make(map[string]*common.ConfigGroup) - for key, configGroup := range groups { - logger.Debugf("loadConfigGroup - %s - found config group ==> %s", name, key) - // The Application group is where config settings are that we want to find - versionsGroup.Groups[key] = &common.ConfigGroup{} - loadConfigGroup(configItems, versionsGroup.Groups[key], configGroup, name+"."+key, key, false) - } - } else { - logger.Debugf("loadConfigGroup - %s - no groups", name) - } - logger.Debugf("loadConfigGroup - %s - << groups", name) - - logger.Debugf("loadConfigGroup - %s - >> values", name) - values := group.GetValues() - if values != nil { - versionsGroup.Values = make(map[string]*common.ConfigValue) - for key, configValue := range values { - versionsGroup.Values[key] = &common.ConfigValue{} - loadConfigValue(configItems, key, versionsGroup.Values[key], configValue, name, org) - } - } else { - logger.Debugf("loadConfigGroup - %s - no values", name) - } - logger.Debugf("loadConfigGroup - %s - << values", name) - - logger.Debugf("loadConfigGroup - %s - >> policies", name) - policies := group.GetPolicies() - if policies != nil { - versionsGroup.Policies = make(map[string]*common.ConfigPolicy) - for key, configPolicy := range policies { - versionsGroup.Policies[key] = &common.ConfigPolicy{} - loadConfigPolicy(configItems, key, versionsGroup.Policies[key], configPolicy, name, org) - } - } else { - logger.Debugf("loadConfigGroup - %s - no policies", name) - } - logger.Debugf("loadConfigGroup - %s - << policies", name) - logger.Debugf("loadConfigGroup - %s - < group", name) - return nil -} - -func loadConfigValue(configItems *configItems, key string, versionsValue *common.ConfigValue, configValue *common.ConfigValue, groupName string, org string) error { - logger.Debugf("loadConfigValue - %s - START value name: %s", groupName, key) - logger.Debugf("loadConfigValue - %s - version: %d", groupName, configValue.Version) - logger.Debugf("loadConfigValue - %s - modPolicy: %s", groupName, configValue.ModPolicy) - - versionsValue.Version = configValue.Version - - switch key { - case channelConfig.AnchorPeersKey: - anchorPeers := &pb.AnchorPeers{} - err := proto.Unmarshal(configValue.Value, anchorPeers) - if err != nil { - return errors.Wrap(err, "unmarshal anchor peers from config failed") - } - - logger.Debugf("loadConfigValue - %s - AnchorPeers :: %s", groupName, anchorPeers) - - if len(anchorPeers.AnchorPeers) > 0 { - for _, anchorPeer := range anchorPeers.AnchorPeers { - oap := &fab.OrgAnchorPeer{Org: org, Host: anchorPeer.Host, Port: anchorPeer.Port} - configItems.anchorPeers = append(configItems.anchorPeers, oap) - logger.Debugf("loadConfigValue - %s - AnchorPeer :: %s:%d:%s", groupName, oap.Host, oap.Port, oap.Org) - } - } - break - - case channelConfig.MSPKey: - mspConfig := &mb.MSPConfig{} - err := proto.Unmarshal(configValue.Value, mspConfig) - if err != nil { - return errors.Wrap(err, "unmarshal MSPConfig from config failed") - } - - logger.Debugf("loadConfigValue - %s - MSP found", groupName) - - mspType := msp.ProviderType(mspConfig.Type) - if mspType != msp.FABRIC { - return errors.Errorf("unsupported MSP type (%v)", mspType) - } - - configItems.msps = append(configItems.msps, mspConfig) - break - - case channelConfig.ConsensusTypeKey: - consensusType := &ab.ConsensusType{} - err := proto.Unmarshal(configValue.Value, consensusType) - if err != nil { - return errors.Wrap(err, "unmarshal ConsensusType from config failed") - } - - logger.Debugf("loadConfigValue - %s - Consensus type value :: %s", groupName, consensusType.Type) - // TODO: Do something with this value - break - - case channelConfig.BatchSizeKey: - batchSize := &ab.BatchSize{} - err := proto.Unmarshal(configValue.Value, batchSize) - if err != nil { - return errors.Wrap(err, "unmarshal batch size from config failed") - } - - logger.Debugf("loadConfigValue - %s - BatchSize maxMessageCount :: %d", groupName, batchSize.MaxMessageCount) - logger.Debugf("loadConfigValue - %s - BatchSize absoluteMaxBytes :: %d", groupName, batchSize.AbsoluteMaxBytes) - logger.Debugf("loadConfigValue - %s - BatchSize preferredMaxBytes :: %d", groupName, batchSize.PreferredMaxBytes) - // TODO: Do something with this value - break - - case channelConfig.BatchTimeoutKey: - batchTimeout := &ab.BatchTimeout{} - err := proto.Unmarshal(configValue.Value, batchTimeout) - if err != nil { - return errors.Wrap(err, "unmarshal batch timeout from config failed") - } - logger.Debugf("loadConfigValue - %s - BatchTimeout timeout value :: %s", groupName, batchTimeout.Timeout) - // TODO: Do something with this value - break - - case channelConfig.ChannelRestrictionsKey: - channelRestrictions := &ab.ChannelRestrictions{} - err := proto.Unmarshal(configValue.Value, channelRestrictions) - if err != nil { - return errors.Wrap(err, "unmarshal channel restrictions from config failed") - } - logger.Debugf("loadConfigValue - %s - ChannelRestrictions max_count value :: %d", groupName, channelRestrictions.MaxCount) - // TODO: Do something with this value - break - - case channelConfig.HashingAlgorithmKey: - hashingAlgorithm := &common.HashingAlgorithm{} - err := proto.Unmarshal(configValue.Value, hashingAlgorithm) - if err != nil { - return errors.Wrap(err, "unmarshal hashing algorithm from config failed") - } - logger.Debugf("loadConfigValue - %s - HashingAlgorithm names value :: %s", groupName, hashingAlgorithm.Name) - // TODO: Do something with this value - break - - case channelConfig.ConsortiumKey: - consortium := &common.Consortium{} - err := proto.Unmarshal(configValue.Value, consortium) - if err != nil { - return errors.Wrap(err, "unmarshal consortium from config failed") - } - logger.Debugf("loadConfigValue - %s - Consortium names value :: %s", groupName, consortium.Name) - // TODO: Do something with this value - break - - case channelConfig.BlockDataHashingStructureKey: - bdhstruct := &common.BlockDataHashingStructure{} - err := proto.Unmarshal(configValue.Value, bdhstruct) - if err != nil { - return errors.Wrap(err, "unmarshal block data hashing structure from config failed") - } - logger.Debugf("loadConfigValue - %s - BlockDataHashingStructure width value :: %s", groupName, bdhstruct.Width) - // TODO: Do something with this value - break - - case channelConfig.OrdererAddressesKey: - ordererAddresses := &common.OrdererAddresses{} - err := proto.Unmarshal(configValue.Value, ordererAddresses) - if err != nil { - return errors.Wrap(err, "unmarshal orderer addresses from config failed") - } - logger.Debugf("loadConfigValue - %s - OrdererAddresses addresses value :: %s", groupName, ordererAddresses.Addresses) - if len(ordererAddresses.Addresses) > 0 { - for _, ordererAddress := range ordererAddresses.Addresses { - configItems.orderers = append(configItems.orderers, ordererAddress) - } - } - break - - default: - logger.Debugf("loadConfigValue - %s - value: %s", groupName, configValue.Value) - } - return nil -} - -func loadPolicy(configItems *configItems, versionsPolicy *common.ConfigPolicy, key string, policy *common.Policy, groupName string, org string) error { - - policyType := common.Policy_PolicyType(policy.Type) - - switch policyType { - case common.Policy_SIGNATURE: - sigPolicyEnv := &common.SignaturePolicyEnvelope{} - err := proto.Unmarshal(policy.Value, sigPolicyEnv) - if err != nil { - return errors.Wrap(err, "unmarshal signature policy envelope from config failed") - } - logger.Debugf("loadConfigPolicy - %s - policy SIGNATURE :: %v", groupName, sigPolicyEnv.Rule) - // TODO: Do something with this value - break - - case common.Policy_MSP: - // TODO: Not implemented yet - logger.Debugf("loadConfigPolicy - %s - policy :: MSP POLICY NOT PARSED ", groupName) - break - - case common.Policy_IMPLICIT_META: - implicitMetaPolicy := &common.ImplicitMetaPolicy{} - err := proto.Unmarshal(policy.Value, implicitMetaPolicy) - if err != nil { - return errors.Wrap(err, "unmarshal implicit meta policy from config failed") - } - logger.Debugf("loadConfigPolicy - %s - policy IMPLICIT_META :: %v", groupName, implicitMetaPolicy) - // TODO: Do something with this value - break - - default: - return errors.Errorf("unknown policy type %v", policyType) - } - return nil -} - -func (c *Channel) loadConfigUpdate(configUpdateBytes []byte) (*configItems, error) { - - configUpdate := &common.ConfigUpdate{} - if err := proto.Unmarshal(configUpdateBytes, configUpdate); err != nil { - return nil, errors.Wrap(err, "unmarshal config update failed") - } - logger.Debugf("loadConfigUpdate - channel ::" + configUpdate.ChannelId) - - readSet := configUpdate.ReadSet - writeSet := configUpdate.WriteSet - - versions := &versions{ - ReadSet: readSet, - WriteSet: writeSet, - } - - configItems := &configItems{ - msps: []*mb.MSPConfig{}, - anchorPeers: []*fab.OrgAnchorPeer{}, - orderers: []string{}, - versions: versions, - } - - err := loadConfigGroup(configItems, configItems.versions.ReadSet, readSet, "read_set", "", false) - if err != nil { - return nil, err - } - // do the write_set second so they update anything in the read set - err = loadConfigGroup(configItems, configItems.versions.WriteSet, writeSet, "write_set", "", false) - if err != nil { - return nil, err - } - err = c.initializeFromConfig(configItems) - if err != nil { - return nil, errors.WithMessage(err, "channel initialization failed") - } - - //TODO should we create orderers and endorsing peers - return configItems, nil -} - -func (c *Channel) loadConfigEnvelope(configEnvelope *common.ConfigEnvelope) (*configItems, error) { - - group := configEnvelope.Config.ChannelGroup - - versions := &versions{ - Channel: &common.ConfigGroup{}, - } - - configItems := &configItems{ - msps: []*mb.MSPConfig{}, - anchorPeers: []*fab.OrgAnchorPeer{}, - orderers: []string{}, - versions: versions, - } - - err := loadConfigGroup(configItems, configItems.versions.Channel, group, "base", "", true) - if err != nil { - return nil, errors.WithMessage(err, "load config items from config group failed") - } - - err = c.initializeFromConfig(configItems) - - logger.Debugf("channel config: %v", configItems) - - return configItems, err -} diff --git a/pkg/fabric-client/channel/config_test.go b/pkg/fabric-client/channel/config_test.go index 89e10fb542..52ef84a1f2 100644 --- a/pkg/fabric-client/channel/config_test.go +++ b/pkg/fabric-client/channel/config_test.go @@ -6,12 +6,9 @@ SPDX-License-Identifier: Apache-2.0 package channel import ( - "io/ioutil" - "path" "testing" "github.com/hyperledger/fabric-sdk-go/pkg/fabric-client/mocks" - "github.com/hyperledger/fabric-sdk-go/test/metadata" ) func TestChannelConfigs(t *testing.T) { @@ -19,7 +16,7 @@ func TestChannelConfigs(t *testing.T) { user := mocks.NewMockUser("test") ctx := mocks.NewMockContext(user) - channel, _ := New(ctx, "testChannel") + channel, _ := New(ctx, mocks.NewMockChannelCfg("testChannel")) if channel.IsReadonly() { //TODO: Rightnow it is returning false always, need to revisit test once actual implementation is provided @@ -34,162 +31,3 @@ func TestChannelConfigs(t *testing.T) { channel.SetMSPManager(nil) } - -func TestLoadConfigUpdateEnvelope(t *testing.T) { - //Get Channel - channel, _ := setupTestChannel() - - //Read config file from test directory - fileLoc := path.Join("../../../", metadata.ChannelConfigPath, "mychannel.tx") - res, err := ioutil.ReadFile(fileLoc) - if err != nil { - t.Fatalf("Could not load config tx file: %s", err) - } - - //Pass config to LoadConfigUpdateEnvelope and test - err = channel.LoadConfigUpdateEnvelope(res) - - if err != nil { - t.Fatalf("LoadConfigUpdateEnvelope Test Failed with, Cause '%s'", err.Error()) - } - - err = channel.Initialize(res) - - if err != nil { - t.Fatalf("Initialize Negative Test Failed with, Cause '%s'", err.Error()) - } - - org1MSPID := "ORG1MSP" - org2MSPID := "ORG2MSP" - - builder := &mocks.MockConfigUpdateEnvelopeBuilder{} - - err = channel.LoadConfigUpdateEnvelope(builder.BuildBytes()) - - if err == nil { - t.Fatal("Expected error was : channel initialization error: unable to load MSPs from config") - } - - builder = &mocks.MockConfigUpdateEnvelopeBuilder{ - ChannelID: "mychannel", - MockConfigGroupBuilder: mocks.MockConfigGroupBuilder{ - ModPolicy: "Admins", - MSPNames: []string{ - org1MSPID, - org2MSPID, - }, - OrdererAddress: "localhost:7054", - RootCA: validRootCA, - }, - } - - //Create mock orderer - configBuilder := &mocks.MockConfigBlockBuilder{ - MockConfigGroupBuilder: mocks.MockConfigGroupBuilder{ - ModPolicy: "Admins", - MSPNames: []string{ - org1MSPID, - org2MSPID, - }, - OrdererAddress: "localhost:7054", - //RootCA: validRootCA, - }, - Index: 0, - LastConfigIndex: 0, - } - orderer := mocks.NewMockOrderer("", nil) - orderer.(mocks.MockOrderer).EnqueueForSendDeliver(configBuilder.Build()) - orderer.(mocks.MockOrderer).EnqueueForSendDeliver(configBuilder.Build()) - channel.AddOrderer(orderer) - - //Add a second orderer - configBuilder = &mocks.MockConfigBlockBuilder{ - MockConfigGroupBuilder: mocks.MockConfigGroupBuilder{ - ModPolicy: "Admins", - MSPNames: []string{ - org1MSPID, - org2MSPID, - }, - OrdererAddress: "localhost:7054", - //RootCA: validRootCA, - }, - Index: 0, - LastConfigIndex: 0, - } - orderer = mocks.NewMockOrderer("", nil) - orderer.(mocks.MockOrderer).EnqueueForSendDeliver(configBuilder.Build()) - orderer.(mocks.MockOrderer).EnqueueForSendDeliver(configBuilder.Build()) - channel.AddOrderer(orderer) - err = channel.Initialize(nil) - - if err == nil { - t.Fatal("Initialize on orderers config supposed to fail with 'could not decode pem bytes'") - } - -} - -func TestChannelInitialize(t *testing.T) { - org1MSPID := "ORG1MSP" - org2MSPID := "ORG2MSP" - - channel, _ := setupTestChannel() - builder := &mocks.MockConfigUpdateEnvelopeBuilder{ - ChannelID: "mychannel", - MockConfigGroupBuilder: mocks.MockConfigGroupBuilder{ - ModPolicy: "Admins", - MSPNames: []string{ - org1MSPID, - org2MSPID, - }, - OrdererAddress: "localhost:7054", - RootCA: validRootCA, - }, - } - - err := channel.Initialize(builder.BuildBytes()) - if err != nil { - t.Fatalf("channel Initialize failed : %v", err) - } - - mspManager := channel.MSPManager() - if mspManager == nil { - t.Fatalf("nil MSPManager on new channel") - } - -} - -//func TestChannelInitializeFromUpdate(t *testing.T) { -// org1MSPID := "ORG1MSP" -// org2MSPID := "ORG2MSP" -// -// client := mocks.NewMockClient() -// user := mocks.NewMockUser("test", ) -// cryptoSuite := &mocks.MockCryptoSuite{} -// client.SaveUserToStateStore(user, true) -// client.SetCryptoSuite(cryptoSuite) -// channel, _ := NewChannel("testChannel", client) -// -// builder := &mocks.MockConfigUpdateEnvelopeBuilder{ -// ChannelID: "mychannel", -// MockConfigGroupBuilder: mocks.MockConfigGroupBuilder{ -// ModPolicy: "Admins", -// MSPNames: []string{ -// org1MSPID, -// org2MSPID, -// }, -// OrdererAddress: "localhost:7054", -// RootCA: validRootCA, -// }, -// } -// -// err := channel.Initialize(builder.BuildBytes()) -// if err != nil { -// t.Fatalf("channel Initialize failed : %v", err) -// } -// -// mspManager := channel.MSPManager() -// if mspManager == nil { -// t.Fatalf("nil MSPManager on new channel") -// } -// -//} diff --git a/pkg/fabric-client/channel/query.go b/pkg/fabric-client/channel/query.go index e7170bb672..3bbbe4de6a 100644 --- a/pkg/fabric-client/channel/query.go +++ b/pkg/fabric-client/channel/query.go @@ -290,26 +290,6 @@ func (c *Channel) QueryConfigBlock(peers []fab.Peer, minResponses int) (*common. return nil, errors.New("config block must contain one transaction") } - envelope := &common.Envelope{} - if err = proto.Unmarshal(block.Data.Data[0], envelope); err != nil { - return nil, errors.Wrap(err, "unmarshal envelope from config block failed") - } - payload := &common.Payload{} - if err := proto.Unmarshal(envelope.Payload, payload); err != nil { - return nil, errors.Wrap(err, "unmarshal payload from envelope failed") - } - channelHeader := &common.ChannelHeader{} - if err := proto.Unmarshal(payload.Header.ChannelHeader, channelHeader); err != nil { - return nil, errors.Wrap(err, "unmarshal payload from envelope failed") - } - if common.HeaderType(channelHeader.Type) != common.HeaderType_CONFIG { - return nil, errors.New("block must be of type 'CONFIG'") - } - configEnvelope := &common.ConfigEnvelope{} - if err := proto.Unmarshal(payload.Data, configEnvelope); err != nil { - return nil, errors.Wrap(err, "unmarshal config envelope failed") - } - - return configEnvelope, nil + return createConfigEnvelope(block.Data.Data[0]) } diff --git a/pkg/fabric-client/channel/txnsender_test.go b/pkg/fabric-client/channel/txnsender_test.go index c68b9b6de8..9db9eb5027 100644 --- a/pkg/fabric-client/channel/txnsender_test.go +++ b/pkg/fabric-client/channel/txnsender_test.go @@ -132,7 +132,7 @@ func TestSendInstantiateProposal(t *testing.T) { //Setup channel user := mocks.NewMockUserWithMSPID("test", "1234") ctx := mocks.NewMockContext(user) - channel, _ := New(ctx, "testChannel") + channel, _ := New(ctx, mocks.NewMockChannelCfg("testChannel")) mockCtrl := gomock.NewController(t) defer mockCtrl.Finish() @@ -208,7 +208,7 @@ func TestSendUpgradeProposal(t *testing.T) { //Setup channel user := mocks.NewMockUserWithMSPID("test", "1234") ctx := mocks.NewMockContext(user) - channel, _ := New(ctx, "testChannel") + channel, _ := New(ctx, mocks.NewMockChannelCfg("testChannel")) mockCtrl := gomock.NewController(t) defer mockCtrl.Finish() diff --git a/pkg/fabric-client/chconfig/chconfig.go b/pkg/fabric-client/chconfig/chconfig.go index b456038f43..530f79ba83 100644 --- a/pkg/fabric-client/chconfig/chconfig.go +++ b/pkg/fabric-client/chconfig/chconfig.go @@ -53,6 +53,46 @@ type ChannelConfig struct { opts Opts } +// ChannelCfg contains channel configuration +type ChannelCfg struct { + name string + msps []*msp.MSPConfig + anchorPeers []*fab.OrgAnchorPeer + orderers []string + versions *fab.Versions +} + +// NewChannelCfg creates channel cfg +// TODO: This is temporary, Remove once we have config injected in sdk +func NewChannelCfg(name string) fab.ChannelCfg { + return &ChannelCfg{name: name} +} + +// Name returns name +func (cfg *ChannelCfg) Name() string { + return cfg.name +} + +// Msps returns msps +func (cfg *ChannelCfg) Msps() []*msp.MSPConfig { + return cfg.msps +} + +// AnchorPeers returns anchor peers +func (cfg *ChannelCfg) AnchorPeers() []*fab.OrgAnchorPeer { + return cfg.anchorPeers +} + +// Orderers returns orderers +func (cfg *ChannelCfg) Orderers() []string { + return cfg.orderers +} + +// Versions returns versions +func (cfg *ChannelCfg) Versions() *fab.Versions { + return cfg.versions +} + // New channel config implementation func New(ctx fab.Context, channelID string, options ...Option) (*ChannelConfig, error) { opts, err := prepareOpts(options...) @@ -64,14 +104,18 @@ func New(ctx fab.Context, channelID string, options ...Option) (*ChannelConfig, } // Query returns channel configuration -func (c *ChannelConfig) Query() (*fab.ChannelCfg, error) { - // TODO: Add orderer impl later on +func (c *ChannelConfig) Query() (fab.ChannelCfg, error) { + + if c.opts.Orderer != "" { + return c.queryOrderer() + } + return c.queryPeers() } -func (c *ChannelConfig) queryPeers() (*fab.ChannelCfg, error) { +func (c *ChannelConfig) queryPeers() (*ChannelCfg, error) { - ch, err := channel.New(c.ctx, c.channelID) + ch, err := channel.New(c.ctx, &ChannelCfg{name: c.channelID}) if err != nil { return nil, errors.WithMessage(err, "NewChannel failed") } @@ -106,7 +150,22 @@ func (c *ChannelConfig) queryPeers() (*fab.ChannelCfg, error) { return nil, errors.WithMessage(err, "QueryBlockConfig failed") } - return extractConfig(configEnvelope) + return extractConfig(c.channelID, configEnvelope) +} + +func (c *ChannelConfig) queryOrderer() (*ChannelCfg, error) { + + ch, err := channel.New(c.ctx, &ChannelCfg{name: c.channelID, orderers: []string{c.opts.Orderer}}) + if err != nil { + return nil, errors.WithMessage(err, "NewChannel failed") + } + + configEnvelope, err := ch.ChannelConfig() + if err != nil { + return nil, errors.WithMessage(err, "ChannelConfig() failed") + } + + return extractConfig(c.channelID, configEnvelope) } // WithPeers encapsulates peers to Option @@ -145,7 +204,7 @@ func prepareOpts(options ...Option) (Opts, error) { return opts, nil } -func extractConfig(configEnvelope *common.ConfigEnvelope) (*fab.ChannelCfg, error) { +func extractConfig(channel string, configEnvelope *common.ConfigEnvelope) (*ChannelCfg, error) { group := configEnvelope.Config.ChannelGroup @@ -153,14 +212,15 @@ func extractConfig(configEnvelope *common.ConfigEnvelope) (*fab.ChannelCfg, erro Channel: &common.ConfigGroup{}, } - config := &fab.ChannelCfg{ - Msps: []*msp.MSPConfig{}, - AnchorPeers: []*fab.OrgAnchorPeer{}, - Orderers: []string{}, - Versions: versions, + config := &ChannelCfg{ + name: channel, + msps: []*msp.MSPConfig{}, + anchorPeers: []*fab.OrgAnchorPeer{}, + orderers: []string{}, + versions: versions, } - err := loadConfig(config, config.Versions.Channel, group, "base", "", true) + err := loadConfig(config, config.versions.Channel, group, "base", "", true) if err != nil { return nil, errors.WithMessage(err, "load config items from config group failed") } @@ -171,7 +231,7 @@ func extractConfig(configEnvelope *common.ConfigEnvelope) (*fab.ChannelCfg, erro } -func loadConfig(configItems *fab.ChannelCfg, versionsGroup *common.ConfigGroup, group *common.ConfigGroup, name string, org string, top bool) error { +func loadConfig(configItems *ChannelCfg, versionsGroup *common.ConfigGroup, group *common.ConfigGroup, name string, org string, top bool) error { logger.Debugf("loadConfigGroup - %s - START groups Org: %s", name, org) if group == nil { return nil @@ -224,7 +284,7 @@ func loadConfig(configItems *fab.ChannelCfg, versionsGroup *common.ConfigGroup, return nil } -func loadConfigPolicy(configItems *fab.ChannelCfg, key string, versionsPolicy *common.ConfigPolicy, configPolicy *common.ConfigPolicy, groupName string, org string) error { +func loadConfigPolicy(configItems *ChannelCfg, key string, versionsPolicy *common.ConfigPolicy, configPolicy *common.ConfigPolicy, groupName string, org string) error { logger.Debugf("loadConfigPolicy - %s - name: %s", groupName, key) logger.Debugf("loadConfigPolicy - %s - version: %d", groupName, configPolicy.Version) logger.Debugf("loadConfigPolicy - %s - mod_policy: %s", groupName, configPolicy.ModPolicy) @@ -233,7 +293,7 @@ func loadConfigPolicy(configItems *fab.ChannelCfg, key string, versionsPolicy *c return loadPolicy(configItems, versionsPolicy, key, configPolicy.Policy, groupName, org) } -func loadPolicy(configItems *fab.ChannelCfg, versionsPolicy *common.ConfigPolicy, key string, policy *common.Policy, groupName string, org string) error { +func loadPolicy(configItems *ChannelCfg, versionsPolicy *common.ConfigPolicy, key string, policy *common.Policy, groupName string, org string) error { policyType := common.Policy_PolicyType(policy.Type) @@ -269,7 +329,7 @@ func loadPolicy(configItems *fab.ChannelCfg, versionsPolicy *common.ConfigPolicy return nil } -func loadConfigValue(configItems *fab.ChannelCfg, key string, versionsValue *common.ConfigValue, configValue *common.ConfigValue, groupName string, org string) error { +func loadConfigValue(configItems *ChannelCfg, key string, versionsValue *common.ConfigValue, configValue *common.ConfigValue, groupName string, org string) error { logger.Debugf("loadConfigValue - %s - START value name: %s", groupName, key) logger.Debugf("loadConfigValue - %s - version: %d", groupName, configValue.Version) logger.Debugf("loadConfigValue - %s - modPolicy: %s", groupName, configValue.ModPolicy) @@ -289,7 +349,7 @@ func loadConfigValue(configItems *fab.ChannelCfg, key string, versionsValue *com if len(anchorPeers.AnchorPeers) > 0 { for _, anchorPeer := range anchorPeers.AnchorPeers { oap := &fab.OrgAnchorPeer{Org: org, Host: anchorPeer.Host, Port: anchorPeer.Port} - configItems.AnchorPeers = append(configItems.AnchorPeers, oap) + configItems.anchorPeers = append(configItems.anchorPeers, oap) logger.Debugf("loadConfigValue - %s - AnchorPeer :: %s:%d:%s", groupName, oap.Host, oap.Port, oap.Org) } } @@ -309,7 +369,7 @@ func loadConfigValue(configItems *fab.ChannelCfg, key string, versionsValue *com return errors.Errorf("unsupported MSP type (%v)", mspType) } - configItems.Msps = append(configItems.Msps, mspConfig) + configItems.msps = append(configItems.msps, mspConfig) break case channelConfig.ConsensusTypeKey: @@ -395,7 +455,7 @@ func loadConfigValue(configItems *fab.ChannelCfg, key string, versionsValue *com logger.Debugf("loadConfigValue - %s - OrdererAddresses addresses value :: %s", groupName, ordererAddresses.Addresses) if len(ordererAddresses.Addresses) > 0 { for _, ordererAddress := range ordererAddresses.Addresses { - configItems.Orderers = append(configItems.Orderers, ordererAddress) + configItems.orderers = append(configItems.orderers, ordererAddress) } } break diff --git a/pkg/fabric-client/chconfig/chconfig_test.go b/pkg/fabric-client/chconfig/chconfig_test.go new file mode 100644 index 0000000000..f6f73133f6 --- /dev/null +++ b/pkg/fabric-client/chconfig/chconfig_test.go @@ -0,0 +1,128 @@ +/* +Copyright SecureKey Technologies Inc. All Rights Reserved. + +SPDX-License-Identifier: Apache-2.0 +*/ +package chconfig + +import ( + "testing" + + "github.com/golang/protobuf/proto" + fab "github.com/hyperledger/fabric-sdk-go/api/apifabclient" + "github.com/hyperledger/fabric-sdk-go/pkg/fabric-client/channel" + "github.com/hyperledger/fabric-sdk-go/pkg/fabric-client/mocks" +) + +const ( + channelID = "testChannel" +) + +func TestChannelConfigWithPeer(t *testing.T) { + + ctx := setupTestContext() + peer := getPeerWithConfigBlockPayload(t) + + channelConfig, err := New(ctx, channelID, WithPeers([]fab.Peer{peer}), WithMinResponses(1)) + if err != nil { + t.Fatalf("Failed to create new channel client: %s", err) + } + + cfg, err := channelConfig.Query() + if err != nil { + t.Fatalf(err.Error()) + } + + if cfg.Name() != channelID { + t.Fatalf("Channel name error. Expecting %s, got %s ", channelID, cfg.Name()) + } +} + +func TestChannelConfigWithPeerError(t *testing.T) { + + ctx := setupTestContext() + peer := getPeerWithConfigBlockPayload(t) + + channelConfig, err := New(ctx, channelID, WithPeers([]fab.Peer{peer}), WithMinResponses(2)) + if err != nil { + t.Fatalf("Failed to create new channel client: %s", err) + } + + _, err = channelConfig.Query() + if err == nil { + t.Fatalf("Should have failed with since there's one endorser and at least two are required") + } +} + +func TestChannelConfigWithOrdererError(t *testing.T) { + + ctx := setupTestContext() + + channelConfig, err := New(ctx, channelID, WithOrderer("localhost:7054")) + if err != nil { + t.Fatalf("Failed to create new channel client: %s", err) + } + + // Expecting error since orderer is not setup + _, err = channelConfig.Query() + if err == nil { + t.Fatalf("Should have failed since orderer is not available") + } + +} + +func setupTestChannel(name string) (*channel.Channel, error) { + ctx := setupTestContext() + return channel.New(ctx, mocks.NewMockChannelCfg(name)) +} + +func setupTestContext() fab.Context { + user := mocks.NewMockUser("test") + ctx := mocks.NewMockContext(user) + return ctx +} + +func getPeerWithConfigBlockPayload(t *testing.T) fab.Peer { + + // create config block builder in order to create valid payload + builder := &mocks.MockConfigBlockBuilder{ + MockConfigGroupBuilder: mocks.MockConfigGroupBuilder{ + ModPolicy: "Admins", + MSPNames: []string{ + "Org1MSP", + "Org2MSP", + }, + OrdererAddress: "localhost:7054", + RootCA: validRootCA, + }, + Index: 0, + LastConfigIndex: 0, + } + + payload, err := proto.Marshal(builder.Build()) + if err != nil { + t.Fatalf("Failed to marshal mock block") + } + + // peer with valid config block payload + peer := &mocks.MockPeer{MockName: "Peer1", MockURL: "http://peer1.com", MockRoles: []string{}, MockCert: nil, Payload: payload} + + return peer +} + +var validRootCA = `-----BEGIN CERTIFICATE----- +MIICYjCCAgmgAwIBAgIUB3CTDOU47sUC5K4kn/Caqnh114YwCgYIKoZIzj0EAwIw +fzELMAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExFjAUBgNVBAcTDVNh +biBGcmFuY2lzY28xHzAdBgNVBAoTFkludGVybmV0IFdpZGdldHMsIEluYy4xDDAK +BgNVBAsTA1dXVzEUMBIGA1UEAxMLZXhhbXBsZS5jb20wHhcNMTYxMDEyMTkzMTAw +WhcNMjExMDExMTkzMTAwWjB/MQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZv +cm5pYTEWMBQGA1UEBxMNU2FuIEZyYW5jaXNjbzEfMB0GA1UEChMWSW50ZXJuZXQg +V2lkZ2V0cywgSW5jLjEMMAoGA1UECxMDV1dXMRQwEgYDVQQDEwtleGFtcGxlLmNv +bTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABKIH5b2JaSmqiQXHyqC+cmknICcF +i5AddVjsQizDV6uZ4v6s+PWiJyzfA/rTtMvYAPq/yeEHpBUB1j053mxnpMujYzBh +MA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBQXZ0I9 +qp6CP8TFHZ9bw5nRtZxIEDAfBgNVHSMEGDAWgBQXZ0I9qp6CP8TFHZ9bw5nRtZxI +EDAKBggqhkjOPQQDAgNHADBEAiAHp5Rbp9Em1G/UmKn8WsCbqDfWecVbZPQj3RK4 +oG5kQQIgQAe4OOKYhJdh3f7URaKfGTf492/nmRmtK+ySKjpHSrU= +-----END CERTIFICATE----- +` diff --git a/pkg/fabric-client/client.go b/pkg/fabric-client/client.go index 86a7ffb3dc..0808893065 100644 --- a/pkg/fabric-client/client.go +++ b/pkg/fabric-client/client.go @@ -18,6 +18,7 @@ import ( "github.com/hyperledger/fabric-sdk-go/api/apicryptosuite" "github.com/hyperledger/fabric-sdk-go/pkg/errors" channel "github.com/hyperledger/fabric-sdk-go/pkg/fabric-client/channel" + "github.com/hyperledger/fabric-sdk-go/pkg/fabric-client/chconfig" "github.com/hyperledger/fabric-sdk-go/pkg/fabric-client/identity" "github.com/hyperledger/fabric-sdk-go/pkg/fabric-client/resource" "github.com/hyperledger/fabric-sdk-go/pkg/logging" @@ -58,7 +59,7 @@ func (c *Client) NewChannel(name string) (fab.Channel, error) { } ctx := fabContext{ProviderContext: c, IdentityContext: c.signingIdentity} - channel, err := channel.New(ctx, name) + channel, err := channel.New(ctx, chconfig.NewChannelCfg(name)) if err != nil { return nil, err } diff --git a/pkg/fabric-client/mocks/mockchconfig.go b/pkg/fabric-client/mocks/mockchconfig.go new file mode 100644 index 0000000000..a34262a67a --- /dev/null +++ b/pkg/fabric-client/mocks/mockchconfig.go @@ -0,0 +1,51 @@ +/* +Copyright SecureKey Technologies Inc. All Rights Reserved. + +SPDX-License-Identifier: Apache-2.0 +*/ + +package mocks + +import ( + fab "github.com/hyperledger/fabric-sdk-go/api/apifabclient" + msp "github.com/hyperledger/fabric-sdk-go/third_party/github.com/hyperledger/fabric/protos/msp" +) + +// MockChannelCfg contains mock channel configuration +type MockChannelCfg struct { + MockName string + MockMsps []*msp.MSPConfig + MockAnchorPeers []*fab.OrgAnchorPeer + MockOrderers []string + MockVersions *fab.Versions +} + +// NewMockChannelCfg ... +func NewMockChannelCfg(name string) fab.ChannelCfg { + return &MockChannelCfg{MockName: name} +} + +// Name returns name +func (cfg *MockChannelCfg) Name() string { + return cfg.MockName +} + +// Msps returns msps +func (cfg *MockChannelCfg) Msps() []*msp.MSPConfig { + return cfg.MockMsps +} + +// AnchorPeers returns anchor peers +func (cfg *MockChannelCfg) AnchorPeers() []*fab.OrgAnchorPeer { + return cfg.MockAnchorPeers +} + +// Orderers returns orderers +func (cfg *MockChannelCfg) Orderers() []string { + return cfg.MockOrderers +} + +// Versions returns versions +func (cfg *MockChannelCfg) Versions() *fab.Versions { + return cfg.MockVersions +} diff --git a/pkg/fabric-client/orderer/deprecated_test.go b/pkg/fabric-client/orderer/deprecated_test.go index b551196707..5589a3f43f 100644 --- a/pkg/fabric-client/orderer/deprecated_test.go +++ b/pkg/fabric-client/orderer/deprecated_test.go @@ -20,104 +20,9 @@ import ( "github.com/hyperledger/fabric-sdk-go/pkg/errors" "github.com/hyperledger/fabric-sdk-go/pkg/errors/status" - client "github.com/hyperledger/fabric-sdk-go/pkg/fabric-client" mocks "github.com/hyperledger/fabric-sdk-go/pkg/fabric-client/mocks" ) -// -// Orderer via chain setOrderer/getOrderer -// -// Set the orderer URL through the chain setOrderer method. Verify that the -// orderer URL was set correctly through the getOrderer method. Repeat the -// process by updating the orderer URL to a different address. -// -func TestDeprecatedOrdererViaChain(t *testing.T) { - client := client.NewClient(mocks.NewMockConfig()) - chain, err := client.NewChannel("testChain-orderer-member") - if err != nil { - t.Fatalf("error from NewChain %v", err) - } - orderer, _ := NewOrderer("localhost:7050", "", "", mocks.NewMockConfig()) - err = chain.AddOrderer(orderer) - if err != nil { - t.Fatalf("Error adding orderer: %v", err) - } - - orderers := chain.Orderers() - if orderers == nil || len(orderers) != 1 || orderers[0].URL() != "localhost:7050" { - t.Fatalf("Failed to retieve the new orderer URL from the chain") - } - chain.RemoveOrderer(orderer) - orderer2, err := NewOrderer("localhost:7054", "", "", mocks.NewMockConfig()) - if err != nil { - t.Fatalf("Failed to create NewOrderer error(%v)", err) - } - err = chain.AddOrderer(orderer2) - if err != nil { - t.Fatalf("Error adding orderer: %v", err) - } - orderers = chain.Orderers() - - if orderers == nil || len(orderers) != 1 || orderers[0].URL() != "localhost:7054" { - t.Fatalf("Failed to retieve the new orderer URL from the chain") - } - -} - -// -// Orderer via chain missing orderer -// -// Attempt to send a request to the orderer with the sendTransaction method -// before the orderer URL was set. Verify that an error is reported when tying -// to send the request. -// -func TestDeprecatedPeerViaChainMissingOrderer(t *testing.T) { - client := client.NewClient(mocks.NewMockConfig()) - chain, err := client.NewChannel("testChain-orderer-member2") - if err != nil { - t.Fatalf("error from NewChain %v", err) - } - _, err = chain.SendTransaction(nil) - if err == nil { - t.Fatalf("SendTransaction didn't return error") - } - if err.Error() != "orderers is nil" { - t.Fatalf("SendTransaction didn't return right error") - } - -} - -// -// Orderer via chain nil data -// -// Attempt to send a request to the orderer with the sendTransaction method -// with the data set to null. Verify that an error is reported when tying -// to send null data. -// -func TestDeprecatedOrdererViaChainNilData(t *testing.T) { - client := client.NewClient(mocks.NewMockConfig()) - chain, err := client.NewChannel("testChain-orderer-member2") - if err != nil { - t.Fatalf("error from NewChain %v", err) - } - orderer, err := NewOrderer("localhost:7050", "", "", mocks.NewMockConfig()) - if err != nil { - t.Fatalf("Failed to create NewOrderer error(%v)", err) - } - err = chain.AddOrderer(orderer) - if err != nil { - t.Fatalf("Error adding orderer: %v", err) - } - - _, err = chain.SendTransaction(nil) - if err == nil { - t.Fatalf("SendTransaction didn't return error") - } - if err.Error() != "transaction is nil" { - t.Fatalf("SendTransaction didn't return right error") - } -} - func TestDeprecatedSendDeliver(t *testing.T) { grpcServer := grpc.NewServer() defer grpcServer.Stop() diff --git a/pkg/fabric-client/orderer/orderer_test.go b/pkg/fabric-client/orderer/orderer_test.go index bd78eda66a..1da4c4eb24 100644 --- a/pkg/fabric-client/orderer/orderer_test.go +++ b/pkg/fabric-client/orderer/orderer_test.go @@ -25,7 +25,6 @@ import ( "github.com/hyperledger/fabric-sdk-go/pkg/errors" "github.com/hyperledger/fabric-sdk-go/pkg/errors/status" - client "github.com/hyperledger/fabric-sdk-go/pkg/fabric-client" mocks "github.com/hyperledger/fabric-sdk-go/pkg/fabric-client/mocks" ) @@ -47,101 +46,6 @@ EDAKBggqhkjOPQQDAgNHADBEAiAHp5Rbp9Em1G/UmKn8WsCbqDfWecVbZPQj3RK4 oG5kQQIgQAe4OOKYhJdh3f7URaKfGTf492/nmRmtK+ySKjpHSrU= -----END CERTIFICATE-----` -// -// Orderer via chain setOrderer/getOrderer -// -// Set the orderer URL through the chain setOrderer method. Verify that the -// orderer URL was set correctly through the getOrderer method. Repeat the -// process by updating the orderer URL to a different address. -// -func TestOrdererViaChain(t *testing.T) { - client := client.NewClient(mocks.NewMockConfig()) - chain, err := client.NewChannel("testChain-orderer-member") - if err != nil { - t.Fatalf("error from NewChain %v", err) - } - orderer, _ := New(mocks.NewMockConfig(), WithURL("localhost:7050")) - err = chain.AddOrderer(orderer) - if err != nil { - t.Fatalf("Error adding orderer: %v", err) - } - - orderers := chain.Orderers() - if orderers == nil || len(orderers) != 1 || orderers[0].URL() != "localhost:7050" { - t.Fatalf("Failed to retieve the new orderer URL from the chain") - } - chain.RemoveOrderer(orderer) - orderer2, err := New(mocks.NewMockConfig(), WithURL("localhost:7054")) - if err != nil { - t.Fatalf("Failed to create New orderer: error(%v)", err) - } - err = chain.AddOrderer(orderer2) - if err != nil { - t.Fatalf("Error adding orderer: %v", err) - } - orderers = chain.Orderers() - - if orderers == nil || len(orderers) != 1 || orderers[0].URL() != "localhost:7054" { - t.Fatalf("Failed to retieve the new orderer URL from the chain") - } - -} - -// -// Orderer via chain missing orderer -// -// Attempt to send a request to the orderer with the sendTransaction method -// before the orderer URL was set. Verify that an error is reported when tying -// to send the request. -// -func TestPeerViaChainMissingOrderer(t *testing.T) { - client := client.NewClient(mocks.NewMockConfig()) - chain, err := client.NewChannel("testChain-orderer-member2") - if err != nil { - t.Fatalf("error from NewChain %v", err) - } - _, err = chain.SendTransaction(nil) - if err == nil { - t.Fatalf("SendTransaction didn't return error") - } - if err.Error() != "orderers is nil" { - t.Fatalf("SendTransaction didn't return right error") - } - -} - -// -// Orderer via chain nil data -// -// Attempt to send a request to the orderer with the sendTransaction method -// with the data set to null. Verify that an error is reported when tying -// to send null data. -// -func TestOrdererViaChainNilData(t *testing.T) { - client := client.NewClient(mocks.NewMockConfig()) - chain, err := client.NewChannel("testChain-orderer-member2") - if err != nil { - t.Fatalf("error from NewChain %v", err) - } - orderer, err := New(mocks.NewMockConfig(), WithURL("localhost:7050")) - - if err != nil { - t.Fatalf("Failed to create New orderer: error(%v)", err) - } - err = chain.AddOrderer(orderer) - if err != nil { - t.Fatalf("Error adding orderer: %v", err) - } - - _, err = chain.SendTransaction(nil) - if err == nil { - t.Fatalf("SendTransaction didn't return error") - } - if err.Error() != "transaction is nil" { - t.Fatalf("SendTransaction didn't return right error") - } -} - func TestSendDeliver(t *testing.T) { grpcServer := grpc.NewServer() defer grpcServer.Stop() diff --git a/pkg/fabric-txn/chclient/chclient_test.go b/pkg/fabric-txn/chclient/chclient_test.go index 79be583916..d9bcefb8ac 100644 --- a/pkg/fabric-txn/chclient/chclient_test.go +++ b/pkg/fabric-txn/chclient/chclient_test.go @@ -327,7 +327,7 @@ func TestExecuteTxWithRetries(t *testing.T) { func setupTestChannel() (*channel.Channel, error) { ctx := setupTestContext() - return channel.New(ctx, "testChannel") + return channel.New(ctx, fcmocks.NewMockChannelCfg("testChannel")) } func setupTestContext() apifabclient.Context { diff --git a/pkg/fabric-txn/resmgmtclient/resmgmt_test.go b/pkg/fabric-txn/resmgmtclient/resmgmt_test.go index 79d48cb5f8..4f34843341 100644 --- a/pkg/fabric-txn/resmgmtclient/resmgmt_test.go +++ b/pkg/fabric-txn/resmgmtclient/resmgmt_test.go @@ -66,7 +66,7 @@ func TestJoinChannel(t *testing.T) { rc := setupResMgmtClient(ctx, nil, t) - channel, err := channel.New(ctx, "mychannel") + channel, err := channel.New(ctx, fcmocks.NewMockChannelCfg("mychannel")) if err != nil { t.Fatalf("Error setting up channel: %v", err) } @@ -962,7 +962,7 @@ func TestCCProposal(t *testing.T) { rc = setupResMgmtClient(ctx, nil, t) - channel, err := channel.New(ctx, "mychannel") + channel, err := channel.New(ctx, fcmocks.NewMockChannelCfg("mychannel")) if err != nil { t.Fatalf("Error setting up channel: %v", err) } @@ -1071,7 +1071,7 @@ func setupResMgmtClient(fabCtx fab.Context, discErr error, t *testing.T) *Resour } // Create test channel and add it to the client (no added orderer yet) - channel, err := channel.New(fabCtx, "mychannel") + channel, err := channel.New(fabCtx, fcmocks.NewMockChannelCfg("mychannel")) if err != nil { t.Fatalf("Failed to setup channel: %s", err) } diff --git a/pkg/fabric-txn/txnhandler/txnhandler_test.go b/pkg/fabric-txn/txnhandler/txnhandler_test.go index a7ebc46cf1..35c57c0f78 100644 --- a/pkg/fabric-txn/txnhandler/txnhandler_test.go +++ b/pkg/fabric-txn/txnhandler/txnhandler_test.go @@ -122,7 +122,7 @@ func prepareRequestContext(request chclient.Request, opts chclient.Opts, t *test func setupTestChannel() (*channel.Channel, error) { ctx := setupTestContext() - return channel.New(ctx, "testChannel") + return channel.New(ctx, fcmocks.NewMockChannelCfg("testChannel")) } func setupTestContext() apifabclient.Context { diff --git a/pkg/fabsdk/provider/fabpvdr/fabpvdr.go b/pkg/fabsdk/provider/fabpvdr/fabpvdr.go index 8d543510f2..0f351e2220 100644 --- a/pkg/fabsdk/provider/fabpvdr/fabpvdr.go +++ b/pkg/fabsdk/provider/fabpvdr/fabpvdr.go @@ -60,7 +60,7 @@ func (f *FabricProvider) NewChannelClient(ic apifabclient.IdentityContext, chann ProviderContext: f.providerContext, IdentityContext: ic, } - channel, err := channelImpl.New(ctx, channelID) + channel, err := channelImpl.New(ctx, chconfig.NewChannelCfg(channelID)) if err != nil { return nil, errors.WithMessage(err, "NewChannel failed") } diff --git a/test/integration/base_test_setup.go b/test/integration/base_test_setup.go index c4f58374aa..f2dad680fb 100644 --- a/test/integration/base_test_setup.go +++ b/test/integration/base_test_setup.go @@ -136,10 +136,6 @@ func (setup *BaseSetupImpl) Initialize(t *testing.T) error { time.Sleep(time.Second * 3) - if err = channel.Initialize(nil); err != nil { - return errors.WithMessage(err, "channel init failed") - } - if err = resMgmtClient.JoinChannel(setup.ChannelID); err != nil { return errors.WithMessage(err, "JoinChannel failed") } diff --git a/test/integration/sdk/channel_config_test.go b/test/integration/sdk/channel_config_test.go index 1d4785190f..27ea26fb1c 100644 --- a/test/integration/sdk/channel_config_test.go +++ b/test/integration/sdk/channel_config_test.go @@ -10,8 +10,13 @@ import ( "path" "testing" + "github.com/hyperledger/fabric-sdk-go/api/apicore" + "github.com/hyperledger/fabric-sdk-go/api/apifabclient" "github.com/hyperledger/fabric-sdk-go/pkg/config" + "github.com/hyperledger/fabric-sdk-go/pkg/fabric-client/chconfig" "github.com/hyperledger/fabric-sdk-go/pkg/fabsdk" + "github.com/hyperledger/fabric-sdk-go/pkg/fabsdk/factory/defcore" + "github.com/hyperledger/fabric-sdk-go/pkg/fabsdk/provider/fabpvdr" "github.com/hyperledger/fabric-sdk-go/test/integration" "github.com/hyperledger/fabric-sdk-go/test/metadata" ) @@ -53,7 +58,7 @@ func TestChannelConfig(t *testing.T) { expected := "orderer.example.com:7050" found := false - for _, o := range response.Orderers { + for _, o := range response.Orderers() { if o == expected { found = true break @@ -61,7 +66,92 @@ func TestChannelConfig(t *testing.T) { } if !found { - t.Fatalf("Expected orderer %s, got %s", expected, response.Orderers) + t.Fatalf("Expected orderer %s, got %s", expected, response.Orderers()) } } + +func TestChannelConfigWithOrderer(t *testing.T) { + + testSetup := integration.BaseSetupImpl{ + ConfigFile: "../" + integration.ConfigTestFile, + ChannelID: "mychannel", + OrgID: org1Name, + ChannelConfig: path.Join("../../../", metadata.ChannelConfigPath, "mychannel.tx"), + ConnectEventHub: true, + } + + if err := testSetup.Initialize(t); err != nil { + t.Fatalf(err.Error()) + } + + // Create SDK setup for channel client with retrieve channel configuration from orderer + sdk, err := fabsdk.New(config.FromFile(testSetup.ConfigFile), + fabsdk.WithCorePkg(&ChannelConfigFromOrdererProviderFactory{orderer: "orderer.example.com"})) + if err != nil { + t.Fatalf("Failed to create new SDK: %s", err) + } + + cs, err := sdk.NewClient(fabsdk.WithUser("User1")).ChannelService(testSetup.ChannelID) + if err != nil { + t.Fatalf("Failed to create new channel service: %s", err) + } + + cfg, err := cs.ChannelConfig() + if err != nil { + t.Fatalf("Failed to create new channel config: %s", err) + } + + response, err := cfg.Query() + if err != nil { + t.Fatalf(err.Error()) + } + + expected := "orderer.example.com:7050" + found := false + for _, o := range response.Orderers() { + if o == expected { + found = true + break + } + } + + if !found { + t.Fatalf("Expected orderer %s, got %s", expected, response.Orderers()) + } + +} + +// ChannelConfigFromOrdererProviderFactory is configured to retrieve channel config from orderer +type ChannelConfigFromOrdererProviderFactory struct { + defcore.ProviderFactory + orderer string +} + +// CustomFabricProvider overrides channel config default implementation +type CustomFabricProvider struct { + fabpvdr.FabricProvider + orderer string + providerContext apifabclient.ProviderContext +} + +// NewChannelConfig initializes the channel config +func (f *CustomFabricProvider) NewChannelConfig(ic apifabclient.IdentityContext, channelID string) (apifabclient.ChannelConfig, error) { + + ctx := chconfig.Context{ + ProviderContext: f.providerContext, + IdentityContext: ic, + } + + return chconfig.New(ctx, channelID, chconfig.WithOrderer(f.orderer)) +} + +// NewFabricProvider returns a new default implementation of fabric primitives +func (f *ChannelConfigFromOrdererProviderFactory) NewFabricProvider(context apifabclient.ProviderContext) (apicore.FabricProvider, error) { + + cfp := CustomFabricProvider{ + providerContext: context, + orderer: f.orderer, + } + return &cfp, nil +}