Skip to content

Commit

Permalink
Merge "Introduce orderer sharedconfig mechanism"
Browse files Browse the repository at this point in the history
  • Loading branch information
gaborh-da authored and Gerrit Code Review committed Dec 5, 2016
2 parents 97e6c35 + e6d3b99 commit da16559
Show file tree
Hide file tree
Showing 9 changed files with 482 additions and 20 deletions.
58 changes: 47 additions & 11 deletions orderer/common/bootstrap/static/static.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,38 +20,74 @@ import (
"github.com/hyperledger/fabric/orderer/common/bootstrap"
"github.com/hyperledger/fabric/orderer/common/cauthdsl"
"github.com/hyperledger/fabric/orderer/common/configtx"
"github.com/hyperledger/fabric/orderer/common/sharedconfig"
"github.com/hyperledger/fabric/orderer/common/util"
cb "github.com/hyperledger/fabric/protos/common"
ab "github.com/hyperledger/fabric/protos/orderer"
)

var TestChainID = "**TEST_CHAINID**"

const msgVersion = int32(1)

type bootstrapper struct {
chainID string
chainID string
lastModified uint64
epoch uint64
consensusType string
batchSize int32
}

// New returns a new static bootstrap helper.
func New() bootstrap.Helper {
return &bootstrapper{chainID: TestChainID}
return &bootstrapper{
chainID: TestChainID,
consensusType: "solo",
batchSize: 10,
}
}

// GenesisBlock returns the genesis block to be used for bootstrapping
func (b *bootstrapper) GenesisBlock() (*cb.Block, error) {
func (b *bootstrapper) encodeConsensusType() *cb.SignedConfigurationItem {
configItemKey := sharedconfig.ConsensusTypeKey
configItemValue := util.MarshalOrPanic(&ab.ConsensusType{Type: b.consensusType})
modPolicy := configtx.DefaultModificationPolicyID

configItemChainHeader := util.MakeChainHeader(cb.HeaderType_CONFIGURATION_ITEM, msgVersion, b.chainID, b.epoch)
configItem := util.MakeConfigurationItem(configItemChainHeader, cb.ConfigurationItem_Orderer, b.lastModified, modPolicy, configItemKey, configItemValue)
return &cb.SignedConfigurationItem{ConfigurationItem: util.MarshalOrPanic(configItem), Signatures: nil}
}

func (b *bootstrapper) encodeBatchSize() *cb.SignedConfigurationItem {
configItemKey := sharedconfig.BatchSizeKey
configItemValue := util.MarshalOrPanic(&ab.BatchSize{Messages: b.batchSize})
modPolicy := configtx.DefaultModificationPolicyID

configItemChainHeader := util.MakeChainHeader(cb.HeaderType_CONFIGURATION_ITEM, msgVersion, b.chainID, b.epoch)
configItem := util.MakeConfigurationItem(configItemChainHeader, cb.ConfigurationItem_Orderer, b.lastModified, modPolicy, configItemKey, configItemValue)
return &cb.SignedConfigurationItem{ConfigurationItem: util.MarshalOrPanic(configItem), Signatures: nil}
}

func (b *bootstrapper) lockDefaultModificationPolicy() *cb.SignedConfigurationItem {
// Lock down the default modification policy to prevent any further policy modifications
configItemKey := configtx.DefaultModificationPolicyID
configItemValue := util.MarshalOrPanic(util.MakePolicyOrPanic(cauthdsl.RejectAllPolicy))
modPolicy := configtx.DefaultModificationPolicyID

lastModified := uint64(0)
epoch := uint64(0)
configItemChainHeader := util.MakeChainHeader(cb.HeaderType_CONFIGURATION_ITEM, msgVersion, b.chainID, epoch)
configItem := util.MakeConfigurationItem(configItemChainHeader, cb.ConfigurationItem_Policy, lastModified, modPolicy, configItemKey, configItemValue)
signedConfigItem := &cb.SignedConfigurationItem{ConfigurationItem: util.MarshalOrPanic(configItem), Signatures: nil}
configItemChainHeader := util.MakeChainHeader(cb.HeaderType_CONFIGURATION_ITEM, msgVersion, b.chainID, b.epoch)
configItem := util.MakeConfigurationItem(configItemChainHeader, cb.ConfigurationItem_Policy, b.lastModified, modPolicy, configItemKey, configItemValue)
return &cb.SignedConfigurationItem{ConfigurationItem: util.MarshalOrPanic(configItem), Signatures: nil}
}

// GenesisBlock returns the genesis block to be used for bootstrapping
func (b *bootstrapper) GenesisBlock() (*cb.Block, error) {
configItemChainHeader := util.MakeChainHeader(cb.HeaderType_CONFIGURATION_ITEM, msgVersion, b.chainID, b.epoch)

configEnvelope := util.MakeConfigurationEnvelope(signedConfigItem)
payloadChainHeader := util.MakeChainHeader(cb.HeaderType_CONFIGURATION_TRANSACTION, configItemChainHeader.Version, b.chainID, epoch)
configEnvelope := util.MakeConfigurationEnvelope(
b.encodeConsensusType(),
b.encodeBatchSize(),
b.lockDefaultModificationPolicy(),
)
payloadChainHeader := util.MakeChainHeader(cb.HeaderType_CONFIGURATION_TRANSACTION, configItemChainHeader.Version, b.chainID, b.epoch)
payloadSignatureHeader := util.MakeSignatureHeader(nil, util.CreateNonceOrPanic())
payloadHeader := util.MakePayloadHeader(payloadChainHeader, payloadSignatureHeader)
payload := &cb.Payload{Header: payloadHeader, Data: util.MarshalOrPanic(configEnvelope)}
Expand Down
4 changes: 2 additions & 2 deletions orderer/common/bootstrap/static/static_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ func TestGenesisBlockData(t *testing.T) {
expectedPayloadChainHeaderType := int32(cb.HeaderType_CONFIGURATION_TRANSACTION)
expectedChainHeaderVersion := msgVersion
expectedChainHeaderEpoch := uint64(0)
expectedConfigEnvelopeItemsLength := 1
expectedConfigEnvelopeItemsLength := 3
expectedConfigurationItemChainHeaderType := int32(cb.HeaderType_CONFIGURATION_ITEM)
expectedConfigurationItemChainHeaderVersion := msgVersion
expectedConfigurationItemType := cb.ConfigurationItem_Policy
Expand Down Expand Up @@ -110,7 +110,7 @@ func TestGenesisBlockData(t *testing.T) {
t.Fatalf("Expected configuration envelope to have %d configuration item(s), got %d", expectedConfigEnvelopeItemsLength, len(configurationEnvelope.Items))
}

signedConfigurationItem := configurationEnvelope.Items[0]
signedConfigurationItem := configurationEnvelope.Items[2]
marshaledConfigurationItem := signedConfigurationItem.ConfigurationItem
configurationItem := &cb.ConfigurationItem{}
if err := proto.Unmarshal(marshaledConfigurationItem, configurationItem); err != nil {
Expand Down
141 changes: 141 additions & 0 deletions orderer/common/sharedconfig/sharedconfig.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
/*
Copyright IBM Corp. 2016 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"
ab "github.com/hyperledger/fabric/protos/orderer"

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

// ConsensusTypeKey is the cb.ConfigurationItem type key name for the ConsensusType message
const ConsensusTypeKey = "ConsensusType"

// BatchSizeKey is the cb.ConfigurationItem type key name for the BatchSize message
const BatchSizeKey = "BatchSize"

var logger = logging.MustGetLogger("orderer/common/sharedconfig")

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

// Manager stores the common shared orderer configuration
// It is intended to be the primary accessor of ManagerImpl
// It is intended to discourage use of the other exported ManagerImpl methods
// which are used for updating the orderer configuration by the ConfigManager
type Manager interface {
// ConsensusType returns the configured consensus type
ConsensusType() string

// BatchSize returns the maximum number of messages to include in a block
BatchSize() int
}

type ordererConfig struct {
consensusType string
batchSize int
}

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

// NewManagerImpl creates a new ManagerImpl with the given CryptoHelper
func NewManagerImpl() *ManagerImpl {
return &ManagerImpl{
config: &ordererConfig{},
}
}

// ConsensusType returns the configured consensus type
func (pm *ManagerImpl) ConsensusType() string {
return pm.config.consensusType
}

// BatchSize returns the maximum number of messages to include in a block
func (pm *ManagerImpl) BatchSize() int {
return pm.config.batchSize
}

// BeginConfig is used to start a new configuration proposal
func (pm *ManagerImpl) BeginConfig() {
if pm.pendingConfig != nil {
logger.Fatalf("Programming error, cannot call begin in the middle of a proposal")
}
pm.pendingConfig = &ordererConfig{}
}

// RollbackConfig is used to abandon a new configuration proposal
func (pm *ManagerImpl) RollbackConfig() {
pm.pendingConfig = nil
}

// CommitConfig is used to commit a new configuration proposal
func (pm *ManagerImpl) CommitConfig() {
if pm.pendingConfig == nil {
logger.Fatalf("Programming error, cannot call commit without an existing proposal")
}
pm.config = pm.pendingConfig
pm.pendingConfig = nil
}

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

switch configItem.Key {
case ConsensusTypeKey:
consensusType := &ab.ConsensusType{}
err := proto.Unmarshal(configItem.Value, consensusType)
if err != nil {
return fmt.Errorf("Unmarshaling error for ConsensusType: %s", err)
}
if pm.config.consensusType == "" {
// The first configuration we accept the consensus type regardless
pm.config.consensusType = consensusType.Type
}
if consensusType.Type != pm.config.consensusType {
return fmt.Errorf("Attempted to change the consensus type from %s to %s after init", pm.config.consensusType, consensusType.Type)
}

pm.pendingConfig.consensusType = consensusType.Type
case BatchSizeKey:
batchSize := &ab.BatchSize{}
err := proto.Unmarshal(configItem.Value, batchSize)
if err != nil {
return fmt.Errorf("Unmarshaling error for BatchSize: %s", err)
}

if batchSize.Messages <= 0 {
return fmt.Errorf("Attempted to set the batch size to %d which is less than or equal to 0", batchSize.Messages)
}

pm.pendingConfig.batchSize = int(batchSize.Messages)
}

return nil
}
Loading

0 comments on commit da16559

Please sign in to comment.