3
0
mirror of https://github.com/Qortal/altcoinj.git synced 2025-01-30 23:02:15 +00:00

Add a TransactionInput.verify() method that checks signatures and use it from the basicSpending test to ensure we generate valid signatures/scripts.

This commit is contained in:
Mike Hearn 2012-12-26 18:14:39 +00:00
parent 2f0d4cdbd8
commit 671a5aec18
3 changed files with 26 additions and 7 deletions

View File

@ -875,7 +875,8 @@ public class Script {
return Utils.decodeMPI(Utils.reverseBytes(chunk), false);
}
private static void executeScript(Transaction txContainingThis, long index, Script script, LinkedList<byte[]> stack) throws ScriptException {
private static void executeScript(Transaction txContainingThis, long index,
Script script, LinkedList<byte[]> stack) throws ScriptException {
int opCount = 0;
int lastCodeSepLocation = 0;
@ -1479,19 +1480,24 @@ public class Script {
/**
* Verifies that this script (interpreted as a scriptSig) correctly spends the given scriptPubKey.
* @param txContainingThis The transaction in which this input scriptSig resides.
* @param scriptSigIndex The index in txContainingThis of the scriptSig (note: NOT the index of the scriptPubKey).
* @param scriptPubKey The connected scriptPubKey containing the conditions needed to claim the value.
* @param enforceP2SH Whether "pay to script hash" rules should be enforced. If in doubt, set to true.
* @throws VerificationException if this script does not correctly spend the scriptPubKey
*/
public void correctlySpends(Transaction txContainingThis, long index, Script scriptPubKey, boolean enforceP2SH) throws ScriptException {
public void correctlySpends(Transaction txContainingThis, long scriptSigIndex, Script scriptPubKey,
boolean enforceP2SH) throws ScriptException {
if (program.length > 10000 || scriptPubKey.program.length > 10000)
throw new ScriptException("Script larger than 10,000 bytes");
LinkedList<byte[]> stack = new LinkedList<byte[]>();
LinkedList<byte[]> p2shStack = null;
executeScript(txContainingThis, index, this, stack);
executeScript(txContainingThis, scriptSigIndex, this, stack);
if (enforceP2SH)
p2shStack = new LinkedList<byte[]>(stack);
executeScript(txContainingThis, index, scriptPubKey, stack);
executeScript(txContainingThis, scriptSigIndex, scriptPubKey, stack);
if (stack.size() == 0)
throw new ScriptException("Stack empty at end of script execution.");
@ -1520,7 +1526,7 @@ public class Script {
byte[] scriptPubKeyBytes = p2shStack.pollLast();
Script scriptPubKeyP2SH = new Script(params, scriptPubKeyBytes, 0, scriptPubKeyBytes.length);
executeScript(txContainingThis, index, scriptPubKeyP2SH, p2shStack);
executeScript(txContainingThis, scriptSigIndex, scriptPubKeyP2SH, p2shStack);
if (p2shStack.size() == 0)
throw new ScriptException("P2SH stack empty at end of script execution.");

View File

@ -340,4 +340,17 @@ public class TransactionInput extends ChildMessage implements Serializable {
public boolean hasSequence() {
return sequence != NO_SEQUENCE;
}
/**
* For a connected transaction, runs the script against the connected pubkey and verifies they are correct.
* @throws ScriptException if the script did not verify.
*/
public void verify() throws ScriptException {
Preconditions.checkNotNull(getOutpoint().fromTx, "Not connected");
long spendingIndex = getOutpoint().getIndex();
Script pubKey = getOutpoint().fromTx.getOutputs().get((int) spendingIndex).getScriptPubKey();
Script sig = getScriptSig();
int myIndex = parentTransaction.getInputs().indexOf(this);
sig.correctlySpends(parentTransaction, myIndex, pubKey, true);
}
}

View File

@ -89,8 +89,8 @@ public class WalletTest {
assertEquals(destination, t2.getOutputs().get(0).getScriptPubKey().getToAddress());
assertEquals(wallet.getChangeAddress(), t2.getOutputs().get(1).getScriptPubKey().getToAddress());
assertEquals(toNanoCoins(0, 49), t2.getOutputs().get(1).getValue());
// We have NOT proven that the signature is correct!
// Check the script runs and signatures verify.
t2.getInputs().get(0).verify();
final LinkedList<Transaction> txns = Lists.newLinkedList();
wallet.addEventListener(new AbstractWalletEventListener() {