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