diff --git a/gorgoneion/src/main/java/com/salesforce/apollo/gorgoneion/Gorgoneion.java b/gorgoneion/src/main/java/com/salesforce/apollo/gorgoneion/Gorgoneion.java index 94c61f47f..937c584b5 100644 --- a/gorgoneion/src/main/java/com/salesforce/apollo/gorgoneion/Gorgoneion.java +++ b/gorgoneion/src/main/java/com/salesforce/apollo/gorgoneion/Gorgoneion.java @@ -157,10 +157,8 @@ private SignedNonce generateNonce(KERL_ application) { .setTimestamp(Timestamp.newBuilder().setSeconds(now.getEpochSecond()).setNanos(now.getNano())) .build(); - var successors = context.size() == 1 ? Collections.singletonList(member) : Context.uniqueSuccessors(context, - digestOf( - ident, - parameters.digestAlgorithm())); + var successors = context.size() == 1 ? Collections.singletonList(member) + : context.bftSubset(digestOf(ident, parameters.digestAlgorithm())); final var majority = context.size() == 1 ? 1 : context.majority(); final var redirecting = new SliceIterator<>("Nonce Endorsement", member, successors, endorsementComm); Set endorsements = Collections.newSetFromMap(new ConcurrentHashMap<>()); @@ -222,8 +220,7 @@ private void notarize(Credentials credentials, Validations validations) { .setValidations(validations) .build(); - var successors = Context.uniqueSuccessors(context, - digestOf(identifier.toIdent(), parameters.digestAlgorithm())); + var successors = context.bftSubset(digestOf(identifier.toIdent(), parameters.digestAlgorithm())); final var majority = context.size() == 1 ? 1 : context.majority(); SliceIterator redirecting = new SliceIterator<>("Enrollment", member, successors, endorsementComm); var completed = new HashSet(); @@ -249,8 +246,7 @@ private Validations register(Credentials request) { var validated = new CompletableFuture(); - var successors = Context.uniqueSuccessors(context, - digestOf(identifier.toIdent(), parameters.digestAlgorithm())); + var successors = context.bftSubset(digestOf(identifier.toIdent(), parameters.digestAlgorithm())); final var majority = context.size() == 1 ? 1 : context.majority(); final var redirecting = new SliceIterator<>("Credential verification", member, successors, endorsementComm); var verifications = new HashSet(); diff --git a/memberships/src/main/java/com/salesforce/apollo/context/Context.java b/memberships/src/main/java/com/salesforce/apollo/context/Context.java index ba40da99d..194a71ae4 100644 --- a/memberships/src/main/java/com/salesforce/apollo/context/Context.java +++ b/memberships/src/main/java/com/salesforce/apollo/context/Context.java @@ -12,7 +12,6 @@ import com.salesforce.apollo.membership.Util; import org.apache.commons.math3.random.BitsStreamGenerator; -import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Set; @@ -34,18 +33,6 @@ public interface Context { double DEFAULT_EPSILON = 0.99999; - static List uniqueSuccessors(Context context, Digest digest) { - Set post = new HashSet<>(); - context.successors(digest, m -> { - if (post.size() == context.getRingCount()) { - return false; - } - return post.add(m); - }); - var successors = new ArrayList<>(post); - return successors; - } - static Digest hashFor(Digest ctxId, int ring, Digest d) { return d.prefix(ctxId, ring); } @@ -516,11 +503,22 @@ default int toleranceLevel() { Iterable traverse(int ring, T member); /** - * collect the list of successors to the key on each ring that pass the provided predicate test and provide a unique - * member per ring if possible. + * collect the list of successors to the key on each ring that pass the provided predicate test, and providing a + * unique member per ring if possible. */ void uniqueSuccessors(Digest key, Predicate test, Set collector); + default Set uniqueSuccessors(Digest digest) { + var collected = new HashSet(); + uniqueSuccessors(digest, collected); + return collected; + } + + /** + * collect the list of successors to the key on each ring, providing a unique member per ring if possible. + */ + void uniqueSuccessors(Digest key, Set collector); + boolean validRing(int ring); /** diff --git a/memberships/src/main/java/com/salesforce/apollo/context/DelegatedContext.java b/memberships/src/main/java/com/salesforce/apollo/context/DelegatedContext.java index 342407b26..ecb159025 100644 --- a/memberships/src/main/java/com/salesforce/apollo/context/DelegatedContext.java +++ b/memberships/src/main/java/com/salesforce/apollo/context/DelegatedContext.java @@ -348,6 +348,11 @@ public void uniqueSuccessors(Digest key, Predicate test, Set collector) { delegate.uniqueSuccessors(key, test, collector); } + @Override + public void uniqueSuccessors(Digest key, Set collector) { + delegate.uniqueSuccessors(key, collector); + } + @Override public boolean validRing(int ring) { return delegate.validRing(ring); diff --git a/memberships/src/main/java/com/salesforce/apollo/context/DynamicContextImpl.java b/memberships/src/main/java/com/salesforce/apollo/context/DynamicContextImpl.java index da248206e..94cd7db62 100644 --- a/memberships/src/main/java/com/salesforce/apollo/context/DynamicContextImpl.java +++ b/memberships/src/main/java/com/salesforce/apollo/context/DynamicContextImpl.java @@ -732,7 +732,6 @@ public Iterable traverse(int ring, T member) { */ @Override public void uniqueSuccessors(Digest key, Predicate test, Set collector) { - Set successors = new HashSet<>(); for (Ring ring : rings) { T successor = ring.successor(key, m -> !collector.contains(m) && test.test(m)); if (successor != null) { @@ -741,6 +740,11 @@ public void uniqueSuccessors(Digest key, Predicate test, Set collector) { } } + @Override + public void uniqueSuccessors(Digest key, Set collector) { + uniqueSuccessors(key, t -> true, collector); + } + @Override public boolean validRing(int ring) { return ring >= 0 && ring < rings.size(); diff --git a/memberships/src/main/java/com/salesforce/apollo/context/StaticContext.java b/memberships/src/main/java/com/salesforce/apollo/context/StaticContext.java index 68c85277f..42d6a1668 100644 --- a/memberships/src/main/java/com/salesforce/apollo/context/StaticContext.java +++ b/memberships/src/main/java/com/salesforce/apollo/context/StaticContext.java @@ -458,6 +458,11 @@ public void uniqueSuccessors(Digest key, Predicate test, Set collector) { } } + @Override + public void uniqueSuccessors(Digest key, Set collector) { + uniqueSuccessors(key, t -> true, collector); + } + @Override public boolean validRing(int ring) { return ring >= 0 && ring < rings.length; diff --git a/memberships/src/main/java/com/salesforce/apollo/ring/SliceIterator.java b/memberships/src/main/java/com/salesforce/apollo/ring/SliceIterator.java index fce9086a6..15fc27209 100644 --- a/memberships/src/main/java/com/salesforce/apollo/ring/SliceIterator.java +++ b/memberships/src/main/java/com/salesforce/apollo/ring/SliceIterator.java @@ -18,9 +18,7 @@ import java.io.IOException; import java.time.Duration; -import java.util.Iterator; -import java.util.List; -import java.util.Optional; +import java.util.*; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; @@ -41,20 +39,20 @@ public class SliceIterator { private Member current; private Iterator currentIteration; - public SliceIterator(String label, SigningMember member, List slice, + public SliceIterator(String label, SigningMember member, Collection slice, CommonCommunications comm) { this(label, member, slice, comm, Executors.newScheduledThreadPool(1, Thread.ofVirtual().factory())); } - public SliceIterator(String label, SigningMember member, List slice, + public SliceIterator(String label, SigningMember member, Collection s, CommonCommunications comm, ScheduledExecutorService scheduler) { - assert member != null && slice != null && comm != null; + assert member != null && s != null && comm != null; this.label = label; this.member = member; - this.slice = slice; + this.slice = new ArrayList<>(s); this.comm = comm; this.scheduler = scheduler; - Entropy.secureShuffle(slice); + Entropy.secureShuffle(this.slice); this.currentIteration = slice.iterator(); log.debug("Slice for: <{}> is: {} on: {}", label, slice.stream().map(m -> m.getId()).toList(), member.getId()); } diff --git a/thoth/src/main/java/com/salesforce/apollo/thoth/Maat.java b/thoth/src/main/java/com/salesforce/apollo/thoth/Maat.java index 7b25f6ad9..4cb27ad8a 100644 --- a/thoth/src/main/java/com/salesforce/apollo/thoth/Maat.java +++ b/thoth/src/main/java/com/salesforce/apollo/thoth/Maat.java @@ -82,10 +82,10 @@ public boolean validate(EstablishmentEvent event) { return false; } final Context ctx = context; - var successors = Context.uniqueSuccessors(ctx, digestOf(event.getIdentifier().toIdent(), digest.getAlgorithm())) - .stream() - .map(m -> m.getId()) - .collect(Collectors.toSet()); + var successors = ctx.bftSubset(digestOf(event.getIdentifier().toIdent(), digest.getAlgorithm())) + .stream() + .map(m -> m.getId()) + .collect(Collectors.toSet()); record validator(EstablishmentEvent validating, JohnHancock signature) { }