github.com/darrenli6/fabric-sdk-example@v0.0.0-20220109053535-94b13b56df8c/common/configtx/update.go (about) 1 /* 2 Copyright IBM Corp. 2016-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 "fmt" 21 "strings" 22 23 "github.com/hyperledger/fabric/common/policies" 24 cb "github.com/hyperledger/fabric/protos/common" 25 "github.com/hyperledger/fabric/protos/utils" 26 ) 27 28 func (c *configSet) verifyReadSet(readSet map[string]comparable) error { 29 for key, value := range readSet { 30 existing, ok := c.configMap[key] 31 if !ok { 32 return fmt.Errorf("Existing config does not contain element for %s but was in the read set", key) 33 } 34 35 if existing.version() != value.version() { 36 return fmt.Errorf("Readset expected key %s at version %d, but got version %d", key, value.version(), existing.version()) 37 } 38 } 39 return nil 40 } 41 42 func ComputeDeltaSet(readSet, writeSet map[string]comparable) map[string]comparable { 43 result := make(map[string]comparable) 44 for key, value := range writeSet { 45 readVal, ok := readSet[key] 46 47 if ok && readVal.version() == value.version() { 48 continue 49 } 50 51 // If the key in the readset is a different version, we include it 52 // Error checking on the sanity of the update is done against the current config 53 result[key] = value 54 } 55 return result 56 } 57 58 func validateModPolicy(modPolicy string) error { 59 if modPolicy == "" { 60 return fmt.Errorf("mod_policy not set") 61 } 62 63 trimmed := modPolicy 64 if modPolicy[0] == '/' { 65 trimmed = modPolicy[1:] 66 } 67 68 for i, pathElement := range strings.Split(trimmed, PathSeparator) { 69 err := validateConfigID(pathElement) 70 if err != nil { 71 return fmt.Errorf("path element at %d is invalid: %s", i, err) 72 } 73 } 74 return nil 75 76 } 77 78 func (cm *configManager) verifyDeltaSet(deltaSet map[string]comparable, signedData []*cb.SignedData) error { 79 if len(deltaSet) == 0 { 80 return fmt.Errorf("Delta set was empty. Update would have no effect.") 81 } 82 83 for key, value := range deltaSet { 84 if err := validateModPolicy(value.modPolicy()); err != nil { 85 return fmt.Errorf("invalid mod_policy for element %s: %s", key, err) 86 } 87 88 existing, ok := cm.current.configMap[key] 89 if !ok { 90 if value.version() != 0 { 91 return fmt.Errorf("Attempted to set key %s to version %d, but key does not exist", key, value.version()) 92 } else { 93 continue 94 } 95 96 } 97 if value.version() != existing.version()+1 { 98 return fmt.Errorf("Attempt to set key %s to version %d, but key is at version %d", key, value.version(), existing.version()) 99 } 100 101 policy, ok := cm.policyForItem(existing) 102 if !ok { 103 return fmt.Errorf("Unexpected missing policy %s for item %s", existing.modPolicy(), key) 104 } 105 106 // Ensure the policy is satisfied 107 if err := policy.Evaluate(signedData); err != nil { 108 return fmt.Errorf("Policy for %s not satisfied: %s", key, err) 109 } 110 } 111 return nil 112 } 113 114 func verifyFullProposedConfig(writeSet, fullProposedConfig map[string]comparable) error { 115 for key, _ := range writeSet { 116 if _, ok := fullProposedConfig[key]; !ok { 117 return fmt.Errorf("Writeset contained key %s which did not appear in proposed config", key) 118 } 119 } 120 return nil 121 } 122 123 // authorizeUpdate validates that all modified config has the corresponding modification policies satisfied by the signature set 124 // it returns a map of the modified config 125 func (cm *configManager) authorizeUpdate(configUpdateEnv *cb.ConfigUpdateEnvelope) (map[string]comparable, error) { 126 if configUpdateEnv == nil { 127 return nil, fmt.Errorf("Cannot process nil ConfigUpdateEnvelope") 128 } 129 130 configUpdate, err := UnmarshalConfigUpdate(configUpdateEnv.ConfigUpdate) 131 if err != nil { 132 return nil, err 133 } 134 135 if configUpdate.ChannelId != cm.current.channelID { 136 return nil, fmt.Errorf("Update not for correct channel: %s for %s", configUpdate.ChannelId, cm.current.channelID) 137 } 138 139 readSet, err := MapConfig(configUpdate.ReadSet) 140 if err != nil { 141 return nil, fmt.Errorf("Error mapping ReadSet: %s", err) 142 } 143 err = cm.current.verifyReadSet(readSet) 144 if err != nil { 145 return nil, fmt.Errorf("Error validating ReadSet: %s", err) 146 } 147 148 writeSet, err := MapConfig(configUpdate.WriteSet) 149 if err != nil { 150 return nil, fmt.Errorf("Error mapping WriteSet: %s", err) 151 } 152 153 deltaSet := ComputeDeltaSet(readSet, writeSet) 154 signedData, err := configUpdateEnv.AsSignedData() 155 if err != nil { 156 return nil, err 157 } 158 159 if err = cm.verifyDeltaSet(deltaSet, signedData); err != nil { 160 return nil, fmt.Errorf("Error validating DeltaSet: %s", err) 161 } 162 163 fullProposedConfig := cm.computeUpdateResult(deltaSet) 164 if err := verifyFullProposedConfig(writeSet, fullProposedConfig); err != nil { 165 return nil, fmt.Errorf("Full config did not verify: %s", err) 166 } 167 168 return fullProposedConfig, nil 169 } 170 171 func (cm *configManager) policyForItem(item comparable) (policies.Policy, bool) { 172 // path is always at least of length 1 173 manager, ok := cm.PolicyManager().Manager(item.path[1:]) 174 if !ok { 175 return nil, ok 176 } 177 178 // In the case of the group type, its key is part of its path for the purposes of finding the policy manager 179 if item.ConfigGroup != nil { 180 manager, ok = manager.Manager([]string{item.key}) 181 } 182 if !ok { 183 return nil, ok 184 } 185 return manager.GetPolicy(item.modPolicy()) 186 } 187 188 // computeUpdateResult takes a configMap generated by an update and produces a new configMap overlaying it onto the old config 189 func (cm *configManager) computeUpdateResult(updatedConfig map[string]comparable) map[string]comparable { 190 newConfigMap := make(map[string]comparable) 191 for key, value := range cm.current.configMap { 192 newConfigMap[key] = value 193 } 194 195 for key, value := range updatedConfig { 196 newConfigMap[key] = value 197 } 198 return newConfigMap 199 } 200 201 func envelopeToConfigUpdate(configtx *cb.Envelope) (*cb.ConfigUpdateEnvelope, error) { 202 configUpdateEnv := &cb.ConfigUpdateEnvelope{} 203 _, err := utils.UnmarshalEnvelopeOfType(configtx, cb.HeaderType_CONFIG_UPDATE, configUpdateEnv) 204 if err != nil { 205 return nil, err 206 } 207 return configUpdateEnv, nil 208 }