导航菜单

页面标题

页面副标题

imToken v3.28.8 - Script.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());
    }
}