Proposal: Reduce size of block hashing blobs for PoW validation
## Background

As of the time of this writing, PoW is checked by RandomX hashing the resultant blob of [`cryptonote::get_block_hashing_blob()`](https://github.com/monero-project/monero/blob/059028a30a8ae9752338a7897329fe8012a310d5/src/cryptonote_basic/cryptonote_format_utils.cpp#L1446). This blob contains the serialized block header + 32 byte merkle tree hash of all transactions in the block + the number of transactions in the block as a `varint`. The resultant blob of `cryptonote::get_block_hashing_blob()` is also hashed to get the block ID, but using the keccak function for speed.

## Proposal

My proposal is to reduce the size of the blob we hash against for PoW by only adding enough bytes to the blob such that the transaction contents of the block are only "bound" (using the cryptographic term loosely here) with at least as much difficulty as the difficulty of the block. Specifically, for each block, we define a new value `rough_diff_bytes = log256ceil(current_difficulty)`. Then, we get the rough tx tree hash: `rough_tx_tree_hash = randomx(<the tx tree>)[:rough_diff_bytes]`, where `string[:n]` means to take the first `n` bytes of `string`. To construct our PoW hashing blob, we concatenate the serialized block header + `rough_tx_tree_hash`. To validate the contents of a block knowing only the PoW hashing blob chain, we can request blocks by the `prev_id` of the block header immediately after it. For the very top block, since there is no following block, we request the top block from a peer node, recompute `rough_tx_tree_hash' = randomx(<the tx tree>)[:rough_diff_bytes]` and check if `rough_tx_tree_hash' =?= rough_tx_tree_hash` for the very top block.

## Trade-off Analysis

### Pro: Reduce data needed to verify PoW by ~37% (28 bytes/block)

Conservatively, let's assume the highest difficulty ever achieved on the Monero blockchain (420 billion) and a low transaction count (1). With our new scheme, `rough_diff_bytes = log256ceil(current_difficulty) = 5`. So instead of serializing the complete 32 merkle tx tree hash (32 bytes) + the number of txs as a varint (1) byte, we just serialize `rough_tx_tree_hash` (5 bytes), and thus save 28 bytes. The typical block header is 43 bytes, so we would save around 28 / (43 + 32 + 1) * 100% = 36.8% total on each downloaded header hashing blob.

### Con: Extra DB space required to cache `rough_tx_tree_hash` (16 bytes/block)

Assuming we don't want to recalculate `rough_tx_tree_hash` each time it is requested, which would entail running RandomX, we need someplace to store it in the database. Realistically, since we assume the difficulty will never rise above 2^128, we would probably store the `rough_tx_tree_hash` as a LE-encoded 128-bit integer in `mdb_block_info_*`.

### Con: One Extra RandomX Call Required before Mining Can Begin

To compute `rough_tx_tree_hash`, we must call RandomX once before we can begin mining which will increase turnover time 
for miners on new block propagation. However, this is a small cost that affects all miners equally, so the effect probably won't be very noticeable.

### Con: Hard Fork and Extra Code Required

This is obviously incompatible with older consensus rules so a hard fork is required. Also, if nodes are actually going to leverage this feature, we would need implement some way retrieve *just* the block header hashing blobs.

## Synergy with @tevador's Fast Partial PoW Proposal

@tevador proposed using an "intermediate hash" to force malicious attackers to expend PoW (in the form of a Blake2B hash) before nodes will execute RandomX in issue #8827. By leveraging the same principal used here (only serializing the amount of entropy required to be at least as hard as the block difficulty), we can actually reduce the intermediate hash size down from 32 bytes to ~5 bytes. If both of these proposals are combined, we can have block header hashing blobs that are ~23 bytes lighter than they currently are **AND** require Blake2B PoW from attackers before clients will expend effort verifying the RandomX. 

These ultra-quick block headers would be excellent for wallets and nodes alike. Nodes will get to toss away bad blocks from peers quicker, retain higher availability, and settle alternative chains faster. It would now be cheaper for wallets to validate block headers directly from the network so they don't have to trust any single node.

