Validate P2SH in Script.correctlySpends

This commit is contained in:
Matt Corallo 2012-09-05 23:04:07 -04:00 committed by Mike Hearn
parent 69f441b6c7
commit 050d70cf15
2 changed files with 25 additions and 5 deletions

View file

@ -113,7 +113,7 @@ public class FullPrunedBlockChain extends AbstractBlockChain {
LinkedList<StoredTransactionOutput> txOutsSpent = new LinkedList<StoredTransactionOutput>(); LinkedList<StoredTransactionOutput> txOutsSpent = new LinkedList<StoredTransactionOutput>();
LinkedList<StoredTransactionOutput> txOutsCreated = new LinkedList<StoredTransactionOutput>(); LinkedList<StoredTransactionOutput> txOutsCreated = new LinkedList<StoredTransactionOutput>();
long sigOps = 0; long sigOps = 0;
boolean enforceBIP16 = block.getTimeSeconds() >= params.BIP16_ENFORCE_TIME; final boolean enforceBIP16 = block.getTimeSeconds() >= params.BIP16_ENFORCE_TIME;
if (scriptVerificationExecutor.isShutdown()) if (scriptVerificationExecutor.isShutdown())
scriptVerificationExecutor = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors()); scriptVerificationExecutor = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());
@ -200,7 +200,7 @@ public class FullPrunedBlockChain extends AbstractBlockChain {
FutureTask<VerificationException> future = new FutureTask<VerificationException>(new Callable<VerificationException>() { FutureTask<VerificationException> future = new FutureTask<VerificationException>(new Callable<VerificationException>() {
public VerificationException call() { public VerificationException call() {
try{ try{
scriptSig.correctlySpends(txCache, currentIndex, scriptPubKey); scriptSig.correctlySpends(txCache, currentIndex, scriptPubKey, enforceBIP16);
} catch (ScriptException e) { } catch (ScriptException e) {
return new VerificationException("Error verifying script: " + e.getMessage()); return new VerificationException("Error verifying script: " + e.getMessage());
} catch (VerificationException e) { } catch (VerificationException e) {
@ -292,7 +292,7 @@ public class FullPrunedBlockChain extends AbstractBlockChain {
LinkedList<StoredTransactionOutput> txOutsSpent = new LinkedList<StoredTransactionOutput>(); LinkedList<StoredTransactionOutput> txOutsSpent = new LinkedList<StoredTransactionOutput>();
LinkedList<StoredTransactionOutput> txOutsCreated = new LinkedList<StoredTransactionOutput>(); LinkedList<StoredTransactionOutput> txOutsCreated = new LinkedList<StoredTransactionOutput>();
long sigOps = 0; long sigOps = 0;
boolean enforcePayToScriptHash = newBlock.getHeader().getTimeSeconds() >= params.BIP16_ENFORCE_TIME; final boolean enforcePayToScriptHash = newBlock.getHeader().getTimeSeconds() >= params.BIP16_ENFORCE_TIME;
if (!params.isCheckpoint(newBlock.getHeight())) { if (!params.isCheckpoint(newBlock.getHeight())) {
for(StoredTransaction tx : transactions) { for(StoredTransaction tx : transactions) {
Sha256Hash hash = tx.getHash(); Sha256Hash hash = tx.getHash();
@ -356,7 +356,7 @@ public class FullPrunedBlockChain extends AbstractBlockChain {
FutureTask<VerificationException> future = new FutureTask<VerificationException>(new Callable<VerificationException>() { FutureTask<VerificationException> future = new FutureTask<VerificationException>(new Callable<VerificationException>() {
public VerificationException call() { public VerificationException call() {
try{ try{
scriptSig.correctlySpends(txCache, currentIndex, scriptPubKey); scriptSig.correctlySpends(txCache, currentIndex, scriptPubKey, enforcePayToScriptHash);
} catch (ScriptException e) { } catch (ScriptException e) {
return new VerificationException("Error verifying script: " + e.getMessage()); return new VerificationException("Error verifying script: " + e.getMessage());
} catch (VerificationException e) { } catch (VerificationException e) {

View file

@ -1479,13 +1479,16 @@ public class Script {
* Verifies that this script (interpreted as a scriptSig) correctly spends the given scriptPubKey * Verifies that this script (interpreted as a scriptSig) correctly spends the given scriptPubKey
* @throws VerificationException if this script does not correctly spend the scriptPubKey * @throws VerificationException if this script does not correctly spend the scriptPubKey
*/ */
public void correctlySpends(Transaction txContainingThis, long index, Script scriptPubKey) throws VerificationException, ScriptException { public void correctlySpends(Transaction txContainingThis, long index, Script scriptPubKey, boolean enforceP2SH) throws VerificationException, ScriptException {
if (program.length > 10000 || scriptPubKey.program.length > 10000) if (program.length > 10000 || scriptPubKey.program.length > 10000)
throw new ScriptException("Script larger than 10,000 bytes"); throw new ScriptException("Script larger than 10,000 bytes");
LinkedList<byte[]> stack = new LinkedList<byte[]>(); LinkedList<byte[]> stack = new LinkedList<byte[]>();
LinkedList<byte[]> p2shStack = null;
executeScript(txContainingThis, index, this, stack); executeScript(txContainingThis, index, this, stack);
if (enforceP2SH)
p2shStack = new LinkedList<byte[]>(stack);
executeScript(txContainingThis, index, scriptPubKey, stack); executeScript(txContainingThis, index, scriptPubKey, stack);
if (stack.size() == 0) if (stack.size() == 0)
@ -1493,5 +1496,22 @@ public class Script {
if (!castToBool(stack.pollLast())) if (!castToBool(stack.pollLast()))
throw new VerificationException("Script resulted in a non-true stack"); throw new VerificationException("Script resulted in a non-true stack");
if(enforceP2SH && scriptPubKey.isPayToScriptHash()) {
for (ScriptChunk chunk : chunks)
if (chunk.isOpCode && (chunk.data[0] & 0xff) > OP_16)
throw new VerificationException("Attempted to spend a P2SH scriptPubKey with a script that contained script ops");
byte[] scriptPubKeyBytes = p2shStack.pollLast();
Script scriptPubKeyP2SH = new Script(params, scriptPubKeyBytes, 0, scriptPubKeyBytes.length);
executeScript(txContainingThis, index, scriptPubKeyP2SH, p2shStack);
if (p2shStack.size() == 0)
throw new VerificationException("P2SH stack empty at end of script execution.");
if (!castToBool(p2shStack.pollLast()))
throw new VerificationException("P2SH script execution resulted in a non-true stack");
}
} }
} }