Commit 80ff15b0 authored by Ivan Jose Lozano Fernandez's avatar Ivan Jose Lozano Fernandez Committed by Daniel Connolly

Test cases fix.

These scenarios have been fixed (Expected results from script_tests.json): SIG_DER, ILLEGAL_FORKID, SIG_HASHTYPE, SIG_PUSHONLY, CLEANSTACK, PUBKEYTYPE.
parent 744b548a
......@@ -24,7 +24,7 @@ package org.bitcoinj.script;
import org.bitcoinj.core.*;
import org.bitcoinj.core.VerificationException.*;
import org.bitcoinj.core.ScriptException.*;
import org.bitcoinj.crypto.TransactionSignature;
import com.google.common.collect.Lists;
import org.slf4j.Logger;
......@@ -87,7 +87,8 @@ public class Script {
CHECKSEQUENCEVERIFY,
SIGHASH_FORKID,
REPLAY_PROTECTION,
MONOLITH_OPCODES // May 15, 2018 Hard fork
MONOLITH_OPCODES, // May 15, 2018 Hard fork
PUBKEYTYPE // June 26, 29018.
}
public static final EnumSet<VerifyFlag> ALL_VERIFY_FLAGS = EnumSet.allOf(VerifyFlag.class);
......@@ -202,16 +203,19 @@ public class Script {
// Read some bytes of data, where how many is the opcode value itself.
dataToRead = opcode;
} else if (opcode == OP_PUSHDATA1) {
if (bis.available() < 1) throw new BadOpcodeException();
if (bis.available() < 1)
throw new ScriptException(ScriptError.SCRIPT_ERR_BAD_OPCODE, "an illegal opcode is present in the script");
dataToRead = bis.read();
} else if (opcode == OP_PUSHDATA2) {
// Read a short, then read that many bytes of data.
if (bis.available() < 2) throw new InvalidStackOperationException();
if (bis.available() < 2)
throw new ScriptException(ScriptError.SCRIPT_ERR_INVALID_STACK_OPERATION, "he operation was invalid given the contents of the stack");
dataToRead = bis.read() | (bis.read() << 8);
} else if (opcode == OP_PUSHDATA4) {
// Read a uint32, then read that many bytes of data.
// Though this is allowed, because its value cannot be > 520, it should never actually be used
if (bis.available() < 4) throw new InvalidStackOperationException();
if (bis.available() < 4) throw new ScriptException(ScriptError.SCRIPT_ERR_INVALID_STACK_OPERATION, "he operation was invalid given the contents of the stack");
dataToRead = ((long)bis.read()) | (((long)bis.read()) << 8) | (((long)bis.read()) << 16) | (((long)bis.read()) << 24);
}
......@@ -220,7 +224,7 @@ public class Script {
chunk = new ScriptChunk(opcode, null, startLocationInProgram);
} else {
if (dataToRead > bis.available())
throw new BadOpcodeException();
throw new ScriptException(ScriptError.SCRIPT_ERR_BAD_OPCODE, "an illegal opcode is present in the script");
byte[] data = new byte[(int)dataToRead];
checkState(dataToRead == 0 || bis.read(data, 0, (int)dataToRead) == dataToRead);
chunk = new ScriptChunk(opcode, data, startLocationInProgram);
......@@ -285,7 +289,7 @@ public class Script {
else if (isPayToScriptHash())
return chunks.get(1).data;
else
throw new NonStandardScriptException();
throw new ScriptException(ScriptError.SCRIPT_ERR_STANDARD, "script is not a recognized standard script");
}
/**
......@@ -298,7 +302,7 @@ public class Script {
*/
public byte[] getPubKey() {
if (chunks.size() != 2) {
throw new InvalidStackOperationException();
throw new ScriptException(ScriptError.SCRIPT_ERR_INVALID_STACK_OPERATION, "he operation was invalid given the contents of the stack");
}
final ScriptChunk chunk0 = chunks.get(0);
final byte[] chunk0data = chunk0.data;
......@@ -311,7 +315,7 @@ public class Script {
// A large constant followed by an OP_CHECKSIG is the key.
return chunk0data;
} else {
throw new InvalidStackOperationException();
throw new ScriptException(ScriptError.SCRIPT_ERR_INVALID_STACK_OPERATION, "he operation was invalid given the contents of the stack");
}
}
......@@ -989,13 +993,14 @@ public class Script {
stack.add(new byte[] {});
} else if (!chunk.isOpCode()) {
if (chunk.data.length > MAX_SCRIPT_ELEMENT_SIZE)
throw new PushSizeException();
throw new ScriptException(ScriptError.SCRIPT_ERR_PUSH_SIZE, "attempted to push value on the stack that was too large");
if (!shouldExecute)
continue;
if (enforceMinimal && !checkMinimalPush(chunk.opcode, chunk.data))
throw new MinimalDataException();
if (enforceMinimal && !chunk.isShortestPossiblePushData())
throw new ScriptException(ScriptError.SCRIPT_ERR_MINIMALDATA
, "PushData operation not compliant to Minimal data. A more specific opCode should be used.");
stack.add(chunk.data);
} else {
......@@ -1003,15 +1008,15 @@ public class Script {
if (opcode > OP_16) {
opCount++;
if (opCount > 201)
throw new OpCountException();
throw new ScriptException(ScriptError.SCRIPT_ERR_OP_COUNT, "script contains too many opcodes");
}
if (opcode == OP_VERIF || opcode == OP_VERNOTIF)
throw new BadOpcodeException();
throw new ScriptException(ScriptError.SCRIPT_ERR_BAD_OPCODE, "an illegal opcode is present in the script");
// Some opcodes are disabled.
if (isOpcodeDisabled(opcode, verifyFlags)) {
throw new DisabledOpcodeException();
throw new ScriptException(ScriptError.SCRIPT_ERR_DISABLED_OPCODE, "script includes a disabled opcode");
}
......@@ -1024,11 +1029,11 @@ public class Script {
continue;
}
if (stack.isEmpty())
throw new UnbalancedConditionalException();
throw new ScriptException(ScriptError.SCRIPT_ERR_UNBALANCED_CONDITIONAL, "the script contains an unbalanced conditional");
// We check MINIMALIF Flag (IMPORTANT: We use peekLast, so the stack is not consumed)
if (verifyFlags.contains(VerifyFlag.MINIMALIF) && !checkMinimalIf(stack.peekLast())) {
throw new MinimalIfException();
throw new ScriptException(ScriptError.SCRIPT_ERR_MINIMALIF, "op of the Stack does NOT meet the MINIMALIF requirements");
}
ifStack.add(castToBool(stack.pollLast()));
......@@ -1039,23 +1044,23 @@ public class Script {
continue;
}
if (stack.isEmpty())
throw new UnbalancedConditionalException();
throw new ScriptException(ScriptError.SCRIPT_ERR_UNBALANCED_CONDITIONAL, "the script contains an unbalanced conditional");
// We check MINIMALIF Flag (IMPORTANT: We use peekLast, so the stack is not consumed)
if (verifyFlags.contains(VerifyFlag.MINIMALIF) && !checkMinimalIf(stack.peekLast())) {
throw new MinimalIfException();
throw new ScriptException(ScriptError.SCRIPT_ERR_MINIMALIF, "op of the Stack does NOT meet the MINIMALIF requirements");
}
ifStack.add(!castToBool(stack.pollLast()));
continue;
case OP_ELSE:
if (ifStack.isEmpty())
throw new UnbalancedConditionalException();
throw new ScriptException(ScriptError.SCRIPT_ERR_UNBALANCED_CONDITIONAL, "the script contains an unbalanced conditional");
ifStack.add(!ifStack.pollLast());
continue;
case OP_ENDIF:
if (ifStack.isEmpty())
throw new UnbalancedConditionalException();
throw new ScriptException(ScriptError.SCRIPT_ERR_UNBALANCED_CONDITIONAL, "the script contains an unbalanced conditional");
ifStack.pollLast();
continue;
}
......@@ -1090,31 +1095,32 @@ public class Script {
break;
case OP_VERIFY:
if (stack.isEmpty())
throw new InvalidStackOperationException();
throw new ScriptException(ScriptError.SCRIPT_ERR_INVALID_STACK_OPERATION, "the operation was invalid given the contents of the stack");
if (!castToBool(stack.pollLast()))
throw new OpVerifyFailed();
throw new ScriptException(ScriptError.SCRIPT_ERR_VERIFY, "the VERIFY failed");
break;
case OP_RETURN:
throw new OpReturnException();
throw new ScriptException(ScriptError.SCRIPT_ERR_OP_RETURN, "the script called OP_RETURN");
case OP_TOALTSTACK:
if (stack.isEmpty())
throw new InvalidStackOperationException();
throw new ScriptException(ScriptError.SCRIPT_ERR_INVALID_STACK_OPERATION, "the operation was invalid given the contents of the stack");
altstack.add(stack.pollLast());
break;
case OP_FROMALTSTACK:
if (altstack.isEmpty())
throw new InvalidAltStackOperationException();
throw new ScriptException(ScriptError.SCRIPT_ERR_INVALID_ALTSTACK_OPERATION,
"the operation was invalid given the contents of the altstack");
stack.add(altstack.pollLast());
break;
case OP_2DROP:
if (stack.size() < 2)
throw new InvalidStackOperationException();
throw new ScriptException(ScriptError.SCRIPT_ERR_INVALID_STACK_OPERATION, "the operation was invalid given the contents of the stack");
stack.pollLast();
stack.pollLast();
break;
case OP_2DUP:
if (stack.size() < 2)
throw new InvalidStackOperationException();
throw new ScriptException(ScriptError.SCRIPT_ERR_INVALID_STACK_OPERATION, "the operation was invalid given the contents of the stack");
Iterator<byte[]> it2DUP = stack.descendingIterator();
byte[] OP2DUPtmpChunk2 = it2DUP.next();
stack.add(it2DUP.next());
......@@ -1122,7 +1128,7 @@ public class Script {
break;
case OP_3DUP:
if (stack.size() < 3)
throw new InvalidStackOperationException();
throw new ScriptException(ScriptError.SCRIPT_ERR_INVALID_STACK_OPERATION, "the operation was invalid given the contents of the stack");
Iterator<byte[]> it3DUP = stack.descendingIterator();
byte[] OP3DUPtmpChunk3 = it3DUP.next();
byte[] OP3DUPtmpChunk2 = it3DUP.next();
......@@ -1132,7 +1138,7 @@ public class Script {
break;
case OP_2OVER:
if (stack.size() < 4)
throw new InvalidStackOperationException();
throw new ScriptException(ScriptError.SCRIPT_ERR_INVALID_STACK_OPERATION, "the operation was invalid given the contents of the stack");
Iterator<byte[]> it2OVER = stack.descendingIterator();
it2OVER.next();
it2OVER.next();
......@@ -1142,7 +1148,7 @@ public class Script {
break;
case OP_2ROT:
if (stack.size() < 6)
throw new InvalidStackOperationException();
throw new ScriptException(ScriptError.SCRIPT_ERR_INVALID_STACK_OPERATION, "the operation was invalid given the contents of the stack");
byte[] OP2ROTtmpChunk6 = stack.pollLast();
byte[] OP2ROTtmpChunk5 = stack.pollLast();
byte[] OP2ROTtmpChunk4 = stack.pollLast();
......@@ -1158,7 +1164,7 @@ public class Script {
break;
case OP_2SWAP:
if (stack.size() < 4)
throw new InvalidStackOperationException();
throw new ScriptException(ScriptError.SCRIPT_ERR_INVALID_STACK_OPERATION, "the operation was invalid given the contents of the stack");
byte[] OP2SWAPtmpChunk4 = stack.pollLast();
byte[] OP2SWAPtmpChunk3 = stack.pollLast();
byte[] OP2SWAPtmpChunk2 = stack.pollLast();
......@@ -1170,7 +1176,7 @@ public class Script {
break;
case OP_IFDUP:
if (stack.isEmpty())
throw new InvalidStackOperationException();
throw new ScriptException(ScriptError.SCRIPT_ERR_INVALID_STACK_OPERATION, "the operation was invalid given the contents of the stack");
if (castToBool(stack.getLast()))
stack.add(stack.getLast());
break;
......@@ -1179,24 +1185,24 @@ public class Script {
break;
case OP_DROP:
if (stack.isEmpty())
throw new InvalidStackOperationException();
throw new ScriptException(ScriptError.SCRIPT_ERR_INVALID_STACK_OPERATION, "the operation was invalid given the contents of the stack");
stack.pollLast();
break;
case OP_DUP:
if (stack.isEmpty())
throw new InvalidStackOperationException();
throw new ScriptException(ScriptError.SCRIPT_ERR_INVALID_STACK_OPERATION, "the operation was invalid given the contents of the stack");
stack.add(stack.getLast());
break;
case OP_NIP:
if (stack.size() < 2)
throw new InvalidStackOperationException();
throw new ScriptException(ScriptError.SCRIPT_ERR_INVALID_STACK_OPERATION, "the operation was invalid given the contents of the stack");
byte[] OPNIPtmpChunk = stack.pollLast();
stack.pollLast();
stack.add(OPNIPtmpChunk);
break;
case OP_OVER:
if (stack.size() < 2)
throw new InvalidStackOperationException();
throw new ScriptException(ScriptError.SCRIPT_ERR_INVALID_STACK_OPERATION, "the operation was invalid given the contents of the stack");
Iterator<byte[]> itOVER = stack.descendingIterator();
itOVER.next();
stack.add(itOVER.next());
......@@ -1204,10 +1210,10 @@ public class Script {
case OP_PICK:
case OP_ROLL:
if (stack.isEmpty())
throw new InvalidStackOperationException();
throw new ScriptException(ScriptError.SCRIPT_ERR_INVALID_STACK_OPERATION, "the operation was invalid given the contents of the stack");
long val = castToBigInteger(stack.pollLast(), enforceMinimal).longValue();
if (val < 0 || val >= stack.size())
throw new InvalidStackOperationException();
throw new ScriptException(ScriptError.SCRIPT_ERR_INVALID_STACK_OPERATION, "the operation was invalid given the contents of the stack");
Iterator<byte[]> itPICK = stack.descendingIterator();
for (long i = 0; i < val; i++)
itPICK.next();
......@@ -1218,7 +1224,7 @@ public class Script {
break;
case OP_ROT:
if (stack.size() < 3)
throw new InvalidStackOperationException();
throw new ScriptException(ScriptError.SCRIPT_ERR_INVALID_STACK_OPERATION, "the operation was invalid given the contents of the stack");
byte[] OPROTtmpChunk3 = stack.pollLast();
byte[] OPROTtmpChunk2 = stack.pollLast();
byte[] OPROTtmpChunk1 = stack.pollLast();
......@@ -1229,7 +1235,7 @@ public class Script {
case OP_SWAP:
case OP_TUCK:
if (stack.size() < 2)
throw new InvalidStackOperationException();
throw new ScriptException(ScriptError.SCRIPT_ERR_INVALID_STACK_OPERATION, "the operation was invalid given the contents of the stack");
byte[] OPSWAPtmpChunk2 = stack.pollLast();
byte[] OPSWAPtmpChunk1 = stack.pollLast();
stack.add(OPSWAPtmpChunk2);
......@@ -1240,13 +1246,13 @@ public class Script {
//byte string operations
case OP_CAT:
if (stack.size() < 2)
throw new InvalidStackOperationException();
throw new ScriptException(ScriptError.SCRIPT_ERR_INVALID_STACK_OPERATION, "the operation was invalid given the contents of the stack");
byte[] catBytes2 = stack.pollLast();
byte[] catBytes1 = stack.pollLast();
int len = catBytes1.length + catBytes2.length;
if (len > MAX_SCRIPT_ELEMENT_SIZE)
throw new PushSizeException();
throw new ScriptException(ScriptError.SCRIPT_ERR_PUSH_SIZE, "attempted to push value on the stack that was too large");
byte[] catOut = new byte[len];
System.arraycopy(catBytes1, 0, catOut, 0, catBytes1.length);
......@@ -1257,7 +1263,7 @@ public class Script {
case OP_SPLIT:
if (stack.size() < 2)
throw new InvalidStackOperationException();
throw new ScriptException(ScriptError.SCRIPT_ERR_INVALID_STACK_OPERATION, "the operation was invalid given the contents of the stack");
BigInteger biSplitPos = castToBigInteger(stack.pollLast(), enforceMinimal);
......@@ -1267,13 +1273,13 @@ public class Script {
//is greater than the target type can hold.
BigInteger biMaxInt = BigInteger.valueOf((long) Integer.MAX_VALUE);
if (biSplitPos.compareTo(biMaxInt) >= 0)
throw new SplitRangeException();
throw new ScriptException(ScriptError.SCRIPT_ERR_SPLIT_RANGE, "invalid OP_SPLIT range");
int splitPos = biSplitPos.intValue();
byte[] splitBytes = stack.pollLast();
if (splitPos > splitBytes.length || splitPos < 0)
throw new SplitRangeException();
throw new ScriptException(ScriptError.SCRIPT_ERR_SPLIT_RANGE, "invalid OP_SPLIT range");
byte[] splitOut1 = new byte[splitPos];
byte[] splitOut2 = new byte[splitBytes.length - splitPos];
......@@ -1287,12 +1293,12 @@ public class Script {
case OP_NUM2BIN:
if (stack.size() < 2)
throw new InvalidStackOperationException();
throw new ScriptException(ScriptError.SCRIPT_ERR_INVALID_STACK_OPERATION, "the operation was invalid given the contents of the stack");
int numSize = castToBigInteger(stack.pollLast(), enforceMinimal).intValue();
if (numSize > MAX_SCRIPT_ELEMENT_SIZE || numSize < 0)
throw new PushSizeException();
throw new ScriptException(ScriptError.SCRIPT_ERR_PUSH_SIZE, "attempted to push value on the stack that was too large");
byte[] rawNumBytes = stack.pollLast();
......@@ -1301,7 +1307,7 @@ public class Script {
byte[] minimalNumBytes = Utils.minimallyEncodeLE(rawNumBytes);
if (minimalNumBytes.length > numSize) {
//we can't
throw new ImpossibleEncoding();
throw new ScriptException(ScriptError.SCRIPT_ERR_IMPOSSIBLE_ENCODING, "the encoding is not possible");
}
if (minimalNumBytes.length == numSize) {
......@@ -1325,30 +1331,30 @@ public class Script {
case OP_BIN2NUM:
if (stack.isEmpty())
throw new InvalidStackOperationException();
throw new ScriptException(ScriptError.SCRIPT_ERR_INVALID_STACK_OPERATION, "the operation was invalid given the contents of the stack");
byte[] binBytes = stack.pollLast();
byte[] numBytes = Utils.minimallyEncodeLE(binBytes);
if (!Utils.checkMinimallyEncodedLE(numBytes, DEFAULT_MAX_NUM_ELEMENT_SIZE))
throw new InvalidNumberRangeException();
throw new ScriptException(ScriptError.SCRIPT_ERR_INVALID_NUMBER_RANGE, "operand is not a number in the valid range");
stack.addLast(numBytes);
break;
case OP_SIZE:
if (stack.isEmpty())
throw new InvalidStackOperationException();
throw new ScriptException(ScriptError.SCRIPT_ERR_INVALID_STACK_OPERATION, "the operation was invalid given the contents of the stack");
stack.add(Utils.reverseBytes(Utils.encodeMPI(BigInteger.valueOf(stack.getLast().length), false)));
break;
case OP_INVERT:
throw new DisabledOpcodeException();
throw new ScriptException(ScriptError.SCRIPT_ERR_DISABLED_OPCODE, "script includes a disabled opcode");
case OP_AND:
case OP_OR:
case OP_XOR:
// (x1 x2 - out)
if (stack.size() < 2) {
throw new InvalidStackOperationException();
throw new ScriptException(ScriptError.SCRIPT_ERR_INVALID_STACK_OPERATION, "the operation was invalid given the contents of the stack");
}
//valtype &vch1 = stacktop(-2);
......@@ -1358,7 +1364,7 @@ public class Script {
// Inputs must be the same size
if (vch1.length != vch2.length) {
throw new OperandSizeException();
throw new ScriptException(ScriptError.SCRIPT_ER_OPERAND_SIZE, "invalid operand size");
}
// To avoid allocating, we modify vch1 in place.
......@@ -1392,14 +1398,14 @@ public class Script {
case OP_EQUAL:
if (stack.size() < 2)
throw new InvalidStackOperationException();
throw new ScriptException(ScriptError.SCRIPT_ERR_INVALID_STACK_OPERATION, "the operation was invalid given the contents of the stack");
stack.add(Arrays.equals(stack.pollLast(), stack.pollLast()) ? new byte[] {1} : new byte[] {});
break;
case OP_EQUALVERIFY:
if (stack.size() < 2)
throw new InvalidStackOperationException();
throw new ScriptException(ScriptError.SCRIPT_ERR_INVALID_STACK_OPERATION, "the operation was invalid given the contents of the stack");
if (!Arrays.equals(stack.pollLast(), stack.pollLast()))
throw new EqualVerifyException();
throw new ScriptException(ScriptError.SCRIPT_ERR_EQUALVERIFY, "OP_EQUALVERIFY failed, non-equal operands");
break;
case OP_1ADD:
case OP_1SUB:
......@@ -1408,7 +1414,7 @@ public class Script {
case OP_NOT:
case OP_0NOTEQUAL:
if (stack.isEmpty())
throw new InvalidStackOperationException();
throw new ScriptException(ScriptError.SCRIPT_ERR_INVALID_STACK_OPERATION, "the operation was invalid given the contents of the stack");
BigInteger numericOPnum = castToBigInteger(stack.pollLast(), enforceMinimal);
switch (opcode) {
......@@ -1445,7 +1451,7 @@ public class Script {
break;
case OP_2MUL:
case OP_2DIV:
throw new DisabledOpcodeException();
throw new ScriptException(ScriptError.SCRIPT_ERR_DISABLED_OPCODE, "script includes a disabled opcode");
case OP_ADD:
case OP_SUB:
case OP_DIV:
......@@ -1461,7 +1467,7 @@ public class Script {
case OP_MIN:
case OP_MAX:
if (stack.size() < 2)
throw new InvalidStackOperationException();
throw new ScriptException(ScriptError.SCRIPT_ERR_INVALID_STACK_OPERATION, "the operation was invalid given the contents of the stack");
BigInteger numericOPnum2 = castToBigInteger(stack.pollLast(), enforceMinimal);
BigInteger numericOPnum1 = castToBigInteger(stack.pollLast(), enforceMinimal);
......@@ -1476,13 +1482,13 @@ public class Script {
case OP_DIV:
if (numericOPnum2.intValue() == 0)
throw new DivByZeroException();
throw new ScriptException(ScriptError.SCRIPT_ERR_DIV_BY_ZERO, "divide by zero error");
numericOPresult = numericOPnum1.divide(numericOPnum2);
break;
case OP_MOD:
if (numericOPnum2.intValue() == 0)
throw new ModByZeroException();
throw new ScriptException(ScriptError.SCRIPT_ERR_MOD_BY_ZERO, "modulo by zero error");
/**
* BigInteger doesn't behave the way we want for modulo operations. Firstly it's
......@@ -1575,19 +1581,19 @@ public class Script {
case OP_MUL:
case OP_LSHIFT:
case OP_RSHIFT:
throw new DisabledOpcodeException();
throw new ScriptException(ScriptError.SCRIPT_ERR_DISABLED_OPCODE, "script includes a disabled opcode");
case OP_NUMEQUALVERIFY:
if (stack.size() < 2)
throw new InvalidStackOperationException();
throw new ScriptException(ScriptError.SCRIPT_ERR_INVALID_STACK_OPERATION, "the operation was invalid given the contents of the stack");
BigInteger OPNUMEQUALVERIFYnum2 = castToBigInteger(stack.pollLast(), enforceMinimal);
BigInteger OPNUMEQUALVERIFYnum1 = castToBigInteger(stack.pollLast(), enforceMinimal);
if (!OPNUMEQUALVERIFYnum1.equals(OPNUMEQUALVERIFYnum2))
throw new NumEqualVerifyException();
throw new ScriptException(ScriptError.SCRIPT_ERR_NUMEQUALVERIFY, "P_NUMEQUALVERIFY failed, non-equal operands");
break;
case OP_WITHIN:
if (stack.size() < 3)
throw new InvalidStackOperationException();
throw new ScriptException(ScriptError.SCRIPT_ERR_INVALID_STACK_OPERATION, "the operation was invalid given the contents of the stack");
BigInteger OPWITHINnum3 = castToBigInteger(stack.pollLast(), enforceMinimal);
BigInteger OPWITHINnum2 = castToBigInteger(stack.pollLast(), enforceMinimal);
BigInteger OPWITHINnum1 = castToBigInteger(stack.pollLast(), enforceMinimal);
......@@ -1598,7 +1604,7 @@ public class Script {
break;
case OP_RIPEMD160:
if (stack.isEmpty())
throw new InvalidStackOperationException();
throw new ScriptException(ScriptError.SCRIPT_ERR_INVALID_STACK_OPERATION, "the operation was invalid given the contents of the stack");
RIPEMD160Digest digest = new RIPEMD160Digest();
byte[] dataToHash = stack.pollLast();
digest.update(dataToHash, 0, dataToHash.length);
......@@ -1608,7 +1614,7 @@ public class Script {
break;
case OP_SHA1:
if (stack.isEmpty())
throw new InvalidStackOperationException();
throw new ScriptException(ScriptError.SCRIPT_ERR_INVALID_STACK_OPERATION, "the operation was invalid given the contents of the stack");
try {
stack.add(MessageDigest.getInstance("SHA-1").digest(stack.pollLast()));
} catch (NoSuchAlgorithmException e) {
......@@ -1617,17 +1623,17 @@ public class Script {
break;
case OP_SHA256:
if (stack.isEmpty())
throw new InvalidStackOperationException();
throw new ScriptException(ScriptError.SCRIPT_ERR_INVALID_STACK_OPERATION, "the operation was invalid given the contents of the stack");
stack.add(Sha256Hash.hash(stack.pollLast()));
break;
case OP_HASH160:
if (stack.isEmpty())
throw new InvalidStackOperationException();
throw new ScriptException(ScriptError.SCRIPT_ERR_INVALID_STACK_OPERATION, "the operation was invalid given the contents of the stack");
stack.add(Utils.sha256hash160(stack.pollLast()));
break;
case OP_HASH256:
if (stack.isEmpty())
throw new InvalidStackOperationException();
throw new ScriptException(ScriptError.SCRIPT_ERR_INVALID_STACK_OPERATION, "the operation was invalid given the contents of the stack");
stack.add(Sha256Hash.hashTwice(stack.pollLast()));
break;
case OP_CODESEPARATOR:
......@@ -1649,7 +1655,7 @@ public class Script {
if (!verifyFlags.contains(VerifyFlag.CHECKLOCKTIMEVERIFY)) {
// not enabled; treat as a NOP2
if (verifyFlags.contains(VerifyFlag.DISCOURAGE_UPGRADABLE_NOPS)) {
throw new DiscourageUpgradableNopsException();
throw new ScriptException(ScriptError.SCRIPT_ERR_DISCOURAGE_UPGRADABLE_NOPS, "script used a reserved opcode");
}
break;
}
......@@ -1659,7 +1665,7 @@ public class Script {
if (!verifyFlags.contains(VerifyFlag.CHECKSEQUENCEVERIFY)) {
// not enabled; treat as a NOP2
if (verifyFlags.contains(VerifyFlag.DISCOURAGE_UPGRADABLE_NOPS)) {
throw new DiscourageUpgradableNopsException();
throw new ScriptException(ScriptError.SCRIPT_ERR_DISCOURAGE_UPGRADABLE_NOPS, "script used a reserved opcode");
}
break;
}
......@@ -1674,17 +1680,17 @@ public class Script {
case OP_NOP9:
case OP_NOP10:
if (verifyFlags.contains(VerifyFlag.DISCOURAGE_UPGRADABLE_NOPS)) {
throw new DiscourageUpgradableNopsException();
throw new ScriptException(ScriptError.SCRIPT_ERR_DISCOURAGE_UPGRADABLE_NOPS, "script used a reserved opcode");
}
break;
default:
throw new BadOpcodeException();
throw new ScriptException(ScriptError.SCRIPT_ERR_BAD_OPCODE, "an illegal opcode is present in the script");
}
}
if (stack.size() + altstack.size() > 1000 || stack.size() + altstack.size() < 0)
throw new StackSizeException();
throw new ScriptException(ScriptError.SCRIPT_ERR_STACK_SIZE, "stack is, or would be, too large");
if (scriptStateListener != null) {
scriptStateListener.onAfterOpCodeExectuted();
......@@ -1692,7 +1698,7 @@ public class Script {
}
if (!ifStack.isEmpty())
throw new UnbalancedConditionalException();
throw new ScriptException(ScriptError.SCRIPT_ERR_UNBALANCED_CONDITIONAL, "the script contains an unbalanced conditional");
if (scriptStateListener != null) {
scriptStateListener.onScriptComplete();
......@@ -1704,14 +1710,14 @@ public class Script {
int lastCodeSepLocation, int opcode,
Set<VerifyFlag> verifyFlags) {
if (stack.isEmpty())
throw new InvalidStackOperationException();
throw new ScriptException(ScriptError.SCRIPT_ERR_INVALID_STACK_OPERATION, "the operation was invalid given the contents of the stack");
// Thus as a special case we tell CScriptNum to accept up
// to 5-byte bignums to avoid year 2038 issue.
final BigInteger nLockTime = castToBigInteger(stack.getLast(), 5, verifyFlags.contains(VerifyFlag.MINIMALDATA));
if (nLockTime.compareTo(BigInteger.ZERO) < 0)
throw new NegativeLocktime();
throw new ScriptException(ScriptError.SCRIPT_ERR_NEGATIVE_LOCKTIME, "Negative locktime");
// There are two kinds of nLockTime, need to ensure we're comparing apples-to-apples
if (!(
......@@ -1723,7 +1729,7 @@ public class Script {
// Now that we know we're comparing apples-to-apples, the
// comparison is a simple numeric one.
if (nLockTime.compareTo(BigInteger.valueOf(txContainingThis.getLockTime())) > 0)
throw new UnsatisfiedLocktime("Locktime requirement not satisfied");
throw new ScriptException(ScriptError.SCRIPT_ERR_UNSATISFIED_LOCKTIME, "Locktime requirement not satisfied");
// Finally the nLockTime feature can be disabled and thus
// CHECKLOCKTIMEVERIFY bypassed if every txin has been
......@@ -1736,15 +1742,16 @@ public class Script {
// inputs, but testing just this input minimizes the data
// required to prove correct CHECKLOCKTIMEVERIFY execution.
if (!txContainingThis.getInput(index).hasSequence())
throw new UnsatisfiedLocktime("Transaction contains a final transaction input for a CHECKLOCKTIMEVERIFY script.");
throw new ScriptException(ScriptError.SCRIPT_ERR_UNSATISFIED_LOCKTIME
, "Transaction contains a final transaction input for a CHECKLOCKTIMEVERIFY script.");
}
/**
* Implementation of the CHECKSEQUENCEVERIFY OpCode, as defined in BIP 112.
* Implementation from Bitcoin-abc used as a reference.
* (Implementation from Bitcoin-abc used as a reference)
*
* @param txContainingThis Transaction this script is included into
* @param index position within the script
* @param index index
* @param script Script to execute
* @param stack Script execution stack
* @param verifyFlags Verification flags
......@@ -1754,27 +1761,29 @@ public class Script {
Set<VerifyFlag> verifyFlags) {
// If the stack is empty, we raise an Error
if (stack.isEmpty())
throw new InvalidStackOperationException();
throw new ScriptException(ScriptError.SCRIPT_ERR_INVALID_STACK_OPERATION, "he operation was invalid given the contents of the stack");
// Thus as a special case we tell CScriptNum to accept up
// to 5-byte bignums to avoid year 2038 issue.
final BigInteger nSequence = castToBigInteger(stack.getLast(), 5, verifyFlags.contains(VerifyFlag.MINIMALDATA));
// Thus as a special case we accept up to 5-byte bignums to avoid year 2038 issue.
final long nSequence = castToBigInteger(stack.getLast()
, 5
, verifyFlags.contains(VerifyFlag.MINIMALDATA)).longValue();
if (nSequence < 0)
throw new ScriptException(ScriptError.SCRIPT_ERR_NEGATIVE_LOCKTIME, "Negative locktime");
if (nSequence.compareTo(BigInteger.ZERO) < 0)
throw new NegativeLocktime();
// if the 31-bit bit is enabled, we continue with the execution, otherwise
// we do nothing else and let the rest of the script execute...
// 31 bit enabled = 0x80000000
BigInteger disabledFlagMask = new BigInteger("80000000", 16);
if (nSequence.and(disabledFlagMask).compareTo(BigInteger.ZERO) == 0)
if ((nSequence & TransactionInput.SEQUENCE_LOCKTIME_DISABLE_FLAG) == 0)
if (!checkSequence(txContainingThis, nSequence, index))
throw new UnsatisfiedLocktime("Relative time lock requirement not satisfied");
throw new ScriptException(ScriptError.SCRIPT_ERR_UNSATISFIED_LOCKTIME, "Relative time lock requirement not satisfied");
}
/**
* Auxiliar method for the CHECKSEUQNCEVERUFY Op. It checks the nSequence from the top of the stack against
* Auxiliar method for the CHECKSEUQNCEVERIFY Op. It checks the nSequence from the top of the stack against
* The sequence in the transaction input.
*
* @param txContainingThis Transaction this script is included into
......@@ -1782,26 +1791,23 @@ public class Script {
* @param vinIndex transaction input index
* @return TRue (valid), False (invalid).
*/
private static boolean checkSequence(Transaction txContainingThis, BigInteger nSequence, int vinIndex) {
private static boolean checkSequence(Transaction txContainingThis, long nSequence, int vinIndex) {
boolean result = true;
// Regarding the nSequence value structure (both in the parameter from the
// topStck or the "nSequence" field from the input:
// - 3 important bit sets: DISABLED_FLAG, TYPE-FLAG and VALUE
// - DISABLED FLAG is the most significant bit (31-bit, starting from 0).
// - 3 important bit sets: SEQUENCE_LOCKTIME_DISABLE_FLAG, SEQUENCE_LOCKTIME_TYPE_FLAG-FLAG and SEQUENCE_LOCKTIME_MASK
// - SEQUENCE_LOCKTIME_DISABLE_FLAG FLAG is the most significant bit (31-bit, starting from 0).
// (mask: 0x80000000)
// - VALUE is the value of the 16 least significant bits
// - SEQUENCE_LOCKTIME_MASK is the value of the 16 least significant bits
// (mask: 0x0000FFFF)
// - FLAG_TYPE is the 23th least-significant bit
// - SEQUENCE_LOCKTIME_TYPE_FLAG is the 23th least-significant bit
// (mask: 0x400000)
// - if set, the VALUE is a multiple of 512 seconds
// - if NOT set, the VALUE is the number of blocks
long disabledFlagMask = 0x80000000;
long typeFlagMask = 1 << 22;
long valueFlagMask = 0x0000FFFF;
long typeAndValueMask = typeFlagMask | valueFlagMask;
long typeAndValueMask = TransactionInput.SEQUENCE_LOCKTIME_TYPE_FLAG | TransactionInput.SEQUENCE_LOCKTIME_MASK;