github.com/adnan-c/fabric_e2e_couchdb@v0.6.1-preview.0.20170228180935-21ce6b23cf91/common/configtx/compare.go (about)

     1  /*
     2  Copyright IBM Corp. 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  	"bytes"
    21  
    22  	cb "github.com/hyperledger/fabric/protos/common"
    23  )
    24  
    25  type comparable struct {
    26  	*cb.ConfigGroup
    27  	*cb.ConfigValue
    28  	*cb.ConfigPolicy
    29  	key  string
    30  	path []string
    31  }
    32  
    33  func (cg comparable) equals(other comparable) bool {
    34  	switch {
    35  	case cg.ConfigGroup != nil:
    36  		if other.ConfigGroup == nil {
    37  			return false
    38  		}
    39  		return equalConfigGroup(cg.ConfigGroup, other.ConfigGroup)
    40  	case cg.ConfigValue != nil:
    41  		if other.ConfigValue == nil {
    42  			return false
    43  		}
    44  		return equalConfigValues(cg.ConfigValue, other.ConfigValue)
    45  	case cg.ConfigPolicy != nil:
    46  		if other.ConfigPolicy == nil {
    47  			return false
    48  		}
    49  		return equalConfigPolicies(cg.ConfigPolicy, other.ConfigPolicy)
    50  	}
    51  
    52  	// Unreachable
    53  	return false
    54  }
    55  
    56  func (cg comparable) version() uint64 {
    57  	switch {
    58  	case cg.ConfigGroup != nil:
    59  		return cg.ConfigGroup.Version
    60  	case cg.ConfigValue != nil:
    61  		return cg.ConfigValue.Version
    62  	case cg.ConfigPolicy != nil:
    63  		return cg.ConfigPolicy.Version
    64  	}
    65  
    66  	// Unreachable
    67  	return 0
    68  }
    69  
    70  func (cg comparable) modPolicy() string {
    71  	switch {
    72  	case cg.ConfigGroup != nil:
    73  		return cg.ConfigGroup.ModPolicy
    74  	case cg.ConfigValue != nil:
    75  		return cg.ConfigValue.ModPolicy
    76  	case cg.ConfigPolicy != nil:
    77  		return cg.ConfigPolicy.ModPolicy
    78  	}
    79  
    80  	// Unreachable
    81  	return ""
    82  }
    83  
    84  func equalConfigValues(lhs, rhs *cb.ConfigValue) bool {
    85  	return lhs.Version == rhs.Version &&
    86  		lhs.ModPolicy == rhs.ModPolicy &&
    87  		bytes.Equal(lhs.Value, rhs.Value)
    88  }
    89  
    90  func equalConfigPolicies(lhs, rhs *cb.ConfigPolicy) bool {
    91  	if lhs.Version != rhs.Version ||
    92  		lhs.ModPolicy != rhs.ModPolicy {
    93  		return false
    94  	}
    95  
    96  	if lhs.Policy == nil || rhs.Policy == nil {
    97  		return lhs.Policy == rhs.Policy
    98  	}
    99  
   100  	return lhs.Policy.Type == rhs.Policy.Type &&
   101  		bytes.Equal(lhs.Policy.Policy, rhs.Policy.Policy)
   102  }
   103  
   104  // The subset functions check if inner is a subset of outer
   105  // TODO, try to consolidate these three methods into one, as the code
   106  // contents are the same, but the function signatures need to be different
   107  func subsetOfGroups(inner, outer map[string]*cb.ConfigGroup) bool {
   108  	// The empty set is a subset of all sets
   109  	if len(inner) == 0 {
   110  		return true
   111  	}
   112  
   113  	// If inner has more elements than outer, it cannot be a subset
   114  	if len(inner) > len(outer) {
   115  		return false
   116  	}
   117  
   118  	// If any element in inner is not in outer, it is not a subset
   119  	for key := range inner {
   120  		if _, ok := outer[key]; !ok {
   121  			return false
   122  		}
   123  	}
   124  
   125  	return true
   126  }
   127  
   128  func subsetOfPolicies(inner, outer map[string]*cb.ConfigPolicy) bool {
   129  	// The empty set is a subset of all sets
   130  	if len(inner) == 0 {
   131  		return true
   132  	}
   133  
   134  	// If inner has more elements than outer, it cannot be a subset
   135  	if len(inner) > len(outer) {
   136  		return false
   137  	}
   138  
   139  	// If any element in inner is not in outer, it is not a subset
   140  	for key := range inner {
   141  		if _, ok := outer[key]; !ok {
   142  			return false
   143  		}
   144  	}
   145  
   146  	return true
   147  }
   148  
   149  func subsetOfValues(inner, outer map[string]*cb.ConfigValue) bool {
   150  	// The empty set is a subset of all sets
   151  	if len(inner) == 0 {
   152  		return true
   153  	}
   154  
   155  	// If inner has more elements than outer, it cannot be a subset
   156  	if len(inner) > len(outer) {
   157  		return false
   158  	}
   159  
   160  	// If any element in inner is not in outer, it is not a subset
   161  	for key := range inner {
   162  		if _, ok := outer[key]; !ok {
   163  			return false
   164  		}
   165  	}
   166  
   167  	return true
   168  }
   169  
   170  func equalConfigGroup(lhs, rhs *cb.ConfigGroup) bool {
   171  	if lhs.Version != rhs.Version ||
   172  		lhs.ModPolicy != rhs.ModPolicy {
   173  		return false
   174  	}
   175  
   176  	if !subsetOfGroups(lhs.Groups, rhs.Groups) ||
   177  		!subsetOfGroups(rhs.Groups, lhs.Groups) ||
   178  		!subsetOfPolicies(lhs.Policies, rhs.Policies) ||
   179  		!subsetOfPolicies(rhs.Policies, lhs.Policies) ||
   180  		!subsetOfValues(lhs.Values, rhs.Values) ||
   181  		!subsetOfValues(rhs.Values, lhs.Values) {
   182  		return false
   183  	}
   184  
   185  	return true
   186  }