正在查看: imToken v3.28.8 应用的 Script.java JAVA 源代码文件
本页面展示 JAVA 反编译生成的源代码文件,支持语法高亮显示。 仅供安全研究与技术分析使用,严禁用于任何非法用途。请遵守相关法律法规。
正在查看: imToken v3.28.8 应用的 Script.java JAVA 源代码文件
本页面展示 JAVA 反编译生成的源代码文件,支持语法高亮显示。 仅供安全研究与技术分析使用,严禁用于任何非法用途。请遵守相关法律法规。
package org.bitcoinj.script;
import com.google.common.base.Preconditions;
import com.google.common.collect.Lists;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.EnumSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import javax.annotation.Nullable;
import kotlin.UByte;
import org.bitcoinj.core.Address;
import org.bitcoinj.core.ECKey;
import org.bitcoinj.core.NetworkParameters;
import org.bitcoinj.core.ProtocolException;
import org.bitcoinj.core.ScriptException;
import org.bitcoinj.core.Sha256Hash;
import org.bitcoinj.core.Transaction;
import org.bitcoinj.core.UnsafeByteArrayOutputStream;
import org.bitcoinj.core.Utils;
import org.bitcoinj.crypto.TransactionSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class Script {
public static final int MAX_P2SH_SIGOPS = 15;
public static final long MAX_SCRIPT_ELEMENT_SIZE = 520;
public static final int SIG_SIZE = 75;
protected List<ScriptChunk> chunks;
private long creationTimeSeconds;
protected byte[] program;
public static final EnumSet<VerifyFlag> ALL_VERIFY_FLAGS = EnumSet.allOf(VerifyFlag.class);
private static final Logger log = LoggerFactory.getLogger(Script.class);
private static final ScriptChunk[] STANDARD_TRANSACTION_SCRIPT_CHUNKS = {new ScriptChunk(118, null, 0), new ScriptChunk(ScriptOpCodes.OP_HASH160, null, 1), new ScriptChunk(ScriptOpCodes.OP_EQUALVERIFY, null, 23), new ScriptChunk(ScriptOpCodes.OP_CHECKSIG, null, 24)};
public enum ScriptType {
NO_TYPE,
P2PKH,
PUB_KEY,
P2SH
}
public enum VerifyFlag {
P2SH,
STRICTENC,
DERSIG,
LOW_S,
NULLDUMMY,
SIGPUSHONLY,
MINIMALDATA,
DISCOURAGE_UPGRADABLE_NOPS,
CLEANSTACK,
CHECKLOCKTIMEVERIFY
}
private Script() {
this.chunks = Lists.newArrayList();
}
Script(List<ScriptChunk> list) {
this.chunks = Collections.unmodifiableList(new ArrayList(list));
this.creationTimeSeconds = Utils.currentTimeSeconds();
}
public Script(byte[] bArr) throws ScriptException {
this.program = bArr;
parse(bArr);
this.creationTimeSeconds = 0L;
}
public Script(byte[] bArr, long j) throws ScriptException {
this.program = bArr;
parse(bArr);
this.creationTimeSeconds = j;
}
public long getCreationTimeSeconds() {
return this.creationTimeSeconds;
}
public void setCreationTimeSeconds(long j) {
this.creationTimeSeconds = j;
}
public String toString() {
return Utils.join(this.chunks);
}
public byte[] getProgram() {
try {
if (this.program != null) {
return Arrays.copyOf(this.program, this.program.length);
}
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
Iterator<ScriptChunk> it = this.chunks.iterator();
while (it.hasNext()) {
it.next().write(byteArrayOutputStream);
}
byte[] byteArray = byteArrayOutputStream.toByteArray();
this.program = byteArray;
return byteArray;
} catch (IOException e) {
throw new RuntimeException(e);
}
}
public List<ScriptChunk> getChunks() {
return Collections.unmodifiableList(this.chunks);
}
private void parse(byte[] bArr) throws ScriptException {
long j;
int read;
ScriptChunk scriptChunk;
this.chunks = new ArrayList(5);
ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(bArr);
int available = byteArrayInputStream.available();
while (byteArrayInputStream.available() > 0) {
int available2 = available - byteArrayInputStream.available();
int read2 = byteArrayInputStream.read();
boolean z = true;
if (read2 < 0 || read2 >= 76) {
if (read2 == 76) {
if (byteArrayInputStream.available() < 1) {
throw new ScriptException("Unexpected end of script");
}
read = byteArrayInputStream.read();
} else if (read2 == 77) {
if (byteArrayInputStream.available() < 2) {
throw new ScriptException("Unexpected end of script");
}
read = byteArrayInputStream.read() | (byteArrayInputStream.read() << 8);
} else if (read2 != 78) {
j = -1;
} else {
if (byteArrayInputStream.available() < 4) {
throw new ScriptException("Unexpected end of script");
}
j = (byteArrayInputStream.read() << 8) | byteArrayInputStream.read() | (byteArrayInputStream.read() << 16) | (byteArrayInputStream.read() << 24);
}
j = read;
} else {
j = read2;
}
if (j == -1) {
scriptChunk = new ScriptChunk(read2, null, available2);
} else {
if (j > byteArrayInputStream.available()) {
throw new ScriptException("Push of data element that is larger than remaining data");
}
byte[] bArr2 = new byte[(int) j];
if (j != 0 && byteArrayInputStream.read(bArr2, 0, r4) != j) {
z = false;
}
Preconditions.checkState(z);
scriptChunk = new ScriptChunk(read2, bArr2, available2);
}
for (ScriptChunk scriptChunk2 : STANDARD_TRANSACTION_SCRIPT_CHUNKS) {
if (scriptChunk2.equals(scriptChunk)) {
scriptChunk = scriptChunk2;
}
}
this.chunks.add(scriptChunk);
}
}
public boolean isSentToRawPubKey() {
return this.chunks.size() == 2 && this.chunks.get(1).equalsOpCode(ScriptOpCodes.OP_CHECKSIG) && !this.chunks.get(0).isOpCode() && this.chunks.get(0).data.length > 1;
}
public boolean isSentToAddress() {
return this.chunks.size() == 5 && this.chunks.get(0).equalsOpCode(118) && this.chunks.get(1).equalsOpCode(ScriptOpCodes.OP_HASH160) && this.chunks.get(2).data.length == 20 && this.chunks.get(3).equalsOpCode(ScriptOpCodes.OP_EQUALVERIFY) && this.chunks.get(4).equalsOpCode(ScriptOpCodes.OP_CHECKSIG);
}
@Deprecated
public boolean isSentToP2SH() {
return isPayToScriptHash();
}
public byte[] getPubKeyHash() throws ScriptException {
if (isSentToAddress()) {
return this.chunks.get(2).data;
}
if (isPayToScriptHash()) {
return this.chunks.get(1).data;
}
throw new ScriptException("Script not in the standard scriptPubKey form");
}
public byte[] getPubKey() throws ScriptException {
if (this.chunks.size() != 2) {
throw new ScriptException("Script not of right size, expecting 2 but got " + this.chunks.size());
}
byte[] bArr = this.chunks.get(0).data;
ScriptChunk scriptChunk = this.chunks.get(1);
byte[] bArr2 = scriptChunk.data;
if (bArr != null && bArr.length > 2 && bArr2 != null && bArr2.length > 2) {
return bArr2;
}
if (scriptChunk.equalsOpCode(ScriptOpCodes.OP_CHECKSIG) && bArr != null && bArr.length > 2) {
return bArr;
}
throw new ScriptException("Script did not match expected form: " + this);
}
public byte[] getCLTVPaymentChannelSenderPubKey() throws ScriptException {
if (!isSentToCLTVPaymentChannel()) {
throw new ScriptException("Script not a standard CHECKLOCKTIMVERIFY transaction: " + this);
}
return this.chunks.get(8).data;
}
public byte[] getCLTVPaymentChannelRecipientPubKey() throws ScriptException {
if (!isSentToCLTVPaymentChannel()) {
throw new ScriptException("Script not a standard CHECKLOCKTIMVERIFY transaction: " + this);
}
return this.chunks.get(1).data;
}
public BigInteger getCLTVPaymentChannelExpiry() {
if (!isSentToCLTVPaymentChannel()) {
throw new ScriptException("Script not a standard CHECKLOCKTIMEVERIFY transaction: " + this);
}
return castToBigInteger(this.chunks.get(4).data, 5);
}
@Deprecated
public Address getFromAddress(NetworkParameters networkParameters) throws ScriptException {
return new Address(networkParameters, Utils.sha256hash160(getPubKey()));
}
public Address getToAddress(NetworkParameters networkParameters) throws ScriptException {
return getToAddress(networkParameters, false);
}
public Address getToAddress(NetworkParameters networkParameters, boolean z) throws ScriptException {
if (isSentToAddress()) {
return new Address(networkParameters, getPubKeyHash());
}
if (isPayToScriptHash()) {
return Address.fromP2SHScript(networkParameters, this);
}
if (z && isSentToRawPubKey()) {
return ECKey.fromPublicOnly(getPubKey()).toAddress(networkParameters);
}
throw new ScriptException("Cannot cast this script to a pay-to-address type");
}
public static void writeBytes(OutputStream outputStream, byte[] bArr) throws IOException {
if (bArr.length < 76) {
outputStream.write(bArr.length);
outputStream.write(bArr);
return;
}
if (bArr.length < 256) {
outputStream.write(76);
outputStream.write(bArr.length);
outputStream.write(bArr);
} else {
if (bArr.length < 65536) {
outputStream.write(77);
outputStream.write(bArr.length & 255);
outputStream.write((bArr.length >> 8) & 255);
outputStream.write(bArr);
return;
}
throw new RuntimeException("Unimplemented");
}
}
public static byte[] createMultiSigOutputScript(int i, List<ECKey> list) {
Preconditions.checkArgument(i > 0);
Preconditions.checkArgument(i <= list.size());
Preconditions.checkArgument(list.size() <= 16);
if (list.size() > 3) {
log.warn("Creating a multi-signature output that is non-standard: {} pubkeys, should be <= 3", Integer.valueOf(list.size()));
}
try {
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
byteArrayOutputStream.write(encodeToOpN(i));
Iterator<ECKey> it = list.iterator();
while (it.hasNext()) {
writeBytes(byteArrayOutputStream, it.next().getPubKey());
}
byteArrayOutputStream.write(encodeToOpN(list.size()));
byteArrayOutputStream.write(ScriptOpCodes.OP_CHECKMULTISIG);
return byteArrayOutputStream.toByteArray();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
public static byte[] createInputScript(byte[] bArr, byte[] bArr2) {
try {
UnsafeByteArrayOutputStream unsafeByteArrayOutputStream = new UnsafeByteArrayOutputStream(bArr.length + bArr2.length + 2);
writeBytes(unsafeByteArrayOutputStream, bArr);
writeBytes(unsafeByteArrayOutputStream, bArr2);
return unsafeByteArrayOutputStream.toByteArray();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
public static byte[] createInputScript(byte[] bArr) {
try {
UnsafeByteArrayOutputStream unsafeByteArrayOutputStream = new UnsafeByteArrayOutputStream(bArr.length + 2);
writeBytes(unsafeByteArrayOutputStream, bArr);
return unsafeByteArrayOutputStream.toByteArray();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
public Script createEmptyInputScript(@Nullable ECKey eCKey, @Nullable Script script) {
if (isSentToAddress()) {
Preconditions.checkArgument(eCKey != null, "Key required to create pay-to-address input script");
return ScriptBuilder.createInputScript(null, eCKey);
}
if (isSentToRawPubKey()) {
return ScriptBuilder.createInputScript(null);
}
if (isPayToScriptHash()) {
Preconditions.checkArgument(script != null, "Redeem script required to create P2SH input script");
return ScriptBuilder.createP2SHMultiSigInputScript(null, script);
}
throw new ScriptException("Do not understand script type: " + this);
}
public org.bitcoinj.script.Script getScriptSigWithSignature(org.bitcoinj.script.Script r4, byte[] r5, int r6) {
throw new UnsupportedOperationException("Method not decompiled: org.bitcoinj.script.Script.getScriptSigWithSignature(org.bitcoinj.script.Script, byte[], int):org.bitcoinj.script.Script");
}
public int getSigInsertionIndex(Sha256Hash sha256Hash, ECKey eCKey) {
List<ScriptChunk> list = this.chunks;
List<ScriptChunk> subList = list.subList(1, list.size() - 1);
List<ScriptChunk> list2 = this.chunks;
ScriptChunk scriptChunk = list2.get(list2.size() - 1);
Preconditions.checkNotNull(scriptChunk.data);
Script script = new Script(scriptChunk.data);
int findKeyInRedeem = script.findKeyInRedeem(eCKey);
int i = 0;
for (ScriptChunk scriptChunk2 : subList) {
if (scriptChunk2.opcode != 0) {
Preconditions.checkNotNull(scriptChunk2.data);
if (findKeyInRedeem < script.findSigInRedeem(scriptChunk2.data, sha256Hash)) {
return i;
}
i++;
}
}
return i;
}
private int findKeyInRedeem(ECKey eCKey) {
int i = 0;
Preconditions.checkArgument(this.chunks.get(0).isOpCode());
int decodeFromOpN = decodeFromOpN(this.chunks.get(r0.size() - 2).opcode);
while (i < decodeFromOpN) {
int i2 = i + 1;
if (Arrays.equals(this.chunks.get(i2).data, eCKey.getPubKey())) {
return i;
}
i = i2;
}
throw new IllegalStateException("Could not find matching key " + eCKey.toString() + " in script " + this);
}
public List<ECKey> getPubKeys() {
if (!isSentToMultiSig()) {
throw new ScriptException("Only usable for multisig scripts.");
}
ArrayList newArrayList = Lists.newArrayList();
int decodeFromOpN = decodeFromOpN(this.chunks.get(r1.size() - 2).opcode);
int i = 0;
while (i < decodeFromOpN) {
i++;
newArrayList.add(ECKey.fromPublicOnly(this.chunks.get(i).data));
}
return newArrayList;
}
private int findSigInRedeem(byte[] bArr, Sha256Hash sha256Hash) {
int i = 0;
Preconditions.checkArgument(this.chunks.get(0).isOpCode());
int decodeFromOpN = decodeFromOpN(this.chunks.get(r0.size() - 2).opcode);
TransactionSignature decodeFromBitcoin = TransactionSignature.decodeFromBitcoin(bArr, true);
while (i < decodeFromOpN) {
int i2 = i + 1;
if (ECKey.fromPublicOnly(this.chunks.get(i2).data).verify(sha256Hash, decodeFromBitcoin)) {
return i;
}
i = i2;
}
throw new IllegalStateException("Could not find matching key for signature on " + sha256Hash.toString() + " sig " + Utils.HEX.encode(bArr));
}
private static int getSigOpCount(List<ScriptChunk> list, boolean z) throws ScriptException {
int i = 0;
int i2 = 255;
for (ScriptChunk scriptChunk : list) {
if (scriptChunk.isOpCode()) {
switch (scriptChunk.opcode) {
case ScriptOpCodes.OP_CHECKSIG:
case ScriptOpCodes.OP_CHECKSIGVERIFY:
i++;
break;
case ScriptOpCodes.OP_CHECKMULTISIG:
case ScriptOpCodes.OP_CHECKMULTISIGVERIFY:
if (!z || i2 < 81 || i2 > 96) {
i += 20;
break;
} else {
i += decodeFromOpN(i2);
break;
}
break;
}
i2 = scriptChunk.opcode;
}
}
return i;
}
static int decodeFromOpN(int i) {
Preconditions.checkArgument(i == 0 || i == 79 || (i >= 81 && i <= 96), "decodeFromOpN called on non OP_N opcode");
if (i == 0) {
return 0;
}
if (i == 79) {
return -1;
}
return (i + 1) - 81;
}
static int encodeToOpN(int i) {
Preconditions.checkArgument(i >= -1 && i <= 16, "encodeToOpN called for " + i + " which we cannot encode in an opcode.");
if (i == 0) {
return 0;
}
if (i == -1) {
return 79;
}
return (i - 1) + 81;
}
public static int getSigOpCount(byte[] bArr) throws ScriptException {
Script script = new Script();
try {
script.parse(bArr);
} catch (ScriptException unused) {
}
return getSigOpCount(script.chunks, false);
}
public static long getP2SHSigOpCount(byte[] bArr) throws ScriptException {
Script script = new Script();
try {
script.parse(bArr);
} catch (ScriptException unused) {
}
for (int size = script.chunks.size() - 1; size >= 0; size--) {
if (!script.chunks.get(size).isOpCode()) {
new Script().parse(script.chunks.get(size).data);
return getSigOpCount(r2.chunks, true);
}
}
return 0L;
}
public int getNumberOfSignaturesRequiredToSpend() {
if (isSentToMultiSig()) {
return decodeFromOpN(this.chunks.get(0).opcode);
}
if (isSentToAddress() || isSentToRawPubKey()) {
return 1;
}
if (isPayToScriptHash()) {
throw new IllegalStateException("For P2SH number of signatures depends on redeem script");
}
throw new IllegalStateException("Unsupported script type");
}
public int getNumberOfBytesRequiredToSpend(@Nullable ECKey eCKey, @Nullable Script script) {
if (isPayToScriptHash()) {
Preconditions.checkArgument(script != null, "P2SH script requires redeemScript to be spent");
return (script.getNumberOfSignaturesRequiredToSpend() * 75) + script.getProgram().length;
}
if (isSentToMultiSig()) {
return (getNumberOfSignaturesRequiredToSpend() * 75) + 1;
}
if (isSentToRawPubKey()) {
return 75;
}
if (isSentToAddress()) {
return (eCKey != null ? eCKey.getPubKey().length : 65) + 75;
}
throw new IllegalStateException("Unsupported script type");
}
public boolean isPayToScriptHash() {
byte[] program = getProgram();
return program.length == 23 && (program[0] & UByte.MAX_VALUE) == 169 && (program[1] & UByte.MAX_VALUE) == 20 && (program[22] & UByte.MAX_VALUE) == 135;
}
public boolean isSentToMultiSig() {
int decodeFromOpN;
if (this.chunks.size() < 4) {
return false;
}
List<ScriptChunk> list = this.chunks;
ScriptChunk scriptChunk = list.get(list.size() - 1);
if (!scriptChunk.isOpCode()) {
return false;
}
if (!scriptChunk.equalsOpCode(ScriptOpCodes.OP_CHECKMULTISIG) && !scriptChunk.equalsOpCode(ScriptOpCodes.OP_CHECKMULTISIGVERIFY)) {
return false;
}
try {
ScriptChunk scriptChunk2 = this.chunks.get(this.chunks.size() - 2);
if (scriptChunk2.isOpCode() && (decodeFromOpN = decodeFromOpN(scriptChunk2.opcode)) >= 1 && this.chunks.size() == decodeFromOpN + 3) {
for (int i = 1; i < this.chunks.size() - 2; i++) {
if (this.chunks.get(i).isOpCode()) {
return false;
}
}
return decodeFromOpN(this.chunks.get(0).opcode) >= 1;
}
} catch (IllegalArgumentException unused) {
}
return false;
}
public boolean isSentToCLTVPaymentChannel() {
return this.chunks.size() == 10 && this.chunks.get(0).equalsOpCode(99) && this.chunks.get(2).equalsOpCode(ScriptOpCodes.OP_CHECKSIGVERIFY) && this.chunks.get(3).equalsOpCode(103) && this.chunks.get(5).equalsOpCode(177) && this.chunks.get(6).equalsOpCode(117) && this.chunks.get(7).equalsOpCode(104) && this.chunks.get(9).equalsOpCode(ScriptOpCodes.OP_CHECKSIG);
}
private static boolean equalsRange(byte[] bArr, int i, byte[] bArr2) {
if (bArr2.length + i > bArr.length) {
return false;
}
for (int i2 = 0; i2 < bArr2.length; i2++) {
if (bArr[i2 + i] != bArr2[i2]) {
return false;
}
}
return true;
}
public static byte[] removeAllInstancesOf(byte[] bArr, byte[] bArr2) {
int i;
UnsafeByteArrayOutputStream unsafeByteArrayOutputStream = new UnsafeByteArrayOutputStream(bArr.length);
int i2 = 0;
while (i2 < bArr.length) {
boolean equalsRange = equalsRange(bArr, i2, bArr2);
int i3 = i2 + 1;
int i4 = bArr[i2] & UByte.MAX_VALUE;
if (i4 >= 0 && i4 < 76) {
i = i4;
} else if (i4 == 76) {
i = (bArr[i3] & UByte.MAX_VALUE) + 1;
} else if (i4 == 77) {
i = ((bArr[i3] & UByte.MAX_VALUE) | ((bArr[i3 + 1] & UByte.MAX_VALUE) << 8)) + 2;
} else if (i4 == 78) {
int i5 = i3 + 1;
i = ((bArr[i3] & UByte.MAX_VALUE) | ((bArr[i5] & UByte.MAX_VALUE) << 8) | ((bArr[i5] & UByte.MAX_VALUE) << 16) | ((bArr[i5] & UByte.MAX_VALUE) << 24)) + 4;
} else {
i = 0;
}
if (!equalsRange) {
try {
unsafeByteArrayOutputStream.write(i4);
unsafeByteArrayOutputStream.write(Arrays.copyOfRange(bArr, i3, i3 + i));
} catch (IOException e) {
throw new RuntimeException(e);
}
}
i2 = i3 + i;
}
return unsafeByteArrayOutputStream.toByteArray();
}
public static byte[] removeAllInstancesOfOp(byte[] bArr, int i) {
return removeAllInstancesOf(bArr, new byte[]{(byte) i});
}
private static boolean castToBool(byte[] bArr) {
int i = 0;
while (i < bArr.length) {
if (bArr[i] != 0) {
return (i == bArr.length - 1 && (bArr[i] & UByte.MAX_VALUE) == 128) ? false : true;
}
i++;
}
return false;
}
private static BigInteger castToBigInteger(byte[] bArr) throws ScriptException {
if (bArr.length > 4) {
throw new ScriptException("Script attempted to use an integer larger than 4 bytes");
}
return Utils.decodeMPI(Utils.reverseBytes(bArr), false);
}
private static BigInteger castToBigInteger(byte[] bArr, int i) throws ScriptException {
if (bArr.length > i) {
throw new ScriptException("Script attempted to use an integer larger than " + i + " bytes");
}
return Utils.decodeMPI(Utils.reverseBytes(bArr), false);
}
public boolean isOpReturn() {
return this.chunks.size() > 0 && this.chunks.get(0).equalsOpCode(106);
}
@Deprecated
public static void executeScript(@Nullable Transaction transaction, long j, Script script, LinkedList<byte[]> linkedList, boolean z) throws ScriptException {
EnumSet noneOf;
if (z) {
noneOf = EnumSet.of(VerifyFlag.NULLDUMMY);
} else {
noneOf = EnumSet.noneOf(VerifyFlag.class);
}
executeScript(transaction, j, script, linkedList, noneOf);
}
public static void executeScript(@javax.annotation.Nullable org.bitcoinj.core.Transaction r21, long r22, org.bitcoinj.script.Script r24, java.util.LinkedList<byte[]> r25, java.util.Set<org.bitcoinj.script.Script.VerifyFlag> r26) throws org.bitcoinj.core.ScriptException {
throw new UnsupportedOperationException("Method not decompiled: org.bitcoinj.script.Script.executeScript(org.bitcoinj.core.Transaction, long, org.bitcoinj.script.Script, java.util.LinkedList, java.util.Set):void");
}
private static void executeCheckLockTimeVerify(Transaction transaction, int i, Script script, LinkedList<byte[]> linkedList, int i2, int i3, Set<VerifyFlag> set) throws ScriptException {
if (linkedList.size() < 1) {
throw new ScriptException("Attempted OP_CHECKLOCKTIMEVERIFY on a stack with size < 1");
}
BigInteger castToBigInteger = castToBigInteger(linkedList.getLast(), 5);
if (castToBigInteger.compareTo(BigInteger.ZERO) < 0) {
throw new ScriptException("Negative locktime");
}
if ((transaction.getLockTime() >= 500000000 || castToBigInteger.compareTo(Transaction.LOCKTIME_THRESHOLD_BIG) >= 0) && (transaction.getLockTime() < 500000000 || castToBigInteger.compareTo(Transaction.LOCKTIME_THRESHOLD_BIG) < 0)) {
throw new ScriptException("Locktime requirement type mismatch");
}
if (castToBigInteger.compareTo(BigInteger.valueOf(transaction.getLockTime())) > 0) {
throw new ScriptException("Locktime requirement not satisfied");
}
if (!transaction.getInput(i).hasSequence()) {
throw new ScriptException("Transaction contains a final transaction input for a CHECKLOCKTIMEVERIFY script.");
}
}
private static void executeCheckSig(Transaction transaction, int i, Script script, LinkedList<byte[]> linkedList, int i2, int i3, Set<VerifyFlag> set) throws ScriptException {
boolean z;
boolean z2 = set.contains(VerifyFlag.STRICTENC) || set.contains(VerifyFlag.DERSIG) || set.contains(VerifyFlag.LOW_S);
if (linkedList.size() < 2) {
throw new ScriptException("Attempted OP_CHECKSIG(VERIFY) on a stack with size < 2");
}
byte[] pollLast = linkedList.pollLast();
byte[] pollLast2 = linkedList.pollLast();
byte[] program = script.getProgram();
byte[] copyOfRange = Arrays.copyOfRange(program, i2, program.length);
UnsafeByteArrayOutputStream unsafeByteArrayOutputStream = new UnsafeByteArrayOutputStream(pollLast2.length + 1);
try {
writeBytes(unsafeByteArrayOutputStream, pollLast2);
byte[] removeAllInstancesOf = removeAllInstancesOf(copyOfRange, unsafeByteArrayOutputStream.toByteArray());
try {
TransactionSignature decodeFromBitcoin = TransactionSignature.decodeFromBitcoin(pollLast2, z2, set.contains(VerifyFlag.LOW_S));
z = ECKey.verify(transaction.hashForSignature(i, removeAllInstancesOf, (byte) decodeFromBitcoin.sighashFlags).getBytes(), decodeFromBitcoin, pollLast);
} catch (Exception e) {
if (!e.getMessage().contains("Reached past end of ASN.1 stream")) {
log.warn("Signature checking failed!", e);
}
z = false;
}
if (i3 == 172) {
linkedList.add(z ? new byte[]{1} : new byte[0]);
} else if (i3 == 173 && !z) {
throw new ScriptException("Script failed OP_CHECKSIGVERIFY");
}
} catch (IOException e2) {
throw new RuntimeException(e2);
}
}
private static int executeMultiSig(Transaction transaction, int i, Script script, LinkedList<byte[]> linkedList, int i2, int i3, int i4, Set<VerifyFlag> set) throws ScriptException {
boolean z;
boolean z2 = set.contains(VerifyFlag.STRICTENC) || set.contains(VerifyFlag.DERSIG) || set.contains(VerifyFlag.LOW_S);
if (linkedList.size() < 2) {
throw new ScriptException("Attempted OP_CHECKMULTISIG(VERIFY) on a stack with size < 2");
}
int intValue = castToBigInteger(linkedList.pollLast()).intValue();
if (intValue < 0 || intValue > 20) {
throw new ScriptException("OP_CHECKMULTISIG(VERIFY) with pubkey count out of range");
}
int i5 = i2 + intValue;
if (i5 > 201) {
throw new ScriptException("Total op count > 201 during OP_CHECKMULTISIG(VERIFY)");
}
if (linkedList.size() < intValue + 1) {
throw new ScriptException("Attempted OP_CHECKMULTISIG(VERIFY) on a stack with size < num_of_pubkeys + 2");
}
LinkedList linkedList2 = new LinkedList();
for (int i6 = 0; i6 < intValue; i6++) {
linkedList2.add(linkedList.pollLast());
}
int intValue2 = castToBigInteger(linkedList.pollLast()).intValue();
if (intValue2 < 0 || intValue2 > intValue) {
throw new ScriptException("OP_CHECKMULTISIG(VERIFY) with sig count out of range");
}
if (linkedList.size() < intValue2 + 1) {
throw new ScriptException("Attempted OP_CHECKMULTISIG(VERIFY) on a stack with size < num_of_pubkeys + num_of_signatures + 3");
}
LinkedList linkedList3 = new LinkedList();
for (int i7 = 0; i7 < intValue2; i7++) {
linkedList3.add(linkedList.pollLast());
}
byte[] program = script.getProgram();
byte[] copyOfRange = Arrays.copyOfRange(program, i3, program.length);
Iterator it = linkedList3.iterator();
while (it.hasNext()) {
byte[] bArr = (byte[]) it.next();
UnsafeByteArrayOutputStream unsafeByteArrayOutputStream = new UnsafeByteArrayOutputStream(bArr.length + 1);
try {
writeBytes(unsafeByteArrayOutputStream, bArr);
copyOfRange = removeAllInstancesOf(copyOfRange, unsafeByteArrayOutputStream.toByteArray());
} catch (IOException e) {
throw new RuntimeException(e);
}
}
while (true) {
if (linkedList3.size() <= 0) {
z = true;
break;
}
byte[] bArr2 = (byte[]) linkedList2.pollFirst();
try {
TransactionSignature decodeFromBitcoin = TransactionSignature.decodeFromBitcoin((byte[]) linkedList3.getFirst(), z2);
if (ECKey.verify(transaction.hashForSignature(i, copyOfRange, (byte) decodeFromBitcoin.sighashFlags).getBytes(), decodeFromBitcoin, bArr2)) {
linkedList3.pollFirst();
}
} catch (Exception unused) {
}
if (linkedList3.size() > linkedList2.size()) {
z = false;
break;
}
}
byte[] pollLast = linkedList.pollLast();
if (set.contains(VerifyFlag.NULLDUMMY) && pollLast.length > 0) {
throw new ScriptException("OP_CHECKMULTISIG(VERIFY) with non-null nulldummy: " + Arrays.toString(pollLast));
}
if (i4 == 174) {
linkedList.add(z ? new byte[]{1} : new byte[0]);
} else if (i4 == 175 && !z) {
throw new ScriptException("Script failed OP_CHECKMULTISIGVERIFY");
}
return i5;
}
@Deprecated
public void correctlySpends(Transaction transaction, long j, Script script) throws ScriptException {
correctlySpends(transaction, j, script, ALL_VERIFY_FLAGS);
}
public void correctlySpends(Transaction transaction, long j, Script script, Set<VerifyFlag> set) throws ScriptException {
try {
Transaction makeTransaction = transaction.getParams().getDefaultSerializer().makeTransaction(transaction.bitcoinSerialize());
if (getProgram().length > 10000 || script.getProgram().length > 10000) {
throw new ScriptException("Script larger than 10,000 bytes");
}
LinkedList linkedList = new LinkedList();
executeScript(makeTransaction, j, this, (LinkedList<byte[]>) linkedList, set);
LinkedList linkedList2 = set.contains(VerifyFlag.P2SH) ? new LinkedList(linkedList) : null;
executeScript(makeTransaction, j, script, (LinkedList<byte[]>) linkedList, set);
if (linkedList.size() == 0) {
throw new ScriptException("Stack empty at end of script execution.");
}
if (!castToBool((byte[]) linkedList.pollLast())) {
throw new ScriptException("Script resulted in a non-true stack: " + linkedList);
}
if (set.contains(VerifyFlag.P2SH) && script.isPayToScriptHash()) {
for (ScriptChunk scriptChunk : this.chunks) {
if (scriptChunk.isOpCode() && scriptChunk.opcode > 96) {
throw new ScriptException("Attempted to spend a P2SH scriptPubKey with a script that contained script ops");
}
}
executeScript(makeTransaction, j, new Script((byte[]) linkedList2.pollLast()), (LinkedList<byte[]>) linkedList2, set);
if (linkedList2.size() == 0) {
throw new ScriptException("P2SH stack empty at end of script execution.");
}
if (!castToBool((byte[]) linkedList2.pollLast())) {
throw new ScriptException("P2SH script execution resulted in a non-true stack");
}
}
} catch (ProtocolException e) {
throw new RuntimeException(e);
}
}
private byte[] getQuickProgram() {
byte[] bArr = this.program;
return bArr != null ? bArr : getProgram();
}
public ScriptType getScriptType() {
ScriptType scriptType = ScriptType.NO_TYPE;
if (isSentToAddress()) {
return ScriptType.P2PKH;
}
if (isSentToRawPubKey()) {
return ScriptType.PUB_KEY;
}
return isPayToScriptHash() ? ScriptType.P2SH : scriptType;
}
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null || getClass() != obj.getClass()) {
return false;
}
return Arrays.equals(getQuickProgram(), ((Script) obj).getQuickProgram());
}
public int hashCode() {
return Arrays.hashCode(getQuickProgram());
}
}