mirror of
https://github.com/sparrowwallet/drongo.git
synced 2024-12-25 09:36:44 +00:00
add support for named xpubs in output descriptors
This commit is contained in:
parent
8313d16e97
commit
bae4ce6605
2 changed files with 53 additions and 0 deletions
|
@ -33,11 +33,16 @@ public class OutputDescriptor {
|
||||||
private final int multisigThreshold;
|
private final int multisigThreshold;
|
||||||
private final Map<ExtendedKey, KeyDerivation> extendedPublicKeys;
|
private final Map<ExtendedKey, KeyDerivation> extendedPublicKeys;
|
||||||
private final Map<ExtendedKey, String> mapChildrenDerivations;
|
private final Map<ExtendedKey, String> mapChildrenDerivations;
|
||||||
|
private final Map<ExtendedKey, String> mapExtendedPublicKeyLabels;
|
||||||
|
|
||||||
public OutputDescriptor(ScriptType scriptType, ExtendedKey extendedPublicKey, KeyDerivation keyDerivation) {
|
public OutputDescriptor(ScriptType scriptType, ExtendedKey extendedPublicKey, KeyDerivation keyDerivation) {
|
||||||
this(scriptType, Collections.singletonMap(extendedPublicKey, 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<ExtendedKey, KeyDerivation> extendedPublicKeys) {
|
public OutputDescriptor(ScriptType scriptType, Map<ExtendedKey, KeyDerivation> extendedPublicKeys) {
|
||||||
this(scriptType, 0, extendedPublicKeys);
|
this(scriptType, 0, extendedPublicKeys);
|
||||||
}
|
}
|
||||||
|
@ -47,10 +52,15 @@ public class OutputDescriptor {
|
||||||
}
|
}
|
||||||
|
|
||||||
public OutputDescriptor(ScriptType scriptType, int multisigThreshold, Map<ExtendedKey, KeyDerivation> extendedPublicKeys, Map<ExtendedKey, String> mapChildrenDerivations) {
|
public OutputDescriptor(ScriptType scriptType, int multisigThreshold, Map<ExtendedKey, KeyDerivation> extendedPublicKeys, Map<ExtendedKey, String> mapChildrenDerivations) {
|
||||||
|
this(scriptType, multisigThreshold, extendedPublicKeys, mapChildrenDerivations, new LinkedHashMap<>());
|
||||||
|
}
|
||||||
|
|
||||||
|
public OutputDescriptor(ScriptType scriptType, int multisigThreshold, Map<ExtendedKey, KeyDerivation> extendedPublicKeys, Map<ExtendedKey, String> mapChildrenDerivations, Map<ExtendedKey, String> mapExtendedPublicKeyLabels) {
|
||||||
this.scriptType = scriptType;
|
this.scriptType = scriptType;
|
||||||
this.multisigThreshold = multisigThreshold;
|
this.multisigThreshold = multisigThreshold;
|
||||||
this.extendedPublicKeys = extendedPublicKeys;
|
this.extendedPublicKeys = extendedPublicKeys;
|
||||||
this.mapChildrenDerivations = mapChildrenDerivations;
|
this.mapChildrenDerivations = mapChildrenDerivations;
|
||||||
|
this.mapExtendedPublicKeyLabels = mapExtendedPublicKeyLabels;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Set<ExtendedKey> getExtendedPublicKeys() {
|
public Set<ExtendedKey> getExtendedPublicKeys() {
|
||||||
|
@ -69,6 +79,10 @@ public class OutputDescriptor {
|
||||||
return mapChildrenDerivations.get(extendedPublicKey);
|
return mapChildrenDerivations.get(extendedPublicKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getExtendedPublicKeyLabel(ExtendedKey extendedPublicKey) {
|
||||||
|
return mapExtendedPublicKeyLabels.get(extendedPublicKey);
|
||||||
|
}
|
||||||
|
|
||||||
public boolean describesMultipleAddresses(ExtendedKey extendedPublicKey) {
|
public boolean describesMultipleAddresses(ExtendedKey extendedPublicKey) {
|
||||||
return getChildDerivationPath(extendedPublicKey) == null || getChildDerivationPath(extendedPublicKey).endsWith("/*");
|
return getChildDerivationPath(extendedPublicKey) == null || getChildDerivationPath(extendedPublicKey).endsWith("/*");
|
||||||
}
|
}
|
||||||
|
@ -246,6 +260,7 @@ public class OutputDescriptor {
|
||||||
keystore.setWalletModel(WalletModel.SPARROW);
|
keystore.setWalletModel(WalletModel.SPARROW);
|
||||||
keystore.setKeyDerivation(extKeyEntry.getValue());
|
keystore.setKeyDerivation(extKeyEntry.getValue());
|
||||||
keystore.setExtendedPublicKey(extKeyEntry.getKey());
|
keystore.setExtendedPublicKey(extKeyEntry.getKey());
|
||||||
|
setKeystoreLabel(keystore);
|
||||||
wallet.makeLabelsUnique(keystore);
|
wallet.makeLabelsUnique(keystore);
|
||||||
wallet.getKeystores().add(keystore);
|
wallet.getKeystores().add(keystore);
|
||||||
}
|
}
|
||||||
|
@ -269,12 +284,23 @@ public class OutputDescriptor {
|
||||||
Keystore keystore = new Keystore();
|
Keystore keystore = new Keystore();
|
||||||
keystore.setKeyDerivation(new KeyDerivation(masterFingerprint, KeyDerivation.writePath(getKeyDerivation(extendedKey).getDerivation())));
|
keystore.setKeyDerivation(new KeyDerivation(masterFingerprint, KeyDerivation.writePath(getKeyDerivation(extendedKey).getDerivation())));
|
||||||
keystore.setExtendedPublicKey(extendedKey);
|
keystore.setExtendedPublicKey(extendedKey);
|
||||||
|
setKeystoreLabel(keystore);
|
||||||
wallet.getKeystores().add(keystore);
|
wallet.getKeystores().add(keystore);
|
||||||
wallet.setDefaultPolicy(Policy.getPolicy(isCosigner() ? PolicyType.MULTI : PolicyType.SINGLE, wallet.getScriptType(), wallet.getKeystores(), 1));
|
wallet.setDefaultPolicy(Policy.getPolicy(isCosigner() ? PolicyType.MULTI : PolicyType.SINGLE, wallet.getScriptType(), wallet.getKeystores(), 1));
|
||||||
|
|
||||||
return wallet;
|
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) {
|
public static String toDescriptorString(Address address) {
|
||||||
return "addr(" + address + ")";
|
return "addr(" + address + ")";
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,13 @@
|
||||||
package com.sparrowwallet.drongo;
|
package com.sparrowwallet.drongo;
|
||||||
|
|
||||||
|
import com.sparrowwallet.drongo.protocol.ScriptType;
|
||||||
|
import com.sparrowwallet.drongo.wallet.Wallet;
|
||||||
import org.junit.Assert;
|
import org.junit.Assert;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
public class OutputDescriptorTest {
|
public class OutputDescriptorTest {
|
||||||
|
@ -107,4 +111,27 @@ public class OutputDescriptorTest {
|
||||||
public void testPubKeyMulti() {
|
public void testPubKeyMulti() {
|
||||||
OutputDescriptor descriptor = OutputDescriptor.getOutputDescriptor("sh(multi(2,022f01e5e15cca351daff3843fb70f3c2f0a1bdd05e5af888a67784ef3e10a2a01,03acd484e2f0c7f65309ad178a9f559abde09796974c57e714c35f110dfc27ccbe))");
|
OutputDescriptor descriptor = OutputDescriptor.getOutputDescriptor("sh(multi(2,022f01e5e15cca351daff3843fb70f3c2f0a1bdd05e5af888a67784ef3e10a2a01,03acd484e2f0c7f65309ad178a9f559abde09796974c57e714c35f110dfc27ccbe))");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testUniqueLabels() {
|
||||||
|
Map<ExtendedKey, KeyDerivation> extendedKeys = new LinkedHashMap<>();
|
||||||
|
Map<ExtendedKey, String> 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());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue