Skip to content

Commit 018d888

Browse files
author
Jason Yellick
committed
[FAB-2323] Implement ImplicitMetaPolicy
https://jira.hyperledger.org/browse/FAB-2323 This CR adds support to the policies manager for evaluating the new ImplicitMetaPolicy policy type. Unlike the cauthdsl policy provider, the implicit metapolicy needs to live inside the policy manager to hook into the transactional nature of the policy manager. Change-Id: I8f11ea46950da6566833daa65b2e056faa2f63d6 Signed-off-by: Jason Yellick <[email protected]>
1 parent 1ffb87e commit 018d888

File tree

4 files changed

+215
-32
lines changed

4 files changed

+215
-32
lines changed

common/mocks/policies/policies.go

+1-12
Original file line numberDiff line numberDiff line change
@@ -44,21 +44,10 @@ type Manager struct {
4444
// PolicyMap is returned is used to look up Policies in
4545
PolicyMap map[string]*Policy
4646

47-
// SubManagers is used for the return value of Manager and SubManagers
47+
// SubManagers is used for the return value of Manager
4848
SubManagersMap map[string]*Manager
4949
}
5050

51-
// Managers returns the values of SubManagers
52-
func (m *Manager) SubManagers() []policies.Manager {
53-
result := make([]policies.Manager, len(m.SubManagersMap))
54-
i := 0
55-
for _, manager := range m.SubManagersMap {
56-
result[i] = manager
57-
i++
58-
}
59-
return result
60-
}
61-
6251
// PolicyNames panics
6352
func (m *Manager) PolicyNames() []string {
6453
panic("Unimplimented")

common/policies/implicitmeta.go

+83
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
/*
2+
Copyright IBM Corp. 2016 All Rights Reserved.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package policies
18+
19+
import (
20+
"fmt"
21+
22+
cb "github.com/hyperledger/fabric/protos/common"
23+
24+
"github.com/golang/protobuf/proto"
25+
)
26+
27+
type implicitMetaPolicy struct {
28+
conf *cb.ImplicitMetaPolicy
29+
threshold int
30+
subPolicies []Policy
31+
}
32+
33+
// NewPolicy creates a new policy based on the policy bytes
34+
func newImplicitMetaPolicy(data []byte) (*implicitMetaPolicy, error) {
35+
imp := &cb.ImplicitMetaPolicy{}
36+
if err := proto.Unmarshal(data, imp); err != nil {
37+
return nil, fmt.Errorf("Error unmarshaling to ImplicitMetaPolicy: %s", err)
38+
}
39+
40+
return &implicitMetaPolicy{
41+
conf: imp,
42+
}, nil
43+
}
44+
45+
func (imp *implicitMetaPolicy) initialize(config *policyConfig) {
46+
imp.subPolicies = make([]Policy, len(config.managers))
47+
i := 0
48+
for _, manager := range config.managers {
49+
imp.subPolicies[i], _ = manager.GetPolicy(imp.conf.SubPolicy)
50+
i++
51+
}
52+
53+
switch imp.conf.Rule {
54+
case cb.ImplicitMetaPolicy_ANY:
55+
imp.threshold = 1
56+
case cb.ImplicitMetaPolicy_ALL:
57+
imp.threshold = len(imp.subPolicies)
58+
case cb.ImplicitMetaPolicy_MAJORITY:
59+
imp.threshold = len(imp.subPolicies)/2 + 1
60+
}
61+
62+
// In the special case that there are no policies, consider 0 to be a majority or any
63+
if len(imp.subPolicies) == 0 {
64+
imp.threshold = 0
65+
}
66+
}
67+
68+
// Evaluate takes a set of SignedData and evaluates whether this set of signatures satisfies the policy
69+
func (imp *implicitMetaPolicy) Evaluate(signatureSet []*cb.SignedData) error {
70+
remaining := imp.threshold
71+
for _, policy := range imp.subPolicies {
72+
if policy.Evaluate(signatureSet) == nil {
73+
remaining--
74+
if remaining == 0 {
75+
return nil
76+
}
77+
}
78+
}
79+
if remaining == 0 {
80+
return nil
81+
}
82+
return fmt.Errorf("Failed to reach implicit threshold of %d sub-policies, required %d remaining", imp.threshold, remaining)
83+
}

common/policies/implicitmeta_test.go

+101
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
/*
2+
Copyright IBM Corp. 2017 All Rights Reserved.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package policies
18+
19+
import (
20+
"fmt"
21+
"testing"
22+
23+
cb "github.com/hyperledger/fabric/protos/common"
24+
"github.com/hyperledger/fabric/protos/utils"
25+
26+
"github.com/stretchr/testify/assert"
27+
)
28+
29+
const TestPolicyName = "TestPolicyName"
30+
31+
type acceptPolicy struct{}
32+
33+
func (rp acceptPolicy) Evaluate(signedData []*cb.SignedData) error {
34+
return nil
35+
}
36+
37+
func TestimplicitMarshalError(t *testing.T) {
38+
_, err := newImplicitMetaPolicy([]byte("GARBAGE"))
39+
assert.Error(t, err, "Should have errored unmarshaling garbage")
40+
}
41+
42+
func makeManagers(count, passing int) map[string]*ManagerImpl {
43+
result := make(map[string]*ManagerImpl)
44+
remaining := passing
45+
for i := 0; i < count; i++ {
46+
policyMap := make(map[string]Policy)
47+
if remaining > 0 {
48+
policyMap[TestPolicyName] = acceptPolicy{}
49+
}
50+
remaining--
51+
52+
result[fmt.Sprintf("%d", i)] = &ManagerImpl{
53+
config: &policyConfig{
54+
policies: policyMap,
55+
},
56+
}
57+
}
58+
return result
59+
}
60+
61+
// makePolicyTest creates an implicitMetaPolicy with a set of
62+
func runPolicyTest(rule cb.ImplicitMetaPolicy_Rule, managerCount int, passingCount int) error {
63+
imp, err := newImplicitMetaPolicy(utils.MarshalOrPanic(&cb.ImplicitMetaPolicy{
64+
Rule: rule,
65+
SubPolicy: TestPolicyName,
66+
}))
67+
if err != nil {
68+
panic(err)
69+
}
70+
71+
imp.initialize(&policyConfig{
72+
managers: makeManagers(managerCount, passingCount),
73+
})
74+
75+
return imp.Evaluate(nil)
76+
}
77+
78+
func TestImplicitMetaAny(t *testing.T) {
79+
assert.NoError(t, runPolicyTest(cb.ImplicitMetaPolicy_ANY, 1, 1))
80+
assert.NoError(t, runPolicyTest(cb.ImplicitMetaPolicy_ANY, 10, 1))
81+
assert.NoError(t, runPolicyTest(cb.ImplicitMetaPolicy_ANY, 10, 8))
82+
assert.Error(t, runPolicyTest(cb.ImplicitMetaPolicy_ANY, 10, 0))
83+
assert.NoError(t, runPolicyTest(cb.ImplicitMetaPolicy_ANY, 0, 0))
84+
}
85+
86+
func TestImplicitMetaAll(t *testing.T) {
87+
assert.NoError(t, runPolicyTest(cb.ImplicitMetaPolicy_ALL, 1, 1))
88+
assert.Error(t, runPolicyTest(cb.ImplicitMetaPolicy_ALL, 10, 1))
89+
assert.NoError(t, runPolicyTest(cb.ImplicitMetaPolicy_ALL, 10, 10))
90+
assert.Error(t, runPolicyTest(cb.ImplicitMetaPolicy_ALL, 10, 0))
91+
assert.NoError(t, runPolicyTest(cb.ImplicitMetaPolicy_ALL, 0, 0))
92+
}
93+
94+
func TestImplicitMetaMajority(t *testing.T) {
95+
assert.NoError(t, runPolicyTest(cb.ImplicitMetaPolicy_MAJORITY, 1, 1))
96+
assert.Error(t, runPolicyTest(cb.ImplicitMetaPolicy_MAJORITY, 10, 5))
97+
assert.NoError(t, runPolicyTest(cb.ImplicitMetaPolicy_MAJORITY, 10, 6))
98+
assert.NoError(t, runPolicyTest(cb.ImplicitMetaPolicy_MAJORITY, 3, 2))
99+
assert.Error(t, runPolicyTest(cb.ImplicitMetaPolicy_MAJORITY, 10, 0))
100+
assert.NoError(t, runPolicyTest(cb.ImplicitMetaPolicy_MAJORITY, 0, 0))
101+
}

common/policies/policy.go

+30-20
Original file line numberDiff line numberDiff line change
@@ -45,9 +45,6 @@ type Manager interface {
4545

4646
// Policies returns all policy names defined in the manager
4747
PolicyNames() []string
48-
49-
// SubManagers() returns all managers immediately descended from this one
50-
SubManagers() []Manager
5148
}
5249

5350
// Proposer is the interface used by the configtx manager for policy management
@@ -70,6 +67,7 @@ type Provider interface {
7067
type policyConfig struct {
7168
policies map[string]Policy
7269
managers map[string]*ManagerImpl
70+
imps []*implicitMetaPolicy
7371
}
7472

7573
// ManagerImpl is an implementation of Manager and configtx.ConfigHandler
@@ -83,6 +81,11 @@ type ManagerImpl struct {
8381

8482
// NewManagerImpl creates a new ManagerImpl with the given CryptoHelper
8583
func NewManagerImpl(basePath string, providers map[int32]Provider) *ManagerImpl {
84+
_, ok := providers[int32(cb.Policy_IMPLICIT_META)]
85+
if ok {
86+
logger.Panicf("ImplicitMetaPolicy type must be provider by the policy manager")
87+
}
88+
8689
return &ManagerImpl{
8790
basePath: basePath,
8891
providers: providers,
@@ -104,16 +107,6 @@ func (pm *ManagerImpl) BasePath() string {
104107
return pm.basePath
105108
}
106109

107-
func (pm *ManagerImpl) SubManagers() []Manager {
108-
managers := make([]Manager, len(pm.config.managers))
109-
i := 0
110-
for _, manager := range pm.config.managers {
111-
managers[i] = manager
112-
i++
113-
}
114-
return managers
115-
}
116-
117110
func (pm *ManagerImpl) PolicyNames() []string {
118111
policyNames := make([]string, len(pm.config.policies))
119112
i := 0
@@ -192,6 +185,11 @@ func (pm *ManagerImpl) CommitProposals() {
192185
}
193186
}
194187

188+
// Now that all the policies are present, initialize the meta policies
189+
for _, imp := range pm.pendingConfig.imps {
190+
imp.initialize(pm.pendingConfig)
191+
}
192+
195193
pm.config = pm.pendingConfig
196194
pm.pendingConfig = nil
197195
}
@@ -203,14 +201,26 @@ func (pm *ManagerImpl) ProposePolicy(key string, configPolicy *cb.ConfigPolicy)
203201
return fmt.Errorf("Policy cannot be nil")
204202
}
205203

206-
provider, ok := pm.providers[int32(policy.Type)]
207-
if !ok {
208-
return fmt.Errorf("Unknown policy type: %v", policy.Type)
209-
}
204+
var cPolicy Policy
210205

211-
cPolicy, err := provider.NewPolicy(policy.Policy)
212-
if err != nil {
213-
return err
206+
if policy.Type == int32(cb.Policy_IMPLICIT_META) {
207+
imp, err := newImplicitMetaPolicy(policy.Policy)
208+
if err != nil {
209+
return err
210+
}
211+
pm.pendingConfig.imps = append(pm.pendingConfig.imps, imp)
212+
cPolicy = imp
213+
} else {
214+
provider, ok := pm.providers[int32(policy.Type)]
215+
if !ok {
216+
return fmt.Errorf("Unknown policy type: %v", policy.Type)
217+
}
218+
219+
var err error
220+
cPolicy, err = provider.NewPolicy(policy.Policy)
221+
if err != nil {
222+
return err
223+
}
214224
}
215225

216226
pm.pendingConfig.policies[key] = cPolicy

0 commit comments

Comments
 (0)