mirror of
https://github.com/sparrowwallet/drongo.git
synced 2024-12-27 02:26:44 +00:00
support better script descriptors in wallet policy
This commit is contained in:
parent
10ebfe463d
commit
3115669c46
3 changed files with 112 additions and 14 deletions
|
@ -37,19 +37,19 @@ public class Policy {
|
||||||
|
|
||||||
public static Policy getPolicy(PolicyType policyType, ScriptType scriptType, List<Keystore> keystores, Integer threshold) {
|
public static Policy getPolicy(PolicyType policyType, ScriptType scriptType, List<Keystore> keystores, Integer threshold) {
|
||||||
if(SINGLE.equals(policyType)) {
|
if(SINGLE.equals(policyType)) {
|
||||||
if(P2PK.equals(scriptType)) {
|
return new Policy(new Miniscript(scriptType.getDescriptor() + keystores.get(0).getScriptName() + scriptType.getCloseDescriptor()));
|
||||||
return new Policy(new Miniscript("pk(" + keystores.get(0).getScriptName() + ")"));
|
|
||||||
}
|
|
||||||
return new Policy(new Miniscript("pkh(" + keystores.get(0).getScriptName() + ")"));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if(MULTI.equals(policyType)) {
|
if(MULTI.equals(policyType)) {
|
||||||
StringBuilder builder = new StringBuilder("multi(");
|
StringBuilder builder = new StringBuilder();
|
||||||
|
builder.append(scriptType.getDescriptor());
|
||||||
|
builder.append(MULTISIG.getDescriptor());
|
||||||
builder.append(threshold);
|
builder.append(threshold);
|
||||||
for(Keystore keystore : keystores) {
|
for(Keystore keystore : keystores) {
|
||||||
builder.append(",").append(keystore.getScriptName());
|
builder.append(",").append(keystore.getScriptName());
|
||||||
}
|
}
|
||||||
builder.append(")");
|
builder.append(MULTISIG.getCloseDescriptor());
|
||||||
|
builder.append(scriptType.getCloseDescriptor());
|
||||||
return new Policy(new Miniscript(builder.toString()));
|
return new Policy(new Miniscript(builder.toString()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -58,7 +58,7 @@ public enum ScriptType {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getOutputDescriptor(ECKey key) {
|
public String getOutputDescriptor(ECKey key) {
|
||||||
return "pk(" + Utils.bytesToHex(key.getPubKey()) + ")";
|
return getDescriptor() + Utils.bytesToHex(key.getPubKey()) + getCloseDescriptor();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -66,6 +66,11 @@ public enum ScriptType {
|
||||||
throw new ProtocolException("No script derived output descriptor for non pay to script type");
|
throw new ProtocolException("No script derived output descriptor for non pay to script type");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getDescriptor() {
|
||||||
|
return "pk(";
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isScriptType(Script script) {
|
public boolean isScriptType(Script script) {
|
||||||
List<ScriptChunk> chunks = script.chunks;
|
List<ScriptChunk> chunks = script.chunks;
|
||||||
|
@ -165,7 +170,7 @@ public enum ScriptType {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getOutputDescriptor(ECKey key) {
|
public String getOutputDescriptor(ECKey key) {
|
||||||
return "pkh(" + Utils.bytesToHex(key.getPubKey()) + ")";
|
return getDescriptor() + Utils.bytesToHex(key.getPubKey()) + getCloseDescriptor();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -173,6 +178,11 @@ public enum ScriptType {
|
||||||
throw new ProtocolException("No script derived output descriptor for non pay to script type");
|
throw new ProtocolException("No script derived output descriptor for non pay to script type");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getDescriptor() {
|
||||||
|
return "pkh(";
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isScriptType(Script script) {
|
public boolean isScriptType(Script script) {
|
||||||
List<ScriptChunk> chunks = script.chunks;
|
List<ScriptChunk> chunks = script.chunks;
|
||||||
|
@ -320,7 +330,12 @@ public enum ScriptType {
|
||||||
joiner.add(Utils.bytesToHex(pubKey));
|
joiner.add(Utils.bytesToHex(pubKey));
|
||||||
}
|
}
|
||||||
|
|
||||||
return "multi(" + threshold + "," + joiner.toString() + ")";
|
return getDescriptor() + threshold + "," + joiner.toString() + getCloseDescriptor();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getDescriptor() {
|
||||||
|
return "multi(";
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -461,7 +476,12 @@ public enum ScriptType {
|
||||||
throw new IllegalArgumentException("Can only create output descriptor from multisig script");
|
throw new IllegalArgumentException("Can only create output descriptor from multisig script");
|
||||||
}
|
}
|
||||||
|
|
||||||
return "sh(" + MULTISIG.getOutputDescriptor(script) + ")";
|
return getDescriptor() + MULTISIG.getOutputDescriptor(script) + getCloseDescriptor();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getDescriptor() {
|
||||||
|
return "sh(";
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -577,7 +597,7 @@ public enum ScriptType {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getOutputDescriptor(ECKey key) {
|
public String getOutputDescriptor(ECKey key) {
|
||||||
return "sh(wpkh(" + Utils.bytesToHex(key.getPubKey()) + "))";
|
return getDescriptor() + Utils.bytesToHex(key.getPubKey()) + getCloseDescriptor();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -585,6 +605,11 @@ public enum ScriptType {
|
||||||
throw new ProtocolException("No script derived output descriptor for non pay to script type");
|
throw new ProtocolException("No script derived output descriptor for non pay to script type");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getDescriptor() {
|
||||||
|
return "sh(wpkh(";
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isScriptType(Script script) {
|
public boolean isScriptType(Script script) {
|
||||||
return P2SH.isScriptType(script);
|
return P2SH.isScriptType(script);
|
||||||
|
@ -676,7 +701,12 @@ public enum ScriptType {
|
||||||
throw new IllegalArgumentException("Can only create output descriptor from multisig script");
|
throw new IllegalArgumentException("Can only create output descriptor from multisig script");
|
||||||
}
|
}
|
||||||
|
|
||||||
return "sh(wsh(" + MULTISIG.getOutputDescriptor(script) + "))";
|
return getDescriptor() + MULTISIG.getOutputDescriptor(script) + getCloseDescriptor();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getDescriptor() {
|
||||||
|
return "sh(wsh(";
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -765,7 +795,7 @@ public enum ScriptType {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getOutputDescriptor(ECKey key) {
|
public String getOutputDescriptor(ECKey key) {
|
||||||
return "wpkh(" + Utils.bytesToHex(key.getPubKey()) + ")";
|
return getDescriptor() + Utils.bytesToHex(key.getPubKey()) + getCloseDescriptor();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -773,6 +803,11 @@ public enum ScriptType {
|
||||||
throw new ProtocolException("No script derived output descriptor for non pay to script type");
|
throw new ProtocolException("No script derived output descriptor for non pay to script type");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getDescriptor() {
|
||||||
|
return "wpkh(";
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isScriptType(Script script) {
|
public boolean isScriptType(Script script) {
|
||||||
List<ScriptChunk> chunks = script.chunks;
|
List<ScriptChunk> chunks = script.chunks;
|
||||||
|
@ -874,7 +909,12 @@ public enum ScriptType {
|
||||||
throw new IllegalArgumentException("Can only create output descriptor from multisig script");
|
throw new IllegalArgumentException("Can only create output descriptor from multisig script");
|
||||||
}
|
}
|
||||||
|
|
||||||
return "wsh(" + MULTISIG.getOutputDescriptor(script) + ")";
|
return getDescriptor() + MULTISIG.getOutputDescriptor(script) + getCloseDescriptor();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getDescriptor() {
|
||||||
|
return "wsh(";
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -1003,6 +1043,12 @@ public enum ScriptType {
|
||||||
|
|
||||||
public abstract String getOutputDescriptor(Script script);
|
public abstract String getOutputDescriptor(Script script);
|
||||||
|
|
||||||
|
public abstract String getDescriptor();
|
||||||
|
|
||||||
|
public String getCloseDescriptor() {
|
||||||
|
return getDescriptor().chars().filter(ch -> ch == '(').boxed().map(n -> ")").collect(Collectors.joining());
|
||||||
|
}
|
||||||
|
|
||||||
public abstract boolean isScriptType(Script script);
|
public abstract boolean isScriptType(Script script);
|
||||||
|
|
||||||
public abstract byte[] getHashFromScript(Script script);
|
public abstract byte[] getHashFromScript(Script script);
|
||||||
|
@ -1055,6 +1101,16 @@ public enum ScriptType {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static ScriptType fromDescriptor(String descriptor) {
|
||||||
|
for(ScriptType type : values()) {
|
||||||
|
if(type.getDescriptor().equals(descriptor.toLowerCase())) {
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Determines the dust threshold for the given output for this script type.
|
* Determines the dust threshold for the given output for this script type.
|
||||||
*
|
*
|
||||||
|
|
|
@ -0,0 +1,42 @@
|
||||||
|
package com.sparrowwallet.drongo.wallet;
|
||||||
|
|
||||||
|
import com.sparrowwallet.drongo.policy.Policy;
|
||||||
|
import com.sparrowwallet.drongo.policy.PolicyType;
|
||||||
|
import com.sparrowwallet.drongo.protocol.ScriptType;
|
||||||
|
import org.junit.Assert;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class PolicyTest {
|
||||||
|
@Test
|
||||||
|
public void testMiniscriptParsing() {
|
||||||
|
Keystore keystore1 = new Keystore("Keystore 1");
|
||||||
|
Keystore keystore2 = new Keystore("Keystore 2");
|
||||||
|
Keystore keystore3 = new Keystore("Keystore 3");
|
||||||
|
|
||||||
|
Policy policy = Policy.getPolicy(PolicyType.SINGLE, ScriptType.P2PKH, List.of(keystore1), 1);
|
||||||
|
Assert.assertEquals("pkh(keystore1)", policy.getMiniscript().toString());
|
||||||
|
Assert.assertEquals(1, policy.getNumSignaturesRequired());
|
||||||
|
|
||||||
|
Policy policy2 = Policy.getPolicy(PolicyType.SINGLE, ScriptType.P2SH_P2WPKH, List.of(keystore1), 1);
|
||||||
|
Assert.assertEquals("sh(wpkh(keystore1))", policy2.getMiniscript().toString());
|
||||||
|
Assert.assertEquals(1, policy2.getNumSignaturesRequired());
|
||||||
|
|
||||||
|
Policy policy3 = Policy.getPolicy(PolicyType.SINGLE, ScriptType.P2WPKH, List.of(keystore1), 1);
|
||||||
|
Assert.assertEquals("wpkh(keystore1)", policy3.getMiniscript().toString());
|
||||||
|
Assert.assertEquals(1, policy3.getNumSignaturesRequired());
|
||||||
|
|
||||||
|
Policy policy4 = Policy.getPolicy(PolicyType.MULTI, ScriptType.P2SH, List.of(keystore1, keystore2, keystore3), 2);
|
||||||
|
Assert.assertEquals("sh(multi(2,keystore1,keystore2,keystore3))", policy4.getMiniscript().toString());
|
||||||
|
Assert.assertEquals(2, policy4.getNumSignaturesRequired());
|
||||||
|
|
||||||
|
Policy policy5 = Policy.getPolicy(PolicyType.MULTI, ScriptType.P2SH_P2WSH, List.of(keystore1, keystore2, keystore3), 2);
|
||||||
|
Assert.assertEquals("sh(wsh(multi(2,keystore1,keystore2,keystore3)))", policy5.getMiniscript().toString());
|
||||||
|
Assert.assertEquals(2, policy5.getNumSignaturesRequired());
|
||||||
|
|
||||||
|
Policy policy6 = Policy.getPolicy(PolicyType.MULTI, ScriptType.P2WSH, List.of(keystore1, keystore2, keystore3), 2);
|
||||||
|
Assert.assertEquals("wsh(multi(2,keystore1,keystore2,keystore3))", policy6.getMiniscript().toString());
|
||||||
|
Assert.assertEquals(2, policy6.getNumSignaturesRequired());
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue