Script: Extract the extraction of the P2PKH and P2SH hashes to ScriptPattern.

This commit is contained in:
Andreas Schildbach
2018-02-26 00:00:16 +01:00
parent e44591a9b5
commit 0a21b586e8
8 changed files with 27 additions and 16 deletions

View File

@@ -76,7 +76,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(ScriptPattern.isPayToScriptHash(scriptPubKey), "Not a P2SH script");
return fromP2SHHash(params, scriptPubKey.getPubKeyHash());
return fromP2SHHash(params, ScriptPattern.extractHashFromPayToScriptHash(scriptPubKey));
}
/**

View File

@@ -705,9 +705,12 @@ public class Transaction extends ChildMessage {
final TransactionOutput connectedOutput = outpoint.getConnectedOutput();
if (connectedOutput != null) {
Script scriptPubKey = connectedOutput.getScriptPubKey();
if (ScriptPattern.isPayToPubKeyHash(scriptPubKey) || ScriptPattern.isPayToScriptHash(scriptPubKey)) {
try {
byte[] pubKeyHash = scriptPubKey.getPubKeyHash();
s.append(" hash160:");
s.append(Utils.HEX.encode(scriptPubKey.getPubKeyHash()));
s.append(Utils.HEX.encode(pubKeyHash));
} catch (ScriptException x) {
// ignore
}
}
if (in.hasSequence()) {

View File

@@ -142,7 +142,7 @@ public class TransactionOutPoint extends ChildMessage {
checkNotNull(connectedOutput, "Input is not connected so cannot retrieve key");
Script connectedScript = connectedOutput.getScriptPubKey();
if (ScriptPattern.isPayToPubKeyHash(connectedScript)) {
byte[] addressBytes = connectedScript.getPubKeyHash();
byte[] addressBytes = ScriptPattern.extractHashFromPayToPubKeyHash(connectedScript);
return keyBag.findKeyFromPubHash(addressBytes);
} else if (ScriptPattern.isPayToPubKey(connectedScript)) {
byte[] pubkeyBytes = connectedScript.getPubKey();
@@ -165,13 +165,13 @@ public class TransactionOutPoint extends ChildMessage {
checkNotNull(connectedOutput, "Input is not connected so cannot retrieve key");
Script connectedScript = connectedOutput.getScriptPubKey();
if (ScriptPattern.isPayToPubKeyHash(connectedScript)) {
byte[] addressBytes = connectedScript.getPubKeyHash();
byte[] addressBytes = ScriptPattern.extractHashFromPayToPubKeyHash(connectedScript);
return RedeemData.of(keyBag.findKeyFromPubHash(addressBytes), connectedScript);
} else if (ScriptPattern.isPayToPubKey(connectedScript)) {
byte[] pubkeyBytes = connectedScript.getPubKey();
return RedeemData.of(keyBag.findKeyFromPubKey(pubkeyBytes), connectedScript);
} else if (ScriptPattern.isPayToScriptHash(connectedScript)) {
byte[] scriptHash = connectedScript.getPubKeyHash();
byte[] scriptHash = ScriptPattern.extractHashFromPayToScriptHash(connectedScript);
return keyBag.findRedeemDataFromScriptHash(scriptHash);
} else {
throw new ScriptException(ScriptError.SCRIPT_ERR_UNKNOWN_ERROR, "Could not understand form of connected output script: " + connectedScript);

View File

@@ -325,7 +325,7 @@ public class TransactionOutput extends ChildMessage {
byte[] pubkey = script.getPubKey();
return transactionBag.isPubKeyMine(pubkey);
} if (ScriptPattern.isPayToScriptHash(script)) {
return transactionBag.isPayToScriptHashMine(script.getPubKeyHash());
return transactionBag.isPayToScriptHashMine(ScriptPattern.extractHashFromPayToScriptHash(script));
} else {
byte[] pubkeyHash = script.getPubKeyHash();
return transactionBag.isPubKeyHashMine(pubkeyHash);

View File

@@ -250,9 +250,9 @@ public class Script {
*/
public byte[] getPubKeyHash() throws ScriptException {
if (ScriptPattern.isPayToPubKeyHash(this))
return chunks.get(2).data;
return ScriptPattern.extractHashFromPayToPubKeyHash(this);
else if (ScriptPattern.isPayToScriptHash(this))
return chunks.get(1).data;
return ScriptPattern.extractHashFromPayToScriptHash(this);
else
throw new ScriptException(ScriptError.SCRIPT_ERR_UNKNOWN_ERROR, "Script not in the standard scriptPubKey form");
}
@@ -341,7 +341,7 @@ public class Script {
*/
public Address getToAddress(NetworkParameters params, boolean forcePayToPubKey) throws ScriptException {
if (ScriptPattern.isPayToPubKeyHash(this))
return new Address(params, getPubKeyHash());
return new Address(params, ScriptPattern.extractHashFromPayToPubKeyHash(this));
else if (ScriptPattern.isPayToScriptHash(this))
return Address.fromP2SHScript(params, this);
else if (forcePayToPubKey && ScriptPattern.isPayToPubKey(this))

View File

@@ -45,6 +45,10 @@ public class ScriptPattern {
chunks.get(4).equalsOpCode(OP_CHECKSIG);
}
public static byte[] extractHashFromPayToPubKeyHash(Script script) {
return script.chunks.get(2).data;
}
/**
* <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
@@ -65,6 +69,10 @@ public class ScriptPattern {
chunks.get(2).equalsOpCode(OP_EQUAL);
}
public static byte[] extractHashFromPayToScriptHash(Script script) {
return script.chunks.get(1).data;
}
/**
* 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

View File

@@ -65,7 +65,7 @@ public class KeyTimeCoinSelector implements CoinSelector {
if (ScriptPattern.isPayToPubKey(scriptPubKey)) {
controllingKey = wallet.findKeyFromPubKey(scriptPubKey.getPubKey());
} else if (ScriptPattern.isPayToPubKeyHash(scriptPubKey)) {
controllingKey = wallet.findKeyFromPubHash(scriptPubKey.getPubKeyHash());
controllingKey = wallet.findKeyFromPubHash(ScriptPattern.extractHashFromPayToPubKeyHash(scriptPubKey));
} else {
log.info("Skipping tx output {} because it's not of simple form.", output);
continue;

View File

@@ -1082,7 +1082,7 @@ public class Wallet extends BaseTaggableObject
byte[] pubkey = script.getPubKey();
keyChainGroup.markPubKeyAsUsed(pubkey);
} else if (ScriptPattern.isPayToPubKeyHash(script)) {
byte[] pubkeyHash = script.getPubKeyHash();
byte[] pubkeyHash = ScriptPattern.extractHashFromPayToPubKeyHash(script);
keyChainGroup.markPubKeyHashAsUsed(pubkeyHash);
} else if (ScriptPattern.isPayToScriptHash(script)) {
Address a = Address.fromP2SHScript(tx.getParams(), script);
@@ -4192,10 +4192,10 @@ public class Wallet extends BaseTaggableObject
ECKey key = findKeyFromPubKey(pubkey);
return key != null && (key.isEncrypted() || key.hasPrivKey());
} if (ScriptPattern.isPayToScriptHash(script)) {
RedeemData data = findRedeemDataFromScriptHash(script.getPubKeyHash());
RedeemData data = findRedeemDataFromScriptHash(ScriptPattern.extractHashFromPayToScriptHash(script));
return data != null && canSignFor(data.redeemScript);
} else if (ScriptPattern.isPayToPubKeyHash(script)) {
ECKey key = findKeyFromPubHash(script.getPubKeyHash());
ECKey key = findKeyFromPubHash(ScriptPattern.extractHashFromPayToPubKeyHash(script));
return key != null && (key.isEncrypted() || key.hasPrivKey());
} else if (ScriptPattern.isSentToMultisig(script)) {
for (ECKey pubkey : script.getPubKeys()) {
@@ -4982,10 +4982,10 @@ public class Wallet extends BaseTaggableObject
ECKey key = null;
Script redeemScript = null;
if (ScriptPattern.isPayToPubKeyHash(script)) {
key = findKeyFromPubHash(script.getPubKeyHash());
key = findKeyFromPubHash(ScriptPattern.extractHashFromPayToPubKeyHash(script));
checkNotNull(key, "Coin selection includes unspendable outputs");
} else if (ScriptPattern.isPayToScriptHash(script)) {
redeemScript = findRedeemDataFromScriptHash(script.getPubKeyHash()).redeemScript;
redeemScript = findRedeemDataFromScriptHash(ScriptPattern.extractHashFromPayToScriptHash(script)).redeemScript;
checkNotNull(redeemScript, "Coin selection includes unspendable outputs");
}
size += script.getNumberOfBytesRequiredToSpend(key, redeemScript);