@@ -112,10 +112,41 @@ func QueryPaths(ia addr.IA) ([]snet.Path, error) {
112
112
if err != nil || len (paths ) == 0 {
113
113
return nil , err
114
114
}
115
+ paths = filterDuplicates (paths )
115
116
return paths , nil
116
117
}
117
118
}
118
119
120
+ // filterDuplicates filters paths with identical sequence of interfaces.
121
+ // These duplicates occur because sciond may return the same "effective" path with
122
+ // different short-cut "upstream" parts.
123
+ // We don't need these duplicates, they are identical for our purposes; we simply pick
124
+ // the one with latest expiry.
125
+ func filterDuplicates (paths []snet.Path ) []snet.Path {
126
+
127
+ chosenPath := make (map [snet.PathFingerprint ]int )
128
+ for i := range paths {
129
+ fingerprint := paths [i ].Fingerprint () // Fingerprint is a hash of p.Interfaces()
130
+ e , dupe := chosenPath [fingerprint ]
131
+ if ! dupe || paths [e ].Expiry ().Before (paths [i ].Expiry ()) {
132
+ chosenPath [fingerprint ] = i
133
+ }
134
+ }
135
+
136
+ // filter, keep paths in input order:
137
+ kept := make (map [int ]struct {})
138
+ for _ , p := range chosenPath {
139
+ kept [p ] = struct {}{}
140
+ }
141
+ filtered := make ([]snet.Path , 0 , len (kept ))
142
+ for i := range paths {
143
+ if _ , ok := kept [i ]; ok {
144
+ filtered = append (filtered , paths [i ])
145
+ }
146
+ }
147
+ return filtered
148
+ }
149
+
119
150
func pathSelection (paths []snet.Path , pathAlgo int ) snet.Path {
120
151
var selectedPath snet.Path
121
152
var metric float64
0 commit comments