github.com/myafeier/fabric@v1.0.1-0.20170722181825-3a4b1f2bce86/common/tools/configtxlator/update/update.go (about) 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 update 18 19 import ( 20 "fmt" 21 "reflect" 22 23 cb "github.com/hyperledger/fabric/protos/common" 24 ) 25 26 func computePoliciesMapUpdate(original, updated map[string]*cb.ConfigPolicy) (readSet, writeSet, sameSet map[string]*cb.ConfigPolicy, updatedMembers bool) { 27 readSet = make(map[string]*cb.ConfigPolicy) 28 writeSet = make(map[string]*cb.ConfigPolicy) 29 30 // All modified config goes into the read/write sets, but in case the map membership changes, we retain the 31 // config which was the same to add to the read/write sets 32 sameSet = make(map[string]*cb.ConfigPolicy) 33 34 for policyName, originalPolicy := range original { 35 updatedPolicy, ok := updated[policyName] 36 if !ok { 37 updatedMembers = true 38 continue 39 } 40 41 if originalPolicy.ModPolicy == updatedPolicy.ModPolicy && reflect.DeepEqual(originalPolicy.Policy, updatedPolicy.Policy) { 42 sameSet[policyName] = &cb.ConfigPolicy{ 43 Version: originalPolicy.Version, 44 } 45 continue 46 } 47 48 writeSet[policyName] = &cb.ConfigPolicy{ 49 Version: originalPolicy.Version + 1, 50 ModPolicy: updatedPolicy.ModPolicy, 51 Policy: updatedPolicy.Policy, 52 } 53 } 54 55 for policyName, updatedPolicy := range updated { 56 if _, ok := original[policyName]; ok { 57 // If the updatedPolicy is in the original set of policies, it was already handled 58 continue 59 } 60 updatedMembers = true 61 writeSet[policyName] = &cb.ConfigPolicy{ 62 Version: 0, 63 ModPolicy: updatedPolicy.ModPolicy, 64 Policy: updatedPolicy.Policy, 65 } 66 } 67 68 return 69 } 70 71 func computeValuesMapUpdate(original, updated map[string]*cb.ConfigValue) (readSet, writeSet, sameSet map[string]*cb.ConfigValue, updatedMembers bool) { 72 readSet = make(map[string]*cb.ConfigValue) 73 writeSet = make(map[string]*cb.ConfigValue) 74 75 // All modified config goes into the read/write sets, but in case the map membership changes, we retain the 76 // config which was the same to add to the read/write sets 77 sameSet = make(map[string]*cb.ConfigValue) 78 79 for valueName, originalValue := range original { 80 updatedValue, ok := updated[valueName] 81 if !ok { 82 updatedMembers = true 83 continue 84 } 85 86 if originalValue.ModPolicy == updatedValue.ModPolicy && reflect.DeepEqual(originalValue.Value, updatedValue.Value) { 87 sameSet[valueName] = &cb.ConfigValue{ 88 Version: originalValue.Version, 89 } 90 continue 91 } 92 93 writeSet[valueName] = &cb.ConfigValue{ 94 Version: originalValue.Version + 1, 95 ModPolicy: updatedValue.ModPolicy, 96 Value: updatedValue.Value, 97 } 98 } 99 100 for valueName, updatedValue := range updated { 101 if _, ok := original[valueName]; ok { 102 // If the updatedValue is in the original set of values, it was already handled 103 continue 104 } 105 updatedMembers = true 106 writeSet[valueName] = &cb.ConfigValue{ 107 Version: 0, 108 ModPolicy: updatedValue.ModPolicy, 109 Value: updatedValue.Value, 110 } 111 } 112 113 return 114 } 115 116 func computeGroupsMapUpdate(original, updated map[string]*cb.ConfigGroup) (readSet, writeSet, sameSet map[string]*cb.ConfigGroup, updatedMembers bool) { 117 readSet = make(map[string]*cb.ConfigGroup) 118 writeSet = make(map[string]*cb.ConfigGroup) 119 120 // All modified config goes into the read/write sets, but in case the map membership changes, we retain the 121 // config which was the same to add to the read/write sets 122 sameSet = make(map[string]*cb.ConfigGroup) 123 124 for groupName, originalGroup := range original { 125 updatedGroup, ok := updated[groupName] 126 if !ok { 127 updatedMembers = true 128 continue 129 } 130 131 groupReadSet, groupWriteSet, groupUpdated := computeGroupUpdate(originalGroup, updatedGroup) 132 if !groupUpdated { 133 sameSet[groupName] = groupReadSet 134 continue 135 } 136 137 readSet[groupName] = groupReadSet 138 writeSet[groupName] = groupWriteSet 139 140 } 141 142 for groupName, updatedGroup := range updated { 143 if _, ok := original[groupName]; ok { 144 // If the updatedGroup is in the original set of groups, it was already handled 145 continue 146 } 147 updatedMembers = true 148 _, groupWriteSet, _ := computeGroupUpdate(cb.NewConfigGroup(), updatedGroup) 149 writeSet[groupName] = &cb.ConfigGroup{ 150 Version: 0, 151 ModPolicy: updatedGroup.ModPolicy, 152 Policies: groupWriteSet.Policies, 153 Values: groupWriteSet.Values, 154 Groups: groupWriteSet.Groups, 155 } 156 } 157 158 return 159 } 160 161 func computeGroupUpdate(original, updated *cb.ConfigGroup) (readSet, writeSet *cb.ConfigGroup, updatedGroup bool) { 162 readSetPolicies, writeSetPolicies, sameSetPolicies, policiesMembersUpdated := computePoliciesMapUpdate(original.Policies, updated.Policies) 163 readSetValues, writeSetValues, sameSetValues, valuesMembersUpdated := computeValuesMapUpdate(original.Values, updated.Values) 164 readSetGroups, writeSetGroups, sameSetGroups, groupsMembersUpdated := computeGroupsMapUpdate(original.Groups, updated.Groups) 165 166 // If the updated group is 'Equal' to the updated group (none of the members nor the mod policy changed) 167 if !(policiesMembersUpdated || valuesMembersUpdated || groupsMembersUpdated || original.ModPolicy != updated.ModPolicy) { 168 169 // If there were no modified entries in any of the policies/values/groups maps 170 if len(readSetPolicies) == 0 && 171 len(writeSetPolicies) == 0 && 172 len(readSetValues) == 0 && 173 len(writeSetValues) == 0 && 174 len(readSetGroups) == 0 && 175 len(writeSetGroups) == 0 { 176 return &cb.ConfigGroup{ 177 Version: original.Version, 178 }, &cb.ConfigGroup{ 179 Version: original.Version, 180 }, false 181 } 182 183 return &cb.ConfigGroup{ 184 Version: original.Version, 185 Policies: readSetPolicies, 186 Values: readSetValues, 187 Groups: readSetGroups, 188 }, &cb.ConfigGroup{ 189 Version: original.Version, 190 Policies: writeSetPolicies, 191 Values: writeSetValues, 192 Groups: writeSetGroups, 193 }, true 194 } 195 196 for k, samePolicy := range sameSetPolicies { 197 readSetPolicies[k] = samePolicy 198 writeSetPolicies[k] = samePolicy 199 } 200 201 for k, sameValue := range sameSetValues { 202 readSetValues[k] = sameValue 203 writeSetValues[k] = sameValue 204 } 205 206 for k, sameGroup := range sameSetGroups { 207 readSetGroups[k] = sameGroup 208 writeSetGroups[k] = sameGroup 209 } 210 211 return &cb.ConfigGroup{ 212 Version: original.Version, 213 Policies: readSetPolicies, 214 Values: readSetValues, 215 Groups: readSetGroups, 216 }, &cb.ConfigGroup{ 217 Version: original.Version + 1, 218 Policies: writeSetPolicies, 219 Values: writeSetValues, 220 Groups: writeSetGroups, 221 ModPolicy: updated.ModPolicy, 222 }, true 223 } 224 225 func Compute(original, updated *cb.Config) (*cb.ConfigUpdate, error) { 226 readSet, writeSet, groupUpdated := computeGroupUpdate(original.ChannelGroup, updated.ChannelGroup) 227 if !groupUpdated { 228 return nil, fmt.Errorf("no differences detected between original and updated config") 229 } 230 return &cb.ConfigUpdate{ 231 ReadSet: readSet, 232 WriteSet: writeSet, 233 }, nil 234 }