upleb.uk

Public git repos — served from a NIP-34 GRASP relay at git.upleb.uk

summaryrefslogtreecommitdiff
path: root/src/compactblock.h
diff options
context:
space:
mode:
authorbitflash-maintainer <noreply@bitflash.invalid>2026-09-05 22:46:52 +0000
committerbitflash-maintainer <noreply@bitflash.invalid>2026-09-05 22:46:52 +0000
commitceae3d076b5ad11ee84729ae43f14e9312896646 (patch)
tree7e9132aa871fdc01cb95268d2f5ea3bb11853ddf /src/compactblock.h
parentbe63e83d79e7e00e6b8ca889a70e6a19886aa1d8 (diff)
parent66e0b9158d050c46b1ff2509faeee3f4573cac1c (diff)
Bring main onto the line this project actually ships
main had drifted to a history with no ancestor in common with the tree we build and deploy. It sat at be63e83 (2026-08-09) with 28 commits; the shipped line, deploy/soak-2026-08-21, had 383. The two shared nothing -- git merge-base returns no result at all -- so anyone cloning this repository landed on a default branch that was neither current nor related to the running node. The 28 commits on main were audited before this merge: every one is already present in the tree by content, including the two that are hardest to see because they were rewritten afterwards -- the payout reorg-safety work (PayoutBlockStillOnChain, since evolved to re-check on every retry rather than once at maturity) and the nostr relay certificate verification (SSL_set1_host, now with a Windows root-store path). Nothing on main is lost by this merge. Recorded as a merge rather than a force-push: main only ever moves forward, its old history stays reachable as the first parent, and this is revertible. The tree is taken wholesale from the merged branch, so main's content is now exactly what was built and tested. What this brings onto main: - compactblock: BIP152-style compact block relay ported from upstream 1.2.23, primitives and unit test only, with the RAND_bytes failure path closed and the reconstruction allocation bounded. - upstream/main 17741d9: isolated testnet parameters and genesis, optional 2 MB large pages for RandomX. Mainnet genesis verified byte-identical through upstream's BuildGenesisBlock() refactor. - deploy: every image built on bookworm so binaries run on Debian 12, and the container build now honours the RandomX and libsecp256k1 pins it had been silently ignoring since before 1.2.15. Gates at this tree: 15/15 selftests, compactblock's 17 checks, consensus constants unchanged against e4f898c apart from the pre-existing MAX_BLOCK_SIZE_GEN, mainnet genesis intact, money-log check ok.
Diffstat (limited to 'src/compactblock.h')
-rw-r--r--src/compactblock.h113
1 files changed, 113 insertions, 0 deletions
diff --git a/src/compactblock.h b/src/compactblock.h
new file mode 100644
index 0000000..745ee3b
--- /dev/null
+++ b/src/compactblock.h
@@ -0,0 +1,113 @@
1// Copyright (c) 2026 Bitflash developers
2// Distributed under the MIT/X11 software license.
3//
4// Compact block relay (BIP152-style). Instead of sending a peer's full set
5// of transactions for a block they're about to receive -- almost all of
6// which they already have in their mempool from normal tx relay -- send a
7// short (48-bit, keyed-hash) ID per transaction instead. A peer that already
8// has every referenced transaction reconstructs the full block locally from
9// its mempool without any of the transaction bytes crossing the wire at
10// all; only genuinely missing transactions (typically just the coinbase)
11// need a follow-up round trip.
12//
13// Compatibility: this is purely additive. A peer that never sends
14// "sendcmpct" is never sent a compact block -- it keeps getting full
15// "block" messages exactly as before (see the getdata handler in
16// main.cpp). Old, unupgraded nodes on the live network are completely
17// unaffected; ProcessMessage's unknown-command handling means they simply
18// never see the new message types. No coordinated network upgrade needed.
19//
20// Deliberately scoped down from full BIP152: no high-bandwidth (unsolicited
21// push) mode, no differential-index encoding for prefilled transactions,
22// only the current chain tip is ever offered in compact form (an old block
23// is unlikely to still overlap much with any peer's current mempool, so the
24// bandwidth win doesn't apply -- full "block" is sent for those, same as
25// today). Only the coinbase is prefilled; every other transaction position
26// carries a short ID.
27
28#ifndef BITFLASH_COMPACTBLOCK_H
29#define BITFLASH_COMPACTBLOCK_H
30
31// Requires CBlock/CTransaction already visible -- #include "headers.h" (or
32// main.h) before this file. Deliberately doesn't include main.h itself:
33// main.h has no include guard (matches this codebase's existing headers, it
34// relies on being pulled in exactly once via headers.h), so a second
35// #include "main.h" here would break every translation unit that already
36// brought it in via headers.h first.
37#include <vector>
38
39// The compact representation of a block: header fields, a per-block nonce
40// (keys the short-ID hash so IDs can't be precomputed/ground across blocks),
41// the coinbase in full, and a 48-bit short ID for every other transaction
42// in block order.
43class CCmpctBlock
44{
45public:
46 // header
47 int nVersion;
48 uint256 hashPrevBlock;
49 uint256 hashMerkleRoot;
50 unsigned int nTime;
51 unsigned int nBits;
52 unsigned int nNonce;
53
54 // Keys the short-ID hash for this block specifically -- chosen fresh
55 // per block (not reused from nNonce, which is public PoW data an
56 // attacker already knows and could otherwise grind against).
57 uint64 shortIdNonce;
58
59 // Sent in full. In this implementation: always exactly the coinbase,
60 // at index 0.
61 std::vector<unsigned int> vPrefilledIndex;
62 std::vector<CTransaction> vPrefilledTx;
63
64 // One short ID per NON-prefilled transaction, in ascending block-index
65 // order (i.e. the Nth entry here belongs to the Nth block position that
66 // isn't in vPrefilledIndex).
67 std::vector<uint64> vShortTxId;
68
69 IMPLEMENT_SERIALIZE
70 (
71 READWRITE(this->nVersion);
72 nVersion = this->nVersion;
73 READWRITE(hashPrevBlock);
74 READWRITE(hashMerkleRoot);
75 READWRITE(nTime);
76 READWRITE(nBits);
77 READWRITE(nNonce);
78 READWRITE(shortIdNonce);
79 READWRITE(vPrefilledIndex);
80 READWRITE(vPrefilledTx);
81 READWRITE(vShortTxId);
82 )
83
84 uint256 HeaderHash() const;
85};
86
87// Compute the 48-bit short ID for a transaction under a given block's
88// short-ID nonce. Keyed (via the block's hashPrevBlock + shortIdNonce) so
89// IDs from one block can't be precomputed before that block exists, and
90// differ block to block even for the same transaction.
91uint64 ComputeShortTxId(const uint256& hashPrevBlock, uint64 shortIdNonce, const uint256& txid);
92
93// Build the compact form of `block` (which must have vtx[0] as the
94// coinbase, as every block on this chain does).
95bool BuildCompactBlock(const CBlock& block, CCmpctBlock& out);
96
97// Attempt to reconstruct a full block from a received compact block using
98// the local mempool. On full success, returns true and fills `outBlock`.
99// On partial success (some transactions not found locally), returns false
100// and fills `vMissingIndex` with the block-position indices that still need
101// to be requested via "getblocktxn" -- outBlock is left partially built
102// (coinbase and any resolved positions filled; caller must not use it until
103// FillMissingAndFinish completes it).
104bool TryReconstructBlock(const CCmpctBlock& cmpct, CBlock& outBlock, std::vector<unsigned int>& vMissingIndex);
105
106// Complete a partially-reconstructed block (from a prior TryReconstructBlock
107// that returned false) using the transactions received in a "blocktxn"
108// response. vTxn must be in the same order as the indices this node
109// requested via "getblocktxn" for this block.
110bool FillMissingAndFinish(CBlock& outBlock, const std::vector<unsigned int>& vMissingIndex,
111 const std::vector<CTransaction>& vTxn);
112
113#endif