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  }