Skip to content

Commit 1f66393

Browse files
Anil Ambatiyacovm
authored andcommitted
[FAB-6951] Add resource configuration functions to cscc
Added GetConfigTree and SimulateConfigTreeUpdate verbs to the configuration system chaincode. Change-Id: I43cff8078c956b2ed73611f0cd6c8d4acb57f904 Signed-off-by: Anil Ambati <aambati@us.ibm.com> Signed-off-by: yacovm <yacovm@il.ibm.com>
1 parent 510e612 commit 1f66393

File tree

12 files changed

+237
-34
lines changed

12 files changed

+237
-34
lines changed

common/config/api.go

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
/*
2+
Copyright IBM Corp. 2017 All Rights Reserved.
3+
4+
SPDX-License-Identifier: Apache-2.0
5+
*/
6+
package config
7+
8+
import (
9+
cb "github.com/hyperledger/fabric/protos/common"
10+
)
11+
12+
// Config encapsulates config (channel or resource) tree
13+
type Config interface {
14+
// ConfigProto returns the current config
15+
ConfigProto() *cb.Config
16+
17+
// ProposeConfigUpdate attempts to validate a new configtx against the current config state
18+
ProposeConfigUpdate(configtx *cb.Envelope) (*cb.ConfigEnvelope, error)
19+
}
20+
21+
// Manager provides access to the resource config
22+
type Manager interface {
23+
// GetChannelConfig defines methods that are related to channel configuration
24+
GetChannelConfig(channel string) Config
25+
26+
// GetResourceConfig defines methods that are related to resource configuration
27+
GetResourceConfig(channel string) Config
28+
}

core/aclmgmt/aclmgmt.go

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -42,9 +42,11 @@ const (
4242
QSCC_GetBlockByTxID = "QSCC.GetBlockByTxID"
4343

4444
//CSCC resources
45-
CSCC_JoinChain = "CSCC.JoinChain"
46-
CSCC_GetConfigBlock = "CSCC.GetConfigBlock"
47-
CSCC_GetChannels = "CSCC.GetChannels"
45+
CSCC_JoinChain = "CSCC.JoinChain"
46+
CSCC_GetConfigBlock = "CSCC.GetConfigBlock"
47+
CSCC_GetChannels = "CSCC.GetChannels"
48+
CSCC_GetConfigTree = "CSCC.GetConfigTree"
49+
CSCC_SimulateConfigTreeUpdate = "CSCC.SimulateConfigTreeUpdate"
4850

4951
//Chaincode-to-Chaincode call
5052
CC2CC = "CC2CC"

core/aclmgmt/defaultaclprovider.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,8 @@ func (d *defaultACLProvider) initialize() {
8181

8282
//c resources
8383
d.cResourcePolicyMap[CSCC_GetConfigBlock] = CHANNELREADERS
84+
d.cResourcePolicyMap[CSCC_GetConfigTree] = CHANNELREADERS
85+
d.cResourcePolicyMap[CSCC_SimulateConfigTreeUpdate] = CHANNELWRITERS
8486

8587
//---------------- non-scc resources ------------
8688
//Propose

core/peer/peer.go

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import (
1515
"github.com/hyperledger/fabric/core/ledger/customtx"
1616

1717
"github.com/hyperledger/fabric/common/channelconfig"
18+
cc "github.com/hyperledger/fabric/common/config"
1819
"github.com/hyperledger/fabric/common/configtx"
1920
configtxtest "github.com/hyperledger/fabric/common/configtx/test"
2021
"github.com/hyperledger/fabric/common/deliver"
@@ -737,3 +738,41 @@ func (flbs fileLedgerBlockStore) AddBlock(*common.Block) error {
737738
func (flbs fileLedgerBlockStore) RetrieveBlocks(startBlockNumber uint64) (commonledger.ResultsIterator, error) {
738739
return flbs.GetBlocksIterator(startBlockNumber)
739740
}
741+
742+
// NewResourceConfigSupport returns
743+
func NewConfigSupport() cc.Manager {
744+
return &configSupport{}
745+
}
746+
747+
type configSupport struct {
748+
}
749+
750+
// GetChannelConfig returns an instance of a object that represents
751+
// current channel configuration tree of the specified channel. The
752+
// ConfigProto method of the returned object can be used to get the
753+
// proto representing the channel configuration.
754+
func (*configSupport) GetChannelConfig(channel string) cc.Config {
755+
chains.RLock()
756+
defer chains.RUnlock()
757+
chain := chains.list[channel]
758+
if chain == nil {
759+
peerLogger.Error("GetChannelConfig: channel", channel, "not found in the list of channels associated with this peer")
760+
return nil
761+
}
762+
return chain.cs.bundleSource.ChannelConfig().ConfigtxValidator()
763+
}
764+
765+
// GetResourceConfig returns an instance of a object that represents
766+
// current resource configuration tree of the specified channel. The
767+
// ConfigProto method of the returned object can be used to get the
768+
// proto representing the resource configuration.
769+
func (*configSupport) GetResourceConfig(channel string) cc.Config {
770+
chains.RLock()
771+
defer chains.RUnlock()
772+
chain := chains.list[channel]
773+
if chain == nil {
774+
peerLogger.Error("GetResourceConfig: channel", channel, "not found in the list of channels associated with this peer")
775+
return nil
776+
}
777+
return chain.cs.bundleSource.ConfigtxValidator()
778+
}

core/peer/peer_test.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,13 @@ func TestCreateChainFromBlock(t *testing.T) {
159159
t.Fatalf("failed to get correct block")
160160
}
161161

162+
cfgSupport := configSupport{}
163+
chCfg := cfgSupport.GetChannelConfig(testChainID)
164+
assert.NotNil(t, chCfg, "failed to get channel config")
165+
166+
resCfg := cfgSupport.GetResourceConfig(testChainID)
167+
assert.NotNil(t, resCfg, "failed to get resource config")
168+
162169
// Bad block
163170
block = GetCurrConfigBlock("BogusBlock")
164171
if block != nil {

core/scc/cscc/configure.go

Lines changed: 92 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,11 @@ limitations under the License.
2222
package cscc
2323

2424
import (
25-
"errors"
2625
"fmt"
2726

2827
"github.com/golang/protobuf/proto"
2928
"github.com/hyperledger/fabric/common/channelconfig"
29+
"github.com/hyperledger/fabric/common/config"
3030
"github.com/hyperledger/fabric/common/flogging"
3131
"github.com/hyperledger/fabric/core/aclmgmt"
3232
"github.com/hyperledger/fabric/core/chaincode/shim"
@@ -37,22 +37,26 @@ import (
3737
"github.com/hyperledger/fabric/protos/common"
3838
pb "github.com/hyperledger/fabric/protos/peer"
3939
"github.com/hyperledger/fabric/protos/utils"
40+
"github.com/pkg/errors"
4041
)
4142

4243
// PeerConfiger implements the configuration handler for the peer. For every
4344
// configuration transaction coming in from the ordering service, the
4445
// committer calls this system chaincode to process the transaction.
4546
type PeerConfiger struct {
4647
policyChecker policy.PolicyChecker
48+
configMgr config.Manager
4749
}
4850

4951
var cnflogger = flogging.MustGetLogger("cscc")
5052

5153
// These are function names from Invoke first parameter
5254
const (
53-
JoinChain string = "JoinChain"
54-
GetConfigBlock string = "GetConfigBlock"
55-
GetChannels string = "GetChannels"
55+
JoinChain string = "JoinChain"
56+
GetConfigBlock string = "GetConfigBlock"
57+
GetChannels string = "GetChannels"
58+
GetConfigTree string = "GetConfigTree"
59+
SimulateConfigTreeUpdate string = "SimulateConfigTreeUpdate"
5660
)
5761

5862
// Init is called once per chain when the chain is created.
@@ -67,7 +71,7 @@ func (e *PeerConfiger) Init(stub shim.ChaincodeStubInterface) pb.Response {
6771
mgmt.GetLocalMSP(),
6872
mgmt.NewLocalMSPPrincipalGetter(),
6973
)
70-
74+
e.configMgr = peer.NewConfigSupport()
7175
return shim.Success(nil)
7276
}
7377

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

142146
return getConfigBlock(args[1])
147+
case GetConfigTree:
148+
// 2. check policy
149+
if err = aclmgmt.GetACLProvider().CheckACL(aclmgmt.CSCC_GetConfigTree, string(args[1]), sp); err != nil {
150+
return shim.Error(fmt.Sprintf("\"GetConfigTree\" request failed authorization check for channel [%s]: [%s]", args[1], err))
151+
}
152+
153+
return e.getConfigTree(args[1])
154+
case SimulateConfigTreeUpdate:
155+
// Check policy
156+
if err = aclmgmt.GetACLProvider().CheckACL(aclmgmt.CSCC_SimulateConfigTreeUpdate, string(args[1]), sp); err != nil {
157+
return shim.Error(fmt.Sprintf("\"SimulateConfigTreeUpdate\" request failed authorization check for channel [%s]: [%s]", args[1], err))
158+
}
159+
return e.simulateConfigTreeUpdate(args[1], args[2])
143160
case GetChannels:
144161
// 2. check local MSP Members policy
145162
// TODO: move to ACLProvider once it will support chainless ACLs
@@ -157,13 +174,13 @@ func (e *PeerConfiger) Invoke(stub shim.ChaincodeStubInterface) pb.Response {
157174
func validateConfigBlock(block *common.Block) error {
158175
envelopeConfig, err := utils.ExtractEnvelope(block, 0)
159176
if err != nil {
160-
return errors.New(fmt.Sprintf("Failed to %s", err))
177+
return errors.Errorf("Failed to %s", err)
161178
}
162179

163180
configEnv := &common.ConfigEnvelope{}
164181
_, err = utils.UnmarshalEnvelopeOfType(envelopeConfig, common.HeaderType_CONFIG, configEnv)
165182
if err != nil {
166-
return errors.New(fmt.Sprintf("Bad configuration envelope: %s", err))
183+
return errors.Errorf("Bad configuration envelope: %s", err)
167184
}
168185

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

181198
_, exists := configEnv.Config.ChannelGroup.Groups[channelconfig.ApplicationGroupKey]
182199
if !exists {
183-
return errors.New(fmt.Sprintf("Invalid configuration block, missing %s "+
184-
"configuration group", channelconfig.ApplicationGroupKey))
200+
return errors.Errorf("Invalid configuration block, missing %s "+
201+
"configuration group", channelconfig.ApplicationGroupKey)
185202
}
186203

187204
return nil
@@ -227,6 +244,72 @@ func getConfigBlock(chainID []byte) pb.Response {
227244
return shim.Success(blockBytes)
228245
}
229246

247+
// getConfigTree returns the current channel and resources configuration for the specified chainID.
248+
// If the peer doesn't belong to the chain, returns error
249+
func (e *PeerConfiger) getConfigTree(chainID []byte) pb.Response {
250+
if chainID == nil {
251+
return shim.Error("Chain ID must not be nil")
252+
}
253+
channelCfg := e.configMgr.GetChannelConfig(string(chainID)).ConfigProto()
254+
if channelCfg == nil {
255+
return shim.Error(fmt.Sprintf("Unknown chain ID, %s", string(chainID)))
256+
}
257+
resCfg := e.configMgr.GetResourceConfig(string(chainID)).ConfigProto()
258+
if resCfg == nil {
259+
return shim.Error(fmt.Sprintf("Unknown chain ID, %s", string(chainID)))
260+
}
261+
agCfg := &pb.ConfigTree{ChannelConfig: channelCfg, ResourcesConfig: resCfg}
262+
configBytes, err := utils.Marshal(agCfg)
263+
if err != nil {
264+
return shim.Error(err.Error())
265+
}
266+
return shim.Success(configBytes)
267+
}
268+
269+
func (e *PeerConfiger) simulateConfigTreeUpdate(chainID []byte, envb []byte) pb.Response {
270+
if chainID == nil {
271+
return shim.Error("Chain ID must not be nil")
272+
}
273+
if envb == nil {
274+
return shim.Error("Config delta bytes must not be nil")
275+
}
276+
env := &common.Envelope{}
277+
err := proto.Unmarshal(envb, env)
278+
if err != nil {
279+
return shim.Error(err.Error())
280+
}
281+
cfg, err := supportByType(e, chainID, env)
282+
if err != nil {
283+
return shim.Error(err.Error())
284+
}
285+
_, err = cfg.ProposeConfigUpdate(env)
286+
if err != nil {
287+
return shim.Error(err.Error())
288+
}
289+
return shim.Success([]byte("Simulation is successful"))
290+
}
291+
292+
func supportByType(pc *PeerConfiger, chainID []byte, env *common.Envelope) (config.Config, error) {
293+
payload := &common.Payload{}
294+
295+
if err := proto.Unmarshal(env.Payload, payload); err != nil {
296+
return nil, errors.Errorf("failed unmarshaling payload: %v", err)
297+
}
298+
299+
channelHdr := &common.ChannelHeader{}
300+
if err := proto.Unmarshal(payload.Header.ChannelHeader, channelHdr); err != nil {
301+
return nil, errors.Errorf("failed unmarshaling payload header: %v", err)
302+
}
303+
304+
switch common.HeaderType(channelHdr.Type) {
305+
case common.HeaderType_CONFIG_UPDATE:
306+
return pc.configMgr.GetChannelConfig(string(chainID)), nil
307+
case common.HeaderType_PEER_RESOURCE_UPDATE:
308+
return pc.configMgr.GetResourceConfig(string(chainID)), nil
309+
}
310+
return nil, errors.Errorf("invalid payload header type: %d", channelHdr.Type)
311+
}
312+
230313
// getChannels returns information about all channels for this peer
231314
func getChannels() pb.Response {
232315
channelInfoArray := peer.GetChannelsInfo()

peer/channel/join.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ func executeJoin(cf *ChannelCmdFactory) (err error) {
124124
if proposalResp.Response.Status != 0 && proposalResp.Response.Status != 200 {
125125
return ProposalFailedErr(fmt.Sprintf("bad proposal response %d", proposalResp.Response.Status))
126126
}
127-
logger.Infof("Successfully submitted proposal to join channel '%s'", channelID)
127+
logger.Info("Successfully submitted proposal to join channel")
128128
return nil
129129
}
130130

protos/common/configtx.proto

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,4 +112,4 @@ message ConfigPolicy {
112112
message ConfigSignature {
113113
bytes signature_header = 1; // A marshaled SignatureHeader
114114
bytes signature = 2; // Signature over the concatenation signatureHeader bytes and config bytes
115-
}
115+
}

protos/common/configuration.proto

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,4 +86,4 @@ message Capabilities {
8686
// message rather than a constant, so that we may extend capabilities with other fields
8787
// if the need arises in the future. For the time being, a capability being in the
8888
// capabilities map requires that that capability be supported.
89-
message Capability { }
89+
message Capability { }

protos/peer/admin.pb.go

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)