| 1664 | } |
| 1665 | |
| 1666 | static RPCHelpMan finalizecompactblock() |
| 1667 | { |
| 1668 | return RPCHelpMan{"finalizecompactblock", |
| 1669 | "Takes the two transaction lists, fills out the compact block and attempts to finalize it.", |
| 1670 | { |
| 1671 | {"compact_hex", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "Hex serialized compact block."}, |
| 1672 | {"block_transactions", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "Hex serialized BlockTransactions, the response to getblocktxn."}, |
| 1673 | {"found_transactions", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "Hex serialized list of transactions that were found in response to receiving a compact sketch in `consumecompactsketch`."}, |
| 1674 | }, |
| 1675 | RPCResult{ |
| 1676 | RPCResult::Type::STR_HEX, "block", "The serialized final block", |
| 1677 | }, |
| 1678 | RPCExamples{ |
| 1679 | HelpExampleCli("finalizecompactblock", "<compact_hex> <block_transactions> <found_transactions>") |
| 1680 | }, |
| 1681 | [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue |
| 1682 | { |
| 1683 | // Compact block |
| 1684 | std::vector<unsigned char> compact_block_bytes(ParseHex(request.params[0].get_str())); |
| 1685 | CDataStream ssCompactBlock(compact_block_bytes, SER_NETWORK, PROTOCOL_VERSION); |
| 1686 | CBlockHeaderAndShortTxIDs cmpctblock; |
| 1687 | ssCompactBlock >> cmpctblock; |
| 1688 | |
| 1689 | // BlockTransactions from the server |
| 1690 | std::vector<unsigned char> block_tx(ParseHex(request.params[1].get_str())); |
| 1691 | CDataStream ssResp(block_tx, SER_NETWORK, PROTOCOL_VERSION); |
| 1692 | |
| 1693 | BlockTransactions transactions; |
| 1694 | ssResp >> transactions; |
| 1695 | |
| 1696 | // Cached transactions |
| 1697 | std::vector<unsigned char> found_tx(ParseHex(request.params[2].get_str())); |
| 1698 | CDataStream ssFound(found_tx, SER_NETWORK, PROTOCOL_VERSION); |
| 1699 | |
| 1700 | std::vector<CTransactionRef> found; |
| 1701 | ssFound >> found; |
| 1702 | |
| 1703 | // Make mega-list |
| 1704 | found.insert(found.end(), transactions.txn.begin(), transactions.txn.end()); |
| 1705 | |
| 1706 | // Now construct the final block! (use dummy mempool here, otherwise reconstruction may fail) |
| 1707 | CTxMemPool dummy_pool; |
| 1708 | PartiallyDownloadedBlock partialBlock(&dummy_pool); |
| 1709 | |
| 1710 | // "Extra" list is really our combined list that will be put into place using InitData |
| 1711 | std::vector<std::pair<uint256, CTransactionRef>> extra_txn; |
| 1712 | for (const auto& found_tx : found) { |
| 1713 | extra_txn.push_back(std::make_pair(found_tx->GetWitnessHash(), found_tx)); |
| 1714 | } |
| 1715 | std::shared_ptr<CBlock> pblock = std::make_shared<CBlock>(); |
| 1716 | if (partialBlock.InitData(cmpctblock, extra_txn) != READ_STATUS_OK) { |
| 1717 | throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "compact_hex appears malformed."); |
| 1718 | } |
| 1719 | const std::vector<CTransactionRef> dummy_missing; |
| 1720 | auto result = partialBlock.FillBlock(*pblock, dummy_missing, false /* pow_check*/); |
| 1721 | if (result == READ_STATUS_FAILED) { |
| 1722 | throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "Failed to complete block though all transactions were apparently found. Could be random short ID collision; requires full block instead."); |
| 1723 | } else if (result != READ_STATUS_OK) { |
nothing calls this directly
no test coverage detected