diff --git a/account/src/main/java/bisq/account/accounts/Account.java b/account/src/main/java/bisq/account/accounts/Account.java index 066b10cdad..e149293c53 100644 --- a/account/src/main/java/bisq/account/accounts/Account.java +++ b/account/src/main/java/bisq/account/accounts/Account.java @@ -19,6 +19,7 @@ import bisq.account.settlement.SettlementMethod; import bisq.common.currency.TradeCurrency; +import bisq.common.data.ByteArray; import bisq.common.proto.Proto; import bisq.common.proto.UnresolvableProtobufMessageException; import bisq.common.util.StringUtils; @@ -27,6 +28,7 @@ import lombok.ToString; import lombok.extern.slf4j.Slf4j; +import java.util.Comparator; import java.util.Date; import java.util.List; import java.util.Set; @@ -63,6 +65,8 @@ public Account(String id, long creationDate, this.payload = payload; this.settlementMethod = settlementMethod; this.tradeCurrencies = tradeCurrencies; + // We need to sort deterministically as the data is used in the proof of work check + this.tradeCurrencies.sort(Comparator.comparing((TradeCurrency e) -> new ByteArray(e.serialize()))); } diff --git a/chat/src/main/java/bisq/chat/channel/Channel.java b/chat/src/main/java/bisq/chat/channel/Channel.java index 90f3d9a925..ebc16ecd97 100644 --- a/chat/src/main/java/bisq/chat/channel/Channel.java +++ b/chat/src/main/java/bisq/chat/channel/Channel.java @@ -27,7 +27,7 @@ import bisq.chat.trade.priv.PrivateTradeChannel; import bisq.chat.trade.pub.PublicTradeChannel; import bisq.common.observable.Observable; -import bisq.common.observable.ObservableSet; +import bisq.common.observable.ObservableArray; import bisq.common.proto.Proto; import bisq.common.proto.UnresolvableProtobufMessageException; import lombok.EqualsAndHashCode; @@ -86,7 +86,7 @@ public static Channel fromProto(bisq.chat.protobuf.Channe case PUBLICSUPPORTCHANNEL: { return PublicSupportChannel.fromProto(proto, proto.getPublicSupportChannel()); } - + case MESSAGE_NOT_SET: { throw new UnresolvableProtobufMessageException(proto); } @@ -94,7 +94,7 @@ public static Channel fromProto(bisq.chat.protobuf.Channe throw new UnresolvableProtobufMessageException(proto); } - abstract public ObservableSet getChatMessages(); + abstract public ObservableArray getChatMessages(); abstract public void addChatMessage(T chatMessage); diff --git a/chat/src/main/java/bisq/chat/channel/PrivateChannel.java b/chat/src/main/java/bisq/chat/channel/PrivateChannel.java index bfa9a883c8..f8a7877b30 100644 --- a/chat/src/main/java/bisq/chat/channel/PrivateChannel.java +++ b/chat/src/main/java/bisq/chat/channel/PrivateChannel.java @@ -18,14 +18,16 @@ package bisq.chat.channel; import bisq.chat.message.PrivateChatMessage; -import bisq.common.observable.ObservableSet; +import bisq.common.data.ByteArray; +import bisq.common.observable.ObservableArray; import bisq.user.identity.UserIdentity; import bisq.user.profile.UserProfile; import lombok.EqualsAndHashCode; import lombok.Getter; import lombok.ToString; -import java.util.Set; +import java.util.Comparator; +import java.util.List; @Getter @ToString(callSuper = true) @@ -35,17 +37,18 @@ public abstract class PrivateChannel extends Chann protected final UserIdentity myUserIdentity; // We persist the messages as they are NOT persisted in the P2P data store. - protected final ObservableSet chatMessages = new ObservableSet<>(); + protected final ObservableArray chatMessages = new ObservableArray<>(); public PrivateChannel(String id, UserProfile peer, UserIdentity myUserIdentity, - Set chatMessages, + List chatMessages, ChannelNotificationType channelNotificationType) { super(id, channelNotificationType); this.peer = peer; this.myUserIdentity = myUserIdentity; this.chatMessages.addAll(chatMessages); + this.chatMessages.sort(Comparator.comparing((T e) -> new ByteArray(e.serialize()))); } public static String createChannelId(String peersId, String myId) { diff --git a/chat/src/main/java/bisq/chat/channel/PublicChannel.java b/chat/src/main/java/bisq/chat/channel/PublicChannel.java index bb8b36ac5b..b4efff17ee 100644 --- a/chat/src/main/java/bisq/chat/channel/PublicChannel.java +++ b/chat/src/main/java/bisq/chat/channel/PublicChannel.java @@ -18,7 +18,7 @@ package bisq.chat.channel; import bisq.chat.message.PublicChatMessage; -import bisq.common.observable.ObservableSet; +import bisq.common.observable.ObservableArray; import lombok.EqualsAndHashCode; import lombok.Getter; import lombok.ToString; @@ -28,7 +28,7 @@ @EqualsAndHashCode(callSuper = true, onlyExplicitlyIncluded = true) public abstract class PublicChannel extends Channel { // We do not persist the messages as they are persisted in the P2P data store. - protected transient final ObservableSet chatMessages = new ObservableSet<>(); + protected transient final ObservableArray chatMessages = new ObservableArray<>(); public PublicChannel(String id, ChannelNotificationType channelNotificationType) { super(id, channelNotificationType); diff --git a/chat/src/main/java/bisq/chat/discuss/priv/PrivateDiscussionChannel.java b/chat/src/main/java/bisq/chat/discuss/priv/PrivateDiscussionChannel.java index 9e48cff5ab..120f2c9fb4 100644 --- a/chat/src/main/java/bisq/chat/discuss/priv/PrivateDiscussionChannel.java +++ b/chat/src/main/java/bisq/chat/discuss/priv/PrivateDiscussionChannel.java @@ -25,9 +25,9 @@ import lombok.Getter; import lombok.ToString; +import java.util.ArrayList; import java.util.Collection; -import java.util.HashSet; -import java.util.Set; +import java.util.List; import java.util.stream.Collectors; @ToString(callSuper = true) @@ -39,14 +39,14 @@ public PrivateDiscussionChannel(UserProfile peer, UserIdentity myProfile) { this(PrivateChannel.createChannelId(peer.getId(), myProfile.getId()), peer, myProfile, - new HashSet<>(), + new ArrayList<>(), ChannelNotificationType.ALL); } private PrivateDiscussionChannel(String id, UserProfile peer, UserIdentity myProfile, - Set chatMessages, + List chatMessages, ChannelNotificationType channelNotificationType) { super(id, peer, myProfile, chatMessages, channelNotificationType); } @@ -70,7 +70,7 @@ public static PrivateDiscussionChannel fromProto(bisq.chat.protobuf.Channel base UserIdentity.fromProto(proto.getMyUserIdentity()), proto.getChatMessagesList().stream() .map(PrivateDiscussionChatMessage::fromProto) - .collect(Collectors.toSet()), + .collect(Collectors.toList()), ChannelNotificationType.fromProto(baseProto.getChannelNotificationType())); } diff --git a/chat/src/main/java/bisq/chat/discuss/pub/PublicDiscussionChannel.java b/chat/src/main/java/bisq/chat/discuss/pub/PublicDiscussionChannel.java index a62a7cb9c2..e2f6efe423 100644 --- a/chat/src/main/java/bisq/chat/discuss/pub/PublicDiscussionChannel.java +++ b/chat/src/main/java/bisq/chat/discuss/pub/PublicDiscussionChannel.java @@ -24,9 +24,10 @@ import lombok.Getter; import lombok.ToString; +import java.util.ArrayList; import java.util.Collection; -import java.util.HashSet; -import java.util.Set; +import java.util.Comparator; +import java.util.List; @Getter @ToString(callSuper = true) @@ -35,14 +36,14 @@ public final class PublicDiscussionChannel extends PublicChannel channelModeratorIds; + private final List channelModeratorIds; public PublicDiscussionChannel(String id) { this(id, Res.get("discussion." + id + ".name"), Res.get("discussion." + id + ".description"), "", - new HashSet<>(), + new ArrayList<>(), ChannelNotificationType.MENTION); } @@ -50,7 +51,7 @@ public PublicDiscussionChannel(String id, String channelName, String description, String channelAdminId, - Set channelModeratorIds) { + List channelModeratorIds) { this(id, channelName, description, @@ -63,7 +64,7 @@ private PublicDiscussionChannel(String id, String channelName, String description, String channelAdminId, - Set channelModeratorIds, + List channelModeratorIds, ChannelNotificationType channelNotificationType) { super(id, channelNotificationType); @@ -71,6 +72,8 @@ private PublicDiscussionChannel(String id, this.description = description; this.channelAdminId = channelAdminId; this.channelModeratorIds = channelModeratorIds; + // We need to sort deterministically as the data is used in the proof of work check + this.channelModeratorIds.sort(Comparator.comparing((String e) -> e)); } public bisq.chat.protobuf.Channel toProto() { @@ -90,7 +93,7 @@ public static PublicDiscussionChannel fromProto(bisq.chat.protobuf.Channel baseP proto.getChannelName(), proto.getDescription(), proto.getChannelAdminId(), - new HashSet<>(proto.getChannelModeratorIdsList()), + new ArrayList<>(proto.getChannelModeratorIdsList()), ChannelNotificationType.fromProto(baseProto.getChannelNotificationType())); } diff --git a/chat/src/main/java/bisq/chat/events/priv/PrivateEventsChannel.java b/chat/src/main/java/bisq/chat/events/priv/PrivateEventsChannel.java index 5693cd2efd..df99ee8f56 100644 --- a/chat/src/main/java/bisq/chat/events/priv/PrivateEventsChannel.java +++ b/chat/src/main/java/bisq/chat/events/priv/PrivateEventsChannel.java @@ -25,9 +25,9 @@ import lombok.Getter; import lombok.ToString; +import java.util.ArrayList; import java.util.Collection; -import java.util.HashSet; -import java.util.Set; +import java.util.List; import java.util.stream.Collectors; @ToString(callSuper = true) @@ -39,14 +39,14 @@ public PrivateEventsChannel(UserProfile peer, UserIdentity myProfile) { this(PrivateChannel.createChannelId(peer.getId(), myProfile.getId()), peer, myProfile, - new HashSet<>(), + new ArrayList<>(), ChannelNotificationType.ALL); } private PrivateEventsChannel(String id, UserProfile peer, UserIdentity myProfile, - Set chatMessages, + List chatMessages, ChannelNotificationType channelNotificationType) { super(id, peer, myProfile, chatMessages, channelNotificationType); } @@ -70,7 +70,7 @@ public static PrivateEventsChannel fromProto(bisq.chat.protobuf.Channel baseProt UserIdentity.fromProto(proto.getMyUserIdentity()), proto.getChatMessagesList().stream() .map(PrivateEventsChatMessage::fromProto) - .collect(Collectors.toSet()), + .collect(Collectors.toList()), ChannelNotificationType.fromProto(baseProto.getChannelNotificationType())); } diff --git a/chat/src/main/java/bisq/chat/events/pub/PublicEventsChannel.java b/chat/src/main/java/bisq/chat/events/pub/PublicEventsChannel.java index bb93547e71..bf9c32cb77 100644 --- a/chat/src/main/java/bisq/chat/events/pub/PublicEventsChannel.java +++ b/chat/src/main/java/bisq/chat/events/pub/PublicEventsChannel.java @@ -24,9 +24,10 @@ import lombok.Getter; import lombok.ToString; +import java.util.ArrayList; import java.util.Collection; -import java.util.HashSet; -import java.util.Set; +import java.util.Comparator; +import java.util.List; @Getter @ToString(callSuper = true) @@ -35,14 +36,14 @@ public final class PublicEventsChannel extends PublicChannel channelModeratorIds; + private final List channelModeratorIds; public PublicEventsChannel(String id) { this(id, Res.get("events." + id + ".name"), Res.get("events." + id + ".description"), "", - new HashSet<>(), + new ArrayList<>(), ChannelNotificationType.MENTION); } @@ -50,7 +51,7 @@ public PublicEventsChannel(String id, String channelName, String description, String channelAdminId, - Set channelModeratorIds) { + List channelModeratorIds) { this(id, channelName, description, @@ -63,7 +64,7 @@ private PublicEventsChannel(String id, String channelName, String description, String channelAdminId, - Set channelModeratorIds, + List channelModeratorIds, ChannelNotificationType channelNotificationType) { super(id, channelNotificationType); @@ -71,6 +72,8 @@ private PublicEventsChannel(String id, this.description = description; this.channelAdminId = channelAdminId; this.channelModeratorIds = channelModeratorIds; + // We need to sort deterministically as the data is used in the proof of work check + this.channelModeratorIds.sort(Comparator.comparing((String e) -> e)); } public bisq.chat.protobuf.Channel toProto() { @@ -90,7 +93,7 @@ public static PublicEventsChannel fromProto(bisq.chat.protobuf.Channel baseProto proto.getChannelName(), proto.getDescription(), proto.getChannelAdminId(), - new HashSet<>(proto.getChannelModeratorIdsList()), + new ArrayList<>(proto.getChannelModeratorIdsList()), ChannelNotificationType.fromProto(baseProto.getChannelNotificationType())); } diff --git a/chat/src/main/java/bisq/chat/support/priv/PrivateSupportChannel.java b/chat/src/main/java/bisq/chat/support/priv/PrivateSupportChannel.java index 2393243fe5..814c4659b5 100644 --- a/chat/src/main/java/bisq/chat/support/priv/PrivateSupportChannel.java +++ b/chat/src/main/java/bisq/chat/support/priv/PrivateSupportChannel.java @@ -25,9 +25,9 @@ import lombok.Getter; import lombok.ToString; +import java.util.ArrayList; import java.util.Collection; -import java.util.HashSet; -import java.util.Set; +import java.util.List; import java.util.stream.Collectors; @ToString(callSuper = true) @@ -39,14 +39,14 @@ public PrivateSupportChannel(UserProfile peer, UserIdentity myProfile) { this(PrivateChannel.createChannelId(peer.getId(), myProfile.getId()), peer, myProfile, - new HashSet<>(), + new ArrayList<>(), ChannelNotificationType.ALL); } private PrivateSupportChannel(String id, UserProfile peer, UserIdentity myProfile, - Set chatMessages, + List chatMessages, ChannelNotificationType channelNotificationType) { super(id, peer, myProfile, chatMessages, channelNotificationType); } @@ -70,7 +70,7 @@ public static PrivateSupportChannel fromProto(bisq.chat.protobuf.Channel basePro UserIdentity.fromProto(proto.getMyUserIdentity()), proto.getChatMessagesList().stream() .map(PrivateSupportChatMessage::fromProto) - .collect(Collectors.toSet()), + .collect(Collectors.toList()), ChannelNotificationType.fromProto(baseProto.getChannelNotificationType())); } diff --git a/chat/src/main/java/bisq/chat/support/pub/PublicSupportChannel.java b/chat/src/main/java/bisq/chat/support/pub/PublicSupportChannel.java index 1ff46bfaa2..0674312188 100644 --- a/chat/src/main/java/bisq/chat/support/pub/PublicSupportChannel.java +++ b/chat/src/main/java/bisq/chat/support/pub/PublicSupportChannel.java @@ -24,9 +24,10 @@ import lombok.Getter; import lombok.ToString; +import java.util.ArrayList; import java.util.Collection; -import java.util.HashSet; -import java.util.Set; +import java.util.Comparator; +import java.util.List; @Getter @ToString(callSuper = true) @@ -35,14 +36,14 @@ public final class PublicSupportChannel extends PublicChannel channelModeratorIds; + private final List channelModeratorIds; public PublicSupportChannel(String id) { this(id, Res.get("support." + id + ".name"), Res.get("support." + id + ".description"), "", - new HashSet<>(), + new ArrayList<>(), ChannelNotificationType.MENTION); } @@ -50,7 +51,7 @@ public PublicSupportChannel(String id, String channelName, String description, String channelAdminId, - Set channelModeratorIds) { + List channelModeratorIds) { this(id, channelName, description, @@ -63,7 +64,7 @@ private PublicSupportChannel(String id, String channelName, String description, String channelAdminId, - Set channelModeratorIds, + List channelModeratorIds, ChannelNotificationType channelNotificationType) { super(id, channelNotificationType); @@ -71,9 +72,12 @@ private PublicSupportChannel(String id, this.description = description; this.channelAdminId = channelAdminId; this.channelModeratorIds = channelModeratorIds; + // We need to sort deterministically as the data is used in the proof of work check + this.channelModeratorIds.sort(Comparator.comparing((String e) -> e)); } public bisq.chat.protobuf.Channel toProto() { + return getChannelBuilder() .setPublicSupportChannel(bisq.chat.protobuf.PublicSupportChannel.newBuilder() .setChannelName(channelName) @@ -90,7 +94,7 @@ public static PublicSupportChannel fromProto(bisq.chat.protobuf.Channel baseProt proto.getChannelName(), proto.getDescription(), proto.getChannelAdminId(), - new HashSet<>(proto.getChannelModeratorIdsList()), + new ArrayList<>(proto.getChannelModeratorIdsList()), ChannelNotificationType.fromProto(baseProto.getChannelNotificationType())); } diff --git a/chat/src/main/java/bisq/chat/trade/priv/PrivateTradeChannel.java b/chat/src/main/java/bisq/chat/trade/priv/PrivateTradeChannel.java index add9e6b135..d56f245b74 100644 --- a/chat/src/main/java/bisq/chat/trade/priv/PrivateTradeChannel.java +++ b/chat/src/main/java/bisq/chat/trade/priv/PrivateTradeChannel.java @@ -27,10 +27,10 @@ import lombok.Getter; import lombok.ToString; +import java.util.ArrayList; import java.util.Collection; -import java.util.HashSet; +import java.util.List; import java.util.Optional; -import java.util.Set; import java.util.stream.Collectors; @ToString(callSuper = true) @@ -47,7 +47,7 @@ public PrivateTradeChannel(UserIdentity myUserIdentity, UserProfile trader1, Use super(PrivateChannel.createChannelId(trader1.getId(), trader2.getId()), trader1, myUserIdentity, - new HashSet<>(), + new ArrayList<>(), ChannelNotificationType.ALL); this.trader1 = trader1; this.trader2 = trader2; @@ -59,7 +59,7 @@ private PrivateTradeChannel(String id, UserProfile peer, UserIdentity myUserIdentity, Optional mediator, - Set chatMessages, + List chatMessages, ChannelNotificationType channelNotificationType) { super(id, peer, myUserIdentity, chatMessages, channelNotificationType); @@ -91,7 +91,7 @@ public static PrivateTradeChannel fromProto(bisq.chat.protobuf.Channel baseProto proto.hasMediator() ? Optional.of(UserProfile.fromProto(proto.getMediator())) : Optional.empty(), proto.getChatMessagesList().stream() .map(PrivateTradeChatMessage::fromProto) - .collect(Collectors.toSet()), + .collect(Collectors.toList()), ChannelNotificationType.fromProto(baseProto.getChannelNotificationType())); privateTradeChannel.getMediationActivated().set(proto.getMediationActivated()); return privateTradeChannel; diff --git a/chat/src/main/java/bisq/chat/trade/pub/TradeChatOffer.java b/chat/src/main/java/bisq/chat/trade/pub/TradeChatOffer.java index 0fb8a1ad4c..218935199d 100644 --- a/chat/src/main/java/bisq/chat/trade/pub/TradeChatOffer.java +++ b/chat/src/main/java/bisq/chat/trade/pub/TradeChatOffer.java @@ -14,8 +14,8 @@ import lombok.extern.slf4j.Slf4j; import java.util.ArrayList; -import java.util.HashSet; -import java.util.Set; +import java.util.Comparator; +import java.util.List; @ToString @EqualsAndHashCode @@ -26,7 +26,7 @@ public final class TradeChatOffer implements Proto { private final long baseSideAmount; private final Market market; private final long quoteSideAmount; - private final Set paymentMethods; + private final List paymentMethods; private final String makersTradeTerms; private final long requiredTotalReputationScore; @@ -36,7 +36,7 @@ public TradeChatOffer(Direction direction, Market market, long baseSideAmount, long quoteSideAmount, - Set paymentMethods, + List paymentMethods, String makersTradeTerms, long requiredTotalReputationScore) { this.direction = direction; @@ -47,6 +47,8 @@ public TradeChatOffer(Direction direction, this.makersTradeTerms = makersTradeTerms; this.requiredTotalReputationScore = requiredTotalReputationScore; + // We need to sort deterministically as the data is used in the proof of work check + this.paymentMethods.sort(Comparator.comparing((String e) -> e)); chatMessageText = Res.get("createOffer.tradeChatOffer.chatMessage", Res.get(direction.name().toLowerCase()).toUpperCase(), AmountFormatter.formatAmountWithCode(Fiat.of(quoteSideAmount, market.getQuoteCurrencyCode()), true), @@ -60,7 +62,7 @@ public bisq.chat.protobuf.TradeChatOffer toProto() { .setMarket(market.toProto()) .setBaseSideAmount(baseSideAmount) .setQuoteSideAmount(quoteSideAmount) - .addAllPaymentMethods(new ArrayList<>(paymentMethods)) + .addAllPaymentMethods(paymentMethods) .setMakersTradeTerms(makersTradeTerms) .setRequiredTotalReputationScore(requiredTotalReputationScore) .build(); @@ -71,7 +73,7 @@ public static TradeChatOffer fromProto(bisq.chat.protobuf.TradeChatOffer proto) Market.fromProto(proto.getMarket()), proto.getBaseSideAmount(), proto.getQuoteSideAmount(), - new HashSet<>(proto.getPaymentMethodsList()), + new ArrayList<>(proto.getPaymentMethodsList()), proto.getMakersTradeTerms(), proto.getRequiredTotalReputationScore()); } diff --git a/desktop/src/main/java/bisq/desktop/primary/overlay/createOffer/review/ReviewOfferController.java b/desktop/src/main/java/bisq/desktop/primary/overlay/createOffer/review/ReviewOfferController.java index ef4c836128..688ac711df 100644 --- a/desktop/src/main/java/bisq/desktop/primary/overlay/createOffer/review/ReviewOfferController.java +++ b/desktop/src/main/java/bisq/desktop/primary/overlay/createOffer/review/ReviewOfferController.java @@ -135,7 +135,7 @@ public void onActivate() { model.getMarket(), model.getBaseSideAmount().getValue(), model.getQuoteSideAmount().getValue(), - new HashSet<>(model.getPaymentMethods()), + new ArrayList<>(model.getPaymentMethods()), userIdentity.getUserProfile().getTerms(), settingsService.getRequiredTotalReputationScore().get()); model.setMyOfferText(StringUtils.truncate(tradeChatOffer.getChatMessageText(), 100)); @@ -263,7 +263,7 @@ private Predicate getTakeOfferPredicate() { return false; } - Set paymentMethods = peersOffer.getPaymentMethods(); + List paymentMethods = peersOffer.getPaymentMethods(); if (myChatOffer.getPaymentMethods().stream().noneMatch(paymentMethods::contains)) { return false; } diff --git a/network/network/src/main/java/bisq/network/NetworkId.java b/network/network/src/main/java/bisq/network/NetworkId.java index 5556d33b51..9b565d59d5 100644 --- a/network/network/src/main/java/bisq/network/NetworkId.java +++ b/network/network/src/main/java/bisq/network/NetworkId.java @@ -61,8 +61,8 @@ public bisq.network.protobuf.NetworkId toProto() { } public static NetworkId fromProto(bisq.network.protobuf.NetworkId proto) { - Map addressByNetworkType = proto.getAddressNetworkTypeTupleList().stream(). - map(AddressTransportTypeTuple::fromProto) + Map addressByNetworkType = proto.getAddressNetworkTypeTupleList().stream() + .map(AddressTransportTypeTuple::fromProto) .collect(Collectors.toMap(e -> e.transportType, e -> e.address)); return new NetworkId(addressByNetworkType, PubKey.fromProto(proto.getPubKey()), proto.getNodeId()); } diff --git a/network/network/src/main/java/bisq/network/p2p/node/Capability.java b/network/network/src/main/java/bisq/network/p2p/node/Capability.java index 4b6f28d428..7e60a41b84 100644 --- a/network/network/src/main/java/bisq/network/p2p/node/Capability.java +++ b/network/network/src/main/java/bisq/network/p2p/node/Capability.java @@ -24,7 +24,8 @@ import lombok.Getter; import lombok.ToString; -import java.util.Set; +import java.util.Comparator; +import java.util.List; import java.util.stream.Collectors; @Getter @@ -32,27 +33,28 @@ @EqualsAndHashCode public final class Capability implements Proto { private final Address address; - private final Set supportedTransportTypes; + private final List supportedTransportTypes; - public Capability(Address address, Set supportedTransportTypes) { + public Capability(Address address, List supportedTransportTypes) { this.address = address; this.supportedTransportTypes = supportedTransportTypes; + // We need to sort deterministically as the data is used in the proof of work check + this.supportedTransportTypes.sort(Comparator.comparing(Enum::ordinal)); } public bisq.network.protobuf.Capability toProto() { return bisq.network.protobuf.Capability.newBuilder() .setAddress(address.toProto()) .addAllSupportedTransportTypes(supportedTransportTypes.stream() - .sorted(Enum::compareTo) .map(Enum::name) .collect(Collectors.toList())) .build(); } public static Capability fromProto(bisq.network.protobuf.Capability proto) { - Set supportedTransportTypes = proto.getSupportedTransportTypesList().stream() + List supportedTransportTypes = proto.getSupportedTransportTypesList().stream() .map(e -> ProtobufUtils.enumFromProto(Transport.Type.class, e)) - .collect(Collectors.toSet()); + .collect(Collectors.toList()); return new Capability(Address.fromProto(proto.getAddress()), supportedTransportTypes); } } diff --git a/network/network/src/main/java/bisq/network/p2p/node/Node.java b/network/network/src/main/java/bisq/network/p2p/node/Node.java index cdbdc7375a..00887b925c 100644 --- a/network/network/src/main/java/bisq/network/p2p/node/Node.java +++ b/network/network/src/main/java/bisq/network/p2p/node/Node.java @@ -45,6 +45,7 @@ import java.net.SocketTimeoutException; import java.net.UnknownHostException; import java.time.Duration; +import java.util.ArrayList; import java.util.Map; import java.util.Optional; import java.util.Set; @@ -203,7 +204,7 @@ private void doInitialize(int port) { private void createServerAndListen(int port) { Transport.ServerSocketResult serverSocketResult = transport.getServerSocket(port, nodeId); - myCapability = Optional.of(new Capability(serverSocketResult.getAddress(), config.getSupportedTransportTypes())); + myCapability = Optional.of(new Capability(serverSocketResult.getAddress(), new ArrayList<>(config.getSupportedTransportTypes()))); server = Optional.of(new Server(serverSocketResult, socket -> onClientSocket(socket, serverSocketResult, myCapability.get()), exception -> { diff --git a/network/network/src/main/java/bisq/network/p2p/services/data/DataService.java b/network/network/src/main/java/bisq/network/p2p/services/data/DataService.java index 5e7d0705e8..7d8da0c5c2 100644 --- a/network/network/src/main/java/bisq/network/p2p/services/data/DataService.java +++ b/network/network/src/main/java/bisq/network/p2p/services/data/DataService.java @@ -42,8 +42,8 @@ import java.security.GeneralSecurityException; import java.security.KeyPair; import java.security.PublicKey; +import java.util.ArrayList; import java.util.HashMap; -import java.util.HashSet; import java.util.Map; import java.util.Set; import java.util.concurrent.CompletableFuture; @@ -292,11 +292,11 @@ public void requestInventory() { } public void requestInventory(StorageService.StoreType storeType) { - requestInventory(new DataFilter(new HashSet<>(storageService.getFilterEntries(storeType)))); + requestInventory(new DataFilter(new ArrayList<>(storageService.getFilterEntries(storeType)))); } public void requestInventory(String storeName) { - requestInventory(new DataFilter(new HashSet<>(storageService.getFilterEntries(storeName)))); + requestInventory(new DataFilter(new ArrayList<>(storageService.getFilterEntries(storeName)))); } public void requestInventory(DataFilter dataFilter) { @@ -372,6 +372,6 @@ private void processRemoveDataRequest(RemoveDataRequest removeDataRequest, boole } private void doRequestInventory(DataNetworkService dataNetworkService) { - requestInventory(new DataFilter(new HashSet<>(storageService.getFilterEntries(StorageService.StoreType.ALL))), dataNetworkService); + requestInventory(new DataFilter(new ArrayList<>(storageService.getFilterEntries(StorageService.StoreType.ALL))), dataNetworkService); } } \ No newline at end of file diff --git a/network/network/src/main/java/bisq/network/p2p/services/data/filter/DataFilter.java b/network/network/src/main/java/bisq/network/p2p/services/data/filter/DataFilter.java index 2df9299bbd..09a86cec44 100644 --- a/network/network/src/main/java/bisq/network/p2p/services/data/filter/DataFilter.java +++ b/network/network/src/main/java/bisq/network/p2p/services/data/filter/DataFilter.java @@ -18,22 +18,26 @@ package bisq.network.p2p.services.data.filter; +import bisq.common.data.ByteArray; import bisq.common.proto.Proto; import lombok.EqualsAndHashCode; import lombok.Getter; import lombok.ToString; -import java.util.Set; +import java.util.Comparator; +import java.util.List; import java.util.stream.Collectors; @Getter @ToString @EqualsAndHashCode public final class DataFilter implements Proto { - private final Set filterEntries; + private final List filterEntries; - public DataFilter(Set filterEntries) { + public DataFilter(List filterEntries) { this.filterEntries = filterEntries; + // We need to sort deterministically as the data is used in the proof of work check + this.filterEntries.sort(Comparator.comparing((FilterEntry e) -> new ByteArray(e.serialize()))); } public bisq.network.protobuf.DataFilter toProto() { @@ -47,6 +51,6 @@ public bisq.network.protobuf.DataFilter toProto() { public static DataFilter fromProto(bisq.network.protobuf.DataFilter proto) { return new DataFilter(proto.getFilterEntriesList().stream() .map(FilterEntry::fromProto) - .collect(Collectors.toSet())); + .collect(Collectors.toList())); } } \ No newline at end of file diff --git a/network/network/src/main/java/bisq/network/p2p/services/data/inventory/Inventory.java b/network/network/src/main/java/bisq/network/p2p/services/data/inventory/Inventory.java index 33a2407cef..dbdb3ab4b4 100644 --- a/network/network/src/main/java/bisq/network/p2p/services/data/inventory/Inventory.java +++ b/network/network/src/main/java/bisq/network/p2p/services/data/inventory/Inventory.java @@ -44,7 +44,7 @@ public Inventory(Collection entries, int numDropped) { this.numDropped = numDropped; // We need to sort deterministically as the data is used in the proof of work check - this.entries.sort(Comparator.comparing((DataRequest o) -> new ByteArray(o.serialize()))); + this.entries.sort(Comparator.comparing((DataRequest e) -> new ByteArray(e.serialize()))); } public bisq.network.protobuf.Inventory toProto() { diff --git a/network/network/src/main/java/bisq/network/p2p/services/peergroup/exchange/PeerExchangeRequest.java b/network/network/src/main/java/bisq/network/p2p/services/peergroup/exchange/PeerExchangeRequest.java index 0b6acebf7b..a6d9b77a3b 100644 --- a/network/network/src/main/java/bisq/network/p2p/services/peergroup/exchange/PeerExchangeRequest.java +++ b/network/network/src/main/java/bisq/network/p2p/services/peergroup/exchange/PeerExchangeRequest.java @@ -17,13 +17,15 @@ package bisq.network.p2p.services.peergroup.exchange; +import bisq.common.data.ByteArray; import bisq.network.p2p.message.NetworkMessage; import bisq.network.p2p.services.peergroup.Peer; import lombok.EqualsAndHashCode; import lombok.Getter; import lombok.ToString; -import java.util.Set; +import java.util.Comparator; +import java.util.List; import java.util.stream.Collectors; @Getter @@ -31,11 +33,13 @@ @EqualsAndHashCode public final class PeerExchangeRequest implements NetworkMessage { private final int nonce; - private final Set peers; + private final List peers; - public PeerExchangeRequest(int nonce, Set peers) { + public PeerExchangeRequest(int nonce, List peers) { this.nonce = nonce; this.peers = peers; + // We need to sort deterministically as the data is used in the proof of work check + this.peers.sort(Comparator.comparing((Peer e) -> new ByteArray(e.serialize()))); } @Override @@ -43,12 +47,14 @@ public bisq.network.protobuf.NetworkMessage toProto() { return getNetworkMessageBuilder().setPeerExchangeRequest( bisq.network.protobuf.PeerExchangeRequest.newBuilder() .setNonce(nonce) - .addAllPeers(peers.stream().map(Peer::toProto).collect(Collectors.toSet()))) + .addAllPeers(peers.stream() + .map(Peer::toProto) + .collect(Collectors.toList()))) .build(); } public static PeerExchangeRequest fromProto(bisq.network.protobuf.PeerExchangeRequest proto) { return new PeerExchangeRequest(proto.getNonce(), - proto.getPeersList().stream().map(Peer::fromProto).collect(Collectors.toSet())); + proto.getPeersList().stream().map(Peer::fromProto).collect(Collectors.toList())); } } \ No newline at end of file diff --git a/network/network/src/main/java/bisq/network/p2p/services/peergroup/exchange/PeerExchangeRequestHandler.java b/network/network/src/main/java/bisq/network/p2p/services/peergroup/exchange/PeerExchangeRequestHandler.java index 131755b9e8..538f7932d3 100644 --- a/network/network/src/main/java/bisq/network/p2p/services/peergroup/exchange/PeerExchangeRequestHandler.java +++ b/network/network/src/main/java/bisq/network/p2p/services/peergroup/exchange/PeerExchangeRequestHandler.java @@ -25,6 +25,8 @@ import lombok.Getter; import lombok.extern.slf4j.Slf4j; +import java.util.ArrayList; +import java.util.HashSet; import java.util.Random; import java.util.Set; import java.util.concurrent.CompletableFuture; @@ -51,7 +53,7 @@ CompletableFuture> request(Set peersForPeerExchange) { ts = System.currentTimeMillis(); try { // We get called from the IO thread, so we do not use the async send method - node.send(new PeerExchangeRequest(nonce, peersForPeerExchange), connection); + node.send(new PeerExchangeRequest(nonce, new ArrayList<>(peersForPeerExchange)), connection); } catch (Throwable throwable) { future.completeExceptionally(throwable); dispose(); @@ -73,7 +75,7 @@ public void onNetworkMessage(NetworkMessage networkMessage) { node, connection.getPeerAddress(), response.getPeers().size()); connection.getMetrics().addRtt(ts = System.currentTimeMillis() - ts); removeListeners(); - future.complete(response.getPeers()); + future.complete(new HashSet<>(response.getPeers())); } else { log.warn("Node {} received a PeerExchangeResponse from {} with an invalid nonce. response.nonce()={}, nonce={}", node, connection.getPeerAddress(), response.getNonce(), nonce); diff --git a/network/network/src/main/java/bisq/network/p2p/services/peergroup/exchange/PeerExchangeResponse.java b/network/network/src/main/java/bisq/network/p2p/services/peergroup/exchange/PeerExchangeResponse.java index 97cc67c8b8..8b6acb0cb4 100644 --- a/network/network/src/main/java/bisq/network/p2p/services/peergroup/exchange/PeerExchangeResponse.java +++ b/network/network/src/main/java/bisq/network/p2p/services/peergroup/exchange/PeerExchangeResponse.java @@ -17,13 +17,15 @@ package bisq.network.p2p.services.peergroup.exchange; +import bisq.common.data.ByteArray; import bisq.network.p2p.message.NetworkMessage; import bisq.network.p2p.services.peergroup.Peer; import lombok.EqualsAndHashCode; import lombok.Getter; import lombok.ToString; -import java.util.Set; +import java.util.Comparator; +import java.util.List; import java.util.stream.Collectors; @Getter @@ -31,11 +33,13 @@ @EqualsAndHashCode public final class PeerExchangeResponse implements NetworkMessage { private final int nonce; - private final Set peers; + private final List peers; - public PeerExchangeResponse(int nonce, Set peers) { + public PeerExchangeResponse(int nonce, List peers) { this.nonce = nonce; this.peers = peers; + // We need to sort deterministically as the data is used in the proof of work check + this.peers.sort(Comparator.comparing((Peer e) -> new ByteArray(e.serialize()))); } @Override @@ -43,12 +47,14 @@ public bisq.network.protobuf.NetworkMessage toProto() { return getNetworkMessageBuilder().setPeerExchangeResponse( bisq.network.protobuf.PeerExchangeResponse.newBuilder() .setNonce(nonce) - .addAllPeers(peers.stream().map(Peer::toProto).collect(Collectors.toSet()))) + .addAllPeers(peers.stream() + .map(Peer::toProto) + .collect(Collectors.toList()))) .build(); } public static PeerExchangeResponse fromProto(bisq.network.protobuf.PeerExchangeResponse proto) { return new PeerExchangeResponse(proto.getNonce(), - proto.getPeersList().stream().map(Peer::fromProto).collect(Collectors.toSet())); + proto.getPeersList().stream().map(Peer::fromProto).collect(Collectors.toList())); } } \ No newline at end of file diff --git a/network/network/src/main/java/bisq/network/p2p/services/peergroup/exchange/PeerExchangeService.java b/network/network/src/main/java/bisq/network/p2p/services/peergroup/exchange/PeerExchangeService.java index 3df2c4dde2..03ac95a031 100644 --- a/network/network/src/main/java/bisq/network/p2p/services/peergroup/exchange/PeerExchangeService.java +++ b/network/network/src/main/java/bisq/network/p2p/services/peergroup/exchange/PeerExchangeService.java @@ -29,9 +29,7 @@ import lombok.Getter; import lombok.extern.slf4j.Slf4j; -import java.util.Map; -import java.util.Optional; -import java.util.Set; +import java.util.*; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.TimeUnit; @@ -181,8 +179,8 @@ public void onMessage(NetworkMessage networkMessage, Connection connection, Stri PeerExchangeRequest request = (PeerExchangeRequest) networkMessage; //log.debug("Node {} received PeerExchangeRequest with myPeers {}", node, request.peers()); Address peerAddress = connection.getPeerAddress(); - peerExchangeStrategy.addReportedPeers(request.getPeers(), peerAddress); - Set myPeers = peerExchangeStrategy.getPeers(peerAddress); + peerExchangeStrategy.addReportedPeers(new HashSet<>(request.getPeers()), peerAddress); + List myPeers = new ArrayList<>(peerExchangeStrategy.getPeers(peerAddress)); NETWORK_IO_POOL.submit(() -> node.send(new PeerExchangeResponse(request.getNonce(), myPeers), connection)); log.debug("Node {} sent PeerExchangeResponse with my myPeers {}", node, myPeers); } diff --git a/restApi/src/main/java/bisq/restApi/dto/PublicDiscussionChannelDto.java b/restApi/src/main/java/bisq/restApi/dto/PublicDiscussionChannelDto.java index 14bae019b2..851f8b7948 100644 --- a/restApi/src/main/java/bisq/restApi/dto/PublicDiscussionChannelDto.java +++ b/restApi/src/main/java/bisq/restApi/dto/PublicDiscussionChannelDto.java @@ -6,7 +6,7 @@ import lombok.Getter; import lombok.ToString; -import java.util.Set; +import java.util.List; @EqualsAndHashCode(onlyExplicitlyIncluded = true) @@ -19,7 +19,7 @@ public final class PublicDiscussionChannelDto { private String channelName; private String description; private String channelAdminId; - private Set channelModeratorIds; + private List channelModeratorIds; public static PublicDiscussionChannelDto from(PublicDiscussionChannel publicDiscussionChannel) { PublicDiscussionChannelDto dto = new PublicDiscussionChannelDto(); diff --git a/support/src/main/java/bisq/support/MediationRequest.java b/support/src/main/java/bisq/support/MediationRequest.java index d3c6825e4c..0fe2938f27 100644 --- a/support/src/main/java/bisq/support/MediationRequest.java +++ b/support/src/main/java/bisq/support/MediationRequest.java @@ -18,6 +18,7 @@ package bisq.support; import bisq.chat.trade.priv.PrivateTradeChatMessage; +import bisq.common.data.ByteArray; import bisq.common.proto.ProtoResolver; import bisq.common.proto.UnresolvableProtobufMessageException; import bisq.network.p2p.services.data.storage.MetaData; @@ -30,7 +31,8 @@ import lombok.Getter; import lombok.ToString; -import java.util.Set; +import java.util.Comparator; +import java.util.List; import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; @@ -43,12 +45,15 @@ public final class MediationRequest implements MailboxMessage { MediationRequest.class.getSimpleName()); private final UserProfile requester; private final UserProfile peer; - private final Set chatMessages; + private final List chatMessages; - public MediationRequest(Set chatMessages, UserProfile requester, UserProfile peer) { + public MediationRequest(List chatMessages, UserProfile requester, UserProfile peer) { this.chatMessages = chatMessages; this.requester = requester; this.peer = peer; + + // We need to sort deterministically as the data is used in the proof of work check + this.chatMessages.sort(Comparator.comparing((PrivateTradeChatMessage e) -> new ByteArray(e.serialize()))); } @Override @@ -72,7 +77,7 @@ private bisq.support.protobuf.MediationRequest toMediationRequestProto() { public static MediationRequest fromProto(bisq.support.protobuf.MediationRequest proto) { return new MediationRequest(proto.getChatMessagesList().stream() .map(PrivateTradeChatMessage::fromProto) - .collect(Collectors.toSet()), + .collect(Collectors.toList()), UserProfile.fromProto(proto.getRequester()), UserProfile.fromProto(proto.getPeer())); } diff --git a/support/src/main/java/bisq/support/MediationService.java b/support/src/main/java/bisq/support/MediationService.java index 67d44da899..ba716284eb 100644 --- a/support/src/main/java/bisq/support/MediationService.java +++ b/support/src/main/java/bisq/support/MediationService.java @@ -40,7 +40,6 @@ import java.math.BigInteger; import java.nio.charset.StandardCharsets; import java.util.ArrayList; -import java.util.HashSet; import java.util.Optional; import java.util.Set; import java.util.concurrent.CompletableFuture; @@ -124,7 +123,7 @@ public void onMessage(NetworkMessage networkMessage) { public void requestMediation(UserIdentity myProfile, UserProfile peer, UserProfile mediator) { PrivateTradeChannel channel = (PrivateTradeChannel) tradeChannelSelectionService.getSelectedChannel().get(); - MediationRequest networkMessage = new MediationRequest(new HashSet<>(channel.getChatMessages()), + MediationRequest networkMessage = new MediationRequest(new ArrayList<>(channel.getChatMessages()), myProfile.getUserProfile(), peer); networkService.confidentialSend(networkMessage, mediator.getNetworkId(), myProfile.getNodeIdAndKeyPair());