From 64a3f1c00b0dac8f9db4d585bfa53f93f64a98cf Mon Sep 17 00:00:00 2001 From: Craig Raw Date: Mon, 2 Dec 2024 10:07:55 +0200 Subject: [PATCH] ensure consistent xpub ordering when copying output descriptors without child derivations --- .../sparrowwallet/drongo/OutputDescriptor.java | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/sparrowwallet/drongo/OutputDescriptor.java b/src/main/java/com/sparrowwallet/drongo/OutputDescriptor.java index 292f878..9fd068a 100644 --- a/src/main/java/com/sparrowwallet/drongo/OutputDescriptor.java +++ b/src/main/java/com/sparrowwallet/drongo/OutputDescriptor.java @@ -15,6 +15,7 @@ import java.math.BigInteger; import java.util.*; import java.util.regex.Matcher; import java.util.regex.Pattern; +import java.util.stream.Collectors; import static com.sparrowwallet.drongo.KeyDerivation.parsePath; @@ -681,7 +682,19 @@ public class OutputDescriptor { } public OutputDescriptor copy(boolean includeChildDerivations) { - return new OutputDescriptor(scriptType, multisigThreshold, extendedPublicKeys, - includeChildDerivations ? mapChildrenDerivations : Collections.emptyMap(), mapExtendedPublicKeyLabels, extendedMasterPrivateKeys); + Map copyExtendedPublicKeys = new LinkedHashMap<>(extendedPublicKeys); + Map copyChildDerivations = new LinkedHashMap<>(mapChildrenDerivations); + Map copyExtendedPublicKeyLabels = new LinkedHashMap<>(mapExtendedPublicKeyLabels); + Map copyExtendedMasterPrivateKeys = new LinkedHashMap<>(extendedMasterPrivateKeys); + + if(!includeChildDerivations) { + //Ensure consistent xpub order by sorting on the first receive address + Map childDerivations = copyExtendedPublicKeys.entrySet().stream().collect(Collectors.toMap(Map.Entry::getKey, _ -> "/0/0")); + OutputDescriptor copyFirstReceive = new OutputDescriptor(scriptType, multisigThreshold, copyExtendedPublicKeys, childDerivations); + OutputDescriptor copySortedXpubs = OutputDescriptor.getOutputDescriptor(copyFirstReceive.toString()); + return new OutputDescriptor(scriptType, multisigThreshold, copySortedXpubs.extendedPublicKeys, Collections.emptyMap(), copyExtendedPublicKeyLabels, copyExtendedMasterPrivateKeys); + } + + return new OutputDescriptor(scriptType, multisigThreshold, copyExtendedPublicKeys, copyChildDerivations, copyExtendedPublicKeyLabels, copyExtendedMasterPrivateKeys); } }