Repository: bitcoin/bitcoin
File: src/kernel/bitcoinkernel.cpp (C++)

Code before:
}

const btck_ScriptPubkey* btck_transaction_output_get_script_pubkey(const btck_TransactionOutput* output)
{
    return btck_ScriptPubkey::ref(&btck_TransactionOutput::get(output).scriptPubKey);
}

int64_t btck_transaction_output_get_amount(const btck_TransactionOutput* output)
{
    return btck_TransactionOutput::get(output).nValue;
}

void btck_transaction_output_destroy(btck_TransactionOutput* output)
{
    delete output;
}

int btck_script_pubkey_verify(const btck_ScriptPubkey* script_pubkey,
                              const int64_t amount,
                              const btck_Transaction* tx_to,
                              const btck_TransactionOutput** spent_outputs_, size_t spent_outputs_len,
                              const unsigned int input_index,
                              const btck_ScriptVerificationFlags flags,
                              btck_ScriptVerifyStatus* status)
{
    // Assert that all specified flags are part of the interface before continuing
    assert((flags & ~btck_ScriptVerificationFlags_ALL) == 0);

    if (!is_valid_flag_combination(script_verify_flags::from_int(flags))) {
        if (status) *status = btck_ScriptVerifyStatus_ERROR_INVALID_FLAGS_COMBINATION;
        return 0;
    }

    if (flags & btck_ScriptVerificationFlags_TAPROOT && spent_outputs_ == nullptr) {
        if (status) *status = btck_ScriptVerifyStatus_ERROR_SPENT_OUTPUTS_REQUIRED;
        return 0;
    }

    if (status) *status = btck_ScriptVerifyStatus_OK;

    const CTransaction& tx{*btck_Transaction::get(tx_to)};
    std::vector<CTxOut> spent_outputs;
    if (spent_outputs_ != nullptr) {
        assert(spent_outputs_len == tx.vin.size());
        spent_outputs.reserve(spent_outputs_len);
        for (size_t i = 0; i < spent_outputs_len; i++) {
            const CTxOut& tx_out{btck_TransactionOutput::get(spent_outputs_[i])};
            spent_outputs.push_back(tx_out);
        }
    }


Review comment (suggestion):
Can you also check that spent_outputs_len is 0 here? It might be the case that the passed in pointer is not null by chance, or UB for that matter, but the intent is still clearly communicated by passing a zero size.

Code after:
}

const btck_ScriptPubkey* btck_transaction_output_get_script_pubkey(const btck_TransactionOutput* output)
{
    return btck_ScriptPubkey::ref(&btck_TransactionOutput::get(output).scriptPubKey);
}

int64_t btck_transaction_output_get_amount(const btck_TransactionOutput* output)
{
    return btck_TransactionOutput::get(output).nValue;
}

void btck_transaction_output_destroy(btck_TransactionOutput* output)
{
    delete output;
}

btck_PrecomputedTransactionData* btck_precomputed_transaction_data_create(
    const btck_Transaction* tx_to,
    const btck_TransactionOutput** spent_outputs_, size_t spent_outputs_len)
{
    try {
        const CTransaction& tx{*btck_Transaction::get(tx_to)};
        auto txdata{btck_PrecomputedTransactionData::create()};
        if (spent_outputs_ != nullptr && spent_outputs_len > 0) {
            assert(spent_outputs_len == tx.vin.size());
            std::vector<CTxOut> spent_outputs;
            spent_outputs.reserve(spent_outputs_len);
            for (size_t i = 0; i < spent_outputs_len; i++) {
                const CTxOut& tx_out{btck_TransactionOutput::get(spent_outputs_[i])};
                spent_outputs.push_back(tx_out);
            }
            btck_PrecomputedTransactionData::get(txdata).Init(tx, std::move(spent_outputs));
        } else {
            btck_PrecomputedTransactionData::get(txdata).Init(tx, {});
        }

        return txdata;
    } catch (...) {
        return nullptr;
    }
}

btck_PrecomputedTransactionData* btck_precomputed_transaction_data_copy(const btck_PrecomputedTransactionData* precomputed_txdata)
{
    return btck_PrecomputedTransactionData::copy(precomputed_txdata);
}

void btck_precomputed_transaction_data_destroy(btck_PrecomputedTransactionData* precomputed_txdata)
{
    delete precomputed_txdata;