Skip to content

Commit dc30c8e

Browse files
author
Jason Yellick
committed
[FAB-2142] Make new config comparable
https://jira.hyperledger.org/browse/FAB-2142 The new configuration structure needs to be comparable in order to validate which portions of the incoming configuration have changed. This CR adds a set of utilities to do just that. Change-Id: I061288145e7d4ae257568043d152c087f1796957 Signed-off-by: Jason Yellick <[email protected]>
1 parent 1246b13 commit dc30c8e

File tree

2 files changed

+476
-0
lines changed

2 files changed

+476
-0
lines changed

common/configtx/compare.go

+171
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,171 @@
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 configtx
18+
19+
import (
20+
"bytes"
21+
22+
cb "github.com/hyperledger/fabric/protos/common"
23+
)
24+
25+
type comparable struct {
26+
*cb.ConfigGroup
27+
*cb.ConfigValue
28+
*cb.ConfigPolicy
29+
}
30+
31+
func (cg comparable) equals(other comparable) bool {
32+
switch {
33+
case cg.ConfigGroup != nil:
34+
if other.ConfigGroup == nil {
35+
return false
36+
}
37+
return equalConfigGroup(cg.ConfigGroup, other.ConfigGroup)
38+
case cg.ConfigValue != nil:
39+
if other.ConfigValue == nil {
40+
return false
41+
}
42+
return equalConfigValues(cg.ConfigValue, other.ConfigValue)
43+
case cg.ConfigPolicy != nil:
44+
if other.ConfigPolicy == nil {
45+
return false
46+
}
47+
return equalConfigPolicies(cg.ConfigPolicy, other.ConfigPolicy)
48+
}
49+
50+
// Unreachable
51+
return false
52+
}
53+
54+
func equalConfigValues(lhs, rhs *cb.ConfigValue) bool {
55+
return lhs.Version == rhs.Version &&
56+
lhs.ModPolicy == rhs.ModPolicy &&
57+
bytes.Equal(lhs.Value, rhs.Value)
58+
}
59+
60+
func equalConfigPolicies(lhs, rhs *cb.ConfigPolicy) bool {
61+
if lhs.Version != rhs.Version ||
62+
lhs.ModPolicy != rhs.ModPolicy {
63+
return false
64+
}
65+
66+
if lhs.Policy == nil || rhs.Policy == nil {
67+
return lhs.Policy == rhs.Policy
68+
}
69+
70+
return lhs.Policy.Type == rhs.Policy.Type &&
71+
bytes.Equal(lhs.Policy.Policy, rhs.Policy.Policy)
72+
}
73+
74+
// The subset functions check if inner is a subset of outer
75+
// TODO, try to consolidate these three methods into one, as the code
76+
// contents are the same, but the function signatures need to be different
77+
func subsetOfGroups(inner, outer map[string]*cb.ConfigGroup) bool {
78+
// The empty set is a subset of all sets
79+
if len(inner) == 0 {
80+
return true
81+
}
82+
83+
// If inner is not the empty set, then the outer empty set cannot be a superset of inner
84+
if len(outer) == 0 {
85+
return false
86+
}
87+
88+
// If any element in inner is not in outer, it is not a subset
89+
for key := range inner {
90+
if _, ok := outer[key]; !ok {
91+
return false
92+
}
93+
}
94+
95+
return true
96+
}
97+
98+
func subsetOfPolicies(inner, outer map[string]*cb.ConfigPolicy) bool {
99+
// The empty set is a subset of all sets
100+
if len(inner) == 0 {
101+
return true
102+
}
103+
104+
// If inner is not the empty set, then the outer empty set cannot be a superset of inner
105+
if len(outer) == 0 {
106+
return false
107+
}
108+
109+
// If any element in inner is not in outer, it is not a subset
110+
for key := range inner {
111+
if _, ok := outer[key]; !ok {
112+
return false
113+
}
114+
}
115+
116+
return true
117+
}
118+
119+
func subsetOfValues(inner, outer map[string]*cb.ConfigValue) bool {
120+
// The empty set is a subset of all sets
121+
if len(inner) == 0 {
122+
return true
123+
}
124+
125+
// If inner is not the empty set, then the outer empty set cannot be a superset of inner
126+
if len(outer) == 0 {
127+
return false
128+
}
129+
130+
// If any element in inner is not in outer, it is not a subset
131+
for key := range inner {
132+
if _, ok := outer[key]; !ok {
133+
return false
134+
}
135+
}
136+
137+
return true
138+
}
139+
140+
func equalConfigGroup(lhs, rhs *cb.ConfigGroup) bool {
141+
if lhs.Version != rhs.Version ||
142+
lhs.ModPolicy != rhs.ModPolicy {
143+
return false
144+
}
145+
146+
if !subsetOfGroups(lhs.Groups, rhs.Groups) {
147+
return false
148+
}
149+
150+
if !subsetOfGroups(rhs.Groups, lhs.Groups) {
151+
return false
152+
}
153+
154+
if !subsetOfPolicies(lhs.Policies, rhs.Policies) {
155+
return false
156+
}
157+
158+
if !subsetOfPolicies(rhs.Policies, lhs.Policies) {
159+
return false
160+
}
161+
162+
if !subsetOfValues(lhs.Values, rhs.Values) {
163+
return false
164+
}
165+
166+
if !subsetOfValues(rhs.Values, lhs.Values) {
167+
return false
168+
}
169+
170+
return true
171+
}

0 commit comments

Comments
 (0)