From cda9954c27fcc94db52ab5581b627e0c2a285c9b Mon Sep 17 00:00:00 2001 From: HenrikJannsen Date: Wed, 21 Dec 2022 12:31:41 -0500 Subject: [PATCH] Add deterministic sorting to Inventory as proof of work check compares byte arrays of payload and could fail otherwise --- .../main/java/bisq/common/data/ByteArray.java | 8 +++++++- .../p2p/services/data/inventory/Inventory.java | 18 ++++++++++++------ .../services/data/storage/StorageService.java | 4 ++-- 3 files changed, 21 insertions(+), 9 deletions(-) diff --git a/common/src/main/java/bisq/common/data/ByteArray.java b/common/src/main/java/bisq/common/data/ByteArray.java index c515704e4b..e43443146e 100644 --- a/common/src/main/java/bisq/common/data/ByteArray.java +++ b/common/src/main/java/bisq/common/data/ByteArray.java @@ -22,10 +22,11 @@ import com.google.protobuf.ByteString; import lombok.Getter; +import java.math.BigInteger; import java.util.Arrays; @Getter -public final class ByteArray implements Proto { +public final class ByteArray implements Proto, Comparable { private final byte[] bytes; public ByteArray(byte[] bytes) { @@ -57,4 +58,9 @@ public int hashCode() { public String toString() { return Hex.encode(bytes); } + + @Override + public int compareTo(ByteArray o) { + return new BigInteger(this.getBytes()).compareTo(new BigInteger(o.getBytes())); + } } 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 0ed08e186f..33a2407cef 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 @@ -17,6 +17,7 @@ package bisq.network.p2p.services.data.inventory; +import bisq.common.data.ByteArray; import bisq.common.proto.Proto; import bisq.network.p2p.services.data.DataRequest; import lombok.EqualsAndHashCode; @@ -24,8 +25,10 @@ import lombok.ToString; import lombok.extern.slf4j.Slf4j; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Comparator; import java.util.List; -import java.util.Set; import java.util.stream.Collectors; @Getter @@ -33,12 +36,15 @@ @EqualsAndHashCode @Slf4j public final class Inventory implements Proto { - private final Set entries; + private final List entries; private final int numDropped; - public Inventory(Set entries, int numDropped) { - this.entries = entries; + public Inventory(Collection entries, int numDropped) { + this.entries = new ArrayList<>(entries); 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()))); } public bisq.network.protobuf.Inventory toProto() { @@ -50,9 +56,9 @@ public bisq.network.protobuf.Inventory toProto() { public static Inventory fromProto(bisq.network.protobuf.Inventory proto) { List entriesList = proto.getEntriesList(); - Set entries = entriesList.stream() + List entries = entriesList.stream() .map(DataRequest::fromProto) - .collect(Collectors.toSet()); + .collect(Collectors.toList()); return new Inventory(entries, proto.getNumDropped()); } } diff --git a/network/network/src/main/java/bisq/network/p2p/services/data/storage/StorageService.java b/network/network/src/main/java/bisq/network/p2p/services/data/storage/StorageService.java index 7f46bccc39..9613bc0dfb 100644 --- a/network/network/src/main/java/bisq/network/p2p/services/data/storage/StorageService.java +++ b/network/network/src/main/java/bisq/network/p2p/services/data/storage/StorageService.java @@ -312,10 +312,10 @@ public Inventory getInventoryFromStore(DataFilter dataFilter, DataStorageService private Inventory getInventory(DataFilter dataFilter, Set> entrySet) { - HashSet result = entrySet.stream() + Set result = entrySet.stream() .filter(mapEntry -> !dataFilter.getFilterEntries().contains(getFilterEntry(mapEntry))) .map(Map.Entry::getValue) - .collect(Collectors.toCollection(HashSet::new)); + .collect(Collectors.toSet()); return new Inventory(result, entrySet.size() - result.size()); }