From f7908cd6cd5580885e5f3f085184f4aaf612a70c Mon Sep 17 00:00:00 2001 From: HenrikJannsen Date: Wed, 28 Feb 2024 07:52:21 +0700 Subject: [PATCH] Remove Handle and HandleFactory. Use an integer array instead of encoding the data into a long which added limitations and made the code more complicate. --- .../desktop/components/cathash/CatHash.java | 13 +-- .../components/cathash/Configuration.java | 13 +++ .../desktop/components/cathash/Handle.java | 50 ---------- .../components/cathash/HandleFactory.java | 97 ------------------- .../cathash/VariableSizeHashing.java | 13 +++ .../CreateProfileController.java | 4 +- 6 files changed, 32 insertions(+), 158 deletions(-) delete mode 100644 apps/desktop/desktop/src/main/java/bisq/desktop/components/cathash/Handle.java delete mode 100644 apps/desktop/desktop/src/main/java/bisq/desktop/components/cathash/HandleFactory.java diff --git a/apps/desktop/desktop/src/main/java/bisq/desktop/components/cathash/CatHash.java b/apps/desktop/desktop/src/main/java/bisq/desktop/components/cathash/CatHash.java index 41513e253e..f3458bd635 100644 --- a/apps/desktop/desktop/src/main/java/bisq/desktop/components/cathash/CatHash.java +++ b/apps/desktop/desktop/src/main/java/bisq/desktop/components/cathash/CatHash.java @@ -30,7 +30,6 @@ @Slf4j public class CatHash { private static final int MAX_CACHE_SIZE = 10000; - private static final HandleFactory HANDLE_FACTORY = new HandleFactory(); private static final ConcurrentHashMap CACHE = new ConcurrentHashMap<>(); public static Image getImage(byte[] pubKeyHash) { @@ -48,20 +47,16 @@ private static Image getImage(ByteArray pubKeyHash, boolean useCache) { BigInteger bigInteger = new BigInteger(pubKeyHash.getBytes()); Configuration configuration = new Configuration(); VariableSizeHashing hashing = new VariableSizeHashing(configuration.getBucketSizes()); - byte[] data = hashing.createBuckets(bigInteger); - Handle handle = HANDLE_FACTORY.calculateHandle(data); - Image image = imageForHandle(handle, configuration); + int[] integerBuckets = hashing.createIntegerBuckets(bigInteger); + Image image = imageFromIntegerBuckets(integerBuckets, configuration); if (useCache && CACHE.size() < MAX_CACHE_SIZE) { CACHE.put(pubKeyHash, image); } return image; } - private static Image imageForHandle(Handle handle, Configuration configuration) { - long ts = System.currentTimeMillis(); - byte[] bucketValues = handle.bucketValues(); - String[] paths = configuration.convertToFacetParts(bucketValues); - log.debug("Generated paths for CatHash image in {} ms", System.currentTimeMillis() - ts); // typically <1ms + private static Image imageFromIntegerBuckets(int[] integerBuckets, Configuration configuration) { + String[] paths = configuration.integerBucketsToPaths(integerBuckets); return ImageUtil.composeImage(paths, configuration.width(), configuration.height()); } } diff --git a/apps/desktop/desktop/src/main/java/bisq/desktop/components/cathash/Configuration.java b/apps/desktop/desktop/src/main/java/bisq/desktop/components/cathash/Configuration.java index 44b37be2de..10afde8a0c 100644 --- a/apps/desktop/desktop/src/main/java/bisq/desktop/components/cathash/Configuration.java +++ b/apps/desktop/desktop/src/main/java/bisq/desktop/components/cathash/Configuration.java @@ -56,6 +56,19 @@ public class Configuration { }; } + public String[] integerBucketsToPaths(int[] integerBuckets) { + if (integerBuckets.length != BUCKET_COUNT) { + throw new IllegalArgumentException(); + } + + String[] paths = new String[FACET_COUNT]; + for (int facet = 0; facet < FACET_COUNT; facet++) { + int bucketValue = integerBuckets[facet]; + paths[facet] = generatePath(FACET_PATH_TEMPLATES[facet], bucketValue); + } + return paths; + } + public String[] convertToFacetParts(byte[] bucketValues) { if (bucketValues.length != BUCKET_COUNT) { throw new IllegalArgumentException(); diff --git a/apps/desktop/desktop/src/main/java/bisq/desktop/components/cathash/Handle.java b/apps/desktop/desktop/src/main/java/bisq/desktop/components/cathash/Handle.java deleted file mode 100644 index 7c057457b4..0000000000 --- a/apps/desktop/desktop/src/main/java/bisq/desktop/components/cathash/Handle.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * 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.desktop.components.cathash; - -public final class Handle { - private final long value; - - Handle(long v) { - this.value = v; - } - - @Override - protected Object clone() throws CloneNotSupportedException { - return super.clone(); - } - - @Override - public boolean equals(Object o) { - return super.equals(o); - } - - @Override - public String toString() { - return String.format("%016X", value); - } - - @Override - public int hashCode() { - return (int) value; - } - - public byte[] bucketValues() { - return HandleFactory.bucketValues(this.value); - } -} diff --git a/apps/desktop/desktop/src/main/java/bisq/desktop/components/cathash/HandleFactory.java b/apps/desktop/desktop/src/main/java/bisq/desktop/components/cathash/HandleFactory.java deleted file mode 100644 index 456512a006..0000000000 --- a/apps/desktop/desktop/src/main/java/bisq/desktop/components/cathash/HandleFactory.java +++ /dev/null @@ -1,97 +0,0 @@ -/* - * 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.desktop.components.cathash; - -import lombok.extern.slf4j.Slf4j; - -@Slf4j -public class HandleFactory { - - Handle calculateHandle(byte[] data) { - return new Handle(calculateHandleValue(data)); - } - - static byte[] bucketValues(long handle) { - int buckets = getSize(handle); - byte[] values = new byte[buckets]; - for (int i = 0; i < buckets; i++) { - values[buckets - i - 1] = getNibbleAt(handle, i); - } - return values; - } - - /** - * Encodes an array of bytes (data) into a single long value, which serves as a compact, unique identifier - * (or "handle") for a set of values. Each byte in the array represents a "nibble" (a 4-bit value), and the function - * ensures that these values, along with the length of the data, are packed into the returned long. - * - * @param data The distributed hash over the buckets - * @return val The composite handle value, which encodes both the sequence of nibbles and the length of the data array - */ - private static long calculateHandleValue(byte[] data) { - // Check if the input array exceeds the maximum length of 14 bytes. - // This limit ensures that the data can be encoded into a 64-bit long value without overflow. - // Since 8 bits are reserved for length encoding only 56 bits can be used (14 * 4) - // This means that the maximum number of buckets that we can have is 14 - if (data.length > 14) { - throw new IllegalArgumentException(); - } - - long val = 0; - for (int i = 0; i < data.length; i++) { - int nibble = data[i]; - - // Validate that the current nibble does not exceed the maximum value of 15 (0xF), ensuring it's a - // valid 4-bit value. - // Each nibble uses 4 bits, therefore we can only encode 2^4 (0..15) possibilities - // (i.e. max size per bucket is 15, which represent 16 images) - if (nibble > 15) { // 0xf - throw new IllegalArgumentException(String.format("nibble to large @%d: %02X", i, nibble)); - } - - // Shift the current handle value 4 bits to the left to make room for the new nibble. This operation - // progressively builds up the handle value from its constituent nibbles. - val <<= 4; - - // Incorporate the current nibble into the lowest 4 bits of the handle value. - val |= nibble; - } - - // After processing all nibbles, encode the length of the data array into the handle value. - // This is achieved by shifting the length leftward by (14 * 4) bits (56 bits), which positions the length - // information in the upper 8 bits of the 64-bit long value. This ensures the length can be retrieved from the - // handle and also contributes to the uniqueness of the handle. - val |= ((long) data.length) << (14 * 4); - return val; - } - - private static byte getNibbleAt(long value, int index) { - if (index < 0 || index > 15) { - throw new IllegalArgumentException(String.format("index @%d", index)); - } - - long mask = (long) 0xf << (index * 4); - long maskedValue = (value & mask); - - return (byte) (maskedValue >> index * 4); - } - - private static int getSize(long value) { - return getNibbleAt(value, 14); - } -} diff --git a/apps/desktop/desktop/src/main/java/bisq/desktop/components/cathash/VariableSizeHashing.java b/apps/desktop/desktop/src/main/java/bisq/desktop/components/cathash/VariableSizeHashing.java index e117b036b9..77bd03c477 100644 --- a/apps/desktop/desktop/src/main/java/bisq/desktop/components/cathash/VariableSizeHashing.java +++ b/apps/desktop/desktop/src/main/java/bisq/desktop/components/cathash/VariableSizeHashing.java @@ -67,4 +67,17 @@ public byte[] createBuckets(BigInteger hash) { return ret; } + + public int[] createIntegerBuckets(BigInteger input) { + int currentBucket = 0; + int[] result = new int[bucketSizes.length]; + while (currentBucket < bucketSizes.length) { + BigInteger[] divisorReminder = input.divideAndRemainder(BigInteger.valueOf(bucketSizes[currentBucket])); + input = divisorReminder[0]; + long reminder = divisorReminder[1].longValue(); + result[currentBucket] = (int) Math.abs(reminder % bucketSizes[currentBucket]); + currentBucket++; + } + return result; + } } diff --git a/apps/desktop/desktop/src/main/java/bisq/desktop/overlay/onboarding/create_profile/CreateProfileController.java b/apps/desktop/desktop/src/main/java/bisq/desktop/overlay/onboarding/create_profile/CreateProfileController.java index 52cbf02798..2b2267bba2 100644 --- a/apps/desktop/desktop/src/main/java/bisq/desktop/overlay/onboarding/create_profile/CreateProfileController.java +++ b/apps/desktop/desktop/src/main/java/bisq/desktop/overlay/onboarding/create_profile/CreateProfileController.java @@ -22,8 +22,8 @@ import bisq.desktop.common.threading.UIThread; import bisq.desktop.common.view.Controller; import bisq.desktop.common.view.Navigation; -import bisq.desktop.components.overlay.Popup; import bisq.desktop.components.cathash.CatHash; +import bisq.desktop.components.overlay.Popup; import bisq.desktop.overlay.OverlayController; import bisq.i18n.Res; import bisq.identity.IdentityService; @@ -153,7 +153,7 @@ private CompletableFuture createProofOfWork(byte[] pubKeyHash) { .thenApply(proofOfWork -> { long powDuration = System.currentTimeMillis() - ts; log.info("Proof of work creation completed after {} ms", powDuration); - createSimulatedDelay(powDuration); + //createSimulatedDelay(powDuration); UIThread.run(() -> { model.setProofOfWork(Optional.of(proofOfWork)); String nym = NymIdGenerator.fromHash(pubKeyHash);