public void correctlySpends(Transaction txContainingThis, int scriptSigIndex, @Nullable TransactionWitness witness, @Nullable Coin value,
            Script scriptPubKey, Set<VerifyFlag> verifyFlags) throws ScriptException {
        if (ScriptPattern.isP2WPKH(scriptPubKey)) {
            // For segwit, full validation isn't implemented. So we simply check the signature. P2SH_P2WPKH is handled
            // by the P2SH code for now.
            if (witness.getPushCount() < 2)
                throw new ScriptException(ScriptError.SCRIPT_ERR_WITNESS_PROGRAM_WITNESS_EMPTY, witness.toString());
            TransactionSignature signature;
            try {
                signature = TransactionSignature.decodeFromBitcoin(witness.getPush(0), true, true);
            } catch (SignatureDecodeException x) {
                throw new ScriptException(ScriptError.SCRIPT_ERR_SIG_DER, "Cannot decode", x);
            }
            ECKey pubkey = ECKey.fromPublicOnly(witness.getPush(1));
            Script scriptCode = ScriptBuilder.createP2PKHOutputScript(pubkey);
            Sha256Hash sigHash = txContainingThis.hashForWitnessSignature(scriptSigIndex, scriptCode, value,
                    signature.sigHashMode(), false);
            boolean validSig = pubkey.verify(sigHash, signature);
            if (!validSig)
                throw new ScriptException(ScriptError.SCRIPT_ERR_CHECKSIGVERIFY, "Invalid signature");
        } else if (ScriptPattern.isP2PKH(scriptPubKey)) {
            if (chunks.size() != 2)
                throw new ScriptException(ScriptError.SCRIPT_ERR_SCRIPT_SIZE, "Invalid size: " + chunks.size());
            TransactionSignature signature;
            try {
                signature = TransactionSignature.decodeFromBitcoin(chunks.get(0).data, true, true);
            } catch (SignatureDecodeException x) {
                throw new ScriptException(ScriptError.SCRIPT_ERR_SIG_DER, "Cannot decode", x);
            }
            ECKey pubkey = ECKey.fromPublicOnly(chunks.get(1).data);
            Sha256Hash sigHash = txContainingThis.hashForSignature(scriptSigIndex, scriptPubKey,
                    signature.sigHashMode(), false);
            boolean validSig = pubkey.verify(sigHash, signature);
            if (!validSig)
                throw new ScriptException(ScriptError.SCRIPT_ERR_CHECKSIGVERIFY, "Invalid signature");
        } else if (ScriptPattern.isP2PK(scriptPubKey)) {
            if (chunks.size() != 1)
                throw new ScriptException(ScriptError.SCRIPT_ERR_SCRIPT_SIZE, "Invalid size: " + chunks.size());
            TransactionSignature signature;
            try {
                signature = TransactionSignature.decodeFromBitcoin(chunks.get(0).data, false, false);
            } catch (SignatureDecodeException x) {
                throw new ScriptException(ScriptError.SCRIPT_ERR_SIG_DER, "Cannot decode", x);
            }
            ECKey pubkey = ECKey.fromPublicOnly(ScriptPattern.extractKeyFromP2PK(scriptPubKey));
            Sha256Hash sigHash = txContainingThis.hashForSignature(scriptSigIndex, scriptPubKey,
                    signature.sigHashMode(), false);
            boolean validSig = pubkey.verify(sigHash, signature);
            if (!validSig)
                throw new ScriptException(ScriptError.SCRIPT_ERR_CHECKSIGVERIFY, "Invalid signature");
        } else {
            correctlySpends(txContainingThis, scriptSigIndex, scriptPubKey, verifyFlags);
        }
    }
@Test
    public void dataDrivenValidTransactions() throws Exception {
        JsonNode json = new ObjectMapper().readTree(new InputStreamReader(getClass().getResourceAsStream(
                "tx_valid.json"), StandardCharsets.UTF_8));
        for (JsonNode test : json) {
            if (test.isArray() && test.size() == 1 && test.get(0).isTextual())
                continue; // This is a comment.
            Transaction transaction = null;
            try {
                Map<TransactionOutPoint, Script> scriptPubKeys = parseScriptPubKeys(test.get(0));
                transaction = TESTNET.getDefaultSerializer().makeTransaction(ByteBuffer.wrap(ByteUtils.parseHex(test.get(1).asText().toLowerCase())));
                Transaction.verify(TESTNET.network(), transaction);
                Set<VerifyFlag> verifyFlags = parseVerifyFlags(test.get(2).asText());

                for (int i = 0; i < transaction.getInputs().size(); i++) {
                    TransactionInput input = transaction.getInput(i);
                    assertTrue(scriptPubKeys.containsKey(input.getOutpoint()));
                    input.getScriptSig().correctlySpends(transaction, i, null, null,
                            scriptPubKeys.get(input.getOutpoint()), verifyFlags);
                }
            } catch (Exception e) {
                System.err.println(test);
                if (transaction != null)
                    System.err.println(transaction);
                throw e;
            }
        }
    }