Skip to content

Commit

Permalink
[FAB-1851] Add peer sharedconfig
Browse files Browse the repository at this point in the history
https://jira.hyperledger.org/browse/FAB-1851

This changeset adds a peer sharedconfig package.  The sharedconfig is
named as such, because it is configuration which is shared across all
peers for a channel, as opposed to the local configuration which the
peer sources from its yaml file.

Change-Id: I46bc408ed15a065020722666ee8e50d9f679e665
Signed-off-by: Jason Yellick <jyellick@us.ibm.com>
  • Loading branch information
Jason Yellick committed Jan 25, 2017
1 parent e111bac commit 9f07b96
Show file tree
Hide file tree
Showing 4 changed files with 259 additions and 1 deletion.
5 changes: 4 additions & 1 deletion core/peer/peer.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ import (
"github.com/hyperledger/fabric/core/ledger/ledgermgmt"
"github.com/hyperledger/fabric/gossip/service"
mspmgmt "github.com/hyperledger/fabric/msp/mgmt"
"github.com/hyperledger/fabric/peer/sharedconfig"
"github.com/hyperledger/fabric/protos/common"
"github.com/hyperledger/fabric/protos/utils"
)
Expand Down Expand Up @@ -160,8 +161,10 @@ func createChain(cid string, ledger ledger.PeerLedger, cb *common.Block) error {
return err
}

sharedConfigHandler := sharedconfig.NewDescriptorImpl()

configtxInitializer := configtx.NewInitializer()
// TODO Hook peer shared config manager in here once it exists
configtxInitializer.Handlers()[common.ConfigurationItem_Peer] = sharedConfigHandler
configtxManager, err := configtx.NewManagerImpl(configEnvelope, configtxInitializer)
if err != nil {
return err
Expand Down
114 changes: 114 additions & 0 deletions peer/sharedconfig/sharedconfig.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
/*
Copyright IBM Corp. 2017 All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package sharedconfig

import (
"fmt"

cb "github.com/hyperledger/fabric/protos/common"
pb "github.com/hyperledger/fabric/protos/peer"

"github.com/golang/protobuf/proto"
"github.com/op/go-logging"
)

// Peer config keys
const (
// AnchorPeersKey is the cb.ConfigurationItem type key name for the AnchorPeers message
AnchorPeersKey = "AnchorPeers"
)

var logger = logging.MustGetLogger("peer/sharedconfig")

// Descriptor stores the common peer configuration
// It is intended to be the primary accessor of DescriptorImpl
// It is intended to discourage use of the other exported DescriptorImpl methods
// which are used for updating the chain configuration by the configtx.Manager
type Descriptor interface {
// AnchorPeers returns the list of anchor peers for the channel
AnchorPeers() []*pb.AnchorPeer
}

type sharedConfig struct {
anchorPeers []*pb.AnchorPeer
}

// DescriptorImpl is an implementation of Manager and configtx.ConfigHandler
// In general, it should only be referenced as an Impl for the configtx.Manager
type DescriptorImpl struct {
pendingConfig *sharedConfig
config *sharedConfig
}

// NewDescriptorImpl creates a new DescriptorImpl with the given CryptoHelper
func NewDescriptorImpl() *DescriptorImpl {
return &DescriptorImpl{
config: &sharedConfig{},
}
}

// AnchorPeers returns the list of valid orderer addresses to connect to to invoke Broadcast/Deliver
func (di *DescriptorImpl) AnchorPeers() []*pb.AnchorPeer {
return di.config.anchorPeers
}

// BeginConfig is used to start a new configuration proposal
func (di *DescriptorImpl) BeginConfig() {
logger.Debugf("Beginning a possible new peer shared configuration")
if di.pendingConfig != nil {
logger.Panicf("Programming error, cannot call begin in the middle of a proposal")
}
di.pendingConfig = &sharedConfig{}
}

// RollbackConfig is used to abandon a new configuration proposal
func (di *DescriptorImpl) RollbackConfig() {
logger.Debugf("Rolling back proposed peer shared configuration")
di.pendingConfig = nil
}

// CommitConfig is used to commit a new configuration proposal
func (di *DescriptorImpl) CommitConfig() {
logger.Debugf("Committing new peer shared configuration")
if di.pendingConfig == nil {
logger.Panicf("Programming error, cannot call commit without an existing proposal")
}
di.config = di.pendingConfig
di.pendingConfig = nil
}

// ProposeConfig is used to add new configuration to the configuration proposal
func (di *DescriptorImpl) ProposeConfig(configItem *cb.ConfigurationItem) error {
if configItem.Type != cb.ConfigurationItem_Peer {
return fmt.Errorf("Expected type of ConfigurationItem_Peer, got %v", configItem.Type)
}

switch configItem.Key {
case AnchorPeersKey:
anchorPeers := &pb.AnchorPeers{}
if err := proto.Unmarshal(configItem.Value, anchorPeers); err != nil {
return fmt.Errorf("Unmarshaling error for %s: %s", configItem.Key, err)
}
if logger.IsEnabledFor(logging.DEBUG) {
logger.Debugf("Setting %s to %v", configItem.Key, anchorPeers.AnchorPeers)
}
di.pendingConfig.anchorPeers = anchorPeers.AnchorPeers
default:
logger.Warningf("Uknown Peer configuration item with key %s", configItem.Key)
}
return nil
}
102 changes: 102 additions & 0 deletions peer/sharedconfig/sharedconfig_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
/*
Copyright IBM Corp. 2017 All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package sharedconfig

import (
"reflect"
"testing"

cb "github.com/hyperledger/fabric/protos/common"
pb "github.com/hyperledger/fabric/protos/peer"

logging "github.com/op/go-logging"
)

func init() {
logging.SetLevel(logging.DEBUG, "")
}

func makeInvalidConfigItem(key string) *cb.ConfigurationItem {
return &cb.ConfigurationItem{
Type: cb.ConfigurationItem_Peer,
Key: key,
Value: []byte("Garbage Data"),
}
}

func TestInterface(t *testing.T) {
_ = Descriptor(NewDescriptorImpl())
}

func TestDoubleBegin(t *testing.T) {
defer func() {
if err := recover(); err == nil {
t.Fatalf("Should have panicked on multiple begin configs")
}
}()

m := NewDescriptorImpl()
m.BeginConfig()
m.BeginConfig()
}

func TestCommitWithoutBegin(t *testing.T) {
defer func() {
if err := recover(); err == nil {
t.Fatalf("Should have panicked on multiple begin configs")
}
}()

m := NewDescriptorImpl()
m.CommitConfig()
}

func TestRollback(t *testing.T) {
m := NewDescriptorImpl()
m.pendingConfig = &sharedConfig{}
m.RollbackConfig()
if m.pendingConfig != nil {
t.Fatalf("Should have cleared pending config on rollback")
}
}

func TestAnchorPeers(t *testing.T) {
endVal := []*pb.AnchorPeer{
&pb.AnchorPeer{Host: "foo", Port: 234, Cert: []byte("foocert")},
&pb.AnchorPeer{Host: "bar", Port: 237, Cert: []byte("barcert")},
}
invalidMessage := makeInvalidConfigItem(AnchorPeersKey)
validMessage := TemplateAnchorPeers(endVal)
m := NewDescriptorImpl()
m.BeginConfig()

err := m.ProposeConfig(invalidMessage)
if err == nil {
t.Fatalf("Should have failed on invalid message")
}

err = m.ProposeConfig(validMessage)
if err != nil {
t.Fatalf("Error applying valid config: %s", err)
}

m.CommitConfig()

if newVal := m.AnchorPeers(); !reflect.DeepEqual(newVal, endVal) {
t.Fatalf("Unexpected anchor peers, got %v expected %v", newVal, endVal)
}
}
39 changes: 39 additions & 0 deletions peer/sharedconfig/sharedconfig_util.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/*
Copyright IBM Corp. 2017 All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package sharedconfig

import (
cb "github.com/hyperledger/fabric/protos/common"
pb "github.com/hyperledger/fabric/protos/peer"
"github.com/hyperledger/fabric/protos/utils"
)

var defaultAnchorPeers = []*pb.AnchorPeer{}

// TemplateAnchorPeers creates a headerless configuration item representing the anchor peers
func TemplateAnchorPeers(anchorPeers []*pb.AnchorPeer) *cb.ConfigurationItem {
return &cb.ConfigurationItem{
Type: cb.ConfigurationItem_Peer,
Key: AnchorPeersKey,
Value: utils.MarshalOrPanic(&pb.AnchorPeers{AnchorPeers: anchorPeers}),
}
}

// DefaultAnchorPeers creates a headerless configuration item for the default orderer addresses
func DefaultAnchorPeers() *cb.ConfigurationItem {
return TemplateAnchorPeers(defaultAnchorPeers)
}

0 comments on commit 9f07b96

Please sign in to comment.