Script: Deprecate the old matcher methods, move their Javadocs over to ScriptPattern and use only the equivalents in ScriptPattern.

This commit is contained in:
Andreas Schildbach 2018-02-25 22:45:19 +01:00
parent 8d98c3e1e2
commit e44591a9b5
20 changed files with 129 additions and 118 deletions

View File

@ -24,6 +24,7 @@ import java.io.ObjectOutputStream;
import org.bitcoinj.params.Networks;
import org.bitcoinj.script.Script;
import org.bitcoinj.script.ScriptPattern;
import javax.annotation.Nullable;
@ -74,7 +75,7 @@ public class Address extends VersionedChecksummedBytes {
/** Returns an Address that represents the script hash extracted from the given scriptPubKey */
public static Address fromP2SHScript(NetworkParameters params, Script scriptPubKey) {
checkArgument(scriptPubKey.isPayToScriptHash(), "Not a P2SH script");
checkArgument(ScriptPattern.isPayToScriptHash(scriptPubKey), "Not a P2SH script");
return fromP2SHHash(params, scriptPubKey.getPubKeyHash());
}

View File

@ -19,6 +19,8 @@ package org.bitcoinj.core;
import org.bitcoinj.script.Script;
import org.bitcoinj.script.ScriptChunk;
import org.bitcoinj.script.ScriptPattern;
import com.google.common.base.Objects;
import com.google.common.collect.Lists;
@ -330,7 +332,7 @@ public class BloomFilter extends Message {
if (!chunk.isPushData())
continue;
if (contains(chunk.data)) {
boolean isSendingToPubKeys = script.isSentToRawPubKey() || script.isSentToMultiSig();
boolean isSendingToPubKeys = ScriptPattern.isPayToPubKey(script) || ScriptPattern.isSentToMultisig(script);
if (flag == BloomUpdate.UPDATE_ALL || (flag == BloomUpdate.UPDATE_P2PUBKEY_ONLY && isSendingToPubKeys))
insert(output.getOutPointFor().unsafeBitcoinSerialize());
found = true;

View File

@ -19,6 +19,7 @@ package org.bitcoinj.core;
import org.bitcoinj.script.Script;
import org.bitcoinj.script.Script.VerifyFlag;
import org.bitcoinj.script.ScriptPattern;
import org.bitcoinj.store.BlockStoreException;
import org.bitcoinj.store.FullPrunedBlockStore;
import org.bitcoinj.utils.*;
@ -269,7 +270,7 @@ public class FullPrunedBlockChain extends AbstractBlockChain {
// TODO: Check we're not spending the genesis transaction here. Bitcoin Core won't allow it.
valueIn = valueIn.add(prevOut.getValue());
if (verifyFlags.contains(VerifyFlag.P2SH)) {
if (prevOut.getScript().isPayToScriptHash())
if (ScriptPattern.isPayToScriptHash(prevOut.getScript()))
sigOps += Script.getP2SHSigOpCount(in.getScriptBytes());
if (sigOps > Block.MAX_BLOCK_SIGOPS)
throw new VerificationException("Too many P2SH SigOps in block");
@ -397,7 +398,7 @@ public class FullPrunedBlockChain extends AbstractBlockChain {
throw new VerificationException("Tried to spend coinbase at depth " + (newBlock.getHeight() - prevOut.getHeight()));
valueIn = valueIn.add(prevOut.getValue());
if (verifyFlags.contains(VerifyFlag.P2SH)) {
if (prevOut.getScript().isPayToScriptHash())
if (ScriptPattern.isPayToScriptHash(prevOut.getScript()))
sigOps += Script.getP2SHSigOpCount(in.getScriptBytes());
if (sigOps > Block.MAX_BLOCK_SIGOPS)
throw new VerificationException("Too many P2SH SigOps in block");

View File

@ -200,7 +200,7 @@ public class PeerGroup implements TransactionBroadcaster {
// filter. In case (1), we need to retransmit the filter to the connected peers. In case (2), we don't
// and shouldn't, we should just recalculate and cache the new filter for next time.
for (TransactionOutput output : tx.getOutputs()) {
if (output.getScriptPubKey().isSentToRawPubKey() && output.isMine(wallet)) {
if (ScriptPattern.isPayToPubKey(output.getScriptPubKey()) && output.isMine(wallet)) {
if (tx.getConfidence().getConfidenceType() == TransactionConfidence.ConfidenceType.BUILDING)
recalculateFastCatchupAndFilter(FilterRecalculateMode.SEND_IF_CHANGED);
else

View File

@ -24,6 +24,7 @@ import org.bitcoinj.script.ScriptBuilder;
import org.bitcoinj.script.ScriptError;
import org.bitcoinj.script.ScriptException;
import org.bitcoinj.script.ScriptOpCodes;
import org.bitcoinj.script.ScriptPattern;
import org.bitcoinj.signers.TransactionSigner;
import org.bitcoinj.utils.ExchangeRate;
import org.bitcoinj.wallet.Wallet;
@ -704,7 +705,7 @@ public class Transaction extends ChildMessage {
final TransactionOutput connectedOutput = outpoint.getConnectedOutput();
if (connectedOutput != null) {
Script scriptPubKey = connectedOutput.getScriptPubKey();
if (scriptPubKey.isSentToAddress() || scriptPubKey.isPayToScriptHash()) {
if (ScriptPattern.isPayToPubKeyHash(scriptPubKey) || ScriptPattern.isPayToScriptHash(scriptPubKey)) {
s.append(" hash160:");
s.append(Utils.HEX.encode(scriptPubKey.getPubKeyHash()));
}
@ -819,9 +820,9 @@ public class Transaction extends ChildMessage {
Sha256Hash hash = hashForSignature(inputs.size() - 1, scriptPubKey, sigHash, anyoneCanPay);
ECKey.ECDSASignature ecSig = sigKey.sign(hash);
TransactionSignature txSig = new TransactionSignature(ecSig, sigHash, anyoneCanPay);
if (scriptPubKey.isSentToRawPubKey())
if (ScriptPattern.isPayToPubKey(scriptPubKey))
input.setScriptSig(ScriptBuilder.createInputScript(txSig));
else if (scriptPubKey.isSentToAddress())
else if (ScriptPattern.isPayToPubKeyHash(scriptPubKey))
input.setScriptSig(ScriptBuilder.createInputScript(txSig, sigKey));
else
throw new ScriptException(ScriptError.SCRIPT_ERR_UNKNOWN_ERROR, "Don't know how to sign for this kind of scriptPubKey: " + scriptPubKey);

View File

@ -141,10 +141,10 @@ public class TransactionOutPoint extends ChildMessage {
TransactionOutput connectedOutput = getConnectedOutput();
checkNotNull(connectedOutput, "Input is not connected so cannot retrieve key");
Script connectedScript = connectedOutput.getScriptPubKey();
if (connectedScript.isSentToAddress()) {
if (ScriptPattern.isPayToPubKeyHash(connectedScript)) {
byte[] addressBytes = connectedScript.getPubKeyHash();
return keyBag.findKeyFromPubHash(addressBytes);
} else if (connectedScript.isSentToRawPubKey()) {
} else if (ScriptPattern.isPayToPubKey(connectedScript)) {
byte[] pubkeyBytes = connectedScript.getPubKey();
return keyBag.findKeyFromPubKey(pubkeyBytes);
} else {
@ -164,13 +164,13 @@ public class TransactionOutPoint extends ChildMessage {
TransactionOutput connectedOutput = getConnectedOutput();
checkNotNull(connectedOutput, "Input is not connected so cannot retrieve key");
Script connectedScript = connectedOutput.getScriptPubKey();
if (connectedScript.isSentToAddress()) {
if (ScriptPattern.isPayToPubKeyHash(connectedScript)) {
byte[] addressBytes = connectedScript.getPubKeyHash();
return RedeemData.of(keyBag.findKeyFromPubHash(addressBytes), connectedScript);
} else if (connectedScript.isSentToRawPubKey()) {
} else if (ScriptPattern.isPayToPubKey(connectedScript)) {
byte[] pubkeyBytes = connectedScript.getPubKey();
return RedeemData.of(keyBag.findKeyFromPubKey(pubkeyBytes), connectedScript);
} else if (connectedScript.isPayToScriptHash()) {
} else if (ScriptPattern.isPayToScriptHash(connectedScript)) {
byte[] scriptHash = connectedScript.getPubKeyHash();
return keyBag.findRedeemDataFromScriptHash(scriptHash);
} else {

View File

@ -130,7 +130,7 @@ public class TransactionOutput extends ChildMessage {
*/
@Nullable
public Address getAddressFromP2PKHScript(NetworkParameters networkParameters) throws ScriptException{
if (getScriptPubKey().isSentToAddress())
if (ScriptPattern.isPayToPubKeyHash(getScriptPubKey()))
return getScriptPubKey().getToAddress(networkParameters);
return null;
@ -150,7 +150,7 @@ public class TransactionOutput extends ChildMessage {
*/
@Nullable
public Address getAddressFromP2SH(NetworkParameters networkParameters) throws ScriptException{
if (getScriptPubKey().isPayToScriptHash())
if (ScriptPattern.isPayToScriptHash(getScriptPubKey()))
return getScriptPubKey().getToAddress(networkParameters);
return null;
@ -212,7 +212,7 @@ public class TransactionOutput extends ChildMessage {
*/
public boolean isDust() {
// Transactions that are OP_RETURN can't be dust regardless of their value.
if (getScriptPubKey().isOpReturn())
if (ScriptPattern.isOpReturn(getScriptPubKey()))
return false;
return getValue().isLessThan(getMinNonDustValue());
}
@ -321,10 +321,10 @@ public class TransactionOutput extends ChildMessage {
public boolean isMine(TransactionBag transactionBag) {
try {
Script script = getScriptPubKey();
if (script.isSentToRawPubKey()) {
if (ScriptPattern.isPayToPubKey(script)) {
byte[] pubkey = script.getPubKey();
return transactionBag.isPubKeyMine(pubkey);
} if (script.isPayToScriptHash()) {
} if (ScriptPattern.isPayToScriptHash(script)) {
return transactionBag.isPayToScriptHashMine(script.getPubKeyHash());
} else {
byte[] pubkeyHash = script.getPubKeyHash();
@ -346,11 +346,11 @@ public class TransactionOutput extends ChildMessage {
Script script = getScriptPubKey();
StringBuilder buf = new StringBuilder("TxOut of ");
buf.append(Coin.valueOf(value).toFriendlyString());
if (script.isSentToAddress() || script.isPayToScriptHash())
if (ScriptPattern.isPayToPubKeyHash(script) || ScriptPattern.isPayToScriptHash(script))
buf.append(" to ").append(script.getToAddress(params));
else if (script.isSentToRawPubKey())
else if (ScriptPattern.isPayToPubKey(script))
buf.append(" to pubkey ").append(Utils.HEX.encode(script.getPubKey()));
else if (script.isSentToMultiSig())
else if (ScriptPattern.isSentToMultisig(script))
buf.append(" to multisig");
else
buf.append(" (unknown type)");

View File

@ -226,22 +226,12 @@ public class Script {
}
}
/**
* Returns true if this script is of the form <pubkey> OP_CHECKSIG. This form was originally intended for transactions
* where the peers talked to each other directly via TCP/IP, but has fallen out of favor with time due to that mode
* of operation being susceptible to man-in-the-middle attacks. It is still used in coinbase outputs and can be
* useful more exotic types of transaction, but today most payments are to addresses.
*/
@Deprecated
public boolean isSentToRawPubKey() {
return ScriptPattern.isPayToPubKey(this);
}
/**
* Returns true if this script is of the form DUP HASH160 <pubkey hash> EQUALVERIFY CHECKSIG, ie, payment to an
* address like 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.
*/
@Deprecated
public boolean isSentToAddress() {
return ScriptPattern.isPayToPubKeyHash(this);
}
@ -259,9 +249,9 @@ public class Script {
*
*/
public byte[] getPubKeyHash() throws ScriptException {
if (isSentToAddress())
if (ScriptPattern.isPayToPubKeyHash(this))
return chunks.get(2).data;
else if (isPayToScriptHash())
else if (ScriptPattern.isPayToScriptHash(this))
return chunks.get(1).data;
else
throw new ScriptException(ScriptError.SCRIPT_ERR_UNKNOWN_ERROR, "Script not in the standard scriptPubKey form");
@ -300,7 +290,7 @@ public class Script {
* @throws ScriptException
*/
public byte[] getCLTVPaymentChannelSenderPubKey() throws ScriptException {
if (!isSentToCLTVPaymentChannel()) {
if (!ScriptPattern.isSentToCltvPaymentChannel(this)) {
throw new ScriptException(ScriptError.SCRIPT_ERR_UNKNOWN_ERROR, "Script not a standard CHECKLOCKTIMVERIFY transaction: " + this);
}
return chunks.get(8).data;
@ -312,14 +302,14 @@ public class Script {
* @throws ScriptException
*/
public byte[] getCLTVPaymentChannelRecipientPubKey() throws ScriptException {
if (!isSentToCLTVPaymentChannel()) {
if (!ScriptPattern.isSentToCltvPaymentChannel(this)) {
throw new ScriptException(ScriptError.SCRIPT_ERR_UNKNOWN_ERROR, "Script not a standard CHECKLOCKTIMVERIFY transaction: " + this);
}
return chunks.get(1).data;
}
public BigInteger getCLTVPaymentChannelExpiry() {
if (!isSentToCLTVPaymentChannel()) {
if (!ScriptPattern.isSentToCltvPaymentChannel(this)) {
throw new ScriptException(ScriptError.SCRIPT_ERR_UNKNOWN_ERROR, "Script not a standard CHECKLOCKTIMEVERIFY transaction: " + this);
}
return castToBigInteger(chunks.get(4).data, 5, false);
@ -350,11 +340,11 @@ public class Script {
* showing addresses rather than pubkeys.
*/
public Address getToAddress(NetworkParameters params, boolean forcePayToPubKey) throws ScriptException {
if (isSentToAddress())
if (ScriptPattern.isPayToPubKeyHash(this))
return new Address(params, getPubKeyHash());
else if (isPayToScriptHash())
else if (ScriptPattern.isPayToScriptHash(this))
return Address.fromP2SHScript(params, this);
else if (forcePayToPubKey && isSentToRawPubKey())
else if (forcePayToPubKey && ScriptPattern.isPayToPubKey(this))
return ECKey.fromPublicOnly(getPubKey()).toAddress(params);
else
throw new ScriptException(ScriptError.SCRIPT_ERR_UNKNOWN_ERROR, "Cannot cast this script to a pay-to-address type");
@ -435,12 +425,12 @@ public class Script {
* It is expected that this program later on will be updated with proper signatures.
*/
public Script createEmptyInputScript(@Nullable ECKey key, @Nullable Script redeemScript) {
if (isSentToAddress()) {
if (ScriptPattern.isPayToPubKeyHash(this)) {
checkArgument(key != null, "Key required to create pay-to-address input script");
return ScriptBuilder.createInputScript(null, key);
} else if (isSentToRawPubKey()) {
} else if (ScriptPattern.isPayToPubKey(this)) {
return ScriptBuilder.createInputScript(null);
} else if (isPayToScriptHash()) {
} else if (ScriptPattern.isPayToScriptHash(this)) {
checkArgument(redeemScript != null, "Redeem script required to create P2SH input script");
return ScriptBuilder.createP2SHMultiSigInputScript(null, redeemScript);
} else {
@ -454,12 +444,12 @@ public class Script {
public Script getScriptSigWithSignature(Script scriptSig, byte[] sigBytes, int index) {
int sigsPrefixCount = 0;
int sigsSuffixCount = 0;
if (isPayToScriptHash()) {
if (ScriptPattern.isPayToScriptHash(this)) {
sigsPrefixCount = 1; // OP_0 <sig>* <redeemScript>
sigsSuffixCount = 1;
} else if (isSentToMultiSig()) {
} else if (ScriptPattern.isSentToMultisig(this)) {
sigsPrefixCount = 1; // OP_0 <sig>*
} else if (isSentToAddress()) {
} else if (ScriptPattern.isPayToPubKeyHash(this)) {
sigsSuffixCount = 1; // <sig> <pubkey>
}
return ScriptBuilder.updateScriptWithSignature(scriptSig, sigBytes, index, sigsPrefixCount, sigsSuffixCount);
@ -511,7 +501,7 @@ public class Script {
* @throws ScriptException if the script type is not understood or is pay to address or is P2SH (run this method on the "Redeem script" instead).
*/
public List<ECKey> getPubKeys() {
if (!isSentToMultiSig())
if (!ScriptPattern.isSentToMultisig(this))
throw new ScriptException(ScriptError.SCRIPT_ERR_UNKNOWN_ERROR, "Only usable for multisig scripts.");
ArrayList<ECKey> result = Lists.newArrayList();
@ -620,14 +610,14 @@ public class Script {
* Returns number of signatures required to satisfy this script.
*/
public int getNumberOfSignaturesRequiredToSpend() {
if (isSentToMultiSig()) {
if (ScriptPattern.isSentToMultisig(this)) {
// for N of M CHECKMULTISIG script we will need N signatures to spend
ScriptChunk nChunk = chunks.get(0);
return Script.decodeFromOpN(nChunk.opcode);
} else if (isSentToAddress() || isSentToRawPubKey()) {
} else if (ScriptPattern.isPayToPubKeyHash(this) || ScriptPattern.isPayToPubKey(this)) {
// pay-to-address and pay-to-pubkey require single sig
return 1;
} else if (isPayToScriptHash()) {
} else if (ScriptPattern.isPayToScriptHash(this)) {
throw new IllegalStateException("For P2SH number of signatures depends on redeem script");
} else {
throw new IllegalStateException("Unsupported script type");
@ -639,17 +629,17 @@ public class Script {
* be required for certain types of script to estimate target size.
*/
public int getNumberOfBytesRequiredToSpend(@Nullable ECKey pubKey, @Nullable Script redeemScript) {
if (isPayToScriptHash()) {
if (ScriptPattern.isPayToScriptHash(this)) {
// scriptSig: <sig> [sig] [sig...] <redeemscript>
checkArgument(redeemScript != null, "P2SH script requires redeemScript to be spent");
return redeemScript.getNumberOfSignaturesRequiredToSpend() * SIG_SIZE + redeemScript.getProgram().length;
} else if (isSentToMultiSig()) {
} else if (ScriptPattern.isSentToMultisig(this)) {
// scriptSig: OP_0 <sig> [sig] [sig...]
return getNumberOfSignaturesRequiredToSpend() * SIG_SIZE + 1;
} else if (isSentToRawPubKey()) {
} else if (ScriptPattern.isPayToPubKey(this)) {
// scriptSig: <sig>
return SIG_SIZE;
} else if (isSentToAddress()) {
} else if (ScriptPattern.isPayToPubKeyHash(this)) {
// scriptSig: <sig> <pubkey>
int uncompressedPubKeySize = 65;
return SIG_SIZE + (pubKey != null ? pubKey.getPubKey().length : uncompressedPubKeySize);
@ -658,30 +648,17 @@ public class Script {
}
}
/**
* <p>Whether or not this is a scriptPubKey representing a pay-to-script-hash 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. This rule is "soft enforced" by the network as it does
* not exist in Bitcoin Core. It means blocks containing P2SH transactions that don't match
* correctly are considered valid, but won't be mined upon, so they'll be rapidly re-orgd out of the chain. This
* logic is defined by <a href="https://github.com/bitcoin/bips/blob/master/bip-0016.mediawiki">BIP 16</a>.</p>
*
* <p>bitcoinj does not support creation of P2SH transactions today. The goal of P2SH is to allow short addresses
* even for complex scripts (eg, multi-sig outputs) so they are convenient to work with in things like QRcodes or
* with copy/paste, and also to minimize the size of the unspent output set (which improves performance of the
* Bitcoin system).</p>
*/
@Deprecated
public boolean isPayToScriptHash() {
return ScriptPattern.isPayToScriptHash(this);
}
/**
* Returns whether this script matches the format used for multisig outputs: [n] [keys...] [m] CHECKMULTISIG
*/
@Deprecated
public boolean isSentToMultiSig() {
return ScriptPattern.isSentToMultisig(this);
}
@Deprecated
public boolean isSentToCLTVPaymentChannel() {
return ScriptPattern.isSentToCltvPaymentChannel(this);
}
@ -795,6 +772,7 @@ public class Script {
return Utils.decodeMPI(Utils.reverseBytes(chunk), false);
}
@Deprecated
public boolean isOpReturn() {
return ScriptPattern.isOpReturn(this);
}
@ -1643,7 +1621,7 @@ public class Script {
// overall scalability and performance.
// TODO: Check if we can take out enforceP2SH if there's a checkpoint at the enforcement block.
if (verifyFlags.contains(VerifyFlag.P2SH) && scriptPubKey.isPayToScriptHash()) {
if (verifyFlags.contains(VerifyFlag.P2SH) && ScriptPattern.isPayToScriptHash(scriptPubKey)) {
for (ScriptChunk chunk : chunks)
if (chunk.isOpCode() && chunk.opcode > OP_16)
throw new ScriptException(ScriptError.SCRIPT_ERR_SIG_PUSHONLY, "Attempted to spend a P2SH scriptPubKey with a script that contained script ops");
@ -1674,11 +1652,11 @@ public class Script {
*/
public ScriptType getScriptType() {
ScriptType type = ScriptType.NO_TYPE;
if (isSentToAddress()) {
if (ScriptPattern.isPayToPubKeyHash(this)) {
type = ScriptType.P2PKH;
} else if (isSentToRawPubKey()) {
} else if (ScriptPattern.isPayToPubKey(this)) {
type = ScriptType.PUB_KEY;
} else if (isPayToScriptHash()) {
} else if (ScriptPattern.isPayToScriptHash(this)) {
type = ScriptType.P2SH;
}
return type;

View File

@ -28,6 +28,12 @@ import static org.bitcoinj.script.ScriptOpCodes.*;
* This is a Script pattern matcher with some typical script patterns
*/
public class ScriptPattern {
/**
* Returns true if this script is of the form DUP HASH160 <pubkey hash> EQUALVERIFY CHECKSIG, ie, payment to an
* address like 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 isPayToPubKeyHash(Script script) {
List<ScriptChunk> chunks = script.chunks;
return chunks.size() == 5 &&
@ -39,6 +45,11 @@ public class ScriptPattern {
chunks.get(4).equalsOpCode(OP_CHECKSIG);
}
/**
* <p>Whether or not this is a scriptPubKey representing a pay-to-script-hash 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.
*/
public static boolean isPayToScriptHash(Script script) {
List<ScriptChunk> chunks = script.chunks;
// We check for the effective serialized form because BIP16 defines a P2SH output using an exact byte
@ -54,6 +65,12 @@ public class ScriptPattern {
chunks.get(2).equalsOpCode(OP_EQUAL);
}
/**
* Returns true if this script is of the form <pubkey> OP_CHECKSIG. This form was originally intended for transactions
* where the peers talked to each other directly via TCP/IP, but has fallen out of favor with time due to that mode
* of operation being susceptible to man-in-the-middle attacks. It is still used in coinbase outputs and can be
* useful more exotic types of transaction, but today most payments are to addresses.
*/
public static boolean isPayToPubKey(Script script) {
List<ScriptChunk> chunks = script.chunks;
return chunks.size() == 2 &&
@ -63,6 +80,9 @@ public class ScriptPattern {
chunks.get(0).data.length > 1;
}
/**
* Returns whether this script matches the format used for multisig outputs: [n] [keys...] [m] CHECKMULTISIG
*/
public static boolean isSentToMultisig(Script script) {
List<ScriptChunk> chunks = script.chunks;
if (chunks.size() < 4) return false;

View File

@ -21,6 +21,7 @@ import org.bitcoinj.crypto.ChildNumber;
import org.bitcoinj.crypto.TransactionSignature;
import org.bitcoinj.script.Script;
import org.bitcoinj.script.ScriptException;
import org.bitcoinj.script.ScriptPattern;
import org.bitcoinj.wallet.KeyBag;
import org.bitcoinj.wallet.RedeemData;
import org.slf4j.Logger;
@ -58,7 +59,7 @@ public abstract class CustomTransactionSigner extends StatelessTransactionSigner
continue;
}
Script scriptPubKey = txOut.getScriptPubKey();
if (!scriptPubKey.isPayToScriptHash()) {
if (!ScriptPattern.isPayToScriptHash(scriptPubKey)) {
log.warn("CustomTransactionSigner works only with P2SH transactions");
return false;
}

View File

@ -21,6 +21,7 @@ import org.bitcoinj.core.TransactionInput;
import org.bitcoinj.crypto.TransactionSignature;
import org.bitcoinj.script.Script;
import org.bitcoinj.script.ScriptChunk;
import org.bitcoinj.script.ScriptPattern;
import org.bitcoinj.wallet.KeyBag;
import org.bitcoinj.wallet.Wallet;
import org.slf4j.Logger;
@ -66,8 +67,8 @@ public class MissingSigResolutionSigner extends StatelessTransactionSigner {
Script scriptPubKey = txIn.getConnectedOutput().getScriptPubKey();
Script inputScript = txIn.getScriptSig();
if (scriptPubKey.isPayToScriptHash() || scriptPubKey.isSentToMultiSig()) {
int sigSuffixCount = scriptPubKey.isPayToScriptHash() ? 1 : 0;
if (ScriptPattern.isPayToScriptHash(scriptPubKey) || ScriptPattern.isSentToMultisig(scriptPubKey)) {
int sigSuffixCount = ScriptPattern.isPayToScriptHash(scriptPubKey) ? 1 : 0;
// all chunks except the first one (OP_0) and the last (redeem script) are signatures
for (int j = 1; j < inputScript.getChunks().size() - sigSuffixCount; j++) {
ScriptChunk scriptChunk = inputScript.getChunks().get(j);

View File

@ -236,7 +236,7 @@ public class KeyChainGroup implements KeyBag {
DeterministicKeyChain chain = getActiveKeyChain();
if (chain.isMarried()) {
Script outputScript = chain.freshOutputScript(purpose);
checkState(outputScript.isPayToScriptHash()); // Only handle P2SH for now
checkState(ScriptPattern.isPayToScriptHash(outputScript)); // Only handle P2SH for now
Address freshAddress = Address.fromP2SHScript(params, outputScript);
maybeLookaheadScripts();
currentAddresses.put(purpose, freshAddress);

View File

@ -19,6 +19,7 @@ package org.bitcoinj.wallet;
import org.bitcoinj.core.*;
import org.bitcoinj.script.Script;
import org.bitcoinj.script.ScriptException;
import org.bitcoinj.script.ScriptPattern;
import com.google.common.collect.Lists;
import org.slf4j.Logger;
@ -61,9 +62,9 @@ public class KeyTimeCoinSelector implements CoinSelector {
// We ignore any other kind of exotic output on the assumption we can't spend it ourselves.
final Script scriptPubKey = output.getScriptPubKey();
ECKey controllingKey;
if (scriptPubKey.isSentToRawPubKey()) {
if (ScriptPattern.isPayToPubKey(scriptPubKey)) {
controllingKey = wallet.findKeyFromPubKey(scriptPubKey.getPubKey());
} else if (scriptPubKey.isSentToAddress()) {
} else if (ScriptPattern.isPayToPubKeyHash(scriptPubKey)) {
controllingKey = wallet.findKeyFromPubHash(scriptPubKey.getPubKeyHash());
} else {
log.info("Skipping tx output {} because it's not of simple form.", output);

View File

@ -18,6 +18,7 @@ package org.bitcoinj.wallet;
import org.bitcoinj.core.ECKey;
import org.bitcoinj.script.Script;
import org.bitcoinj.script.ScriptPattern;
import java.util.ArrayList;
import java.util.Collections;
@ -53,7 +54,7 @@ public class RedeemData {
* to spend such inputs and provided program should be a proper CHECKSIG program.
*/
public static RedeemData of(ECKey key, Script program) {
checkArgument(program.isSentToAddress() || program.isSentToRawPubKey());
checkArgument(ScriptPattern.isPayToPubKeyHash(program) || ScriptPattern.isPayToPubKey(program));
return key != null ? new RedeemData(Collections.singletonList(key), program) : null;
}

View File

@ -974,7 +974,7 @@ public class Wallet extends BaseTaggableObject
try {
List<Address> addresses = new LinkedList<>();
for (Script script : watchedScripts)
if (script.isSentToAddress())
if (ScriptPattern.isPayToPubKeyHash(script))
addresses.add(script.getToAddress(params));
return addresses;
} finally {
@ -1078,13 +1078,13 @@ public class Wallet extends BaseTaggableObject
for (TransactionOutput o : tx.getOutputs()) {
try {
Script script = o.getScriptPubKey();
if (script.isSentToRawPubKey()) {
if (ScriptPattern.isPayToPubKey(script)) {
byte[] pubkey = script.getPubKey();
keyChainGroup.markPubKeyAsUsed(pubkey);
} else if (script.isSentToAddress()) {
} else if (ScriptPattern.isPayToPubKeyHash(script)) {
byte[] pubkeyHash = script.getPubKeyHash();
keyChainGroup.markPubKeyHashAsUsed(pubkeyHash);
} else if (script.isPayToScriptHash()) {
} else if (ScriptPattern.isPayToScriptHash(script)) {
Address a = Address.fromP2SHScript(tx.getParams(), script);
keyChainGroup.markP2SHAddressAsUsed(a);
}
@ -3986,7 +3986,7 @@ public class Wallet extends BaseTaggableObject
for (TransactionOutput output : req.tx.getOutputs()) {
if (output.isDust())
throw new DustySendRequested();
if (output.getScriptPubKey().isOpReturn())
if (ScriptPattern.isOpReturn(output.getScriptPubKey()))
++opReturnCount;
}
if (opReturnCount > 1) // Only 1 OP_RETURN per transaction allowed.
@ -4187,23 +4187,23 @@ public class Wallet extends BaseTaggableObject
* false if the form of the script is not known or if the script is OP_RETURN.
*/
public boolean canSignFor(Script script) {
if (script.isSentToRawPubKey()) {
if (ScriptPattern.isPayToPubKey(script)) {
byte[] pubkey = script.getPubKey();
ECKey key = findKeyFromPubKey(pubkey);
return key != null && (key.isEncrypted() || key.hasPrivKey());
} if (script.isPayToScriptHash()) {
} if (ScriptPattern.isPayToScriptHash(script)) {
RedeemData data = findRedeemDataFromScriptHash(script.getPubKeyHash());
return data != null && canSignFor(data.redeemScript);
} else if (script.isSentToAddress()) {
} else if (ScriptPattern.isPayToPubKeyHash(script)) {
ECKey key = findKeyFromPubHash(script.getPubKeyHash());
return key != null && (key.isEncrypted() || key.hasPrivKey());
} else if (script.isSentToMultiSig()) {
} else if (ScriptPattern.isSentToMultisig(script)) {
for (ECKey pubkey : script.getPubKeys()) {
ECKey key = findKeyFromPubKey(pubkey.getPubKey());
if (key != null && (key.isEncrypted() || key.hasPrivKey()))
return true;
}
} else if (script.isSentToCLTVPaymentChannel()) {
} else if (ScriptPattern.isSentToCltvPaymentChannel(script)) {
// Any script for which we are the recipient or sender counts.
byte[] sender = script.getCLTVPaymentChannelSenderPubKey();
ECKey senderKey = findKeyFromPubKey(sender);
@ -4724,7 +4724,7 @@ public class Wallet extends BaseTaggableObject
// Returns true if the output is one that won't be selected by a data element matching in the scriptSig.
private boolean isTxOutputBloomFilterable(TransactionOutput out) {
Script script = out.getScriptPubKey();
boolean isScriptTypeSupported = script.isSentToRawPubKey() || script.isPayToScriptHash();
boolean isScriptTypeSupported = ScriptPattern.isPayToPubKey(script) || ScriptPattern.isPayToScriptHash(script);
return (isScriptTypeSupported && myUnspents.contains(out)) || watchedScripts.contains(script);
}
@ -4981,10 +4981,10 @@ public class Wallet extends BaseTaggableObject
Script script = output.getScriptPubKey();
ECKey key = null;
Script redeemScript = null;
if (script.isSentToAddress()) {
if (ScriptPattern.isPayToPubKeyHash(script)) {
key = findKeyFromPubHash(script.getPubKeyHash());
checkNotNull(key, "Coin selection includes unspendable outputs");
} else if (script.isPayToScriptHash()) {
} else if (ScriptPattern.isPayToScriptHash(script)) {
redeemScript = findRedeemDataFromScriptHash(script.getPubKeyHash()).redeemScript;
checkNotNull(redeemScript, "Coin selection includes unspendable outputs");
}

View File

@ -23,6 +23,7 @@ import org.bitcoinj.crypto.TransactionSignature;
import org.bitcoinj.script.Script;
import org.bitcoinj.script.ScriptBuilder;
import org.bitcoinj.script.ScriptException;
import org.bitcoinj.script.ScriptPattern;
import com.google.common.base.Preconditions;
@ -1818,7 +1819,7 @@ public class FullBlockTestGenerator {
input.setScriptSig(new ScriptBuilder().op(OP_1).build());
} else {
// Sign input
checkState(prevOut.scriptPubKey.isSentToRawPubKey());
checkState(ScriptPattern.isPayToPubKey(prevOut.scriptPubKey));
Sha256Hash hash = t.hashForSignature(0, prevOut.scriptPubKey, SigHash.ALL, false);
input.setScriptSig(ScriptBuilder.createInputScript(
new TransactionSignature(coinbaseOutKey.sign(hash), SigHash.ALL, false))

View File

@ -18,6 +18,7 @@ package org.bitcoinj.protocols.channels;
import org.bitcoinj.core.*;
import org.bitcoinj.protocols.channels.PaymentChannelClient.VersionSelector;
import org.bitcoinj.script.ScriptPattern;
import org.bitcoinj.testing.TestWithWallet;
import org.bitcoinj.utils.Threading;
import org.bitcoinj.wallet.Wallet;
@ -540,9 +541,9 @@ public class ChannelConnectionTest extends TestWithWallet {
newClientStates.deserializeWalletExtension(wallet, clientStoredChannels.serializeWalletExtension());
broadcastTxPause.release();
if (isMultiSigContract()) {
assertTrue(broadcasts.take().getOutput(0).getScriptPubKey().isSentToMultiSig());
assertTrue(ScriptPattern.isSentToMultisig(broadcasts.take().getOutput(0).getScriptPubKey()));
} else {
assertTrue(broadcasts.take().getOutput(0).getScriptPubKey().isPayToScriptHash());
assertTrue(ScriptPattern.isPayToScriptHash(broadcasts.take().getOutput(0).getScriptPubKey()));
}
broadcastTxPause.release();
assertEquals(TransactionConfidence.Source.SELF, broadcasts.take().getConfidence().getSource());

View File

@ -19,6 +19,7 @@ package org.bitcoinj.protocols.channels;
import org.bitcoinj.core.*;
import org.bitcoinj.script.Script;
import org.bitcoinj.script.ScriptBuilder;
import org.bitcoinj.script.ScriptPattern;
import org.bitcoinj.testing.TestWithWallet;
import org.bitcoinj.wallet.SendRequest;
import org.bitcoinj.wallet.Wallet;
@ -255,12 +256,12 @@ public class PaymentChannelStateTest extends TestWithWallet {
assertEquals(2, multisigContract.getOutputs().size()); // One multi-sig, one change.
Script script = multisigContract.getOutput(0).getScriptPubKey();
if (versionSelector == PaymentChannelClient.VersionSelector.VERSION_1) {
assertTrue(script.isSentToMultiSig());
assertTrue(ScriptPattern.isSentToMultisig(script));
} else {
assertTrue(script.isPayToScriptHash());
assertTrue(ScriptPattern.isPayToScriptHash(script));
}
script = multisigContract.getOutput(1).getScriptPubKey();
assertTrue(script.isSentToAddress());
assertTrue(ScriptPattern.isPayToPubKeyHash(script));
assertTrue(wallet.getPendingTransactions().contains(multisigContract));
// Provide the server with the multisig contract and simulate successful propagation/acceptance.
@ -380,12 +381,12 @@ public class PaymentChannelStateTest extends TestWithWallet {
assertEquals(2, multisigContract.getOutputs().size()); // One multi-sig, one change.
Script script = multisigContract.getOutput(0).getScriptPubKey();
if (versionSelector == PaymentChannelClient.VersionSelector.VERSION_1) {
assertTrue(script.isSentToMultiSig());
assertTrue(ScriptPattern.isSentToMultisig(script));
} else {
assertTrue(script.isPayToScriptHash());
assertTrue(ScriptPattern.isPayToScriptHash(script));
}
script = multisigContract.getOutput(1).getScriptPubKey();
assertTrue(script.isSentToAddress());
assertTrue(ScriptPattern.isPayToPubKeyHash(script));
assertTrue(wallet.getPendingTransactions().contains(multisigContract));
// Provide the server with the multisig contract and simulate successful propagation/acceptance.
@ -856,12 +857,12 @@ public class PaymentChannelStateTest extends TestWithWallet {
assertEquals(2, multisigContract.getOutputs().size()); // One multi-sig, one change.
Script script = multisigContract.getOutput(0).getScriptPubKey();
if (versionSelector == PaymentChannelClient.VersionSelector.VERSION_1) {
assertTrue(script.isSentToMultiSig());
assertTrue(ScriptPattern.isSentToMultisig(script));
} else {
assertTrue(script.isPayToScriptHash());
assertTrue(ScriptPattern.isPayToScriptHash(script));
}
script = multisigContract.getOutput(1).getScriptPubKey();
assertTrue(script.isSentToAddress());
assertTrue(ScriptPattern.isPayToPubKeyHash(script));
assertTrue(wallet.getPendingTransactions().contains(multisigContract));
// Provide the server with the multisig contract and simulate successful propagation/acceptance.
@ -950,12 +951,12 @@ public class PaymentChannelStateTest extends TestWithWallet {
assertEquals(2, multisigContract.getOutputs().size()); // One multi-sig, one change.
Script script = multisigContract.getOutput(0).getScriptPubKey();
if (versionSelector == PaymentChannelClient.VersionSelector.VERSION_1) {
assertTrue(script.isSentToMultiSig());
assertTrue(ScriptPattern.isSentToMultisig(script));
} else {
assertTrue(script.isPayToScriptHash());
assertTrue(ScriptPattern.isPayToScriptHash(script));
}
script = multisigContract.getOutput(1).getScriptPubKey();
assertTrue(script.isSentToAddress());
assertTrue(ScriptPattern.isPayToPubKeyHash(script));
assertTrue(wallet.getPendingTransactions().contains(multisigContract));
// Provide the server with the multisig contract and simulate successful propagation/acceptance.

View File

@ -87,13 +87,13 @@ public class ScriptTest {
@Test
public void testMultiSig() throws Exception {
List<ECKey> keys = Lists.newArrayList(new ECKey(), new ECKey(), new ECKey());
assertTrue(ScriptBuilder.createMultiSigOutputScript(2, keys).isSentToMultiSig());
assertTrue(ScriptPattern.isSentToMultisig(ScriptBuilder.createMultiSigOutputScript(2, keys)));
Script script = ScriptBuilder.createMultiSigOutputScript(3, keys);
assertTrue(script.isSentToMultiSig());
assertTrue(ScriptPattern.isSentToMultisig(script));
List<ECKey> pubkeys = new ArrayList<>(3);
for (ECKey key : keys) pubkeys.add(ECKey.fromPublicOnly(key.getPubKeyPoint()));
assertEquals(script.getPubKeys(), pubkeys);
assertFalse(ScriptBuilder.createOutputScript(new ECKey()).isSentToMultiSig());
assertFalse(ScriptPattern.isSentToMultisig(ScriptBuilder.createOutputScript(new ECKey())));
try {
// Fail if we ask for more signatures than keys.
Script.createMultiSigOutputScript(4, keys);
@ -113,14 +113,14 @@ public class ScriptTest {
@Test
public void testP2SHOutputScript() throws Exception {
Address p2shAddress = Address.fromBase58(MainNetParams.get(), "35b9vsyH1KoFT5a5KtrKusaCcPLkiSo1tU");
assertTrue(ScriptBuilder.createOutputScript(p2shAddress).isPayToScriptHash());
assertTrue(ScriptPattern.isPayToScriptHash(ScriptBuilder.createOutputScript(p2shAddress)));
}
@Test
public void testIp() throws Exception {
byte[] bytes = HEX.decode("41043e96222332ea7848323c08116dddafbfa917b8e37f0bdf63841628267148588a09a43540942d58d49717ad3fabfe14978cf4f0a8b84d2435dad16e9aa4d7f935ac");
Script s = new Script(bytes);
assertTrue(s.isSentToRawPubKey());
assertTrue(ScriptPattern.isPayToPubKey(s));
}
@Test
@ -432,7 +432,7 @@ public class ScriptTest {
@Test
public void testCLTVPaymentChannelOutput() {
Script script = ScriptBuilder.createCLTVPaymentChannelOutput(BigInteger.valueOf(20), new ECKey(), new ECKey());
assertTrue("script is locktime-verify", script.isSentToCLTVPaymentChannel());
assertTrue("script is locktime-verify", ScriptPattern.isSentToCltvPaymentChannel(script));
}
@Test

View File

@ -27,6 +27,7 @@ import org.bitcoinj.protocols.payments.PaymentProtocolException;
import org.bitcoinj.protocols.payments.PaymentSession;
import org.bitcoinj.script.ScriptBuilder;
import org.bitcoinj.script.ScriptException;
import org.bitcoinj.script.ScriptPattern;
import org.bitcoinj.store.*;
import org.bitcoinj.uri.BitcoinURI;
import org.bitcoinj.uri.BitcoinURIParseException;
@ -831,7 +832,7 @@ public class WalletTool {
}
TransactionOutput lockTimeVerifyOutput = null;
for (TransactionOutput out : lockTimeVerify.getOutputs()) {
if (out.getScriptPubKey().isSentToCLTVPaymentChannel()) {
if (ScriptPattern.isSentToCltvPaymentChannel(out.getScriptPubKey())) {
lockTimeVerifyOutput = out;
}
}
@ -935,7 +936,7 @@ public class WalletTool {
}
TransactionOutput lockTimeVerifyOutput = null;
for (TransactionOutput out : lockTimeVerify.getOutputs()) {
if (out.getScriptPubKey().isSentToCLTVPaymentChannel()) {
if (ScriptPattern.isSentToCltvPaymentChannel(out.getScriptPubKey())) {
lockTimeVerifyOutput = out;
}
}