Skip to content

Commit

Permalink
Merge "[FAB-6951] Add resource configuration functions to cscc"
Browse files Browse the repository at this point in the history
  • Loading branch information
Jason Yellick authored and Gerrit Code Review committed Dec 8, 2017
2 parents b495096 + 1f66393 commit eee12ef
Show file tree
Hide file tree
Showing 12 changed files with 237 additions and 34 deletions.
28 changes: 28 additions & 0 deletions common/config/api.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/*
Copyright IBM Corp. 2017 All Rights Reserved.
SPDX-License-Identifier: Apache-2.0
*/
package config

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

// Config encapsulates config (channel or resource) tree
type Config interface {
// ConfigProto returns the current config
ConfigProto() *cb.Config

// ProposeConfigUpdate attempts to validate a new configtx against the current config state
ProposeConfigUpdate(configtx *cb.Envelope) (*cb.ConfigEnvelope, error)
}

// Manager provides access to the resource config
type Manager interface {
// GetChannelConfig defines methods that are related to channel configuration
GetChannelConfig(channel string) Config

// GetResourceConfig defines methods that are related to resource configuration
GetResourceConfig(channel string) Config
}
8 changes: 5 additions & 3 deletions core/aclmgmt/aclmgmt.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,11 @@ const (
QSCC_GetBlockByTxID = "QSCC.GetBlockByTxID"

//CSCC resources
CSCC_JoinChain = "CSCC.JoinChain"
CSCC_GetConfigBlock = "CSCC.GetConfigBlock"
CSCC_GetChannels = "CSCC.GetChannels"
CSCC_JoinChain = "CSCC.JoinChain"
CSCC_GetConfigBlock = "CSCC.GetConfigBlock"
CSCC_GetChannels = "CSCC.GetChannels"
CSCC_GetConfigTree = "CSCC.GetConfigTree"
CSCC_SimulateConfigTreeUpdate = "CSCC.SimulateConfigTreeUpdate"

//Chaincode-to-Chaincode call
CC2CC = "CC2CC"
Expand Down
2 changes: 2 additions & 0 deletions core/aclmgmt/defaultaclprovider.go
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,8 @@ func (d *defaultACLProvider) initialize() {

//c resources
d.cResourcePolicyMap[CSCC_GetConfigBlock] = CHANNELREADERS
d.cResourcePolicyMap[CSCC_GetConfigTree] = CHANNELREADERS
d.cResourcePolicyMap[CSCC_SimulateConfigTreeUpdate] = CHANNELWRITERS

//---------------- non-scc resources ------------
//Propose
Expand Down
39 changes: 39 additions & 0 deletions core/peer/peer.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import (
"github.com/hyperledger/fabric/core/ledger/customtx"

"github.com/hyperledger/fabric/common/channelconfig"
cc "github.com/hyperledger/fabric/common/config"
"github.com/hyperledger/fabric/common/configtx"
configtxtest "github.com/hyperledger/fabric/common/configtx/test"
"github.com/hyperledger/fabric/common/deliver"
Expand Down Expand Up @@ -738,3 +739,41 @@ func (flbs fileLedgerBlockStore) AddBlock(*common.Block) error {
func (flbs fileLedgerBlockStore) RetrieveBlocks(startBlockNumber uint64) (commonledger.ResultsIterator, error) {
return flbs.GetBlocksIterator(startBlockNumber)
}

// NewResourceConfigSupport returns
func NewConfigSupport() cc.Manager {
return &configSupport{}
}

type configSupport struct {
}

// GetChannelConfig returns an instance of a object that represents
// current channel configuration tree of the specified channel. The
// ConfigProto method of the returned object can be used to get the
// proto representing the channel configuration.
func (*configSupport) GetChannelConfig(channel string) cc.Config {
chains.RLock()
defer chains.RUnlock()
chain := chains.list[channel]
if chain == nil {
peerLogger.Error("GetChannelConfig: channel", channel, "not found in the list of channels associated with this peer")
return nil
}
return chain.cs.bundleSource.ChannelConfig().ConfigtxValidator()
}

// GetResourceConfig returns an instance of a object that represents
// current resource configuration tree of the specified channel. The
// ConfigProto method of the returned object can be used to get the
// proto representing the resource configuration.
func (*configSupport) GetResourceConfig(channel string) cc.Config {
chains.RLock()
defer chains.RUnlock()
chain := chains.list[channel]
if chain == nil {
peerLogger.Error("GetResourceConfig: channel", channel, "not found in the list of channels associated with this peer")
return nil
}
return chain.cs.bundleSource.ConfigtxValidator()
}
7 changes: 7 additions & 0 deletions core/peer/peer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,13 @@ func TestCreateChainFromBlock(t *testing.T) {
t.Fatalf("failed to get correct block")
}

cfgSupport := configSupport{}
chCfg := cfgSupport.GetChannelConfig(testChainID)
assert.NotNil(t, chCfg, "failed to get channel config")

resCfg := cfgSupport.GetResourceConfig(testChainID)
assert.NotNil(t, resCfg, "failed to get resource config")

// Bad block
block = GetCurrConfigBlock("BogusBlock")
if block != nil {
Expand Down
101 changes: 92 additions & 9 deletions core/scc/cscc/configure.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,11 @@ limitations under the License.
package cscc

import (
"errors"
"fmt"

"github.com/golang/protobuf/proto"
"github.com/hyperledger/fabric/common/channelconfig"
"github.com/hyperledger/fabric/common/config"
"github.com/hyperledger/fabric/common/flogging"
"github.com/hyperledger/fabric/core/aclmgmt"
"github.com/hyperledger/fabric/core/chaincode/shim"
Expand All @@ -37,22 +37,26 @@ import (
"github.com/hyperledger/fabric/protos/common"
pb "github.com/hyperledger/fabric/protos/peer"
"github.com/hyperledger/fabric/protos/utils"
"github.com/pkg/errors"
)

// PeerConfiger implements the configuration handler for the peer. For every
// configuration transaction coming in from the ordering service, the
// committer calls this system chaincode to process the transaction.
type PeerConfiger struct {
policyChecker policy.PolicyChecker
configMgr config.Manager
}

var cnflogger = flogging.MustGetLogger("cscc")

// These are function names from Invoke first parameter
const (
JoinChain string = "JoinChain"
GetConfigBlock string = "GetConfigBlock"
GetChannels string = "GetChannels"
JoinChain string = "JoinChain"
GetConfigBlock string = "GetConfigBlock"
GetChannels string = "GetChannels"
GetConfigTree string = "GetConfigTree"
SimulateConfigTreeUpdate string = "SimulateConfigTreeUpdate"
)

// Init is called once per chain when the chain is created.
Expand All @@ -67,7 +71,7 @@ func (e *PeerConfiger) Init(stub shim.ChaincodeStubInterface) pb.Response {
mgmt.GetLocalMSP(),
mgmt.NewLocalMSPPrincipalGetter(),
)

e.configMgr = peer.NewConfigSupport()
return shim.Success(nil)
}

Expand Down Expand Up @@ -140,6 +144,19 @@ func (e *PeerConfiger) Invoke(stub shim.ChaincodeStubInterface) pb.Response {
}

return getConfigBlock(args[1])
case GetConfigTree:
// 2. check policy
if err = aclmgmt.GetACLProvider().CheckACL(aclmgmt.CSCC_GetConfigTree, string(args[1]), sp); err != nil {
return shim.Error(fmt.Sprintf("\"GetConfigTree\" request failed authorization check for channel [%s]: [%s]", args[1], err))
}

return e.getConfigTree(args[1])
case SimulateConfigTreeUpdate:
// Check policy
if err = aclmgmt.GetACLProvider().CheckACL(aclmgmt.CSCC_SimulateConfigTreeUpdate, string(args[1]), sp); err != nil {
return shim.Error(fmt.Sprintf("\"SimulateConfigTreeUpdate\" request failed authorization check for channel [%s]: [%s]", args[1], err))
}
return e.simulateConfigTreeUpdate(args[1], args[2])
case GetChannels:
// 2. check local MSP Members policy
// TODO: move to ACLProvider once it will support chainless ACLs
Expand All @@ -157,13 +174,13 @@ func (e *PeerConfiger) Invoke(stub shim.ChaincodeStubInterface) pb.Response {
func validateConfigBlock(block *common.Block) error {
envelopeConfig, err := utils.ExtractEnvelope(block, 0)
if err != nil {
return errors.New(fmt.Sprintf("Failed to %s", err))
return errors.Errorf("Failed to %s", err)
}

configEnv := &common.ConfigEnvelope{}
_, err = utils.UnmarshalEnvelopeOfType(envelopeConfig, common.HeaderType_CONFIG, configEnv)
if err != nil {
return errors.New(fmt.Sprintf("Bad configuration envelope: %s", err))
return errors.Errorf("Bad configuration envelope: %s", err)
}

if configEnv.Config == nil {
Expand All @@ -180,8 +197,8 @@ func validateConfigBlock(block *common.Block) error {

_, exists := configEnv.Config.ChannelGroup.Groups[channelconfig.ApplicationGroupKey]
if !exists {
return errors.New(fmt.Sprintf("Invalid configuration block, missing %s "+
"configuration group", channelconfig.ApplicationGroupKey))
return errors.Errorf("Invalid configuration block, missing %s "+
"configuration group", channelconfig.ApplicationGroupKey)
}

return nil
Expand Down Expand Up @@ -227,6 +244,72 @@ func getConfigBlock(chainID []byte) pb.Response {
return shim.Success(blockBytes)
}

// getConfigTree returns the current channel and resources configuration for the specified chainID.
// If the peer doesn't belong to the chain, returns error
func (e *PeerConfiger) getConfigTree(chainID []byte) pb.Response {
if chainID == nil {
return shim.Error("Chain ID must not be nil")
}
channelCfg := e.configMgr.GetChannelConfig(string(chainID)).ConfigProto()
if channelCfg == nil {
return shim.Error(fmt.Sprintf("Unknown chain ID, %s", string(chainID)))
}
resCfg := e.configMgr.GetResourceConfig(string(chainID)).ConfigProto()
if resCfg == nil {
return shim.Error(fmt.Sprintf("Unknown chain ID, %s", string(chainID)))
}
agCfg := &pb.ConfigTree{ChannelConfig: channelCfg, ResourcesConfig: resCfg}
configBytes, err := utils.Marshal(agCfg)
if err != nil {
return shim.Error(err.Error())
}
return shim.Success(configBytes)
}

func (e *PeerConfiger) simulateConfigTreeUpdate(chainID []byte, envb []byte) pb.Response {
if chainID == nil {
return shim.Error("Chain ID must not be nil")
}
if envb == nil {
return shim.Error("Config delta bytes must not be nil")
}
env := &common.Envelope{}
err := proto.Unmarshal(envb, env)
if err != nil {
return shim.Error(err.Error())
}
cfg, err := supportByType(e, chainID, env)
if err != nil {
return shim.Error(err.Error())
}
_, err = cfg.ProposeConfigUpdate(env)
if err != nil {
return shim.Error(err.Error())
}
return shim.Success([]byte("Simulation is successful"))
}

func supportByType(pc *PeerConfiger, chainID []byte, env *common.Envelope) (config.Config, error) {
payload := &common.Payload{}

if err := proto.Unmarshal(env.Payload, payload); err != nil {
return nil, errors.Errorf("failed unmarshaling payload: %v", err)
}

channelHdr := &common.ChannelHeader{}
if err := proto.Unmarshal(payload.Header.ChannelHeader, channelHdr); err != nil {
return nil, errors.Errorf("failed unmarshaling payload header: %v", err)
}

switch common.HeaderType(channelHdr.Type) {
case common.HeaderType_CONFIG_UPDATE:
return pc.configMgr.GetChannelConfig(string(chainID)), nil
case common.HeaderType_PEER_RESOURCE_UPDATE:
return pc.configMgr.GetResourceConfig(string(chainID)), nil
}
return nil, errors.Errorf("invalid payload header type: %d", channelHdr.Type)
}

// getChannels returns information about all channels for this peer
func getChannels() pb.Response {
channelInfoArray := peer.GetChannelsInfo()
Expand Down
2 changes: 1 addition & 1 deletion peer/channel/join.go
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ func executeJoin(cf *ChannelCmdFactory) (err error) {
if proposalResp.Response.Status != 0 && proposalResp.Response.Status != 200 {
return ProposalFailedErr(fmt.Sprintf("bad proposal response %d", proposalResp.Response.Status))
}
logger.Infof("Successfully submitted proposal to join channel '%s'", channelID)
logger.Info("Successfully submitted proposal to join channel")
return nil
}

Expand Down
2 changes: 1 addition & 1 deletion protos/common/configtx.proto
Original file line number Diff line number Diff line change
Expand Up @@ -112,4 +112,4 @@ message ConfigPolicy {
message ConfigSignature {
bytes signature_header = 1; // A marshaled SignatureHeader
bytes signature = 2; // Signature over the concatenation signatureHeader bytes and config bytes
}
}
2 changes: 1 addition & 1 deletion protos/common/configuration.proto
Original file line number Diff line number Diff line change
Expand Up @@ -86,4 +86,4 @@ message Capabilities {
// message rather than a constant, so that we may extend capabilities with other fields
// if the need arises in the future. For the time being, a capability being in the
// capabilities map requires that that capability be supported.
message Capability { }
message Capability { }
1 change: 1 addition & 0 deletions protos/peer/admin.pb.go

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

Loading

0 comments on commit eee12ef

Please sign in to comment.