Skip to content

Commit

Permalink
[FAB-1697] Add chain hashing algorithm config
Browse files Browse the repository at this point in the history
https://jira.hyperledger.org/browse/FAB-1697

This changeset adds the chain hashing algorithm to the configuration
proto.  It also adds a chain configuration consumer (for configuration
items of chain type) which is capable of processing this message once
embedded in the genesis block.

Actually embedding this and utilizing the chain configuration will come
in later changesets.

Change-Id: I960ce4c6ca73b988840585364876e970cbf99a47
Signed-off-by: Jason Yellick <jyellick@us.ibm.com>
  • Loading branch information
Jason Yellick committed Jan 17, 2017
1 parent 0e0de5c commit e057af8
Show file tree
Hide file tree
Showing 5 changed files with 288 additions and 40 deletions.
120 changes: 120 additions & 0 deletions common/chainconfig/chainconfig.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
/*
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 chainconfig

import (
"fmt"

"github.com/hyperledger/fabric/common/util"
cb "github.com/hyperledger/fabric/protos/common"

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

// Chain config keys
const (
// HashingAlgorithmKey is the cb.ConfigurationItem type key name for the HashingAlgorithm message
HashingAlgorithmKey = "HashingAlgorithm"
)

// Hashing algorithm types
const (
// SHAKE256 is the algorithm type for the sha3 shake256 hashing algorithm with 512 bits of output
SHA3Shake256 = "SHAKE256"
)

var logger = logging.MustGetLogger("common/chainconfig")

// Descriptor stores the common chain 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 {
// HashingAlgorithm returns the default algorithm to be used when hashing
// such as computing block hashes, and CreationPolicy digests
HashingAlgorithm() func(input []byte) []byte
}

type chainConfig struct {
hashingAlgorithm func(input []byte) []byte
}

// 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 *chainConfig
config *chainConfig
}

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

// HashingAlgorithm returns a function pointer to the chain hashing algorihtm
func (pm *DescriptorImpl) HashingAlgorithm() func(input []byte) []byte {
return pm.config.hashingAlgorithm
}

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

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

// CommitConfig is used to commit a new configuration proposal
func (pm *DescriptorImpl) CommitConfig() {
if pm.pendingConfig == nil {
logger.Panicf("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 *DescriptorImpl) ProposeConfig(configItem *cb.ConfigurationItem) error {
if configItem.Type != cb.ConfigurationItem_Chain {
return fmt.Errorf("Expected type of ConfigurationItem_Chain, got %v", configItem.Type)
}

switch configItem.Key {
case HashingAlgorithmKey:
hashingAlgorithm := &cb.HashingAlgorithm{}
if err := proto.Unmarshal(configItem.Value, hashingAlgorithm); err != nil {
return fmt.Errorf("Unmarshaling error for HashingAlgorithm: %s", err)
}
switch hashingAlgorithm.Name {
case SHA3Shake256:
pm.pendingConfig.hashingAlgorithm = util.ComputeCryptoHash
default:
return fmt.Errorf("Unknown hashing algorithm type: %s", hashingAlgorithm.Name)
}
default:
logger.Warningf("Uknown Chain configuration item with key %s", configItem.Key)
}
return nil
}
104 changes: 104 additions & 0 deletions common/chainconfig/chainconfig_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
/*
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 chainconfig

import (
"testing"

cb "github.com/hyperledger/fabric/protos/common"
"github.com/hyperledger/fabric/protos/utils"

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

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

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 = &chainConfig{}
m.RollbackConfig()
if m.pendingConfig != nil {
t.Fatalf("Should have cleared pending config on rollback")
}
}

func TestHashingAlgorithm(t *testing.T) {
invalidMessage :=
&cb.ConfigurationItem{
Type: cb.ConfigurationItem_Chain,
Key: HashingAlgorithmKey,
Value: []byte("Garbage Data"),
}
invalidAlgorithm := &cb.ConfigurationItem{
Type: cb.ConfigurationItem_Chain,
Key: HashingAlgorithmKey,
Value: utils.MarshalOrPanic(&cb.HashingAlgorithm{Name: "MD5"}),
}
validAlgorithm := &cb.ConfigurationItem{
Type: cb.ConfigurationItem_Chain,
Key: HashingAlgorithmKey,
Value: utils.MarshalOrPanic(&cb.HashingAlgorithm{Name: SHA3Shake256}),
}
m := NewDescriptorImpl()
m.BeginConfig()

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

err = m.ProposeConfig(invalidAlgorithm)
if err == nil {
t.Fatalf("Should have failed on invalid algorithm")
}

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

m.CommitConfig()

if m.HashingAlgorithm() == nil {
t.Fatalf("Should have set default hashing algorithm")
}
}
1 change: 1 addition & 0 deletions protos/common/common.pb.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

95 changes: 55 additions & 40 deletions protos/common/configuration.pb.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 8 additions & 0 deletions protos/common/configuration.proto
Original file line number Diff line number Diff line change
Expand Up @@ -116,3 +116,11 @@ message SignaturePolicy {
NOutOf From = 2;
}
}


// HashingAlgorithm is encoded into the configuration transaction as a configuration item of type CHAIN
// with a Key of "HashingAlgorithm" as marshaled protobuf bytes
message HashingAlgorithm {
// Currently supported algorithms are: SHAKE256
string name = 1;
}

0 comments on commit e057af8

Please sign in to comment.