3
0
mirror of https://github.com/Qortal/altcoinj.git synced 2025-01-31 23:32:16 +00:00

Script: Introduce a builder class that makes it easier to assemble scripts without writing raw byte streams.

This commit is contained in:
Mike Hearn 2013-04-24 19:15:06 +02:00
parent 752e7006e5
commit d113cbfc66
8 changed files with 163 additions and 75 deletions

View File

@ -17,6 +17,7 @@
package com.google.bitcoin.core; package com.google.bitcoin.core;
import com.google.bitcoin.script.Script; import com.google.bitcoin.script.Script;
import com.google.bitcoin.script.ScriptBuilder;
import com.google.common.base.Preconditions; import com.google.common.base.Preconditions;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@ -927,7 +928,8 @@ public class Block extends Message {
// Here we will do things a bit differently so a new address isn't needed every time. We'll put a simple // Here we will do things a bit differently so a new address isn't needed every time. We'll put a simple
// counter in the scriptSig so every transaction has a different hash. // counter in the scriptSig so every transaction has a different hash.
coinbase.addInput(new TransactionInput(params, coinbase, new byte[]{(byte) txCounter++, (byte) 1})); coinbase.addInput(new TransactionInput(params, coinbase, new byte[]{(byte) txCounter++, (byte) 1}));
coinbase.addOutput(new TransactionOutput(params, coinbase, value, Script.createOutputScript(pubKeyTo))); coinbase.addOutput(new TransactionOutput(params, coinbase, value,
ScriptBuilder.createOutputScript(new ECKey(null, pubKeyTo)).getProgram()));
transactions.add(coinbase); transactions.add(coinbase);
coinbase.setParent(this); coinbase.setParent(this);
coinbase.length = coinbase.bitcoinSerialize().length; coinbase.length = coinbase.bitcoinSerialize().length;

View File

@ -18,6 +18,7 @@ package com.google.bitcoin.core;
import com.google.bitcoin.core.TransactionConfidence.ConfidenceType; import com.google.bitcoin.core.TransactionConfidence.ConfidenceType;
import com.google.bitcoin.script.Script; import com.google.bitcoin.script.Script;
import com.google.bitcoin.script.ScriptBuilder;
import com.google.bitcoin.script.ScriptOpCodes; import com.google.bitcoin.script.ScriptOpCodes;
import com.google.common.base.Preconditions; import com.google.common.base.Preconditions;
import org.slf4j.Logger; import org.slf4j.Logger;
@ -714,17 +715,16 @@ public class Transaction extends ChildMessage implements Serializable {
} }
/** /**
* Once a transaction has some inputs and outputs added, the signatures in the inputs can be calculated. The * <p>Once a transaction has some inputs and outputs added, the signatures in the inputs can be calculated. The
* signature is over the transaction itself, to prove the redeemer actually created that transaction, * signature is over the transaction itself, to prove the redeemer actually created that transaction,
* so we have to do this step last.<p> * so we have to do this step last.</p>
* <p/>
* This method is similar to SignatureHash in script.cpp
* *
* @param hashType This should always be set to SigHash.ALL currently. Other types are unused. * @param hashType This should always be set to SigHash.ALL currently. Other types are unused.
* @param wallet A wallet is required to fetch the keys needed for signing. * @param wallet A wallet is required to fetch the keys needed for signing.
* @param aesKey The AES key to use to decrypt the key before signing. Null if no decryption is required. * @param aesKey The AES key to use to decrypt the key before signing. Null if no decryption is required.
*/ */
public synchronized void signInputs(SigHash hashType, Wallet wallet, KeyParameter aesKey) throws ScriptException { public synchronized void signInputs(SigHash hashType, Wallet wallet, KeyParameter aesKey) throws ScriptException {
// TODO: This should be a method of the TransactionInput that (possibly?) operates with a copy of this object.
Preconditions.checkState(inputs.size() > 0); Preconditions.checkState(inputs.size() > 0);
Preconditions.checkState(outputs.size() > 0); Preconditions.checkState(outputs.size() > 0);
@ -738,7 +738,8 @@ public class Transaction extends ChildMessage implements Serializable {
// Note that each input may be claiming an output sent to a different key. So we have to look at the outputs // Note that each input may be claiming an output sent to a different key. So we have to look at the outputs
// to figure out which key to sign with. // to figure out which key to sign with.
byte[][] signatures = new byte[inputs.size()][]; int[] sigHashFlags = new int[inputs.size()];
ECKey.ECDSASignature[] signatures = new ECKey.ECDSASignature[inputs.size()];
ECKey[] signingKeys = new ECKey[inputs.size()]; ECKey[] signingKeys = new ECKey[inputs.size()];
for (int i = 0; i < inputs.size(); i++) { for (int i = 0; i < inputs.size(); i++) {
TransactionInput input = inputs.get(i); TransactionInput input = inputs.get(i);
@ -756,18 +757,10 @@ public class Transaction extends ChildMessage implements Serializable {
byte[] connectedPubKeyScript = input.getOutpoint().getConnectedPubKeyScript(); byte[] connectedPubKeyScript = input.getOutpoint().getConnectedPubKeyScript();
Sha256Hash hash = hashTransactionForSignature(i, connectedPubKeyScript, hashType, anyoneCanPay); Sha256Hash hash = hashTransactionForSignature(i, connectedPubKeyScript, hashType, anyoneCanPay);
// Now sign for the output so we can redeem it. We use the keypair to sign the hash, // Now calculate the signatures we need to prove we own this transaction and are authorized to claim the
// and then put the resulting signature in the script along with the public key (below). // associated money.
try { signatures[i] = key.sign(hash, aesKey);
// Usually 71-73 bytes. sigHashFlags[i] = (hashType.ordinal() + 1) | (anyoneCanPay ? 0x80 : 0);
ByteArrayOutputStream bos = new UnsafeByteArrayOutputStream(73);
bos.write(key.sign(hash, aesKey).encodeToDER());
bos.write((hashType.ordinal() + 1) | (anyoneCanPay ? 0x80 : 0));
signatures[i] = bos.toByteArray();
bos.close();
} catch (IOException e) {
throw new RuntimeException(e); // Cannot happen.
}
} }
// Now we have calculated each signature, go through and create the scripts. Reminder: the script consists: // Now we have calculated each signature, go through and create the scripts. Reminder: the script consists:
@ -777,12 +770,11 @@ public class Transaction extends ChildMessage implements Serializable {
// 2) For pay-to-key outputs: just a signature. // 2) For pay-to-key outputs: just a signature.
for (int i = 0; i < inputs.size(); i++) { for (int i = 0; i < inputs.size(); i++) {
TransactionInput input = inputs.get(i); TransactionInput input = inputs.get(i);
ECKey key = signingKeys[i];
Script scriptPubKey = input.getOutpoint().getConnectedOutput().getScriptPubKey(); Script scriptPubKey = input.getOutpoint().getConnectedOutput().getScriptPubKey();
if (scriptPubKey.isSentToAddress()) { if (scriptPubKey.isSentToAddress()) {
input.setScriptBytes(Script.createInputScript(signatures[i], key.getPubKey())); input.setScriptSig(ScriptBuilder.createInputScript(signatures[i], signingKeys[i], sigHashFlags[i]));
} else if (scriptPubKey.isSentToRawPubKey()) { } else if (scriptPubKey.isSentToRawPubKey()) {
input.setScriptBytes(Script.createInputScript(signatures[i])); input.setScriptSig(ScriptBuilder.createInputScript(signatures[i], sigHashFlags[i]));
} else { } else {
// Should be unreachable - if we don't recognize the type of script we're trying to sign for, we should // Should be unreachable - if we don't recognize the type of script we're trying to sign for, we should
// have failed above when fetching the key to sign with. // have failed above when fetching the key to sign with.

View File

@ -154,7 +154,8 @@ public class TransactionInput extends ChildMessage implements Serializable {
} }
/** /**
* Returns the input script. * Returns the script that is fed to the referenced output (scriptPubKey) script in order to satisfy it: usually
* contains signatures and maybe keys, but can contain arbitrary data if the output script accepts it.
*/ */
public Script getScriptSig() throws ScriptException { public Script getScriptSig() throws ScriptException {
// Transactions that generate new coins don't actually have a script. Instead this // Transactions that generate new coins don't actually have a script. Instead this
@ -166,6 +167,13 @@ public class TransactionInput extends ChildMessage implements Serializable {
return scriptSig; return scriptSig;
} }
/** Set the given program as the scriptSig that is supposed to satisfy the connected output script. */
public void setScriptSig(Script scriptSig) {
this.scriptSig = checkNotNull(scriptSig);
// TODO: This should all be cleaned up so we have a consistent internal representation.
setScriptBytes(scriptSig.getProgram());
}
/** /**
* Convenience method that returns the from address of this input by parsing the scriptSig. The concept of a * Convenience method that returns the from address of this input by parsing the scriptSig. The concept of a
* "from address" is not well defined in Bitcoin and you should not assume that senders of a transaction can * "from address" is not well defined in Bitcoin and you should not assume that senders of a transaction can

View File

@ -17,6 +17,7 @@
package com.google.bitcoin.core; package com.google.bitcoin.core;
import com.google.bitcoin.script.Script; import com.google.bitcoin.script.Script;
import com.google.bitcoin.script.ScriptBuilder;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@ -91,7 +92,7 @@ public class TransactionOutput extends ChildMessage implements Serializable {
* {@link Transaction#addOutput(java.math.BigInteger, Address)} instead of creating a TransactionOutput directly. * {@link Transaction#addOutput(java.math.BigInteger, Address)} instead of creating a TransactionOutput directly.
*/ */
public TransactionOutput(NetworkParameters params, Transaction parent, BigInteger value, Address to) { public TransactionOutput(NetworkParameters params, Transaction parent, BigInteger value, Address to) {
this(params, parent, value, Script.createOutputScript(to)); this(params, parent, value, ScriptBuilder.createOutputScript(to).getProgram());
} }
/** /**
@ -100,7 +101,7 @@ public class TransactionOutput extends ChildMessage implements Serializable {
* {@link Transaction#addOutput(java.math.BigInteger, ECKey)} instead of creating an output directly. * {@link Transaction#addOutput(java.math.BigInteger, ECKey)} instead of creating an output directly.
*/ */
public TransactionOutput(NetworkParameters params, Transaction parent, BigInteger value, ECKey to) { public TransactionOutput(NetworkParameters params, Transaction parent, BigInteger value, ECKey to) {
this(params, parent, value, Script.createOutputScript(to)); this(params, parent, value, ScriptBuilder.createOutputScript(to).getProgram());
} }
public TransactionOutput(NetworkParameters params, Transaction parent, BigInteger value, byte[] scriptBytes) { public TransactionOutput(NetworkParameters params, Transaction parent, BigInteger value, byte[] scriptBytes) {

View File

@ -60,10 +60,15 @@ public class Script {
protected byte[] program; protected byte[] program;
/** Creates an empty script that serializes to nothing. */ /** Creates an empty script that serializes to nothing. */
public Script() { private Script() {
chunks = Lists.newArrayList(); chunks = Lists.newArrayList();
} }
// Used from ScriptBuilder.
Script(List<ScriptChunk> chunks) {
this.chunks = Collections.unmodifiableList(new ArrayList<ScriptChunk>(chunks));
}
/** /**
* Construct a Script that copies and wraps the programBytes array. The array is parsed and checked for syntactic * Construct a Script that copies and wraps the programBytes array. The array is parsed and checked for syntactic
* validity. * validity.
@ -267,44 +272,6 @@ public class Script {
} }
} }
public static byte[] createOutputScript(Address to) {
try {
// TODO: Do this by creating a Script *first* then having the script reassemble itself into bytes.
ByteArrayOutputStream bits = new UnsafeByteArrayOutputStream(24);
bits.write(OP_DUP);
bits.write(OP_HASH160);
writeBytes(bits, to.getHash160());
bits.write(OP_EQUALVERIFY);
bits.write(OP_CHECKSIG);
return bits.toByteArray();
} catch (IOException e) {
throw new RuntimeException(e); // Cannot happen.
}
}
/**
* Create a script that sends coins directly to the given public key (eg in a coinbase transaction).
*/
public static byte[] createOutputScript(byte[] pubkey) {
try {
// TODO: Do this by creating a Script *first* then having the script reassemble itself into bytes.
ByteArrayOutputStream bits = new UnsafeByteArrayOutputStream(pubkey.length + 1);
writeBytes(bits, pubkey);
bits.write(OP_CHECKSIG);
return bits.toByteArray();
} catch (IOException e) {
throw new RuntimeException(e); // Cannot happen.
}
}
/**
* Creates a script that sends coins directly to the given public key. Same as
* {@link Script#createOutputScript(byte[])} but more type safe.
*/
public static byte[] createOutputScript(ECKey pubkey) {
return createOutputScript(pubkey.getPubKey());
}
/** Creates a program that requires at least N of the given keys to sign, using OP_CHECKMULTISIG. */ /** Creates a program that requires at least N of the given keys to sign, using OP_CHECKMULTISIG. */
public static byte[] createMultiSigOutputScript(int threshold, List<ECKey> pubkeys) { public static byte[] createMultiSigOutputScript(int threshold, List<ECKey> pubkeys) {
checkArgument(threshold > 0); checkArgument(threshold > 0);
@ -379,10 +346,10 @@ public class Script {
return sigOps; return sigOps;
} }
private static int decodeFromOpN(byte opcode) { static int decodeFromOpN(byte opcode) {
return decodeFromOpN(0xFF & opcode); return decodeFromOpN(0xFF & opcode);
} }
private static int decodeFromOpN(int opcode) { static int decodeFromOpN(int opcode) {
checkArgument(opcode >= 0 && opcode <= OP_16, "decodeFromOpN called on non OP_N opcode"); checkArgument(opcode >= 0 && opcode <= OP_16, "decodeFromOpN called on non OP_N opcode");
if (opcode == OP_0) if (opcode == OP_0)
return 0; return 0;
@ -390,10 +357,10 @@ public class Script {
return opcode + 1 - OP_1; return opcode + 1 - OP_1;
} }
private static int encodeToOpN(byte value) { static int encodeToOpN(byte value) {
return encodeToOpN(0xFF & value); return encodeToOpN(0xFF & value);
} }
private static int encodeToOpN(int value) { static int encodeToOpN(int value) {
checkArgument(value >= 0 && value <= 16, "encodeToOpN called for a value we cannot encode in an opcode."); checkArgument(value >= 0 && value <= 16, "encodeToOpN called for a value we cannot encode in an opcode.");
if (value == 0) if (value == 0)
return OP_0; return OP_0;
@ -1086,6 +1053,7 @@ public class Script {
} catch (Exception e1) { } catch (Exception e1) {
// There is (at least) one exception that could be hit here (EOFException, if the sig is too short) // There is (at least) one exception that could be hit here (EOFException, if the sig is too short)
// Because I can't verify there aren't more, we use a very generic Exception catch // Because I can't verify there aren't more, we use a very generic Exception catch
log.warn(e1.toString());
sigValid = false; sigValid = false;
} }

View File

@ -0,0 +1,113 @@
/*
* Copyright 2013 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.bitcoin.script;
import com.google.bitcoin.core.Address;
import com.google.bitcoin.core.ECKey;
import com.google.common.collect.Lists;
import java.util.Arrays;
import java.util.List;
import static com.google.bitcoin.script.ScriptOpCodes.*;
import static com.google.common.base.Preconditions.checkArgument;
/**
* <p>Tools for the construction of commonly used script types. You don't normally need this as it's hidden behind
* convenience methods on {@link com.google.bitcoin.core.Transaction}, but they are useful when working with the
* protocol at a lower level.</p>
*/
public class ScriptBuilder {
private List<ScriptChunk> chunks;
public ScriptBuilder() {
chunks = Lists.newLinkedList();
}
public ScriptBuilder op(int opcode) {
chunks.add(new ScriptChunk(true, new byte[]{(byte)opcode}));
return this;
}
public ScriptBuilder data(byte[] data) {
byte[] copy = Arrays.copyOf(data, data.length);
chunks.add(new ScriptChunk(false, copy));
return this;
}
public ScriptBuilder smallNum(byte num) {
checkArgument(num >= 0, "Cannot encode negative numbers with smallNum");
checkArgument(num <= 16, "Cannot encode numbers larger than 16 with smallNum");
chunks.add(new ScriptChunk(true, new byte[]{(byte)Script.encodeToOpN(num)}));
return this;
}
public Script build() {
return new Script(chunks);
}
/** Creates a scriptPubKey that encodes payment to the given address. */
public static Script createOutputScript(Address to) {
// OP_DUP OP_HASH160 <pubKeyHash> OP_EQUALVERIFY OP_CHECKSIG
return new ScriptBuilder()
.op(OP_DUP)
.op(OP_HASH160)
.data(to.getHash160())
.op(OP_EQUALVERIFY)
.op(OP_CHECKSIG)
.build();
}
/** Creates a scriptPubKey that encodes payment to the given raw public key. */
public static Script createOutputScript(ECKey key) {
return new ScriptBuilder().data(key.getPubKey()).op(OP_CHECKSIG).build();
}
private static byte[] appendByte(byte[] buf, byte flags) {
byte[] result = Arrays.copyOf(buf, buf.length + 1);
result[result.length - 1] = flags;
return result;
}
/** Creates a scriptSig that can redeem a pay-to-address output. */
public static Script createInputScript(ECKey.ECDSASignature signature, ECKey pubKey, int sigHashFlags) {
byte[] pubkeyBytes = pubKey.getPubKey();
byte[] sigBytes = appendByte(signature.encodeToDER(), (byte) sigHashFlags);
return new ScriptBuilder().data(sigBytes).data(pubkeyBytes).build();
}
/** Creates a scriptSig that can redeem a pay-to-pubkey output. */
public static Script createInputScript(ECKey.ECDSASignature signature, int sigHashFlags) {
byte[] sigBytes = appendByte(signature.encodeToDER(), (byte) sigHashFlags);
return new ScriptBuilder().data(sigBytes).build();
}
/** Creates a program that requires at least N of the given keys to sign, using OP_CHECKMULTISIG. */
public static Script createMultiSigOutputScript(int threshold, List<ECKey> pubkeys) {
checkArgument(threshold > 0);
checkArgument(threshold <= pubkeys.size());
checkArgument(pubkeys.size() <= 16); // That's the max we can represent with a single opcode.
ScriptBuilder builder = new ScriptBuilder();
builder.smallNum((byte)threshold);
for (ECKey key : pubkeys) {
builder.data(key.getPubKey());
}
builder.smallNum((byte)pubkeys.size());
builder.op(OP_CHECKMULTISIG);
return builder.build();
}
}

View File

@ -2,6 +2,7 @@ package com.google.bitcoin.core;
import com.google.bitcoin.core.Transaction.SigHash; import com.google.bitcoin.core.Transaction.SigHash;
import com.google.bitcoin.script.Script; import com.google.bitcoin.script.Script;
import com.google.bitcoin.script.ScriptBuilder;
import com.google.common.base.Preconditions; import com.google.common.base.Preconditions;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
@ -811,6 +812,7 @@ public class FullBlockTestGenerator {
// A valid block created exactly like b44 to make sure the creation itself works // A valid block created exactly like b44 to make sure the creation itself works
Block b44 = new Block(params); Block b44 = new Block(params);
byte[] outScriptBytes = ScriptBuilder.createOutputScript(new ECKey(null, coinbaseOutKeyPubKey)).getProgram();
{ {
b44.setDifficultyTarget(b43.getDifficultyTarget()); b44.setDifficultyTarget(b43.getDifficultyTarget());
b44.addCoinbaseTransaction(coinbaseOutKeyPubKey, BigInteger.ZERO); b44.addCoinbaseTransaction(coinbaseOutKeyPubKey, BigInteger.ZERO);
@ -818,7 +820,7 @@ public class FullBlockTestGenerator {
Transaction t = new Transaction(params); Transaction t = new Transaction(params);
// Entirely invalid scriptPubKey to ensure we aren't pre-verifying too much // Entirely invalid scriptPubKey to ensure we aren't pre-verifying too much
t.addOutput(new TransactionOutput(params, t, BigInteger.valueOf(0), new byte[] {OP_PUSHDATA1 - 1 })); t.addOutput(new TransactionOutput(params, t, BigInteger.valueOf(0), new byte[] {OP_PUSHDATA1 - 1 }));
t.addOutput(new TransactionOutput(params, t, BigInteger.valueOf(1), Script.createOutputScript(coinbaseOutKeyPubKey))); t.addOutput(new TransactionOutput(params, t, BigInteger.valueOf(1), outScriptBytes));
// Spendable output // Spendable output
t.addOutput(new TransactionOutput(params, t, BigInteger.ZERO, new byte[] {OP_1})); t.addOutput(new TransactionOutput(params, t, BigInteger.ZERO, new byte[] {OP_1}));
addOnlyInputToTransaction(t, out14); addOnlyInputToTransaction(t, out14);
@ -841,7 +843,7 @@ public class FullBlockTestGenerator {
Transaction t = new Transaction(params); Transaction t = new Transaction(params);
// Entirely invalid scriptPubKey to ensure we aren't pre-verifying too much // Entirely invalid scriptPubKey to ensure we aren't pre-verifying too much
t.addOutput(new TransactionOutput(params, t, BigInteger.valueOf(0), new byte[] {OP_PUSHDATA1 - 1 })); t.addOutput(new TransactionOutput(params, t, BigInteger.valueOf(0), new byte[] {OP_PUSHDATA1 - 1 }));
t.addOutput(new TransactionOutput(params, t, BigInteger.valueOf(1), Script.createOutputScript(coinbaseOutKeyPubKey))); t.addOutput(new TransactionOutput(params, t, BigInteger.valueOf(1), outScriptBytes));
// Spendable output // Spendable output
t.addOutput(new TransactionOutput(params, t, BigInteger.ZERO, new byte[] {OP_1})); t.addOutput(new TransactionOutput(params, t, BigInteger.ZERO, new byte[] {OP_1}));
addOnlyInputToTransaction(t, out15); addOnlyInputToTransaction(t, out15);
@ -917,7 +919,7 @@ public class FullBlockTestGenerator {
{ {
Transaction coinbase = new Transaction(params); Transaction coinbase = new Transaction(params);
coinbase.addInput(new TransactionInput(params, coinbase, new byte[]{(byte) 0xff, 110, 1})); coinbase.addInput(new TransactionInput(params, coinbase, new byte[]{(byte) 0xff, 110, 1}));
coinbase.addOutput(new TransactionOutput(params, coinbase, BigInteger.ONE, Script.createOutputScript(coinbaseOutKeyPubKey))); coinbase.addOutput(new TransactionOutput(params, coinbase, BigInteger.ONE, outScriptBytes));
b51.addTransaction(coinbase, false); b51.addTransaction(coinbase, false);
} }
b51.solve(); b51.solve();
@ -1273,7 +1275,8 @@ public class FullBlockTestGenerator {
Transaction t = new Transaction(params); Transaction t = new Transaction(params);
// Entirely invalid scriptPubKey to ensure we aren't pre-verifying too much // Entirely invalid scriptPubKey to ensure we aren't pre-verifying too much
t.addOutput(new TransactionOutput(params, t, BigInteger.valueOf(0), new byte[] {OP_PUSHDATA1 - 1 })); t.addOutput(new TransactionOutput(params, t, BigInteger.valueOf(0), new byte[] {OP_PUSHDATA1 - 1 }));
t.addOutput(new TransactionOutput(params, t, BigInteger.valueOf(1), Script.createOutputScript(coinbaseOutKeyPubKey))); t.addOutput(new TransactionOutput(params, t, BigInteger.valueOf(1),
ScriptBuilder.createOutputScript(new ECKey(null, coinbaseOutKeyPubKey)).getProgram()));
// Spendable output // Spendable output
t.addOutput(new TransactionOutput(params, t, BigInteger.ZERO, new byte[] {OP_1})); t.addOutput(new TransactionOutput(params, t, BigInteger.ZERO, new byte[] {OP_1}));
addOnlyInputToTransaction(t, prevOut); addOnlyInputToTransaction(t, prevOut);

View File

@ -66,9 +66,9 @@ public class ScriptTest {
@Test @Test
public void testMultiSig() throws Exception { public void testMultiSig() throws Exception {
List<ECKey> keys = Lists.newArrayList(new ECKey(), new ECKey(), new ECKey()); List<ECKey> keys = Lists.newArrayList(new ECKey(), new ECKey(), new ECKey());
assertTrue(new Script(Script.createMultiSigOutputScript(2, keys)).isSentToMultiSig()); assertTrue(ScriptBuilder.createMultiSigOutputScript(2, keys).isSentToMultiSig());
assertTrue(new Script(Script.createMultiSigOutputScript(3, keys)).isSentToMultiSig()); assertTrue(ScriptBuilder.createMultiSigOutputScript(3, keys).isSentToMultiSig());
assertFalse(new Script(Script.createOutputScript(new ECKey())).isSentToMultiSig()); assertFalse(ScriptBuilder.createOutputScript(new ECKey()).isSentToMultiSig());
try { try {
// Fail if we ask for more signatures than keys. // Fail if we ask for more signatures than keys.
Script.createMultiSigOutputScript(4, keys); Script.createMultiSigOutputScript(4, keys);
@ -82,6 +82,7 @@ public class ScriptTest {
} catch (Throwable e) { } catch (Throwable e) {
// Expected. // Expected.
} }
// Actual execution is tested by the data driven tests.
} }
@Test @Test