diff --git a/common/src/main/java/bisq/common/app/Capabilities.java b/common/src/main/java/bisq/common/app/Capabilities.java index 015a98c74f..1094919f89 100644 --- a/common/src/main/java/bisq/common/app/Capabilities.java +++ b/common/src/main/java/bisq/common/app/Capabilities.java @@ -17,55 +17,87 @@ package bisq.common.app; -import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.HashSet; import java.util.List; +import java.util.Set; import java.util.stream.Collectors; -import lombok.Getter; -import lombok.Setter; - +/** + * hold a set of capabilities and offers appropriate comparison methods. + * + * @author Florian Reimair + */ public class Capabilities { - // We can define here special features the client is supporting. - // Useful for updates to new versions where a new data type would break backwards compatibility or to - // limit a node to certain behaviour and roles like the seed nodes. - // We don't use the Enum in any serialized data, as changes in the enum would break backwards compatibility. We use the ordinal integer instead. - // Sequence in the enum must not be changed (append only). - public enum Capability { - TRADE_STATISTICS, - TRADE_STATISTICS_2, - ACCOUNT_AGE_WITNESS, - SEED_NODE, - DAO_FULL_NODE, - PROPOSAL, - BLIND_VOTE, - ACK_MSG, - BSQ_BLOCK + + /** + * The global set of capabilities, i.e. the capabilities if the local app. + */ + public static final Capabilities app = new Capabilities(); + + protected final Set capabilities = new HashSet<>(); + + public Capabilities(Capability... capabilities) { + this(Arrays.asList(capabilities)); } - // Application need to set supported capabilities at startup - @Getter - @Setter - private static List supportedCapabilities = new ArrayList<>(); - - public static void addCapability(int capability) { - supportedCapabilities.add(capability); + public Capabilities(Capabilities capabilities) { + this(capabilities.capabilities); } - public static boolean isCapabilitySupported(final List requiredItems, final List supportedItems) { - if (requiredItems != null && !requiredItems.isEmpty()) { - if (supportedItems != null && !supportedItems.isEmpty()) { - List matches = new ArrayList<>(); - for (int requiredItem : requiredItems) { - matches.addAll(supportedItems.stream() - .filter(supportedItem -> requiredItem == supportedItem) - .collect(Collectors.toList())); - } - return matches.size() == requiredItems.size(); - } else { - return false; - } - } else { - return true; - } + public Capabilities(Collection capabilities) { + this.capabilities.addAll(capabilities); + } + + public void resetCapabilities(Capability... capabilities) { + resetCapabilities(Arrays.asList(capabilities)); + } + + public void resetCapabilities(Capabilities capabilities) { + resetCapabilities(capabilities.capabilities); + } + + public void resetCapabilities(Collection capabilities) { + this.capabilities.clear(); + this.capabilities.addAll(capabilities); + } + + public boolean isCapabilitySupported(final Set requiredItems) { + return capabilities.containsAll(requiredItems); + } + + public boolean isCapabilitySupported(final Capabilities capabilities) { + return isCapabilitySupported(capabilities.capabilities); + } + + public boolean hasCapabilities() { + return !capabilities.isEmpty(); + } + + + /** + * helper for protobuffer stuff + * + * @param capabilities + * @return int list of Capability ordinals + */ + public static List toIntList(Capabilities capabilities) { + return capabilities.capabilities.stream().map(capability -> capability.ordinal()).sorted().collect(Collectors.toList()); + } + + /** + * helper for protobuffer stuff + * + * @param capabilities a list of Capability ordinals + * @return a {@link Capabilities} object + */ + public static Capabilities fromIntList(List capabilities) { + return new Capabilities(capabilities.stream().map(integer -> Capability.values()[integer]).collect(Collectors.toSet())); + } + + @Override + public String toString() { + return Arrays.toString(Capabilities.toIntList(this).toArray()); } } diff --git a/common/src/main/java/bisq/common/app/Capability.java b/common/src/main/java/bisq/common/app/Capability.java new file mode 100644 index 0000000000..8c5b2c6231 --- /dev/null +++ b/common/src/main/java/bisq/common/app/Capability.java @@ -0,0 +1,35 @@ +/* + * This file is part of Bisq. + * + * Bisq is free software: you can redistribute it and/or modify it + * under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or (at + * your option) any later version. + * + * Bisq is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public + * License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with Bisq. If not, see . + */ + +package bisq.common.app; + +// We can define here special features the client is supporting. +// Useful for updates to new versions where a new data type would break backwards compatibility or to +// limit a node to certain behaviour and roles like the seed nodes. +// We don't use the Enum in any serialized data, as changes in the enum would break backwards compatibility. We use the ordinal integer instead. +// Sequence in the enum must not be changed (append only). +public enum Capability { + TRADE_STATISTICS, + TRADE_STATISTICS_2, + ACCOUNT_AGE_WITNESS, + SEED_NODE, + DAO_FULL_NODE, + PROPOSAL, + BLIND_VOTE, + ACK_MSG, + BSQ_BLOCK +} diff --git a/common/src/test/java/bisq/common/app/CapabilitiesTest.java b/common/src/test/java/bisq/common/app/CapabilitiesTest.java index 23e7ef8338..d9ebfe0ff8 100644 --- a/common/src/test/java/bisq/common/app/CapabilitiesTest.java +++ b/common/src/test/java/bisq/common/app/CapabilitiesTest.java @@ -17,39 +17,47 @@ package bisq.common.app; -import java.util.Arrays; +import java.util.HashSet; import org.junit.Test; +import static bisq.common.app.Capability.*; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; public class CapabilitiesTest { @Test - public void testVersionNumber() { - // if required are null or empty its true - assertTrue(Capabilities.isCapabilitySupported(null, null)); - assertTrue(Capabilities.isCapabilitySupported(null, Arrays.asList())); - assertTrue(Capabilities.isCapabilitySupported(null, Arrays.asList(0))); - assertTrue(Capabilities.isCapabilitySupported(Arrays.asList(), null)); - assertTrue(Capabilities.isCapabilitySupported(Arrays.asList(), Arrays.asList())); - assertTrue(Capabilities.isCapabilitySupported(Arrays.asList(), Arrays.asList(0))); + public void testNoCapabilitiesAvailable() { + Capabilities DUT = new Capabilities(); - // required are not null and not empty but supported is null or empty its false - assertFalse(Capabilities.isCapabilitySupported(Arrays.asList(0), null)); - assertFalse(Capabilities.isCapabilitySupported(Arrays.asList(0), Arrays.asList())); + assertTrue(DUT.isCapabilitySupported(new HashSet<>())); + assertFalse(DUT.isCapabilitySupported(new Capabilities(SEED_NODE))); + } + + @Test + public void testO() { + Capabilities DUT = new Capabilities(TRADE_STATISTICS); + + assertTrue(DUT.isCapabilitySupported(new HashSet<>())); + } + + @Test + public void testSingleMatch() { + Capabilities DUT = new Capabilities(TRADE_STATISTICS); // single match - assertTrue(Capabilities.isCapabilitySupported(Arrays.asList(0), Arrays.asList(0))); - assertFalse(Capabilities.isCapabilitySupported(Arrays.asList(1), Arrays.asList(0))); - assertFalse(Capabilities.isCapabilitySupported(Arrays.asList(0), Arrays.asList(1))); + assertTrue(DUT.isCapabilitySupported(new Capabilities(TRADE_STATISTICS))); + assertFalse(DUT.isCapabilitySupported(new Capabilities(SEED_NODE))); + } - // multi match - assertTrue(Capabilities.isCapabilitySupported(Arrays.asList(0), Arrays.asList(0, 1))); - assertFalse(Capabilities.isCapabilitySupported(Arrays.asList(0), Arrays.asList(1, 2))); - assertTrue(Capabilities.isCapabilitySupported(Arrays.asList(0, 1), Arrays.asList(0, 1))); - assertTrue(Capabilities.isCapabilitySupported(Arrays.asList(0, 1), Arrays.asList(1, 0))); - assertFalse(Capabilities.isCapabilitySupported(Arrays.asList(0, 1), Arrays.asList(0))); + @Test + public void testMultiMatch() { + Capabilities DUT = new Capabilities(TRADE_STATISTICS, TRADE_STATISTICS_2); + + assertTrue(DUT.isCapabilitySupported(new Capabilities(TRADE_STATISTICS))); + assertFalse(DUT.isCapabilitySupported(new Capabilities(SEED_NODE))); + assertTrue(DUT.isCapabilitySupported(new Capabilities(TRADE_STATISTICS, TRADE_STATISTICS_2))); + assertFalse(DUT.isCapabilitySupported(new Capabilities(SEED_NODE, TRADE_STATISTICS_2))); } } diff --git a/core/src/main/java/bisq/core/dao/governance/blindvote/network/RepublishGovernanceDataHandler.java b/core/src/main/java/bisq/core/dao/governance/blindvote/network/RepublishGovernanceDataHandler.java index 75e34d2bbc..7c5bfa5e2e 100644 --- a/core/src/main/java/bisq/core/dao/governance/blindvote/network/RepublishGovernanceDataHandler.java +++ b/core/src/main/java/bisq/core/dao/governance/blindvote/network/RepublishGovernanceDataHandler.java @@ -29,6 +29,7 @@ import bisq.network.p2p.seed.SeedNodeRepository; import bisq.common.Timer; import bisq.common.UserThread; import bisq.common.app.Capabilities; +import bisq.common.app.Capability; import javax.inject.Inject; @@ -164,22 +165,20 @@ public final class RepublishGovernanceDataHandler { } private void connectToAnyFullNode() { - List required = new ArrayList<>(Collections.singletonList( - Capabilities.Capability.DAO_FULL_NODE.ordinal() - )); + Capabilities required = new Capabilities(Capability.DAO_FULL_NODE); List list = peerManager.getLivePeers(null).stream() - .filter(peer -> Capabilities.isCapabilitySupported(required, peer.getSupportedCapabilities())) + .filter(peer -> peer.isCapabilitySupported(required)) .collect(Collectors.toList()); if (list.isEmpty()) list = peerManager.getReportedPeers().stream() - .filter(peer -> Capabilities.isCapabilitySupported(required, peer.getSupportedCapabilities())) + .filter(peer -> peer.isCapabilitySupported(required)) .collect(Collectors.toList()); if (list.isEmpty()) list = peerManager.getPersistedPeers().stream() - .filter(peer -> Capabilities.isCapabilitySupported(required, peer.getSupportedCapabilities())) + .filter(peer -> peer.isCapabilitySupported(required)) .collect(Collectors.toList()); if (!list.isEmpty()) { diff --git a/core/src/main/java/bisq/core/dao/governance/blindvote/network/messages/RepublishGovernanceDataRequest.java b/core/src/main/java/bisq/core/dao/governance/blindvote/network/messages/RepublishGovernanceDataRequest.java index c11ac0500c..420677bb86 100644 --- a/core/src/main/java/bisq/core/dao/governance/blindvote/network/messages/RepublishGovernanceDataRequest.java +++ b/core/src/main/java/bisq/core/dao/governance/blindvote/network/messages/RepublishGovernanceDataRequest.java @@ -21,15 +21,12 @@ import bisq.network.p2p.DirectMessage; import bisq.network.p2p.storage.payload.CapabilityRequiringPayload; import bisq.common.app.Capabilities; +import bisq.common.app.Capability; import bisq.common.app.Version; import bisq.common.proto.network.NetworkEnvelope; import io.bisq.generated.protobuffer.PB; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - import lombok.EqualsAndHashCode; import lombok.Getter; @@ -62,10 +59,8 @@ public final class RepublishGovernanceDataRequest extends NetworkEnvelope implem } @Override - public List getRequiredCapabilities() { - return new ArrayList<>(Collections.singletonList( - Capabilities.Capability.DAO_FULL_NODE.ordinal() - )); + public Capabilities getRequiredCapabilities() { + return new Capabilities(Capability.DAO_FULL_NODE); } @Override diff --git a/core/src/main/java/bisq/core/dao/governance/blindvote/storage/BlindVotePayload.java b/core/src/main/java/bisq/core/dao/governance/blindvote/storage/BlindVotePayload.java index ef081a1a87..0d0496d5f6 100644 --- a/core/src/main/java/bisq/core/dao/governance/blindvote/storage/BlindVotePayload.java +++ b/core/src/main/java/bisq/core/dao/governance/blindvote/storage/BlindVotePayload.java @@ -25,6 +25,7 @@ import bisq.network.p2p.storage.payload.DateTolerantPayload; import bisq.network.p2p.storage.payload.PersistableNetworkPayload; import bisq.common.app.Capabilities; +import bisq.common.app.Capability; import bisq.common.crypto.Hash; import bisq.common.proto.persistable.PersistableEnvelope; import bisq.common.util.Utilities; @@ -33,10 +34,7 @@ import io.bisq.generated.protobuffer.PB; import com.google.protobuf.ByteString; -import java.util.ArrayList; -import java.util.Collections; import java.util.Date; -import java.util.List; import java.util.concurrent.TimeUnit; import lombok.EqualsAndHashCode; @@ -134,10 +132,8 @@ public final class BlindVotePayload implements PersistableNetworkPayload, Persis /////////////////////////////////////////////////////////////////////////////////////////// @Override - public List getRequiredCapabilities() { - return new ArrayList<>(Collections.singletonList( - Capabilities.Capability.BLIND_VOTE.ordinal() - )); + public Capabilities getRequiredCapabilities() { + return new Capabilities(Capability.BLIND_VOTE); } @Override diff --git a/core/src/main/java/bisq/core/dao/governance/proposal/storage/appendonly/ProposalPayload.java b/core/src/main/java/bisq/core/dao/governance/proposal/storage/appendonly/ProposalPayload.java index 45bdc837b8..c6fa08a6c6 100644 --- a/core/src/main/java/bisq/core/dao/governance/proposal/storage/appendonly/ProposalPayload.java +++ b/core/src/main/java/bisq/core/dao/governance/proposal/storage/appendonly/ProposalPayload.java @@ -24,6 +24,7 @@ import bisq.network.p2p.storage.payload.CapabilityRequiringPayload; import bisq.network.p2p.storage.payload.PersistableNetworkPayload; import bisq.common.app.Capabilities; +import bisq.common.app.Capability; import bisq.common.crypto.Hash; import bisq.common.proto.persistable.PersistableEnvelope; import bisq.common.util.Utilities; @@ -32,10 +33,6 @@ import io.bisq.generated.protobuffer.PB; import com.google.protobuf.ByteString; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - import lombok.Value; import lombok.extern.slf4j.Slf4j; @@ -111,10 +108,8 @@ public class ProposalPayload implements PersistableNetworkPayload, PersistableEn /////////////////////////////////////////////////////////////////////////////////////////// @Override - public List getRequiredCapabilities() { - return new ArrayList<>(Collections.singletonList( - Capabilities.Capability.PROPOSAL.ordinal() - )); + public Capabilities getRequiredCapabilities() { + return new Capabilities(Capability.PROPOSAL); } @Override diff --git a/core/src/main/java/bisq/core/dao/governance/proposal/storage/temp/TempProposalPayload.java b/core/src/main/java/bisq/core/dao/governance/proposal/storage/temp/TempProposalPayload.java index e8b510e5b5..8ba1639092 100644 --- a/core/src/main/java/bisq/core/dao/governance/proposal/storage/temp/TempProposalPayload.java +++ b/core/src/main/java/bisq/core/dao/governance/proposal/storage/temp/TempProposalPayload.java @@ -25,6 +25,7 @@ import bisq.network.p2p.storage.payload.LazyProcessedPayload; import bisq.network.p2p.storage.payload.ProtectedStoragePayload; import bisq.common.app.Capabilities; +import bisq.common.app.Capability; import bisq.common.crypto.Sig; import bisq.common.proto.persistable.PersistablePayload; @@ -36,9 +37,6 @@ import org.springframework.util.CollectionUtils; import java.security.PublicKey; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; import java.util.Map; import java.util.Optional; import java.util.concurrent.TimeUnit; @@ -130,10 +128,8 @@ public class TempProposalPayload implements LazyProcessedPayload, ProtectedStora /////////////////////////////////////////////////////////////////////////////////////////// @Override - public List getRequiredCapabilities() { - return new ArrayList<>(Collections.singletonList( - Capabilities.Capability.PROPOSAL.ordinal() - )); + public Capabilities getRequiredCapabilities() { + return new Capabilities(Capability.PROPOSAL); } diff --git a/core/src/main/java/bisq/core/dao/node/messages/GetBlocksRequest.java b/core/src/main/java/bisq/core/dao/node/messages/GetBlocksRequest.java index ee66b69d1a..c8a5fac7ec 100644 --- a/core/src/main/java/bisq/core/dao/node/messages/GetBlocksRequest.java +++ b/core/src/main/java/bisq/core/dao/node/messages/GetBlocksRequest.java @@ -21,15 +21,12 @@ import bisq.network.p2p.DirectMessage; import bisq.network.p2p.storage.payload.CapabilityRequiringPayload; import bisq.common.app.Capabilities; +import bisq.common.app.Capability; import bisq.common.app.Version; import bisq.common.proto.network.NetworkEnvelope; import io.bisq.generated.protobuffer.PB; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - import lombok.EqualsAndHashCode; import lombok.Getter; @@ -68,10 +65,8 @@ public final class GetBlocksRequest extends NetworkEnvelope implements DirectMes } @Override - public List getRequiredCapabilities() { - return new ArrayList<>(Collections.singletonList( - Capabilities.Capability.DAO_FULL_NODE.ordinal() - )); + public Capabilities getRequiredCapabilities() { + return new Capabilities(Capability.DAO_FULL_NODE); } diff --git a/core/src/main/java/bisq/core/dao/node/messages/NewBlockBroadcastMessage.java b/core/src/main/java/bisq/core/dao/node/messages/NewBlockBroadcastMessage.java index fea0f3295f..4bca143878 100644 --- a/core/src/main/java/bisq/core/dao/node/messages/NewBlockBroadcastMessage.java +++ b/core/src/main/java/bisq/core/dao/node/messages/NewBlockBroadcastMessage.java @@ -23,15 +23,12 @@ import bisq.network.p2p.storage.messages.BroadcastMessage; import bisq.network.p2p.storage.payload.CapabilityRequiringPayload; import bisq.common.app.Capabilities; +import bisq.common.app.Capability; import bisq.common.app.Version; import bisq.common.proto.network.NetworkEnvelope; import io.bisq.generated.protobuffer.PB; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - import lombok.EqualsAndHashCode; import lombok.Getter; @@ -70,9 +67,7 @@ public final class NewBlockBroadcastMessage extends BroadcastMessage implements } @Override - public List getRequiredCapabilities() { - return new ArrayList<>(Collections.singletonList( - Capabilities.Capability.BSQ_BLOCK.ordinal() - )); + public Capabilities getRequiredCapabilities() { + return new Capabilities(Capability.BSQ_BLOCK); } } diff --git a/core/src/main/java/bisq/core/offer/messages/OfferAvailabilityRequest.java b/core/src/main/java/bisq/core/offer/messages/OfferAvailabilityRequest.java index 9f0c972880..75c4905ec2 100644 --- a/core/src/main/java/bisq/core/offer/messages/OfferAvailabilityRequest.java +++ b/core/src/main/java/bisq/core/offer/messages/OfferAvailabilityRequest.java @@ -25,7 +25,6 @@ import bisq.common.crypto.PubKeyRing; import io.bisq.generated.protobuffer.PB; -import java.util.List; import java.util.Optional; import java.util.UUID; @@ -42,7 +41,7 @@ public final class OfferAvailabilityRequest extends OfferMessage implements Supp private final PubKeyRing pubKeyRing; private final long takersTradePrice; @Nullable - private final List supportedCapabilities; + private final Capabilities supportedCapabilities; public OfferAvailabilityRequest(String offerId, PubKeyRing pubKeyRing, @@ -50,7 +49,7 @@ public final class OfferAvailabilityRequest extends OfferMessage implements Supp this(offerId, pubKeyRing, takersTradePrice, - Capabilities.getSupportedCapabilities(), + Capabilities.app, Version.getP2PMessageVersion(), UUID.randomUUID().toString()); } @@ -63,7 +62,7 @@ public final class OfferAvailabilityRequest extends OfferMessage implements Supp private OfferAvailabilityRequest(String offerId, PubKeyRing pubKeyRing, long takersTradePrice, - @Nullable List supportedCapabilities, + @Nullable Capabilities supportedCapabilities, int messageVersion, @Nullable String uid) { super(messageVersion, offerId, uid); @@ -79,7 +78,7 @@ public final class OfferAvailabilityRequest extends OfferMessage implements Supp .setPubKeyRing(pubKeyRing.toProtoMessage()) .setTakersTradePrice(takersTradePrice); - Optional.ofNullable(supportedCapabilities).ifPresent(e -> builder.addAllSupportedCapabilities(supportedCapabilities)); + Optional.ofNullable(supportedCapabilities).ifPresent(e -> builder.addAllSupportedCapabilities(Capabilities.toIntList(supportedCapabilities))); Optional.ofNullable(uid).ifPresent(e -> builder.setUid(uid)); return getNetworkEnvelopeBuilder() @@ -91,7 +90,7 @@ public final class OfferAvailabilityRequest extends OfferMessage implements Supp return new OfferAvailabilityRequest(proto.getOfferId(), PubKeyRing.fromProto(proto.getPubKeyRing()), proto.getTakersTradePrice(), - proto.getSupportedCapabilitiesList().isEmpty() ? null : proto.getSupportedCapabilitiesList(), + Capabilities.fromIntList(proto.getSupportedCapabilitiesList()), messageVersion, proto.getUid().isEmpty() ? null : proto.getUid()); } diff --git a/core/src/main/java/bisq/core/offer/messages/OfferAvailabilityResponse.java b/core/src/main/java/bisq/core/offer/messages/OfferAvailabilityResponse.java index 94493ba2dd..03ecfd275d 100644 --- a/core/src/main/java/bisq/core/offer/messages/OfferAvailabilityResponse.java +++ b/core/src/main/java/bisq/core/offer/messages/OfferAvailabilityResponse.java @@ -29,7 +29,6 @@ import bisq.common.proto.ProtoUtil; import io.bisq.generated.protobuffer.PB; -import java.util.List; import java.util.Optional; import java.util.UUID; @@ -45,7 +44,7 @@ import javax.annotation.Nullable; public final class OfferAvailabilityResponse extends OfferMessage implements SupportedCapabilitiesMessage { private final AvailabilityResult availabilityResult; @Nullable - private final List supportedCapabilities; + private final Capabilities supportedCapabilities; // Was introduced in v 0.9.0. Might be null if msg received from node with old version @Nullable @@ -54,7 +53,7 @@ public final class OfferAvailabilityResponse extends OfferMessage implements Sup public OfferAvailabilityResponse(String offerId, AvailabilityResult availabilityResult, NodeAddress arbitrator) { this(offerId, availabilityResult, - Capabilities.getSupportedCapabilities(), + Capabilities.app, Version.getP2PMessageVersion(), UUID.randomUUID().toString(), arbitrator); @@ -67,7 +66,7 @@ public final class OfferAvailabilityResponse extends OfferMessage implements Sup private OfferAvailabilityResponse(String offerId, AvailabilityResult availabilityResult, - @Nullable List supportedCapabilities, + @Nullable Capabilities supportedCapabilities, int messageVersion, @Nullable String uid, @Nullable NodeAddress arbitrator) { @@ -83,7 +82,7 @@ public final class OfferAvailabilityResponse extends OfferMessage implements Sup .setOfferId(offerId) .setAvailabilityResult(PB.AvailabilityResult.valueOf(availabilityResult.name())); - Optional.ofNullable(supportedCapabilities).ifPresent(e -> builder.addAllSupportedCapabilities(supportedCapabilities)); + Optional.ofNullable(supportedCapabilities).ifPresent(e -> builder.addAllSupportedCapabilities(Capabilities.toIntList(supportedCapabilities))); Optional.ofNullable(uid).ifPresent(e -> builder.setUid(uid)); Optional.ofNullable(arbitrator).ifPresent(e -> builder.setArbitrator(arbitrator.toProtoMessage())); @@ -95,7 +94,7 @@ public final class OfferAvailabilityResponse extends OfferMessage implements Sup public static OfferAvailabilityResponse fromProto(PB.OfferAvailabilityResponse proto, int messageVersion) { return new OfferAvailabilityResponse(proto.getOfferId(), ProtoUtil.enumFromProto(AvailabilityResult.class, proto.getAvailabilityResult().name()), - proto.getSupportedCapabilitiesList().isEmpty() ? null : proto.getSupportedCapabilitiesList(), + Capabilities.fromIntList(proto.getSupportedCapabilitiesList()), messageVersion, proto.getUid().isEmpty() ? null : proto.getUid(), proto.hasArbitrator() ? NodeAddress.fromProto(proto.getArbitrator()) : null); diff --git a/core/src/main/java/bisq/core/payment/AccountAgeWitness.java b/core/src/main/java/bisq/core/payment/AccountAgeWitness.java index 876d1dcdd9..78660248a5 100644 --- a/core/src/main/java/bisq/core/payment/AccountAgeWitness.java +++ b/core/src/main/java/bisq/core/payment/AccountAgeWitness.java @@ -24,6 +24,7 @@ import bisq.network.p2p.storage.payload.LazyProcessedPayload; import bisq.network.p2p.storage.payload.PersistableNetworkPayload; import bisq.common.app.Capabilities; +import bisq.common.app.Capability; import bisq.common.proto.persistable.PersistableEnvelope; import bisq.common.util.Utilities; @@ -31,10 +32,7 @@ import io.bisq.generated.protobuffer.PB; import com.google.protobuf.ByteString; -import java.util.ArrayList; -import java.util.Collections; import java.util.Date; -import java.util.List; import java.util.concurrent.TimeUnit; import lombok.Value; @@ -104,10 +102,8 @@ public class AccountAgeWitness implements LazyProcessedPayload, PersistableNetwo // Pre 0.6 version don't know the new message type and throw an error which leads to disconnecting the peer. @Override - public List getRequiredCapabilities() { - return new ArrayList<>(Collections.singletonList( - Capabilities.Capability.ACCOUNT_AGE_WITNESS.ordinal() - )); + public Capabilities getRequiredCapabilities() { + return new Capabilities(Capability.ACCOUNT_AGE_WITNESS); } @Override diff --git a/core/src/main/java/bisq/core/setup/CoreNetworkCapabilities.java b/core/src/main/java/bisq/core/setup/CoreNetworkCapabilities.java index fc4f4faca2..1bf5ce2c90 100644 --- a/core/src/main/java/bisq/core/setup/CoreNetworkCapabilities.java +++ b/core/src/main/java/bisq/core/setup/CoreNetworkCapabilities.java @@ -21,29 +21,30 @@ import bisq.core.app.BisqEnvironment; import bisq.core.dao.DaoOptionKeys; import bisq.common.app.Capabilities; +import bisq.common.app.Capability; import java.util.ArrayList; import java.util.Arrays; public class CoreNetworkCapabilities { public static void setSupportedCapabilities(BisqEnvironment bisqEnvironment) { - final ArrayList supportedCapabilities = new ArrayList<>(Arrays.asList( - Capabilities.Capability.TRADE_STATISTICS.ordinal(), - Capabilities.Capability.TRADE_STATISTICS_2.ordinal(), - Capabilities.Capability.ACCOUNT_AGE_WITNESS.ordinal(), - Capabilities.Capability.ACK_MSG.ordinal() + final ArrayList supportedCapabilities = new ArrayList<>(Arrays.asList( + Capability.TRADE_STATISTICS, + Capability.TRADE_STATISTICS_2, + Capability.ACCOUNT_AGE_WITNESS, + Capability.ACK_MSG )); if (BisqEnvironment.isDaoActivated(bisqEnvironment)) { - supportedCapabilities.add(Capabilities.Capability.PROPOSAL.ordinal()); - supportedCapabilities.add(Capabilities.Capability.BLIND_VOTE.ordinal()); - supportedCapabilities.add(Capabilities.Capability.BSQ_BLOCK.ordinal()); + supportedCapabilities.add(Capability.PROPOSAL); + supportedCapabilities.add(Capability.BLIND_VOTE); + supportedCapabilities.add(Capability.BSQ_BLOCK); String isFullDaoNode = bisqEnvironment.getProperty(DaoOptionKeys.FULL_DAO_NODE, String.class, ""); if (isFullDaoNode != null && !isFullDaoNode.isEmpty()) - supportedCapabilities.add(Capabilities.Capability.DAO_FULL_NODE.ordinal()); + supportedCapabilities.add(Capability.DAO_FULL_NODE); } - Capabilities.setSupportedCapabilities(supportedCapabilities); + Capabilities.app.resetCapabilities(supportedCapabilities); } } diff --git a/core/src/main/java/bisq/core/trade/statistics/TradeStatistics2.java b/core/src/main/java/bisq/core/trade/statistics/TradeStatistics2.java index f2b77c60f2..443b489fe6 100644 --- a/core/src/main/java/bisq/core/trade/statistics/TradeStatistics2.java +++ b/core/src/main/java/bisq/core/trade/statistics/TradeStatistics2.java @@ -29,6 +29,7 @@ import bisq.network.p2p.storage.payload.LazyProcessedPayload; import bisq.network.p2p.storage.payload.PersistableNetworkPayload; import bisq.common.app.Capabilities; +import bisq.common.app.Capability; import bisq.common.crypto.Hash; import bisq.common.proto.persistable.PersistableEnvelope; import bisq.common.util.JsonExclude; @@ -44,10 +45,7 @@ import org.bitcoinj.utils.Fiat; import org.springframework.util.CollectionUtils; -import java.util.ArrayList; -import java.util.Collections; import java.util.Date; -import java.util.List; import java.util.Map; import java.util.Optional; @@ -215,10 +213,8 @@ public final class TradeStatistics2 implements LazyProcessedPayload, Persistable /////////////////////////////////////////////////////////////////////////////////////////// @Override - public List getRequiredCapabilities() { - return new ArrayList<>(Collections.singletonList( - Capabilities.Capability.TRADE_STATISTICS_2.ordinal() - )); + public Capabilities getRequiredCapabilities() { + return new Capabilities(Capability.TRADE_STATISTICS_2); } @Override diff --git a/p2p/src/main/java/bisq/network/p2p/AckMessage.java b/p2p/src/main/java/bisq/network/p2p/AckMessage.java index 9e4f5db79c..62219761b2 100644 --- a/p2p/src/main/java/bisq/network/p2p/AckMessage.java +++ b/p2p/src/main/java/bisq/network/p2p/AckMessage.java @@ -21,6 +21,7 @@ import bisq.network.p2p.storage.payload.CapabilityRequiringPayload; import bisq.network.p2p.storage.payload.ExpirablePayload; import bisq.common.app.Capabilities; +import bisq.common.app.Capability; import bisq.common.app.Version; import bisq.common.proto.ProtoUtil; import bisq.common.proto.network.NetworkEnvelope; @@ -28,9 +29,6 @@ import bisq.common.proto.persistable.PersistablePayload; import io.bisq.generated.protobuffer.PB; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; import java.util.Optional; import java.util.UUID; import java.util.concurrent.TimeUnit; @@ -153,10 +151,8 @@ public final class AckMessage extends NetworkEnvelope implements MailboxMessage, /////////////////////////////////////////////////////////////////////////////////////////// @Override - public List getRequiredCapabilities() { - return new ArrayList<>(Collections.singletonList( - Capabilities.Capability.ACK_MSG.ordinal() - )); + public Capabilities getRequiredCapabilities() { + return new Capabilities(Capability.ACK_MSG); } @Override diff --git a/p2p/src/main/java/bisq/network/p2p/P2PService.java b/p2p/src/main/java/bisq/network/p2p/P2PService.java index 18ac35b22d..3a55fd76b7 100644 --- a/p2p/src/main/java/bisq/network/p2p/P2PService.java +++ b/p2p/src/main/java/bisq/network/p2p/P2PService.java @@ -619,13 +619,12 @@ public class P2PService implements SetupListener, MessageListener, ConnectionLis // it from old versions, so we filter those. Optional optionalPeer = allPeers.stream() .filter(peer -> peer.getNodeAddress().equals(peersNodeAddress)) - .filter(peer -> peer.getSupportedCapabilities() != null) - .filter(peer -> !peer.getSupportedCapabilities().isEmpty()) + .filter(peer -> peer.hasCapabilities()) .findAny(); if (optionalPeer.isPresent()) { Peer peer = optionalPeer.get(); boolean result = Connection.isCapabilityRequired(message) && - !Connection.isCapabilitySupported((CapabilityRequiringPayload) message, peer.getSupportedCapabilities()); + !peer.isCapabilitySupported(((CapabilityRequiringPayload) message).getRequiredCapabilities()); if (result) log.warn("We don't send the message because the peer does not support the required capability. " + diff --git a/p2p/src/main/java/bisq/network/p2p/SupportedCapabilitiesMessage.java b/p2p/src/main/java/bisq/network/p2p/SupportedCapabilitiesMessage.java index c73b72e824..87003312e2 100644 --- a/p2p/src/main/java/bisq/network/p2p/SupportedCapabilitiesMessage.java +++ b/p2p/src/main/java/bisq/network/p2p/SupportedCapabilitiesMessage.java @@ -17,11 +17,11 @@ package bisq.network.p2p; -import java.util.List; +import bisq.common.app.Capabilities; import javax.annotation.Nullable; public interface SupportedCapabilitiesMessage { @Nullable - List getSupportedCapabilities(); + Capabilities getSupportedCapabilities(); } diff --git a/p2p/src/main/java/bisq/network/p2p/network/Connection.java b/p2p/src/main/java/bisq/network/p2p/network/Connection.java index e336491ab1..be88b950a1 100644 --- a/p2p/src/main/java/bisq/network/p2p/network/Connection.java +++ b/p2p/src/main/java/bisq/network/p2p/network/Connection.java @@ -310,26 +310,17 @@ public class Connection implements MessageListener { private boolean isCapabilitySupported(Proto msg) { if (msg instanceof AddDataMessage) { final ProtectedStoragePayload protectedStoragePayload = (((AddDataMessage) msg).getProtectedStorageEntry()).getProtectedStoragePayload(); - return protectedStoragePayload instanceof CapabilityRequiringPayload && isCapabilitySupported((CapabilityRequiringPayload) protectedStoragePayload); + return protectedStoragePayload instanceof CapabilityRequiringPayload && sharedModel.isCapabilitySupported(((CapabilityRequiringPayload) protectedStoragePayload).getRequiredCapabilities()); } else if (msg instanceof AddPersistableNetworkPayloadMessage) { final PersistableNetworkPayload persistableNetworkPayload = ((AddPersistableNetworkPayloadMessage) msg).getPersistableNetworkPayload(); - return persistableNetworkPayload instanceof CapabilityRequiringPayload && isCapabilitySupported((CapabilityRequiringPayload) persistableNetworkPayload); + return persistableNetworkPayload instanceof CapabilityRequiringPayload && sharedModel.isCapabilitySupported(((CapabilityRequiringPayload) persistableNetworkPayload).getRequiredCapabilities()); } else { - return msg instanceof CapabilityRequiringPayload && isCapabilitySupported((CapabilityRequiringPayload) msg); + return msg instanceof CapabilityRequiringPayload && sharedModel.isCapabilitySupported(((CapabilityRequiringPayload) msg).getRequiredCapabilities()); } } - private boolean isCapabilitySupported(CapabilityRequiringPayload payload) { - return isCapabilitySupported(payload, sharedModel.getSupportedCapabilities()); - } - - public static boolean isCapabilitySupported(CapabilityRequiringPayload payload, List supportedCapabilities) { - final List requiredCapabilities = payload.getRequiredCapabilities(); - return Capabilities.isCapabilitySupported(requiredCapabilities, supportedCapabilities); - } - @Nullable - public List getSupportedCapabilities() { + public Capabilities getSupportedCapabilities() { return sharedModel.getSupportedCapabilities(); } @@ -601,7 +592,7 @@ public class Connection implements MessageListener { * Holds all shared data between Connection and InputHandler * Runs in same thread as Connection */ - private static class SharedModel { + private static class SharedModel extends Capabilities { private static final Logger log = LoggerFactory.getLogger(SharedModel.class); private final Connection connection; @@ -612,9 +603,6 @@ public class Connection implements MessageListener { private volatile boolean stopped; private CloseConnectionReason closeConnectionReason; private RuleViolation ruleViolation; - @Nullable - private List supportedCapabilities; - SharedModel(Connection connection, Socket socket) { this.connection = connection; @@ -654,18 +642,8 @@ public class Connection implements MessageListener { } @Nullable - public List getSupportedCapabilities() { - return supportedCapabilities; - } - - @SuppressWarnings("NullableProblems") - public void setSupportedCapabilities(List supportedCapabilities) { - this.supportedCapabilities = supportedCapabilities; - connection.capabilitiesListeners.forEach(l -> { - SupportedCapabilitiesListener supportedCapabilitiesListener = l.get(); - if (supportedCapabilitiesListener != null) - supportedCapabilitiesListener.onChanged(supportedCapabilities); - }); + public Capabilities getSupportedCapabilities() { + return new Capabilities(capabilities); } public void handleConnectionException(Throwable e) { @@ -727,7 +705,7 @@ public class Connection implements MessageListener { ",\n stopped=" + stopped + ",\n closeConnectionReason=" + closeConnectionReason + ",\n ruleViolation=" + ruleViolation + - ",\n supportedCapabilities=" + supportedCapabilities + + ",\n supportedCapabilities=" + capabilities + "\n}"; } } @@ -895,8 +873,8 @@ public class Connection implements MessageListener { return; } - if (sharedModel.getSupportedCapabilities() == null && networkEnvelope instanceof SupportedCapabilitiesMessage) - sharedModel.setSupportedCapabilities(((SupportedCapabilitiesMessage) networkEnvelope).getSupportedCapabilities()); + if (networkEnvelope instanceof SupportedCapabilitiesMessage) + sharedModel.resetCapabilities(((SupportedCapabilitiesMessage) networkEnvelope).getSupportedCapabilities()); if (networkEnvelope instanceof CloseConnectionMessage) { // If we get a CloseConnectionMessage we shut down diff --git a/p2p/src/main/java/bisq/network/p2p/network/SupportedCapabilitiesListener.java b/p2p/src/main/java/bisq/network/p2p/network/SupportedCapabilitiesListener.java index 1209fd3cc6..848b647982 100644 --- a/p2p/src/main/java/bisq/network/p2p/network/SupportedCapabilitiesListener.java +++ b/p2p/src/main/java/bisq/network/p2p/network/SupportedCapabilitiesListener.java @@ -17,8 +17,8 @@ package bisq.network.p2p.network; -import java.util.List; +import bisq.common.app.Capabilities; public interface SupportedCapabilitiesListener { - void onChanged(List supportedCapabilities); + void onChanged(Capabilities supportedCapabilities); } diff --git a/p2p/src/main/java/bisq/network/p2p/peers/PeerManager.java b/p2p/src/main/java/bisq/network/p2p/peers/PeerManager.java index 9dbc79cb51..81bd8e2297 100644 --- a/p2p/src/main/java/bisq/network/p2p/peers/PeerManager.java +++ b/p2p/src/main/java/bisq/network/p2p/peers/PeerManager.java @@ -32,6 +32,7 @@ import bisq.network.p2p.seed.SeedNodeRepository; import bisq.common.Clock; import bisq.common.Timer; import bisq.common.UserThread; +import bisq.common.app.Capabilities; import bisq.common.proto.persistable.PersistedDataHost; import bisq.common.proto.persistable.PersistenceProtoResolver; import bisq.common.storage.Storage; @@ -175,7 +176,7 @@ public class PeerManager implements ConnectionListener, PersistedDataHost { PeerList persistedPeerList = storage.initAndGetPersistedWithFileName("PeerList", 1000); if (persistedPeerList != null) { long peersWithNoCapabilitiesSet = persistedPeerList.getList().stream() - .filter(e -> e.getSupportedCapabilities().isEmpty()) + .filter(e -> e.hasCapabilities()) .mapToInt(e -> 1) .count(); if (peersWithNoCapabilitiesSet > 100) { @@ -659,19 +660,18 @@ public class PeerManager implements ConnectionListener, PersistedDataHost { // filter(connection -> connection.getPeersNodeAddressOptional().isPresent()) return networkNode.getConfirmedConnections().stream() .map((Connection connection) -> { - List supportedCapabilities = connection.getSupportedCapabilities(); + Capabilities supportedCapabilities = connection.getSupportedCapabilities(); // If we have a new connection the supportedCapabilities is empty. // We lookup if we have already stored the supportedCapabilities at the persisted or reported peers // and if so we use that. - if (supportedCapabilities == null || supportedCapabilities.isEmpty()) { + if (!supportedCapabilities.hasCapabilities()) { Set allPeers = new HashSet<>(getPersistedPeers()); allPeers.addAll(getReportedPeers()); - supportedCapabilities = allPeers.stream().filter(peer -> peer.getNodeAddress().equals(connection.getPeersNodeAddressOptional().get())) - .filter(peer -> !peer.getSupportedCapabilities().isEmpty()) - .findAny() - .map(Peer::getSupportedCapabilities) - .filter(list -> !list.isEmpty()) - .orElse(new ArrayList<>()); + Optional ourPeer = allPeers.stream().filter(peer -> peer.getNodeAddress().equals(connection.getPeersNodeAddressOptional().get())) + .filter(peer -> !peer.hasCapabilities()) + .findAny(); + if(ourPeer.isPresent()) + supportedCapabilities = new Capabilities(ourPeer.get()); } Peer peer = new Peer(connection.getPeersNodeAddressOptional().get(), supportedCapabilities); connection.addWeakCapabilitiesListener(peer); diff --git a/p2p/src/main/java/bisq/network/p2p/peers/getdata/GetDataRequestHandler.java b/p2p/src/main/java/bisq/network/p2p/peers/getdata/GetDataRequestHandler.java index b6d6196df9..c1de051a2e 100644 --- a/p2p/src/main/java/bisq/network/p2p/peers/getdata/GetDataRequestHandler.java +++ b/p2p/src/main/java/bisq/network/p2p/peers/getdata/GetDataRequestHandler.java @@ -31,6 +31,7 @@ import bisq.network.p2p.storage.payload.ProtectedStoragePayload; import bisq.common.Timer; import bisq.common.UserThread; +import bisq.common.app.Capabilities; import bisq.common.util.Utilities; import com.google.common.util.concurrent.FutureCallback; @@ -38,7 +39,6 @@ import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.SettableFuture; import java.util.HashSet; -import java.util.List; import java.util.Map; import java.util.Set; import java.util.concurrent.TimeUnit; @@ -159,25 +159,15 @@ public class GetDataRequestHandler { final ProtectedStoragePayload protectedStoragePayload = protectedStorageEntry.getProtectedStoragePayload(); boolean doAdd = false; if (protectedStoragePayload instanceof CapabilityRequiringPayload) { - final List requiredCapabilities = ((CapabilityRequiringPayload) protectedStoragePayload).getRequiredCapabilities(); - final List supportedCapabilities = connection.getSupportedCapabilities(); - if (supportedCapabilities != null) { - for (int messageCapability : requiredCapabilities) { - for (int connectionCapability : supportedCapabilities) { - if (messageCapability == connectionCapability) { - doAdd = true; - break; - } - } - } - if (!doAdd) + final Capabilities supportedCapabilities = connection.getSupportedCapabilities(); + if (supportedCapabilities.hasCapabilities()) { + if (supportedCapabilities.isCapabilitySupported(((CapabilityRequiringPayload) protectedStoragePayload).getRequiredCapabilities())) + doAdd = true; + else log.debug("We do not send the message to the peer because he does not support the required capability for that message type.\n" + - "Required capabilities is: " + requiredCapabilities.toString() + "\n" + - "Supported capabilities is: " + supportedCapabilities.toString() + "\n" + "storagePayload is: " + Utilities.toTruncatedString(protectedStoragePayload)); } else { log.debug("We do not send the message to the peer because he uses an old version which does not support capabilities.\n" + - "Required capabilities is: " + requiredCapabilities.toString() + "\n" + "storagePayload is: " + Utilities.toTruncatedString(protectedStoragePayload)); } } else { diff --git a/p2p/src/main/java/bisq/network/p2p/peers/getdata/messages/GetDataResponse.java b/p2p/src/main/java/bisq/network/p2p/peers/getdata/messages/GetDataResponse.java index 0e4b48a20a..6abd7323f2 100644 --- a/p2p/src/main/java/bisq/network/p2p/peers/getdata/messages/GetDataResponse.java +++ b/p2p/src/main/java/bisq/network/p2p/peers/getdata/messages/GetDataResponse.java @@ -31,7 +31,6 @@ import bisq.common.proto.network.NetworkProtoResolver; import io.bisq.generated.protobuffer.PB; import java.util.HashSet; -import java.util.List; import java.util.Optional; import java.util.Set; import java.util.stream.Collectors; @@ -57,7 +56,7 @@ public final class GetDataResponse extends NetworkEnvelope implements SupportedC private final int requestNonce; private final boolean isGetUpdatedDataResponse; @Nullable - private final List supportedCapabilities; + private final Capabilities supportedCapabilities; public GetDataResponse(Set dataSet, @Nullable Set persistableNetworkPayloadSet, @@ -67,7 +66,7 @@ public final class GetDataResponse extends NetworkEnvelope implements SupportedC persistableNetworkPayloadSet, requestNonce, isGetUpdatedDataResponse, - Capabilities.getSupportedCapabilities(), + Capabilities.app, Version.getP2PMessageVersion()); } @@ -79,7 +78,7 @@ public final class GetDataResponse extends NetworkEnvelope implements SupportedC @Nullable Set persistableNetworkPayloadSet, int requestNonce, boolean isGetUpdatedDataResponse, - @Nullable List supportedCapabilities, + @Nullable Capabilities supportedCapabilities, int messageVersion) { super(messageVersion); @@ -106,7 +105,7 @@ public final class GetDataResponse extends NetworkEnvelope implements SupportedC .setRequestNonce(requestNonce) .setIsGetUpdatedDataResponse(isGetUpdatedDataResponse); - Optional.ofNullable(supportedCapabilities).ifPresent(e -> builder.addAllSupportedCapabilities(supportedCapabilities)); + Optional.ofNullable(supportedCapabilities).ifPresent(e -> builder.addAllSupportedCapabilities(Capabilities.toIntList(supportedCapabilities))); Optional.ofNullable(persistableNetworkPayloadSet).ifPresent(set -> builder.addAllPersistableNetworkPayloadItems(set.stream() .map(PersistableNetworkPayload::toProtoMessage) .collect(Collectors.toList()))); @@ -134,7 +133,7 @@ public final class GetDataResponse extends NetworkEnvelope implements SupportedC persistableNetworkPayloadSet, proto.getRequestNonce(), proto.getIsGetUpdatedDataResponse(), - proto.getSupportedCapabilitiesList().isEmpty() ? null : proto.getSupportedCapabilitiesList(), + Capabilities.fromIntList(proto.getSupportedCapabilitiesList()), messageVersion); } } diff --git a/p2p/src/main/java/bisq/network/p2p/peers/getdata/messages/PreliminaryGetDataRequest.java b/p2p/src/main/java/bisq/network/p2p/peers/getdata/messages/PreliminaryGetDataRequest.java index 58af39daa2..b0038d14bd 100644 --- a/p2p/src/main/java/bisq/network/p2p/peers/getdata/messages/PreliminaryGetDataRequest.java +++ b/p2p/src/main/java/bisq/network/p2p/peers/getdata/messages/PreliminaryGetDataRequest.java @@ -28,7 +28,6 @@ import io.bisq.generated.protobuffer.PB; import com.google.protobuf.ByteString; -import java.util.List; import java.util.Optional; import java.util.Set; import java.util.stream.Collectors; @@ -45,11 +44,11 @@ import javax.annotation.Nullable; public final class PreliminaryGetDataRequest extends GetDataRequest implements AnonymousMessage, SupportedCapabilitiesMessage { // ordinals of enum @Nullable - private final List supportedCapabilities; + private final Capabilities supportedCapabilities; public PreliminaryGetDataRequest(int nonce, Set excludedKeys) { - this(nonce, excludedKeys, Capabilities.getSupportedCapabilities(), Version.getP2PMessageVersion()); + this(nonce, excludedKeys, Capabilities.app, Version.getP2PMessageVersion()); } @@ -59,7 +58,7 @@ public final class PreliminaryGetDataRequest extends GetDataRequest implements A private PreliminaryGetDataRequest(int nonce, Set excludedKeys, - @Nullable List supportedCapabilities, + @Nullable Capabilities supportedCapabilities, int messageVersion) { super(messageVersion, nonce, excludedKeys); @@ -74,7 +73,7 @@ public final class PreliminaryGetDataRequest extends GetDataRequest implements A .map(ByteString::copyFrom) .collect(Collectors.toList())); - Optional.ofNullable(supportedCapabilities).ifPresent(e -> builder.addAllSupportedCapabilities(supportedCapabilities)); + Optional.ofNullable(supportedCapabilities).ifPresent(e -> builder.addAllSupportedCapabilities(Capabilities.toIntList(supportedCapabilities))); return getNetworkEnvelopeBuilder() .setPreliminaryGetDataRequest(builder) @@ -84,7 +83,7 @@ public final class PreliminaryGetDataRequest extends GetDataRequest implements A public static PreliminaryGetDataRequest fromProto(PB.PreliminaryGetDataRequest proto, int messageVersion) { return new PreliminaryGetDataRequest(proto.getNonce(), ProtoUtil.byteSetFromProtoByteStringList(proto.getExcludedKeysList()), - proto.getSupportedCapabilitiesList().isEmpty() ? null : proto.getSupportedCapabilitiesList(), + Capabilities.fromIntList(proto.getSupportedCapabilitiesList()), messageVersion); } } diff --git a/p2p/src/main/java/bisq/network/p2p/peers/peerexchange/Peer.java b/p2p/src/main/java/bisq/network/p2p/peers/peerexchange/Peer.java index 5459d10ea0..c2a6dafeea 100644 --- a/p2p/src/main/java/bisq/network/p2p/peers/peerexchange/Peer.java +++ b/p2p/src/main/java/bisq/network/p2p/peers/peerexchange/Peer.java @@ -20,14 +20,13 @@ package bisq.network.p2p.peers.peerexchange; import bisq.network.p2p.NodeAddress; import bisq.network.p2p.network.SupportedCapabilitiesListener; +import bisq.common.app.Capabilities; import bisq.common.proto.network.NetworkPayload; import bisq.common.proto.persistable.PersistablePayload; import io.bisq.generated.protobuffer.PB; -import java.util.ArrayList; import java.util.Date; -import java.util.List; import lombok.EqualsAndHashCode; import lombok.Getter; @@ -39,31 +38,28 @@ import javax.annotation.Nullable; @Getter @EqualsAndHashCode(exclude = {"date"}) // failedConnectionAttempts is transient and therefore excluded anyway @Slf4j -public final class Peer implements NetworkPayload, PersistablePayload, SupportedCapabilitiesListener { +public final class Peer extends Capabilities implements NetworkPayload, PersistablePayload, SupportedCapabilitiesListener { private static final int MAX_FAILED_CONNECTION_ATTEMPTS = 5; private final NodeAddress nodeAddress; private final long date; // Added in v. 0.7.1 - @Setter - private List supportedCapabilities = new ArrayList<>(); @Setter transient private int failedConnectionAttempts = 0; - public Peer(NodeAddress nodeAddress, @Nullable List supportedCapabilities) { - this(nodeAddress, new Date().getTime(), - supportedCapabilities == null ? new ArrayList<>() : supportedCapabilities); + public Peer(NodeAddress nodeAddress, @Nullable Capabilities supportedCapabilities) { + this(nodeAddress, new Date().getTime(), supportedCapabilities); } /////////////////////////////////////////////////////////////////////////////////////////// // PROTO BUFFER /////////////////////////////////////////////////////////////////////////////////////////// - private Peer(NodeAddress nodeAddress, long date, List supportedCapabilities) { + private Peer(NodeAddress nodeAddress, long date, Capabilities supportedCapabilities) { + super(supportedCapabilities); this.nodeAddress = nodeAddress; this.date = date; - this.supportedCapabilities = supportedCapabilities; } @Override @@ -71,15 +67,14 @@ public final class Peer implements NetworkPayload, PersistablePayload, Supported return PB.Peer.newBuilder() .setNodeAddress(nodeAddress.toProtoMessage()) .setDate(date) - .addAllSupportedCapabilities(supportedCapabilities) + .addAllSupportedCapabilities(Capabilities.toIntList(this)) .build(); } public static Peer fromProto(PB.Peer proto) { return new Peer(NodeAddress.fromProto(proto.getNodeAddress()), proto.getDate(), - proto.getSupportedCapabilitiesList().isEmpty() ? - new ArrayList<>() : new ArrayList<>(proto.getSupportedCapabilitiesList())); + Capabilities.fromIntList(proto.getSupportedCapabilitiesList())); } @@ -100,9 +95,9 @@ public final class Peer implements NetworkPayload, PersistablePayload, Supported } @Override - public void onChanged(List supportedCapabilities) { - if (supportedCapabilities != null && !supportedCapabilities.isEmpty()) - this.supportedCapabilities = supportedCapabilities; + public void onChanged(Capabilities supportedCapabilities) { + if (supportedCapabilities.hasCapabilities()) + resetCapabilities(supportedCapabilities); } @@ -110,7 +105,7 @@ public final class Peer implements NetworkPayload, PersistablePayload, Supported public String toString() { return "Peer{" + "\n nodeAddress=" + nodeAddress + - ",\n supportedCapabilities=" + supportedCapabilities + + ",\n supportedCapabilities=" + capabilities + ",\n failedConnectionAttempts=" + failedConnectionAttempts + ",\n date=" + date + "\n}"; diff --git a/p2p/src/main/java/bisq/network/p2p/peers/peerexchange/messages/GetPeersRequest.java b/p2p/src/main/java/bisq/network/p2p/peers/peerexchange/messages/GetPeersRequest.java index 8b8ab1adf4..e345d9c766 100644 --- a/p2p/src/main/java/bisq/network/p2p/peers/peerexchange/messages/GetPeersRequest.java +++ b/p2p/src/main/java/bisq/network/p2p/peers/peerexchange/messages/GetPeersRequest.java @@ -29,7 +29,6 @@ import bisq.common.proto.network.NetworkEnvelope; import io.bisq.generated.protobuffer.PB; import java.util.HashSet; -import java.util.List; import java.util.Optional; import java.util.Set; import java.util.stream.Collectors; @@ -48,10 +47,10 @@ public final class GetPeersRequest extends NetworkEnvelope implements PeerExchan private final int nonce; private final Set reportedPeers; @Nullable - private final List supportedCapabilities; + private final Capabilities supportedCapabilities; public GetPeersRequest(NodeAddress senderNodeAddress, int nonce, Set reportedPeers) { - this(senderNodeAddress, nonce, reportedPeers, Capabilities.getSupportedCapabilities(), Version.getP2PMessageVersion()); + this(senderNodeAddress, nonce, reportedPeers, Capabilities.app, Version.getP2PMessageVersion()); } @@ -62,7 +61,7 @@ public final class GetPeersRequest extends NetworkEnvelope implements PeerExchan private GetPeersRequest(NodeAddress senderNodeAddress, int nonce, Set reportedPeers, - @Nullable List supportedCapabilities, + @Nullable Capabilities supportedCapabilities, int messageVersion) { super(messageVersion); checkNotNull(senderNodeAddress, "senderNodeAddress must not be null at GetPeersRequest"); @@ -81,7 +80,7 @@ public final class GetPeersRequest extends NetworkEnvelope implements PeerExchan .map(Peer::toProtoMessage) .collect(Collectors.toList())); - Optional.ofNullable(supportedCapabilities).ifPresent(e -> builder.addAllSupportedCapabilities(supportedCapabilities)); + Optional.ofNullable(supportedCapabilities).ifPresent(e -> builder.addAllSupportedCapabilities(Capabilities.toIntList(supportedCapabilities))); return getNetworkEnvelopeBuilder() .setGetPeersRequest(builder) @@ -94,7 +93,7 @@ public final class GetPeersRequest extends NetworkEnvelope implements PeerExchan new HashSet<>(proto.getReportedPeersList().stream() .map(Peer::fromProto) .collect(Collectors.toSet())), - proto.getSupportedCapabilitiesList().isEmpty() ? null : proto.getSupportedCapabilitiesList(), + Capabilities.fromIntList(proto.getSupportedCapabilitiesList()), messageVersion); } } diff --git a/p2p/src/main/java/bisq/network/p2p/peers/peerexchange/messages/GetPeersResponse.java b/p2p/src/main/java/bisq/network/p2p/peers/peerexchange/messages/GetPeersResponse.java index 1f6788b63c..1c01b9cf68 100644 --- a/p2p/src/main/java/bisq/network/p2p/peers/peerexchange/messages/GetPeersResponse.java +++ b/p2p/src/main/java/bisq/network/p2p/peers/peerexchange/messages/GetPeersResponse.java @@ -28,7 +28,6 @@ import bisq.common.proto.network.NetworkEnvelope; import io.bisq.generated.protobuffer.PB; import java.util.HashSet; -import java.util.List; import java.util.Optional; import java.util.Set; import java.util.stream.Collectors; @@ -44,10 +43,10 @@ public final class GetPeersResponse extends NetworkEnvelope implements PeerExcha private final int requestNonce; private final Set reportedPeers; @Nullable - private final List supportedCapabilities; + private final Capabilities supportedCapabilities; public GetPeersResponse(int requestNonce, Set reportedPeers) { - this(requestNonce, reportedPeers, Capabilities.getSupportedCapabilities(), Version.getP2PMessageVersion()); + this(requestNonce, reportedPeers, Capabilities.app, Version.getP2PMessageVersion()); } @@ -57,7 +56,7 @@ public final class GetPeersResponse extends NetworkEnvelope implements PeerExcha private GetPeersResponse(int requestNonce, Set reportedPeers, - @Nullable List supportedCapabilities, + @Nullable Capabilities supportedCapabilities, int messageVersion) { super(messageVersion); this.requestNonce = requestNonce; @@ -73,7 +72,7 @@ public final class GetPeersResponse extends NetworkEnvelope implements PeerExcha .map(Peer::toProtoMessage) .collect(Collectors.toList())); - Optional.ofNullable(supportedCapabilities).ifPresent(e -> builder.addAllSupportedCapabilities(supportedCapabilities)); + Optional.ofNullable(supportedCapabilities).ifPresent(e -> builder.addAllSupportedCapabilities(Capabilities.toIntList(supportedCapabilities))); return getNetworkEnvelopeBuilder() .setGetPeersResponse(builder) @@ -86,12 +85,12 @@ public final class GetPeersResponse extends NetworkEnvelope implements PeerExcha .map(peer -> { NodeAddress nodeAddress = new NodeAddress(peer.getNodeAddress().getHostName(), peer.getNodeAddress().getPort()); - return new Peer(nodeAddress, peer.getSupportedCapabilitiesList()); + return new Peer(nodeAddress, Capabilities.fromIntList(peer.getSupportedCapabilitiesList())); }) .collect(Collectors.toCollection(HashSet::new)); return new GetPeersResponse(proto.getRequestNonce(), reportedPeers, - proto.getSupportedCapabilitiesList().isEmpty() ? null : proto.getSupportedCapabilitiesList(), + Capabilities.fromIntList(proto.getSupportedCapabilitiesList()), messageVersion); } } diff --git a/p2p/src/main/java/bisq/network/p2p/storage/payload/CapabilityRequiringPayload.java b/p2p/src/main/java/bisq/network/p2p/storage/payload/CapabilityRequiringPayload.java index 69e4d04303..b11d1ad80a 100644 --- a/p2p/src/main/java/bisq/network/p2p/storage/payload/CapabilityRequiringPayload.java +++ b/p2p/src/main/java/bisq/network/p2p/storage/payload/CapabilityRequiringPayload.java @@ -17,10 +17,9 @@ package bisq.network.p2p.storage.payload; +import bisq.common.app.Capabilities; import bisq.common.proto.network.NetworkPayload; -import java.util.List; - /** * Used for payloads which requires certain capability. *

@@ -31,5 +30,5 @@ public interface CapabilityRequiringPayload extends NetworkPayload { /** * @return Capabilities the other node need to support to receive that message */ - List getRequiredCapabilities(); + Capabilities getRequiredCapabilities(); } diff --git a/seednode/src/main/java/bisq/seednode/SeedNodeMain.java b/seednode/src/main/java/bisq/seednode/SeedNodeMain.java index 5925baec58..3fd7110298 100644 --- a/seednode/src/main/java/bisq/seednode/SeedNodeMain.java +++ b/seednode/src/main/java/bisq/seednode/SeedNodeMain.java @@ -25,10 +25,13 @@ import bisq.core.app.misc.ModuleForAppWithP2p; import bisq.common.UserThread; import bisq.common.app.AppModule; import bisq.common.app.Capabilities; +import bisq.common.app.Capability; import bisq.common.setup.CommonSetup; import joptsimple.OptionSet; +import java.util.List; + import lombok.extern.slf4j.Slf4j; @Slf4j @@ -60,7 +63,10 @@ public class SeedNodeMain extends ExecutableForAppWithP2p { @Override protected void addCapabilities() { - Capabilities.addCapability(Capabilities.Capability.SEED_NODE.ordinal()); + // TODO got even worse after refactoring + List current = Capabilities.toIntList(Capabilities.app); + current.add(Capability.SEED_NODE.ordinal()); + Capabilities.app.resetCapabilities(Capabilities.fromIntList(current)); } @Override