github.com/prysmaticlabs/prysm@v1.4.4/shared/sszutil/deep_equal.go (about) 1 package sszutil 2 3 import ( 4 "reflect" 5 "unsafe" 6 7 types "github.com/prysmaticlabs/eth2-types" 8 "google.golang.org/protobuf/proto" 9 ) 10 11 // During deepValueEqual, must keep track of checks that are 12 // in progress. The comparison algorithm assumes that all 13 // checks in progress are true when it reencounters them. 14 // Visited comparisons are stored in a map indexed by visit. 15 type visit struct { 16 a1 unsafe.Pointer 17 a2 unsafe.Pointer 18 typ reflect.Type 19 } 20 21 // Copyright 2009 The Go Authors. All rights reserved. 22 // Use of this source code is governed by a BSD-style 23 // license that can be found in the LICENSE file. 24 // 25 // This file extends Go's reflect.DeepEqual function into a sszutil.DeepEqual 26 // function that is compliant with the supported types of ssz and its 27 // intricacies when determining equality of empty values. 28 // 29 // Tests for deep equality using reflected types. The map argument tracks 30 // comparisons that have already been seen, which allows short circuiting on 31 // recursive types. 32 func deepValueEqual(v1, v2 reflect.Value, visited map[visit]bool, depth int) bool { 33 if !v1.IsValid() || !v2.IsValid() { 34 return v1.IsValid() == v2.IsValid() 35 } 36 if v1.Type() != v2.Type() { 37 return false 38 } 39 // We want to avoid putting more in the visited map than we need to. 40 // For any possible reference cycle that might be encountered, 41 // hard(t) needs to return true for at least one of the types in the cycle. 42 hard := func(k reflect.Kind) bool { 43 switch k { 44 case reflect.Slice, reflect.Ptr, reflect.Interface: 45 return true 46 } 47 return false 48 } 49 50 if v1.CanAddr() && v2.CanAddr() && hard(v1.Kind()) { 51 addr1 := unsafe.Pointer(v1.UnsafeAddr()) 52 addr2 := unsafe.Pointer(v2.UnsafeAddr()) 53 if uintptr(addr1) > uintptr(addr2) { 54 // Canonicalize order to reduce number of entries in visited. 55 // Assumes non-moving garbage collector. 56 addr1, addr2 = addr2, addr1 57 } 58 59 // Short circuit if references are already seen. 60 typ := v1.Type() 61 v := visit{addr1, addr2, typ} 62 if visited[v] { 63 return true 64 } 65 66 // Remember for later. 67 visited[v] = true 68 } 69 70 switch v1.Kind() { 71 case reflect.Array: 72 for i := 0; i < v1.Len(); i++ { 73 if !deepValueEqual(v1.Index(i), v2.Index(i), visited, depth+1) { 74 return false 75 } 76 } 77 return true 78 case reflect.Slice: 79 if v1.IsNil() && v2.Len() == 0 { 80 return true 81 } 82 if v1.Len() == 0 && v2.IsNil() { 83 return true 84 } 85 if v1.IsNil() && v2.IsNil() { 86 return true 87 } 88 if v1.Len() != v2.Len() { 89 return false 90 } 91 if v1.Pointer() == v2.Pointer() { 92 return true 93 } 94 for i := 0; i < v1.Len(); i++ { 95 if !deepValueEqual(v1.Index(i), v2.Index(i), visited, depth+1) { 96 return false 97 } 98 } 99 return true 100 case reflect.Interface: 101 if v1.IsNil() || v2.IsNil() { 102 return v1.IsNil() == v2.IsNil() 103 } 104 return deepValueEqual(v1.Elem(), v2.Elem(), visited, depth+1) 105 case reflect.Ptr: 106 if v1.Pointer() == v2.Pointer() { 107 return true 108 } 109 return deepValueEqual(v1.Elem(), v2.Elem(), visited, depth+1) 110 case reflect.Struct: 111 for i, n := 0, v1.NumField(); i < n; i++ { 112 if !deepValueEqual(v1.Field(i), v2.Field(i), visited, depth+1) { 113 return false 114 } 115 } 116 return true 117 default: 118 return deepValueBaseTypeEqual(v1, v2) 119 } 120 } 121 122 func deepValueEqualExportedOnly(v1, v2 reflect.Value, visited map[visit]bool, depth int) bool { 123 if !v1.IsValid() || !v2.IsValid() { 124 return v1.IsValid() == v2.IsValid() 125 } 126 if v1.Type() != v2.Type() { 127 return false 128 } 129 // We want to avoid putting more in the visited map than we need to. 130 // For any possible reference cycle that might be encountered, 131 // hard(t) needs to return true for at least one of the types in the cycle. 132 hard := func(k reflect.Kind) bool { 133 switch k { 134 case reflect.Slice, reflect.Ptr, reflect.Interface: 135 return true 136 } 137 return false 138 } 139 140 if v1.CanAddr() && v2.CanAddr() && hard(v1.Kind()) { 141 addr1 := unsafe.Pointer(v1.UnsafeAddr()) 142 addr2 := unsafe.Pointer(v2.UnsafeAddr()) 143 if uintptr(addr1) > uintptr(addr2) { 144 // Canonicalize order to reduce number of entries in visited. 145 // Assumes non-moving garbage collector. 146 addr1, addr2 = addr2, addr1 147 } 148 149 // Short circuit if references are already seen. 150 typ := v1.Type() 151 v := visit{addr1, addr2, typ} 152 if visited[v] { 153 return true 154 } 155 156 // Remember for later. 157 visited[v] = true 158 } 159 160 switch v1.Kind() { 161 case reflect.Array: 162 for i := 0; i < v1.Len(); i++ { 163 if !deepValueEqualExportedOnly(v1.Index(i), v2.Index(i), visited, depth+1) { 164 return false 165 } 166 } 167 return true 168 case reflect.Slice: 169 if v1.IsNil() && v2.Len() == 0 { 170 return true 171 } 172 if v1.Len() == 0 && v2.IsNil() { 173 return true 174 } 175 if v1.IsNil() && v2.IsNil() { 176 return true 177 } 178 if v1.Len() != v2.Len() { 179 return false 180 } 181 if v1.Pointer() == v2.Pointer() { 182 return true 183 } 184 for i := 0; i < v1.Len(); i++ { 185 if !deepValueEqualExportedOnly(v1.Index(i), v2.Index(i), visited, depth+1) { 186 return false 187 } 188 } 189 return true 190 case reflect.Interface: 191 if v1.IsNil() || v2.IsNil() { 192 return v1.IsNil() == v2.IsNil() 193 } 194 return deepValueEqualExportedOnly(v1.Elem(), v2.Elem(), visited, depth+1) 195 case reflect.Ptr: 196 if v1.Pointer() == v2.Pointer() { 197 return true 198 } 199 return deepValueEqualExportedOnly(v1.Elem(), v2.Elem(), visited, depth+1) 200 case reflect.Struct: 201 for i, n := 0, v1.NumField(); i < n; i++ { 202 v1Field := v1.Field(i) 203 v2Field := v2.Field(i) 204 if !v1Field.CanInterface() || !v2Field.CanInterface() { 205 // Continue for unexported fields, since they cannot be read anyways. 206 continue 207 } 208 if !deepValueEqualExportedOnly(v1Field, v2Field, visited, depth+1) { 209 return false 210 } 211 } 212 return true 213 default: 214 return deepValueBaseTypeEqual(v1, v2) 215 } 216 } 217 218 func deepValueBaseTypeEqual(v1, v2 reflect.Value) bool { 219 switch v1.Kind() { 220 case reflect.String: 221 return v1.String() == v2.String() 222 case reflect.Uint64: 223 switch v1.Type().Name() { 224 case "Epoch": 225 return v1.Interface().(types.Epoch) == v2.Interface().(types.Epoch) 226 case "Slot": 227 return v1.Interface().(types.Slot) == v2.Interface().(types.Slot) 228 case "ValidatorIndex": 229 return v1.Interface().(types.ValidatorIndex) == v2.Interface().(types.ValidatorIndex) 230 case "CommitteeIndex": 231 return v1.Interface().(types.CommitteeIndex) == v2.Interface().(types.CommitteeIndex) 232 } 233 return v1.Interface().(uint64) == v2.Interface().(uint64) 234 case reflect.Uint32: 235 return v1.Interface().(uint32) == v2.Interface().(uint32) 236 case reflect.Int32: 237 return v1.Interface().(int32) == v2.Interface().(int32) 238 case reflect.Uint16: 239 return v1.Interface().(uint16) == v2.Interface().(uint16) 240 case reflect.Uint8: 241 return v1.Interface().(uint8) == v2.Interface().(uint8) 242 case reflect.Bool: 243 return v1.Interface().(bool) == v2.Interface().(bool) 244 default: 245 return false 246 } 247 } 248 249 // DeepEqual reports whether two SSZ-able values x and y are ``deeply equal,'' defined as follows: 250 // Two values of identical type are deeply equal if one of the following cases applies: 251 // 252 // Values of distinct types are never deeply equal. 253 // 254 // Array values are deeply equal when their corresponding elements are deeply equal. 255 // 256 // Struct values are deeply equal if their corresponding fields, 257 // both exported and unexported, are deeply equal. 258 // 259 // Interface values are deeply equal if they hold deeply equal concrete values. 260 // 261 // Pointer values are deeply equal if they are equal using Go's == operator 262 // or if they point to deeply equal values. 263 // 264 // Slice values are deeply equal when all of the following are true: 265 // they are both nil, one is nil and the other is empty or vice-versa, 266 // they have the same length, and either they point to the same initial entry of the same array 267 // (that is, &x[0] == &y[0]) or their corresponding elements (up to length) are deeply equal. 268 // 269 // Other values - numbers, bools, strings, and channels - are deeply equal 270 // if they are equal using Go's == operator. 271 // 272 // In general DeepEqual is a recursive relaxation of Go's == operator. 273 // However, this idea is impossible to implement without some inconsistency. 274 // Specifically, it is possible for a value to be unequal to itself, 275 // either because it is of func type (uncomparable in general) 276 // or because it is a floating-point NaN value (not equal to itself in floating-point comparison), 277 // or because it is an array, struct, or interface containing 278 // such a value. 279 // 280 // On the other hand, pointer values are always equal to themselves, 281 // even if they point at or contain such problematic values, 282 // because they compare equal using Go's == operator, and that 283 // is a sufficient condition to be deeply equal, regardless of content. 284 // DeepEqual has been defined so that the same short-cut applies 285 // to slices and maps: if x and y are the same slice or the same map, 286 // they are deeply equal regardless of content. 287 // 288 // As DeepEqual traverses the data values it may find a cycle. The 289 // second and subsequent times that DeepEqual compares two pointer 290 // values that have been compared before, it treats the values as 291 // equal rather than examining the values to which they point. 292 // This ensures that DeepEqual terminates. 293 // 294 // Credits go to the Go team as this is an extension of the official Go source code's 295 // reflect.DeepEqual function to handle special SSZ edge cases. 296 func DeepEqual(x, y interface{}) bool { 297 if x == nil || y == nil { 298 return x == y 299 } 300 v1 := reflect.ValueOf(x) 301 v2 := reflect.ValueOf(y) 302 if v1.Type() != v2.Type() { 303 return false 304 } 305 if IsProto(x) && IsProto(y) { 306 // Exclude unexported fields for protos. 307 return deepValueEqualExportedOnly(v1, v2, make(map[visit]bool), 0) 308 } 309 return deepValueEqual(v1, v2, make(map[visit]bool), 0) 310 } 311 312 func IsProto(item interface{}) bool { 313 typ := reflect.TypeOf(item) 314 kind := typ.Kind() 315 if kind != reflect.Slice && kind != reflect.Array && kind != reflect.Map { 316 _, ok := item.(proto.Message) 317 return ok 318 } 319 elemTyp := typ.Elem() 320 modelType := reflect.TypeOf((*proto.Message)(nil)).Elem() 321 return elemTyp.Implements(modelType) 322 }