diff --git a/src/main/java/com/sparrowwallet/hummingbird/fountain/FountainDecoder.java b/src/main/java/com/sparrowwallet/hummingbird/fountain/FountainDecoder.java index 9f01662..302cc6f 100644 --- a/src/main/java/com/sparrowwallet/hummingbird/fountain/FountainDecoder.java +++ b/src/main/java/com/sparrowwallet/hummingbird/fountain/FountainDecoder.java @@ -16,6 +16,7 @@ import static com.sparrowwallet.hummingbird.fountain.FountainUtils.chooseFragmen public class FountainDecoder { private final Set recievedPartIndexes = new TreeSet<>(); private Set lastPartIndexes; + private final Set processedPartHashes = new HashSet<>(); private int processedPartsCount = 0; private Result result; private long checksum; @@ -114,8 +115,10 @@ public class FountainDecoder { processQueueItem(); } - // Keep track of how many parts we've processed - processedPartsCount += 1; + // Keep track of how many unique parts we've processed + if(processedPartHashes.add(encoderPart.hashCode())) { + processedPartsCount++; + } //printPartEnd(); return true; diff --git a/src/main/java/com/sparrowwallet/hummingbird/fountain/FountainEncoder.java b/src/main/java/com/sparrowwallet/hummingbird/fountain/FountainEncoder.java index d1faad4..0963da7 100644 --- a/src/main/java/com/sparrowwallet/hummingbird/fountain/FountainEncoder.java +++ b/src/main/java/com/sparrowwallet/hummingbird/fountain/FountainEncoder.java @@ -181,5 +181,41 @@ public class FountainEncoder { return new Part(seqNum.getValue().longValue(), seqLen.getValue().intValue(), messageLen.getValue().intValue(), checksum.getValue().longValue(), data.getBytes()); } + + @Override + public boolean equals(Object o) { + if(this == o) { + return true; + } + if(o == null || getClass() != o.getClass()) { + return false; + } + + Part part = (Part) o; + + if(seqNum != part.seqNum) { + return false; + } + if(seqLen != part.seqLen) { + return false; + } + if(messageLen != part.messageLen) { + return false; + } + if(checksum != part.checksum) { + return false; + } + return Arrays.equals(data, part.data); + } + + @Override + public int hashCode() { + int result = (int) (seqNum ^ (seqNum >>> 32)); + result = 31 * result + seqLen; + result = 31 * result + messageLen; + result = 31 * result + (int) (checksum ^ (checksum >>> 32)); + result = 31 * result + Arrays.hashCode(data); + return result; + } } } diff --git a/src/test/java/com/sparrowwallet/hummingbird/URTest.java b/src/test/java/com/sparrowwallet/hummingbird/URTest.java index 4cc86bd..e397eea 100644 --- a/src/test/java/com/sparrowwallet/hummingbird/URTest.java +++ b/src/test/java/com/sparrowwallet/hummingbird/URTest.java @@ -216,4 +216,26 @@ public class URTest { Assert.assertEquals(TestUtils.bytesToHex(ur.toBytes()), "70736274ff0100520200000001adb4134883273f90371c364743e1816de7099df3895dbc95ebcd19beb83200ec0000000000ffffffff01e80300000000000016001457766b7686ca60e5221119966bdfe1d1f4b62181000000000001011f581b0000000000001600145da1bc9a730b7e9d209f15aff9c096f6bbd89d26220603ccd4532b1350e04cbaff91056bdb08bd3877b4fcb8cd70aaeda5239ce112547b180000000054000080000000800000008000000000060000000000"); Arrays.stream(fragments).forEach(part -> Assert.assertTrue(LegacyURDecoder.isLegacyURFragment(part))); } + + @Test + public void testDuplicateDecode() { + String[] parts = new String[] { + "ur:bytes/1-9/lpadascfadaxcywenbpljkhdcahkadaemejtswhhylkepmykhhtsytsnoyoyaxaedsuttydmmhhpktpmsrjtdkgslpgh", + "ur:bytes/2-9/lpaoascfadaxcywenbpljkhdcagwdpfnsboxgwlbaawzuefywkdplrsrjynbvygabwjldapfcsgmghhkhstlrdcxaefz", + "ur:bytes/3-9/lpaxascfadaxcywenbpljkhdcahelbknlkuejnbadmssfhfrdpsbiegecpasvssovlgeykssjykklronvsjksopdzmol" + }; + + URDecoder urDecoder = new URDecoder(); + Assert.assertEquals(0, urDecoder.getProcessedPartsCount()); + urDecoder.receivePart(parts[0]); + Assert.assertEquals(1, urDecoder.getProcessedPartsCount()); + urDecoder.receivePart(parts[0]); + Assert.assertEquals(1, urDecoder.getProcessedPartsCount()); + urDecoder.receivePart(parts[1]); + Assert.assertEquals(2, urDecoder.getProcessedPartsCount()); + urDecoder.receivePart(parts[0]); + Assert.assertEquals(2, urDecoder.getProcessedPartsCount()); + urDecoder.receivePart(parts[2]); + Assert.assertEquals(3, urDecoder.getProcessedPartsCount()); + } }