diff --git a/src/main/java/com/sparrowwallet/drongo/address/Address.java b/src/main/java/com/sparrowwallet/drongo/address/Address.java index 0a6d5f6..6117b08 100644 --- a/src/main/java/com/sparrowwallet/drongo/address/Address.java +++ b/src/main/java/com/sparrowwallet/drongo/address/Address.java @@ -1,7 +1,7 @@ package com.sparrowwallet.drongo.address; import com.sparrowwallet.drongo.protocol.Base58; -import com.sparrowwallet.drongo.protocol.Script; +import com.sparrowwallet.drongo.protocol.ScriptType; public abstract class Address { protected final byte[] hash; @@ -24,7 +24,7 @@ public abstract class Address { public abstract int getVersion(); - public abstract Script getOutputScript(); + public abstract ScriptType getScriptType(); public abstract byte[] getOutputScriptData(); @@ -42,9 +42,4 @@ public abstract class Address { public int hashCode() { return getAddress().hashCode(); } - - public String getScriptType() { - String className = this.getClass().getSimpleName(); - return className.replace("Address", ""); - } } diff --git a/src/main/java/com/sparrowwallet/drongo/address/P2PKAddress.java b/src/main/java/com/sparrowwallet/drongo/address/P2PKAddress.java index 3033f09..c68f67c 100644 --- a/src/main/java/com/sparrowwallet/drongo/address/P2PKAddress.java +++ b/src/main/java/com/sparrowwallet/drongo/address/P2PKAddress.java @@ -1,9 +1,7 @@ package com.sparrowwallet.drongo.address; import com.sparrowwallet.drongo.Utils; -import com.sparrowwallet.drongo.protocol.Script; -import com.sparrowwallet.drongo.protocol.ScriptChunk; -import com.sparrowwallet.drongo.protocol.ScriptOpCodes; +import com.sparrowwallet.drongo.protocol.ScriptType; import java.util.ArrayList; import java.util.List; @@ -20,12 +18,8 @@ public class P2PKAddress extends Address { return 0; } - public Script getOutputScript() { - List chunks = new ArrayList<>(); - chunks.add(new ScriptChunk(pubKey.length, pubKey)); - chunks.add(new ScriptChunk(ScriptOpCodes.OP_CHECKSIG, null)); - - return new Script(chunks); + public ScriptType getScriptType() { + return ScriptType.P2PK; } @Override diff --git a/src/main/java/com/sparrowwallet/drongo/address/P2PKHAddress.java b/src/main/java/com/sparrowwallet/drongo/address/P2PKHAddress.java index bc5bdea..d18f888 100644 --- a/src/main/java/com/sparrowwallet/drongo/address/P2PKHAddress.java +++ b/src/main/java/com/sparrowwallet/drongo/address/P2PKHAddress.java @@ -1,11 +1,6 @@ package com.sparrowwallet.drongo.address; -import com.sparrowwallet.drongo.protocol.Script; -import com.sparrowwallet.drongo.protocol.ScriptChunk; -import com.sparrowwallet.drongo.protocol.ScriptOpCodes; - -import java.util.ArrayList; -import java.util.List; +import com.sparrowwallet.drongo.protocol.ScriptType; public class P2PKHAddress extends Address { public P2PKHAddress(byte[] pubKeyHash) { @@ -16,15 +11,8 @@ public class P2PKHAddress extends Address { return 0; } - public Script getOutputScript() { - List chunks = new ArrayList<>(); - chunks.add(new ScriptChunk(ScriptOpCodes.OP_DUP, null)); - chunks.add(new ScriptChunk(ScriptOpCodes.OP_HASH160, null)); - chunks.add(new ScriptChunk(hash.length, hash)); - chunks.add(new ScriptChunk(ScriptOpCodes.OP_EQUALVERIFY, null)); - chunks.add(new ScriptChunk(ScriptOpCodes.OP_CHECKSIG, null)); - - return new Script(chunks); + public ScriptType getScriptType() { + return ScriptType.P2PKH; } @Override diff --git a/src/main/java/com/sparrowwallet/drongo/address/P2SHAddress.java b/src/main/java/com/sparrowwallet/drongo/address/P2SHAddress.java index f754820..86ddc68 100644 --- a/src/main/java/com/sparrowwallet/drongo/address/P2SHAddress.java +++ b/src/main/java/com/sparrowwallet/drongo/address/P2SHAddress.java @@ -1,12 +1,7 @@ package com.sparrowwallet.drongo.address; import com.sparrowwallet.drongo.Utils; -import com.sparrowwallet.drongo.protocol.Script; -import com.sparrowwallet.drongo.protocol.ScriptChunk; -import com.sparrowwallet.drongo.protocol.ScriptOpCodes; - -import java.util.ArrayList; -import java.util.List; +import com.sparrowwallet.drongo.protocol.ScriptType; public class P2SHAddress extends Address { public P2SHAddress(byte[] scriptHash) { @@ -17,13 +12,8 @@ public class P2SHAddress extends Address { return 5; } - public Script getOutputScript() { - List chunks = new ArrayList<>(); - chunks.add(new ScriptChunk(ScriptOpCodes.OP_HASH160, null)); - chunks.add(new ScriptChunk(hash.length, hash)); - chunks.add(new ScriptChunk(ScriptOpCodes.OP_EQUAL, null)); - - return new Script(chunks); + public ScriptType getScriptType() { + return ScriptType.P2SH; } @Override diff --git a/src/main/java/com/sparrowwallet/drongo/address/P2WPKHAddress.java b/src/main/java/com/sparrowwallet/drongo/address/P2WPKHAddress.java index 3d92dcd..679dded 100644 --- a/src/main/java/com/sparrowwallet/drongo/address/P2WPKHAddress.java +++ b/src/main/java/com/sparrowwallet/drongo/address/P2WPKHAddress.java @@ -1,11 +1,7 @@ package com.sparrowwallet.drongo.address; import com.sparrowwallet.drongo.protocol.Bech32; -import com.sparrowwallet.drongo.protocol.Script; -import com.sparrowwallet.drongo.protocol.ScriptChunk; - -import java.util.ArrayList; -import java.util.List; +import com.sparrowwallet.drongo.protocol.ScriptType; public class P2WPKHAddress extends Address { public static final String HRP = "bc"; @@ -22,12 +18,8 @@ public class P2WPKHAddress extends Address { return Bech32.encode(HRP, getVersion(), hash); } - public Script getOutputScript() { - List chunks = new ArrayList<>(); - chunks.add(new ScriptChunk(Script.encodeToOpN(getVersion()), null)); - chunks.add(new ScriptChunk(hash.length, hash)); - - return new Script(chunks); + public ScriptType getScriptType() { + return ScriptType.P2WPKH; } @Override diff --git a/src/main/java/com/sparrowwallet/drongo/address/P2WSHAddress.java b/src/main/java/com/sparrowwallet/drongo/address/P2WSHAddress.java index 0c176f6..d23dc07 100644 --- a/src/main/java/com/sparrowwallet/drongo/address/P2WSHAddress.java +++ b/src/main/java/com/sparrowwallet/drongo/address/P2WSHAddress.java @@ -2,9 +2,6 @@ package com.sparrowwallet.drongo.address; import com.sparrowwallet.drongo.protocol.*; -import java.util.ArrayList; -import java.util.List; - import static com.sparrowwallet.drongo.address.P2WPKHAddress.HRP; public class P2WSHAddress extends Address { @@ -20,12 +17,8 @@ public class P2WSHAddress extends Address { return Bech32.encode(HRP, getVersion(), hash); } - public Script getOutputScript() { - List chunks = new ArrayList<>(); - chunks.add(new ScriptChunk(Script.encodeToOpN(getVersion()), null)); - chunks.add(new ScriptChunk(hash.length, hash)); - - return new Script(chunks); + public ScriptType getScriptType() { + return ScriptType.P2WSH; } @Override diff --git a/src/main/java/com/sparrowwallet/drongo/protocol/ScriptPattern.java b/src/main/java/com/sparrowwallet/drongo/protocol/ScriptPattern.java deleted file mode 100644 index 8c688a0..0000000 --- a/src/main/java/com/sparrowwallet/drongo/protocol/ScriptPattern.java +++ /dev/null @@ -1,204 +0,0 @@ -package com.sparrowwallet.drongo.protocol; - -import com.sparrowwallet.drongo.address.Address; -import com.sparrowwallet.drongo.address.P2PKAddress; -import com.sparrowwallet.drongo.crypto.ECKey; - -import java.util.ArrayList; -import java.util.List; - -import static com.sparrowwallet.drongo.protocol.ScriptOpCodes.*; -import static com.sparrowwallet.drongo.protocol.Script.decodeFromOpN; - -public class ScriptPattern { - /** - * Returns true if this script is of the form {@code DUP HASH160 EQUALVERIFY CHECKSIG}, ie, payment to an - * public key like {@code 2102f3b08938a7f8d2609d567aebc4989eeded6e2e880c058fdf092c5da82c3bc5eeac}. - */ - public static boolean isP2PK(Script script) { - List chunks = script.chunks; - if (chunks.size() != 2) - return false; - if (!chunks.get(0).equalsOpCode(0x21) && !chunks.get(0).equalsOpCode(0x41)) - return false; - byte[] chunk2data = chunks.get(0).data; - if (chunk2data == null) - return false; - if (chunk2data.length != 33 && chunk2data.length != 65) - return false; - if (!chunks.get(1).equalsOpCode(OP_CHECKSIG)) - return false; - return true; - } - - /** - * Extract the pubkey from a P2PK scriptPubKey. It's important that the script is in the correct form, so you - * will want to guard calls to this method with {@link #isP2PK(Script)}. - */ - public static ECKey extractPKFromP2PK(Script script) { - return ECKey.fromPublicOnly(script.chunks.get(0).data); - } - - /** - * Returns true if this script is of the form {@code DUP HASH160 EQUALVERIFY CHECKSIG}, ie, payment to an - * address like {@code 1VayNert3x1KzbpzMGt2qdqrAThiRovi8}. This form was originally intended for the case where you wish - * to send somebody money with a written code because their node is offline, but over time has become the standard - * way to make payments due to the short and recognizable base58 form addresses come in. - */ - public static boolean isP2PKH(Script script) { - List chunks = script.chunks; - if (chunks.size() != 5) - return false; - if (!chunks.get(0).equalsOpCode(OP_DUP)) - return false; - if (!chunks.get(1).equalsOpCode(OP_HASH160)) - return false; - byte[] chunk2data = chunks.get(2).data; - if (chunk2data == null) - return false; - if (chunk2data.length != 20) - return false; - if (!chunks.get(3).equalsOpCode(OP_EQUALVERIFY)) - return false; - if (!chunks.get(4).equalsOpCode(OP_CHECKSIG)) - return false; - return true; - } - - /** - * Extract the pubkey hash from a P2PKH scriptPubKey. It's important that the script is in the correct form, so you - * will want to guard calls to this method with {@link #isP2PKH(Script)}. - */ - public static byte[] extractHashFromP2PKH(Script script) { - return script.chunks.get(2).data; - } - - /** - *

- * Whether or not this is a scriptPubKey representing a P2SH output. In such outputs, the logic that - * controls reclamation is not actually in the output at all. Instead there's just a hash, and it's up to the - * spending input to provide a program matching that hash. - *

- *

- * P2SH is described by BIP16. - *

- */ - public static boolean isP2SH(Script script) { - List chunks = script.chunks; - // We check for the effective serialized form because BIP16 defines a P2SH output using an exact byte - // template, not the logical program structure. Thus you can have two programs that look identical when - // printed out but one is a P2SH script and the other isn't! :( - // We explicitly test that the op code used to load the 20 bytes is 0x14 and not something logically - // equivalent like {@code OP_HASH160 OP_PUSHDATA1 0x14 <20 bytes of script hash> OP_EQUAL} - if (chunks.size() != 3) - return false; - if (!chunks.get(0).equalsOpCode(OP_HASH160)) - return false; - ScriptChunk chunk1 = chunks.get(1); - if (chunk1.opcode != 0x14) - return false; - byte[] chunk1data = chunk1.data; - if (chunk1data == null) - return false; - if (chunk1data.length != 20) - return false; - if (!chunks.get(2).equalsOpCode(OP_EQUAL)) - return false; - return true; - } - - /** - * Extract the script hash from a P2SH scriptPubKey. It's important that the script is in the correct form, so you - * will want to guard calls to this method with {@link #isP2SH(Script)}. - */ - public static byte[] extractHashFromP2SH(Script script) { - return script.chunks.get(1).data; - } - - /** - * Returns whether this script matches the format used for multisig outputs: - * {@code [n] [keys...] [m] CHECKMULTISIG} - */ - public static boolean isMultisig(Script script) { - List chunks = script.chunks; - if (chunks.size() < 4) return false; - ScriptChunk chunk = chunks.get(chunks.size() - 1); - // Must end in OP_CHECKMULTISIG[VERIFY]. - if (!chunk.isOpCode()) return false; - if (!(chunk.equalsOpCode(OP_CHECKMULTISIG) || chunk.equalsOpCode(OP_CHECKMULTISIGVERIFY))) return false; - try { - // Second to last chunk must be an OP_N opcode and there should be that many data chunks (keys). - ScriptChunk m = chunks.get(chunks.size() - 2); - if (!m.isOpCode()) return false; - int numKeys = decodeFromOpN(m.opcode); - if (numKeys < 1 || chunks.size() != 3 + numKeys) return false; - for (int i = 1; i < chunks.size() - 2; i++) { - if (chunks.get(i).isOpCode()) return false; - } - // First chunk must be an OP_N opcode too. - if (decodeFromOpN(chunks.get(0).opcode) < 1) return false; - } catch (IllegalStateException e) { - return false; // Not an OP_N opcode. - } - return true; - } - - public static int extractMultisigThreshold(Script script) { - return decodeFromOpN(script.chunks.get(0).opcode); - } - - public static Address[] extractMultisigAddresses(Script script) { - List
addresses = new ArrayList<>(); - - List chunks = script.chunks; - for (int i = 1; i < chunks.size() - 2; i++) { - byte[] pubKey = chunks.get(i).data; - addresses.add(new P2PKAddress(pubKey)); - } - - return addresses.toArray(new Address[addresses.size()]); - } - - /** - * Returns true if this script is of the form {@code OP_0 }. This is a P2WPKH scriptPubKey. - */ - public static boolean isP2WPKH(Script script) { - List chunks = script.chunks; - if (chunks.size() != 2) - return false; - if (!chunks.get(0).equalsOpCode(OP_0)) - return false; - byte[] chunk1data = chunks.get(1).data; - if (chunk1data == null) - return false; - if (chunk1data.length != 20) - return false; - return true; - } - - /** - * Returns true if this script is of the form {@code OP_0 }. This is a P2WSH scriptPubKey. - */ - public static boolean isP2WSH(Script script) { - List chunks = script.chunks; - if (chunks.size() != 2) - return false; - if (!chunks.get(0).equalsOpCode(OP_0)) - return false; - byte[] chunk1data = chunks.get(1).data; - if (chunk1data == null) - return false; - if (chunk1data.length != 32) - return false; - return true; - } - - /** - * Extract the pubkey hash from a P2WPKH or the script hash from a P2WSH scriptPubKey. It's important that the - * script is in the correct form, so you will want to guard calls to this method with - * {@link #isP2WPKH(Script)} or {@link #isP2WSH(Script)}. - */ - public static byte[] extractHashFromP2WH(Script script) { - return script.chunks.get(1).data; - } -}