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