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

Code before:
            size_t num_broadcast{0};
            for (const auto& tx : txns) {
                // We don't want to re-submit the txn for validation in BroadcastTransaction
                if (!mempool.exists(tx->GetHash())) {
                    continue;
                }

                // We do not expect an error here; we are only broadcasting things already/still in mempool
                std::string err_string;
                const auto err = BroadcastTransaction(node, tx, err_string, /*max_tx_fee=*/0, /*relay=*/true, /*wait_callback=*/true);
                if (err != TransactionError::OK) {
                    throw JSONRPCTransactionError(err,
                        strprintf("transaction broadcast failed: %s (%d transactions were broadcast successfully)",
                            err_string, num_broadcast));
                }
                num_broadcast++;
            }

            UniValue rpc_result{UniValue::VOBJ};
            rpc_result.pushKV("package_msg", package_msg);
            UniValue tx_result_map{UniValue::VOBJ};
            std::set<Txid> replaced_txids;
            for (const auto& tx : txns) {
                UniValue result_inner{UniValue::VOBJ};
                result_inner.pushKV("txid", tx->GetHash().GetHex());
                auto it = package_result.m_tx_results.find(tx->GetWitnessHash());
                if (it == package_result.m_tx_results.end()) {
                    // No results, report error and continue
                    result_inner.pushKV("error", "unevaluated");
                    continue;
                }
                const auto& tx_result = it->second;
                switch(it->second.m_result_type) {
                case MempoolAcceptResult::ResultType::DIFFERENT_WITNESS:
                    result_inner.pushKV("other-wtxid", it->second.m_other_wtxid.value().GetHex());
                    break;
                case MempoolAcceptResult::ResultType::INVALID:
                    result_inner.pushKV("error", it->second.m_state.ToString());
                    break;
                case MempoolAcceptResult::ResultType::VALID:
                case MempoolAcceptResult::ResultType::MEMPOOL_ENTRY:
                    result_inner.pushKV("vsize", int64_t{it->second.m_vsize.value()});
                    UniValue fees(UniValue::VOBJ);
                    fees.pushKV("base", ValueFromAmount(it->second.m_base_fees.value()));
                    if (tx_result.m_result_type == MempoolAcceptResult::ResultType::VALID) {
                        // Effective feerate is not provided for MEMPOOL_ENTRY transactions even
                        // though modified fees is known, because it is unknown whether package
                        // feerate was used when it was originally submitted.
                        fees.pushKV("effective-feerate", ValueFromAmount(tx_result.m_effective_feerate.value().GetFeePerK()));
                        UniValue effective_includes_res(UniValue::VARR);
                        for (const auto& wtxid : tx_result.m_wtxids_fee_calculations.value()) {

Review comment (refactor):
Fwiw not a huge deal but I wouldn't recommend doing an unnecessary refactor at the same time as a fix to the missing RPC result.

Looks like this is creating a copy of the string to avoid 2 calls to `GetHex()`, which seems sensible.

Code after:
            size_t num_broadcast{0};
            for (const auto& tx : txns) {
                // We don't want to re-submit the txn for validation in BroadcastTransaction
                if (!mempool.exists(tx->GetHash())) {
                    continue;
                }

                // We do not expect an error here; we are only broadcasting things already/still in mempool
                std::string err_string;
                const auto err = BroadcastTransaction(node, tx, err_string, /*max_tx_fee=*/0, /*relay=*/true, /*wait_callback=*/true);
                if (err != TransactionError::OK) {
                    throw JSONRPCTransactionError(err,
                        strprintf("transaction broadcast failed: %s (%d transactions were broadcast successfully)",
                            err_string, num_broadcast));
                }
                num_broadcast++;
            }

            UniValue rpc_result{UniValue::VOBJ};
            rpc_result.pushKV("package_msg", package_msg);
            UniValue tx_result_map{UniValue::VOBJ};
            std::set<Txid> replaced_txids;
            for (const auto& tx : txns) {
                UniValue result_inner{UniValue::VOBJ};
                result_inner.pushKV("txid", tx->GetHash().GetHex());
                const auto wtxid_hex = tx->GetWitnessHash().GetHex();
                auto it = package_result.m_tx_results.find(tx->GetWitnessHash());
                if (it == package_result.m_tx_results.end()) {
                    // No per-tx result for this wtxid
                    // Current invariant: per-tx results are all-or-none (every member or empty on package abort).
                    // If any exist yet this one is missing, it's an unexpected partial map.
                    CHECK_NONFATAL(package_result.m_tx_results.empty());
                    result_inner.pushKV("error", "package-not-validated");
                    tx_result_map.pushKV(wtxid_hex, std::move(result_inner));
                    continue;
                }
                const auto& tx_result = it->second;
                switch(it->second.m_result_type) {
                case MempoolAcceptResult::ResultType::DIFFERENT_WITNESS:
                    result_inner.pushKV("other-wtxid", it->second.m_other_wtxid.value().GetHex());
                    break;
                case MempoolAcceptResult::ResultType::INVALID:
                    result_inner.pushKV("error", it->second.m_state.ToString());
                    break;
                case MempoolAcceptResult::ResultType::VALID:
                case MempoolAcceptResult::ResultType::MEMPOOL_ENTRY:
                    result_inner.pushKV("vsize", int64_t{it->second.m_vsize.value()});
                    UniValue fees(UniValue::VOBJ);
                    fees.pushKV("base", ValueFromAmount(it->second.m_base_fees.value()));
                    if (tx_result.m_result_type == MempoolAcceptResult::ResultType::VALID) {
                        // Effective feerate is not provided for MEMPOOL_ENTRY transactions even