diff --git a/src/main/java/com/sparrowwallet/drongo/OutputDescriptor.java b/src/main/java/com/sparrowwallet/drongo/OutputDescriptor.java index 6698930..4c02f5f 100644 --- a/src/main/java/com/sparrowwallet/drongo/OutputDescriptor.java +++ b/src/main/java/com/sparrowwallet/drongo/OutputDescriptor.java @@ -33,11 +33,16 @@ public class OutputDescriptor { private final int multisigThreshold; private final Map extendedPublicKeys; private final Map mapChildrenDerivations; + private final Map mapExtendedPublicKeyLabels; public OutputDescriptor(ScriptType scriptType, ExtendedKey extendedPublicKey, KeyDerivation keyDerivation) { this(scriptType, Collections.singletonMap(extendedPublicKey, keyDerivation)); } + public OutputDescriptor(ScriptType scriptType, ExtendedKey extendedPublicKey, KeyDerivation keyDerivation, String extendedPublicKeyLabel) { + this(scriptType, 0, Collections.singletonMap(extendedPublicKey, keyDerivation), new LinkedHashMap<>(), extendedPublicKeyLabel == null ? new LinkedHashMap<>() : Collections.singletonMap(extendedPublicKey, extendedPublicKeyLabel)); + } + public OutputDescriptor(ScriptType scriptType, Map extendedPublicKeys) { this(scriptType, 0, extendedPublicKeys); } @@ -47,10 +52,15 @@ public class OutputDescriptor { } public OutputDescriptor(ScriptType scriptType, int multisigThreshold, Map extendedPublicKeys, Map mapChildrenDerivations) { + this(scriptType, multisigThreshold, extendedPublicKeys, mapChildrenDerivations, new LinkedHashMap<>()); + } + + public OutputDescriptor(ScriptType scriptType, int multisigThreshold, Map extendedPublicKeys, Map mapChildrenDerivations, Map mapExtendedPublicKeyLabels) { this.scriptType = scriptType; this.multisigThreshold = multisigThreshold; this.extendedPublicKeys = extendedPublicKeys; this.mapChildrenDerivations = mapChildrenDerivations; + this.mapExtendedPublicKeyLabels = mapExtendedPublicKeyLabels; } public Set getExtendedPublicKeys() { @@ -69,6 +79,10 @@ public class OutputDescriptor { return mapChildrenDerivations.get(extendedPublicKey); } + public String getExtendedPublicKeyLabel(ExtendedKey extendedPublicKey) { + return mapExtendedPublicKeyLabels.get(extendedPublicKey); + } + public boolean describesMultipleAddresses(ExtendedKey extendedPublicKey) { return getChildDerivationPath(extendedPublicKey) == null || getChildDerivationPath(extendedPublicKey).endsWith("/*"); } @@ -246,6 +260,7 @@ public class OutputDescriptor { keystore.setWalletModel(WalletModel.SPARROW); keystore.setKeyDerivation(extKeyEntry.getValue()); keystore.setExtendedPublicKey(extKeyEntry.getKey()); + setKeystoreLabel(keystore); wallet.makeLabelsUnique(keystore); wallet.getKeystores().add(keystore); } @@ -269,12 +284,23 @@ public class OutputDescriptor { Keystore keystore = new Keystore(); keystore.setKeyDerivation(new KeyDerivation(masterFingerprint, KeyDerivation.writePath(getKeyDerivation(extendedKey).getDerivation()))); keystore.setExtendedPublicKey(extendedKey); + setKeystoreLabel(keystore); wallet.getKeystores().add(keystore); wallet.setDefaultPolicy(Policy.getPolicy(isCosigner() ? PolicyType.MULTI : PolicyType.SINGLE, wallet.getScriptType(), wallet.getKeystores(), 1)); return wallet; } + public void setKeystoreLabel(Keystore keystore) { + if(keystore.getExtendedPublicKey() != null && mapExtendedPublicKeyLabels.get(keystore.getExtendedPublicKey()) != null) { + String label = mapExtendedPublicKeyLabels.get(keystore.getExtendedPublicKey()).trim(); + if(label.length() > Keystore.MAX_LABEL_LENGTH) { + label = label.substring(0, Keystore.MAX_LABEL_LENGTH); + } + keystore.setLabel(label); + } + } + public static String toDescriptorString(Address address) { return "addr(" + address + ")"; } diff --git a/src/test/java/com/sparrowwallet/drongo/OutputDescriptorTest.java b/src/test/java/com/sparrowwallet/drongo/OutputDescriptorTest.java index 8b603ac..6aad892 100644 --- a/src/test/java/com/sparrowwallet/drongo/OutputDescriptorTest.java +++ b/src/test/java/com/sparrowwallet/drongo/OutputDescriptorTest.java @@ -1,9 +1,13 @@ package com.sparrowwallet.drongo; +import com.sparrowwallet.drongo.protocol.ScriptType; +import com.sparrowwallet.drongo.wallet.Wallet; import org.junit.Assert; import org.junit.Test; import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.Map; import java.util.Set; public class OutputDescriptorTest { @@ -107,4 +111,27 @@ public class OutputDescriptorTest { public void testPubKeyMulti() { OutputDescriptor descriptor = OutputDescriptor.getOutputDescriptor("sh(multi(2,022f01e5e15cca351daff3843fb70f3c2f0a1bdd05e5af888a67784ef3e10a2a01,03acd484e2f0c7f65309ad178a9f559abde09796974c57e714c35f110dfc27ccbe))"); } + + @Test + public void testUniqueLabels() { + Map extendedKeys = new LinkedHashMap<>(); + Map extendedKeyLabels = new LinkedHashMap<>(); + + ExtendedKey ext1 = ExtendedKey.fromDescriptor("xpub661MyMwAqRbcFW31YEwpkMuc5THy2PSt5bDMsktWQcFF8syAmRUapSCGu8ED9W6oDMSgv6Zz8idoc4a6mr8BDzTJY47LJhkJ8UB7WEGuduB"); + KeyDerivation kd1 = new KeyDerivation("04fefef0", "m/48'/0'/0'/2'"); + extendedKeys.put(ext1, kd1); + extendedKeyLabels.put(ext1, "Unique"); + + ExtendedKey ext2 = ExtendedKey.fromDescriptor("xpub69H7F5d8KSRgmmdJg2KhpAK8SR3DjMwAdkxj3ZuxV27CprR9LgpeyGmXUbC6wb7ERfvrnKZjXoUmmDznezpbZb7ap6r1D3tgFxHmwMkQTPH"); + KeyDerivation kd2 = new KeyDerivation("04ba1ef0", "m/48'/0'/0'/2'"); + extendedKeys.put(ext2, kd2); + extendedKeyLabels.put(ext2, "Unique"); + + OutputDescriptor descriptor = new OutputDescriptor(ScriptType.P2WSH, 2, extendedKeys, new LinkedHashMap<>(), extendedKeyLabels); + Assert.assertEquals("wsh(sortedmulti(2,[04fefef0/48h/0h/0h/2h]xpub661MyMwAqRbcFW31YEwpkMuc5THy2PSt5bDMsktWQcFF8syAmRUapSCGu8ED9W6oDMSgv6Zz8idoc4a6mr8BDzTJY47LJhkJ8UB7WEGuduB,[04ba1ef0/48h/0h/0h/2h]xpub69H7F5d8KSRgmmdJg2KhpAK8SR3DjMwAdkxj3ZuxV27CprR9LgpeyGmXUbC6wb7ERfvrnKZjXoUmmDznezpbZb7ap6r1D3tgFxHmwMkQTPH))", descriptor.toString()); + + Wallet wallet = descriptor.toWallet(); + Assert.assertEquals("Unique 1", wallet.getKeystores().get(0).getLabel()); + Assert.assertEquals("Unique 2", wallet.getKeystores().get(1).getLabel()); + } }