diff --git a/core/src/main/java/org/bitcoinj/core/Address.java b/core/src/main/java/org/bitcoinj/core/Address.java index 9437a0419..db6342fe2 100644 --- a/core/src/main/java/org/bitcoinj/core/Address.java +++ b/core/src/main/java/org/bitcoinj/core/Address.java @@ -31,7 +31,7 @@ import org.bitcoinj.script.Script.ScriptType; * form. *
*/ -public abstract class Address extends PrefixedChecksummedBytes { +public abstract class Address extends PrefixedChecksummedBytes implements Comparable { public Address(NetworkParameters params, byte[] bytes) { super(params, bytes); } @@ -101,4 +101,44 @@ public abstract class Address extends PrefixedChecksummedBytes { * @return type of output script */ public abstract ScriptType getOutputScriptType(); + + /** + * Comparison field order for addresses is: + *+ * Implementations may use {@code compareAddressPartial} for tests 1 and 2. + * + * @param o other {@code Address} object + * @return comparison result + */ + @Override + abstract public int compareTo(Address o); + + /** + * Comparator for the first two comparison fields in {@code Address} comparisons, see {@link Address#compareTo(Address)}. + * Used by {@link LegacyAddress#compareTo(Address)} and {@link SegwitAddress#compareTo(Address)}. + * + * @param o other {@code Address} object + * @return comparison result + */ + protected int compareAddressPartial(Address o) { + // First compare netParams + int result = this.params.getId().compareTo(o.params.getId()); + if (result != 0) return result; + + // Then compare Legacy vs Segwit + if (this instanceof LegacyAddress && o instanceof SegwitAddress) { + return -1; // Legacy addresses (starting with 1 or 3) come before Segwit addresses. + } else if (this instanceof SegwitAddress && o instanceof LegacyAddress) { + return 1; + } else { + // If both are the same type, then compareTo for that type will finish the comparison + return 0; + } + } } diff --git a/core/src/main/java/org/bitcoinj/core/LegacyAddress.java b/core/src/main/java/org/bitcoinj/core/LegacyAddress.java index cf4049e01..9b6180652 100644 --- a/core/src/main/java/org/bitcoinj/core/LegacyAddress.java +++ b/core/src/main/java/org/bitcoinj/core/LegacyAddress.java @@ -23,6 +23,7 @@ import java.util.Objects; import javax.annotation.Nullable; +import com.google.common.primitives.UnsignedBytes; import org.bitcoinj.params.Networks; import org.bitcoinj.script.Script.ScriptType; @@ -213,4 +214,20 @@ public class LegacyAddress extends Address { public LegacyAddress clone() throws CloneNotSupportedException { return (LegacyAddress) super.clone(); } + + /** + * {@inheritDoc} + * + * @param o other {@code Address} object + * @return comparison result + */ + @Override + public int compareTo(Address o) { + int result = compareAddressPartial(o); + if (result != 0) return result; + + // Compare version byte and finally the {@code bytes} field itself + result = Integer.compare(getVersion(), ((LegacyAddress) o).getVersion()); + return result != 0 ? result : UnsignedBytes.lexicographicalComparator().compare(this.bytes, o.bytes); + } } diff --git a/core/src/main/java/org/bitcoinj/core/PrefixedChecksummedBytes.java b/core/src/main/java/org/bitcoinj/core/PrefixedChecksummedBytes.java index 2bc7eaece..67e191c4c 100644 --- a/core/src/main/java/org/bitcoinj/core/PrefixedChecksummedBytes.java +++ b/core/src/main/java/org/bitcoinj/core/PrefixedChecksummedBytes.java @@ -25,7 +25,6 @@ import java.lang.reflect.Field; import java.util.Arrays; import java.util.Objects; -import com.google.common.primitives.UnsignedBytes; import static com.google.common.base.Preconditions.checkNotNull; /** @@ -41,7 +40,7 @@ import static com.google.common.base.Preconditions.checkNotNull; * keys exported using Bitcoin Core's dumpprivkey command. *
*/ -public abstract class PrefixedChecksummedBytes implements Serializable, Cloneable, Comparable