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