github.com/leonlxy/hyperledger@v1.0.0-alpha.0.20170427033203-34922035d248/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 for key, value := range deltaSet { 59 existing, ok := cm.current.configMap[key] 60 if !ok { 61 if value.version() != 0 { 62 return fmt.Errorf("Attempted to set key %s to version %d, but key does not exist", key, value.version()) 63 } else { 64 continue 65 } 66 67 } 68 if value.version() != existing.version()+1 { 69 return fmt.Errorf("Attempt to set key %s to version %d, but key is at version %d", key, value.version(), existing.version()) 70 } 71 72 policy, ok := cm.policyForItem(existing) 73 if !ok { 74 return fmt.Errorf("Unexpected missing policy %s for item %s", existing.modPolicy(), key) 75 } 76 77 // Ensure the policy is satisfied 78 if err := policy.Evaluate(signedData); err != nil { 79 return fmt.Errorf("Policy for %s not satisfied: %s", key, err) 80 } 81 } 82 return nil 83 } 84 85 func verifyFullProposedConfig(writeSet, fullProposedConfig map[string]comparable) error { 86 for key, _ := range writeSet { 87 if _, ok := fullProposedConfig[key]; !ok { 88 return fmt.Errorf("Writeset contained key %s which did not appear in proposed config", key) 89 } 90 } 91 return nil 92 } 93 94 // authorizeUpdate validates that all modified config has the corresponding modification policies satisfied by the signature set 95 // it returns a map of the modified config 96 func (cm *configManager) authorizeUpdate(configUpdateEnv *cb.ConfigUpdateEnvelope) (map[string]comparable, error) { 97 if configUpdateEnv == nil { 98 return nil, fmt.Errorf("Cannot process nil ConfigUpdateEnvelope") 99 } 100 101 configUpdate, err := UnmarshalConfigUpdate(configUpdateEnv.ConfigUpdate) 102 if err != nil { 103 return nil, err 104 } 105 106 if configUpdate.ChannelId != cm.current.channelID { 107 return nil, fmt.Errorf("Update not for correct channel: %s for %s", configUpdate.ChannelId, cm.current.channelID) 108 } 109 110 readSet, err := MapConfig(configUpdate.ReadSet) 111 if err != nil { 112 return nil, fmt.Errorf("Error mapping ReadSet: %s", err) 113 } 114 err = cm.current.verifyReadSet(readSet) 115 if err != nil { 116 return nil, fmt.Errorf("Error validating ReadSet: %s", err) 117 } 118 119 writeSet, err := MapConfig(configUpdate.WriteSet) 120 if err != nil { 121 return nil, fmt.Errorf("Error mapping WriteSet: %s", err) 122 } 123 124 deltaSet := ComputeDeltaSet(readSet, writeSet) 125 signedData, err := configUpdateEnv.AsSignedData() 126 if err != nil { 127 return nil, err 128 } 129 130 if err = cm.verifyDeltaSet(deltaSet, signedData); err != nil { 131 return nil, fmt.Errorf("Error validating DeltaSet: %s", err) 132 } 133 134 fullProposedConfig := cm.computeUpdateResult(deltaSet) 135 if err := verifyFullProposedConfig(writeSet, fullProposedConfig); err != nil { 136 return nil, fmt.Errorf("Full config did not verify: %s", err) 137 } 138 139 return fullProposedConfig, nil 140 } 141 142 func (cm *configManager) policyForItem(item comparable) (policies.Policy, bool) { 143 // path is always at least of length 1 144 manager, ok := cm.PolicyManager().Manager(item.path[1:]) 145 if !ok { 146 return nil, ok 147 } 148 149 // In the case of the group type, its key is part of its path for the purposes of finding the policy manager 150 if item.ConfigGroup != nil { 151 manager, ok = manager.Manager([]string{item.key}) 152 } 153 if !ok { 154 return nil, ok 155 } 156 return manager.GetPolicy(item.modPolicy()) 157 } 158 159 // computeUpdateResult takes a configMap generated by an update and produces a new configMap overlaying it onto the old config 160 func (cm *configManager) computeUpdateResult(updatedConfig map[string]comparable) map[string]comparable { 161 newConfigMap := make(map[string]comparable) 162 for key, value := range cm.current.configMap { 163 newConfigMap[key] = value 164 } 165 166 for key, value := range updatedConfig { 167 newConfigMap[key] = value 168 } 169 return newConfigMap 170 } 171 172 func envelopeToConfigUpdate(configtx *cb.Envelope) (*cb.ConfigUpdateEnvelope, error) { 173 configUpdateEnv := &cb.ConfigUpdateEnvelope{} 174 _, err := utils.UnmarshalEnvelopeOfType(configtx, cb.HeaderType_CONFIG_UPDATE, configUpdateEnv) 175 if err != nil { 176 return nil, err 177 } 178 return configUpdateEnv, nil 179 }