Repository: bitcoin/bitcoin
File: src/rpc/blockchain.cpp (C++)

Code before:
{
    CHECK_NONFATAL(!coinbase_tx.vin.empty());
    const CTxIn& vin_0{coinbase_tx.vin[0]};
    UniValue coinbase_tx_obj(UniValue::VOBJ);
    coinbase_tx_obj.pushKV("version", coinbase_tx.version);
    coinbase_tx_obj.pushKV("locktime", (int64_t)coinbase_tx.nLockTime);
    coinbase_tx_obj.pushKV("sequence", (int64_t)vin_0.nSequence);
    coinbase_tx_obj.pushKV("is_final", vin_0.nSequence == CTxIn::SEQUENCE_FINAL);
    coinbase_tx_obj.pushKV("script_sig", HexStr(vin_0.scriptSig));
    const auto& witness_stack{vin_0.scriptWitness.stack};
    if (!witness_stack.empty()) {
        CHECK_NONFATAL(witness_stack.size() == 1);
        coinbase_tx_obj.pushKV("witness", HexStr(witness_stack[0]));
    }
    return coinbase_tx_obj;
}

UniValue blockToJSON(BlockManager& blockman, const CBlock& block, const CBlockIndex& tip, const CBlockIndex& blockindex, TxVerbosity verbosity, const uint256 pow_limit)
{
    UniValue result = blockheaderToJSON(tip, blockindex, pow_limit);

    result.pushKV("strippedsize", ::GetSerializeSize(TX_NO_WITNESS(block)));
    result.pushKV("size", ::GetSerializeSize(TX_WITH_WITNESS(block)));
    result.pushKV("weight", ::GetBlockWeight(block));

    CHECK_NONFATAL(!block.vtx.empty());
    result.pushKV("coinbase_tx", coinbaseTxToJSON(*block.vtx[0]));

    UniValue txs(UniValue::VARR);
    txs.reserve(block.vtx.size());

    switch (verbosity) {
        case TxVerbosity::SHOW_TXID:
            for (const CTransactionRef& tx : block.vtx) {
                txs.push_back(tx->GetHash().GetHex());
            }
            break;

        case TxVerbosity::SHOW_DETAILS:
        case TxVerbosity::SHOW_DETAILS_AND_PREVOUT:
            CBlockUndo blockUndo;
            const bool is_not_pruned{WITH_LOCK(::cs_main, return !blockman.IsBlockPruned(blockindex))};
            bool have_undo{is_not_pruned && WITH_LOCK(::cs_main, return blockindex.nStatus & BLOCK_HAVE_UNDO)};
            if (have_undo && !blockman.ReadBlockUndo(blockUndo, blockindex)) {
                throw JSONRPCError(RPC_INTERNAL_ERROR, "Undo data expected but can't be read. This could be due to disk corruption or a conflict with a pruning event.");
            }
            for (size_t i = 0; i < block.vtx.size(); ++i) {
                const CTransactionRef& tx = block.vtx.at(i);
                // coinbase transaction (i.e. i == 0) doesn't have undo data
                const CTxUndo* txundo = (have_undo && i > 0) ? &blockUndo.vtxundo.at(i - 1) : nullptr;
                UniValue objTx(UniValue::VOBJ);

Review comment (suggestion):
nit: could be just `coinbase` instead of `coinbase_tx`?

```suggestion
    result.pushKV("coinbase", coinbaseTxToJSON(*block.vtx[0]));
```

Code after:
{
    CHECK_NONFATAL(!coinbase_tx.vin.empty());
    const CTxIn& vin_0{coinbase_tx.vin[0]};
    UniValue coinbase_tx_obj(UniValue::VOBJ);
    coinbase_tx_obj.pushKV("version", coinbase_tx.version);
    coinbase_tx_obj.pushKV("locktime", coinbase_tx.nLockTime);
    coinbase_tx_obj.pushKV("sequence", vin_0.nSequence);
    coinbase_tx_obj.pushKV("coinbase", HexStr(vin_0.scriptSig));
    const auto& witness_stack{vin_0.scriptWitness.stack};
    if (!witness_stack.empty()) {
        CHECK_NONFATAL(witness_stack.size() == 1);
        coinbase_tx_obj.pushKV("witness", HexStr(witness_stack[0]));
    }
    return coinbase_tx_obj;
}

UniValue blockToJSON(BlockManager& blockman, const CBlock& block, const CBlockIndex& tip, const CBlockIndex& blockindex, TxVerbosity verbosity, const uint256 pow_limit)
{
    UniValue result = blockheaderToJSON(tip, blockindex, pow_limit);

    result.pushKV("strippedsize", ::GetSerializeSize(TX_NO_WITNESS(block)));
    result.pushKV("size", ::GetSerializeSize(TX_WITH_WITNESS(block)));
    result.pushKV("weight", ::GetBlockWeight(block));

    CHECK_NONFATAL(!block.vtx.empty());
    result.pushKV("coinbase_tx", coinbaseTxToJSON(*block.vtx[0]));

    UniValue txs(UniValue::VARR);
    txs.reserve(block.vtx.size());

    switch (verbosity) {
        case TxVerbosity::SHOW_TXID:
            for (const CTransactionRef& tx : block.vtx) {
                txs.push_back(tx->GetHash().GetHex());
            }
            break;

        case TxVerbosity::SHOW_DETAILS:
        case TxVerbosity::SHOW_DETAILS_AND_PREVOUT:
            CBlockUndo blockUndo;
            const bool is_not_pruned{WITH_LOCK(::cs_main, return !blockman.IsBlockPruned(blockindex))};
            bool have_undo{is_not_pruned && WITH_LOCK(::cs_main, return blockindex.nStatus & BLOCK_HAVE_UNDO)};
            if (have_undo && !blockman.ReadBlockUndo(blockUndo, blockindex)) {
                throw JSONRPCError(RPC_INTERNAL_ERROR, "Undo data expected but can't be read. This could be due to disk corruption or a conflict with a pruning event.");
            }
            for (size_t i = 0; i < block.vtx.size(); ++i) {
                const CTransactionRef& tx = block.vtx.at(i);
                // coinbase transaction (i.e. i == 0) doesn't have undo data
                const CTxUndo* txundo = (have_undo && i > 0) ? &blockUndo.vtxundo.at(i - 1) : nullptr;
                UniValue objTx(UniValue::VOBJ);
                TxToUniv(*tx, /*block_hash=*/uint256(), /*entry=*/objTx, /*include_hex=*/true, txundo, verbosity);