github.com/adnan-c/fabric_e2e_couchdb@v0.6.1-preview.0.20170228180935-21ce6b23cf91/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 // authorizeUpdate validates that all modified config has the corresponding modification policies satisfied by the signature set 28 // it returns a map of the modified config 29 func (cm *configManager) authorizeUpdate(configUpdateEnv *cb.ConfigUpdateEnvelope) (map[string]comparable, error) { 30 if configUpdateEnv == nil { 31 return nil, fmt.Errorf("Cannot process nil ConfigUpdateEnvelope") 32 } 33 34 config, err := UnmarshalConfigUpdate(configUpdateEnv.ConfigUpdate) 35 if err != nil { 36 return nil, err 37 } 38 39 if config.Header == nil { 40 return nil, fmt.Errorf("Must have header set") 41 } 42 43 seq := computeSequence(config.WriteSet) 44 if err != nil { 45 return nil, err 46 } 47 48 signedData, err := configUpdateEnv.AsSignedData() 49 if err != nil { 50 return nil, err 51 } 52 53 // Verify config is a sequential update to prevent exhausting sequence numbers 54 if seq != cm.sequence+1 { 55 return nil, fmt.Errorf("Config sequence number jumped from %d to %d", cm.sequence, seq) 56 } 57 58 // Verify config is intended for this globally unique chain ID 59 if config.Header.ChannelId != cm.chainID { 60 return nil, fmt.Errorf("Config is for the wrong chain, expected %s, got %s", cm.chainID, config.Header.ChannelId) 61 } 62 63 configMap, err := mapConfig(config.WriteSet) 64 if err != nil { 65 return nil, err 66 } 67 for key, value := range configMap { 68 logger.Debugf("Processing key %s with value %v", key, value) 69 if key == "[Groups] /Channel" { 70 // XXX temporary hack to prevent group evaluation for modification 71 continue 72 } 73 74 // Ensure the config sequence numbers are correct to prevent replay attacks 75 var isModified bool 76 77 oldValue, ok := cm.config[key] 78 if ok { 79 isModified = !value.equals(oldValue) 80 } else { 81 if value.version() != seq { 82 return nil, fmt.Errorf("Key %v was new, but had an older Sequence %d set", key, value.version()) 83 } 84 isModified = true 85 } 86 87 // If a config item was modified, its Version must be set correctly, and it must satisfy the modification policy 88 if isModified { 89 logger.Debugf("Proposed config item %s on channel %s has been modified", key, cm.chainID) 90 91 if value.version() != seq { 92 return nil, fmt.Errorf("Key %s was modified, but its Version %d does not equal current configtx Sequence %d", key, value.version(), seq) 93 } 94 95 // Get the modification policy for this config item if one was previously specified 96 // or accept it if it is new, as the group policy will be evaluated for its inclusion 97 if ok { 98 policy, ok := cm.policyForItem(oldValue) 99 if !ok { 100 return nil, fmt.Errorf("Unexpected missing policy %s for item %s", oldValue.modPolicy(), key) 101 } 102 103 // Ensure the policy is satisfied 104 if err = policy.Evaluate(signedData); err != nil { 105 return nil, fmt.Errorf("Policy for %s not satisfied: %s", key, err) 106 } 107 } 108 109 } 110 } 111 112 // Ensure that any config items which used to exist still exist, to prevent implicit deletion 113 for key, _ := range cm.config { 114 _, ok := configMap[key] 115 if !ok { 116 return nil, fmt.Errorf("Missing key %v in new config", key) 117 } 118 119 } 120 121 return cm.computeUpdateResult(configMap), nil 122 } 123 124 func (cm *configManager) policyForItem(item comparable) (policies.Policy, bool) { 125 // path is always at least of length 1 126 manager, ok := cm.PolicyManager().Manager(item.path[1:]) 127 if !ok { 128 return nil, ok 129 } 130 return manager.GetPolicy(item.modPolicy()) 131 } 132 133 // computeUpdateResult takes a configMap generated by an update and produces a new configMap overlaying it onto the old config 134 func (cm *configManager) computeUpdateResult(updatedConfig map[string]comparable) map[string]comparable { 135 newConfigMap := make(map[string]comparable) 136 for key, value := range cm.config { 137 newConfigMap[key] = value 138 } 139 140 for key, value := range updatedConfig { 141 newConfigMap[key] = value 142 } 143 return newConfigMap 144 } 145 146 func envelopeToConfigUpdate(configtx *cb.Envelope) (*cb.ConfigUpdateEnvelope, error) { 147 payload, err := utils.UnmarshalPayload(configtx.Payload) 148 if err != nil { 149 return nil, err 150 } 151 152 if payload.Header == nil /* || payload.Header.ChannelHeader == nil */ { 153 return nil, fmt.Errorf("Envelope must have a Header") 154 } 155 156 chdr, err := utils.UnmarshalChannelHeader(payload.Header.ChannelHeader) 157 if err != nil { 158 return nil, fmt.Errorf("Invalid ChannelHeader") 159 } 160 161 if chdr.Type != int32(cb.HeaderType_CONFIG_UPDATE) { 162 return nil, fmt.Errorf("Not a tx of type CONFIG_UPDATE") 163 } 164 165 configUpdateEnv, err := UnmarshalConfigUpdateEnvelope(payload.Data) 166 if err != nil { 167 return nil, fmt.Errorf("Error unmarshaling ConfigUpdateEnvelope: %s", err) 168 } 169 170 return configUpdateEnv, nil 171 }