Skip to content

Commit 6615bde

Browse files
committed
net: Add block undo data messages
1 parent 8c07800 commit 6615bde

File tree

14 files changed

+608
-0
lines changed

14 files changed

+608
-0
lines changed

src/compressor.h

Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
#include <prevector.h>
1010
#include <primitives/transaction.h>
1111
#include <script/script.h>
12+
#include <addresstype.h>
1213
#include <serialize.h>
1314
#include <span.h>
1415

@@ -95,6 +96,136 @@ struct ScriptCompression
9596
}
9697
};
9798

99+
enum class ReconstructableScriptType: uint8_t {
100+
Unknown = 0x00,
101+
P2pkh = 0x01,
102+
P2pkEven = 0x02,
103+
P2pkOdd = 0x03,
104+
P2pkUncompressed = 0x04,
105+
P2sh = 0x06,
106+
P2wsh = 0x07,
107+
P2wpkh = 0x08,
108+
P2tr = 0x09,
109+
};
110+
111+
template <typename Stream>
112+
void Serialize(Stream& s, ReconstructableScriptType type)
113+
{
114+
::Serialize(s, static_cast<uint8_t>(type));
115+
}
116+
117+
struct ReconstructableScript {
118+
119+
template<typename Stream>
120+
void Ser(Stream& s, const CScript& script)
121+
{
122+
if (script.IsPayToTaproot()) {
123+
::Serialize(s, ReconstructableScriptType::P2tr);
124+
::Serialize(s, MakeByteSpan(script).subspan(2, 32));
125+
return;
126+
}
127+
if (script.IsPayToWitnessScriptHash()) {
128+
::Serialize(s, ReconstructableScriptType::P2wsh);
129+
::Serialize(s, MakeByteSpan(script).subspan(2, 32));
130+
return;
131+
}
132+
if (script.size() == 22 && script[0] == OP_0 && script[1] == 20) {
133+
::Serialize(s, ReconstructableScriptType::P2wpkh);
134+
::Serialize(s, MakeByteSpan(script).subspan(2, 20));
135+
return;
136+
}
137+
if (script.IsPayToScriptHash()) {
138+
::Serialize(s, ReconstructableScriptType::P2sh);
139+
::Serialize(s, MakeByteSpan(script).subspan(2, 20));
140+
return;
141+
}
142+
if (script.size() == 25 && script[0] == OP_DUP && script[1] == OP_HASH160
143+
&& script[2] == 20 && script[23] == OP_EQUALVERIFY
144+
&& script[24] == OP_CHECKSIG) {
145+
::Serialize(s, ReconstructableScriptType::P2pkh);
146+
::Serialize(s, MakeByteSpan(script).subspan(3, 20));
147+
return;
148+
}
149+
if (script.size() == 35 && script[0] == 33 && script[34] == OP_CHECKSIG) {
150+
if (script[1] == 0x02) {
151+
::Serialize(s, ReconstructableScriptType::P2pkEven);
152+
::Serialize(s, MakeByteSpan(script).subspan(2, 32));
153+
return;
154+
}
155+
if (script[1] == 0x03) {
156+
::Serialize(s, ReconstructableScriptType::P2pkOdd);
157+
::Serialize(s, MakeByteSpan(script).subspan(2, 32));
158+
return;
159+
}
160+
}
161+
if (script.size() == 67 && script[0] == 65 && script[66] == OP_CHECKSIG && script[1] == 0x04) {
162+
::Serialize(s, ReconstructableScriptType::P2pkUncompressed);
163+
::Serialize(s, MakeByteSpan(script).subspan(2, 64));
164+
return;
165+
}
166+
::Serialize(s, ReconstructableScriptType::Unknown);
167+
::Serialize(s, script);
168+
}
169+
170+
template<typename Stream>
171+
void Unser(Stream& s, CScript& script)
172+
{
173+
uint8_t type;
174+
::Unserialize(s, type);
175+
ReconstructableScriptType s_type{type};
176+
switch (s_type) {
177+
case ReconstructableScriptType::P2tr: {
178+
XOnlyPubKey pk;
179+
s >> pk;
180+
script = GetScriptForDestination(WitnessV1Taproot(pk));
181+
break;
182+
}
183+
case ReconstructableScriptType::P2wsh: {
184+
uint256 hash;
185+
s >> hash;
186+
script = GetScriptForDestination(WitnessV0ScriptHash(hash));
187+
break;
188+
}
189+
case ReconstructableScriptType::P2wpkh: {
190+
uint160 hash;
191+
s >> hash;
192+
script = GetScriptForDestination(WitnessV0KeyHash(hash));
193+
break;
194+
}
195+
case ReconstructableScriptType::P2sh: {
196+
uint160 hash;
197+
s >> hash;
198+
script = GetScriptForDestination(ScriptHash(hash));
199+
break;
200+
}
201+
case ReconstructableScriptType::P2pkh: {
202+
uint160 hash;
203+
s >> hash;
204+
script = GetScriptForDestination(PKHash(hash));
205+
}
206+
case ReconstructableScriptType::P2pkEven:
207+
case ReconstructableScriptType::P2pkOdd: {
208+
unsigned char xcoord[32];
209+
s >> xcoord;
210+
script.resize(35);
211+
script[0] = 33;
212+
script[1] = type;
213+
memcpy(&script[2], xcoord, 32);
214+
script[34] = OP_CHECKSIG;
215+
}
216+
case ReconstructableScriptType::P2pkUncompressed: {
217+
unsigned char public_key[65];
218+
s >> public_key;
219+
script.resize(67);
220+
script[0] = 65;
221+
memcpy(&script[1], public_key, 65);
222+
script[66] = OP_CHECKSIG;
223+
}
224+
default: break;
225+
}
226+
}
227+
};
228+
98229
struct AmountCompression
99230
{
100231
template<typename Stream, typename I> void Ser(Stream& s, I val)

src/init.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -557,6 +557,7 @@ void SetupServerArgs(ArgsManager& argsman, bool can_listen_ipc)
557557
argsman.AddArg("-v2transport", strprintf("Support v2 transport (default: %u)", DEFAULT_V2_TRANSPORT), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
558558
argsman.AddArg("-peerbloomfilters", strprintf("Support filtering of blocks and transaction with bloom filters (default: %u)", DEFAULT_PEERBLOOMFILTERS), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
559559
argsman.AddArg("-peerblockfilters", strprintf("Serve compact block filters to peers per BIP 157 (default: %u)", DEFAULT_PEERBLOCKFILTERS), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
560+
argsman.AddArg("-peerblockinputs", strprintf("Serve historical inputs to blocks (default: %u)", DEFAULT_PEERBLOCKUNDO), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
560561
argsman.AddArg("-txreconciliation", strprintf("Enable transaction reconciliations per BIP 330 (default: %d)", DEFAULT_TXRECONCILIATION_ENABLE), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::CONNECTION);
561562
argsman.AddArg("-port=<port>", strprintf("Listen for connections on <port> (default: %u, testnet3: %u, testnet4: %u, signet: %u, regtest: %u). Not relevant for I2P (see doc/i2p.md). If set to a value x, the default onion listening port will be set to x+1.", defaultChainParams->GetDefaultPort(), testnetChainParams->GetDefaultPort(), testnet4ChainParams->GetDefaultPort(), signetChainParams->GetDefaultPort(), regtestChainParams->GetDefaultPort()), ArgsManager::ALLOW_ANY | ArgsManager::NETWORK_ONLY, OptionsCategory::CONNECTION);
562563
const std::string proxy_doc_for_value =
@@ -984,6 +985,13 @@ bool AppInitParameterInteraction(const ArgsManager& args)
984985
g_local_services = ServiceFlags(g_local_services | NODE_COMPACT_FILTERS);
985986
}
986987

988+
if (args.GetBoolArg("-peerblockinputs", DEFAULT_PEERBLOCKUNDO)) {
989+
if (args.GetIntArg("-prune", 0)) {
990+
return InitError(_("Prune mode is incompatible with serving block inputs."));
991+
}
992+
g_local_services = ServiceFlags(g_local_services | NODE_BLOCK_UNDO);
993+
}
994+
987995
if (args.GetIntArg("-prune", 0)) {
988996
if (args.GetBoolArg("-txindex", DEFAULT_TXINDEX))
989997
return InitError(_("Prune mode is incompatible with -txindex."));

src/net_processing.cpp

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@
5656
#include <tinyformat.h>
5757
#include <txmempool.h>
5858
#include <uint256.h>
59+
#include <undo.h>
5960
#include <util/check.h>
6061
#include <util/strencodings.h>
6162
#include <util/time.h>
@@ -1076,6 +1077,8 @@ class PeerManagerImpl final : public PeerManager
10761077
*/
10771078
void ProcessGetCFCheckPt(CNode& node, Peer& peer, DataStream& vRecv);
10781079

1080+
void ProcessGetBlockUndo(CNode& node, Peer& peer, DataStream& vRecv);
1081+
10791082
/** Checks if address relay is permitted with peer. If needed, initializes
10801083
* the m_addr_known bloom filter and sets m_addr_relay_enabled to true.
10811084
*
@@ -3394,6 +3397,48 @@ void PeerManagerImpl::ProcessGetCFCheckPt(CNode& node, Peer& peer, DataStream& v
33943397
headers);
33953398
}
33963399

3400+
void PeerManagerImpl::ProcessGetBlockUndo(CNode& pfrom, Peer& peer, DataStream& vRecv)
3401+
{
3402+
if ((peer.m_our_services & NODE_BLOCK_UNDO) != NODE_BLOCK_UNDO) {
3403+
LogDebug(BCLog::NET, "ignoring unsupported block undo request, %s\n", pfrom.DisconnectMsg(fLogIPs));
3404+
pfrom.fDisconnect = true;
3405+
return;
3406+
}
3407+
uint256 blockhash;
3408+
vRecv >> blockhash;
3409+
uint32_t cutoff;
3410+
vRecv >> cutoff;
3411+
CBlockIndex* pindex{nullptr};
3412+
{
3413+
LOCK(cs_main);
3414+
pindex = m_chainman.m_blockman.LookupBlockIndex(blockhash);
3415+
if (!pindex) {
3416+
return;
3417+
}
3418+
if (!BlockRequestAllowed(pindex)) {
3419+
LogDebug(BCLog::NET, "%s: ignoring request from peer=%i for old block that isn't in the main chain\n", __func__, pfrom.GetId());
3420+
return;
3421+
}
3422+
// disconnect node in case we have reached the outbound limit for serving historical blocks
3423+
if (m_connman.OutboundTargetReached(true) &&
3424+
(((m_chainman.m_best_header != nullptr) && (m_chainman.m_best_header->GetBlockTime() - pindex->GetBlockTime() > HISTORICAL_BLOCK_AGE))) &&
3425+
!pfrom.HasPermission(NetPermissionFlags::Download) // nodes with the download permission may exceed target
3426+
) {
3427+
LogDebug(BCLog::NET, "historical block serving limit reached, %s\n", pfrom.DisconnectMsg(fLogIPs));
3428+
pfrom.fDisconnect = true;
3429+
return;
3430+
}
3431+
}
3432+
CBlockUndo block_undo{};
3433+
if (m_chainman.m_blockman.ReadBlockUndo(block_undo, *pindex)) {
3434+
auto hash = pindex->GetBlockHash();
3435+
NetworkBlockUndo undo{hash, block_undo};
3436+
MakeAndPushMessage(pfrom, NetMsgType::BLOCKUNDO, undo);
3437+
} else {
3438+
LogError("Cannot load block undo from disk, %s\n", pfrom.DisconnectMsg(fLogIPs));
3439+
}
3440+
}
3441+
33973442
void PeerManagerImpl::ProcessBlock(CNode& node, const std::shared_ptr<const CBlock>& block, bool force_processing, bool min_pow_checked)
33983443
{
33993444
bool new_block{false};
@@ -5120,6 +5165,10 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
51205165
return;
51215166
}
51225167

5168+
if (msg_type == NetMsgType::GETBLOCKUNDO) {
5169+
ProcessGetBlockUndo(pfrom, *peer, vRecv);
5170+
}
5171+
51235172
if (msg_type == NetMsgType::NOTFOUND) {
51245173
std::vector<CInv> vInv;
51255174
vRecv >> vInv;

src/net_processing.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ static constexpr bool DEFAULT_TXRECONCILIATION_ENABLE{false};
4242
static const uint32_t DEFAULT_BLOCK_RECONSTRUCTION_EXTRA_TXN{100};
4343
static const bool DEFAULT_PEERBLOOMFILTERS = false;
4444
static const bool DEFAULT_PEERBLOCKFILTERS = false;
45+
static const bool DEFAULT_PEERBLOCKUNDO = false;
4546
/** Maximum number of outstanding CMPCTBLOCK requests for the same block. */
4647
static const unsigned int MAX_CMPCTBLOCKS_INFLIGHT_PER_BLOCK = 3;
4748
/** Number of headers sent in one getheaders result. We rely on the assumption that if a peer sends

src/protocol.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,7 @@ static std::string serviceFlagToStr(size_t bit)
9999
case NODE_COMPACT_FILTERS: return "COMPACT_FILTERS";
100100
case NODE_NETWORK_LIMITED: return "NETWORK_LIMITED";
101101
case NODE_P2P_V2: return "P2P_V2";
102+
case NODE_BLOCK_UNDO: return "BLOCK_UNDO";
102103
// Not using default, so we get warned when a case is missing
103104
}
104105

src/protocol.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -216,6 +216,10 @@ inline constexpr const char* GETBLOCKTXN{"getblocktxn"};
216216
* @since protocol version 70014 as described by BIP 152
217217
*/
218218
inline constexpr const char* BLOCKTXN{"blocktxn"};
219+
220+
inline constexpr const char* GETBLOCKUNDO{"getbundo"};
221+
222+
inline constexpr const char* BLOCKUNDO{"bundo"};
219223
/**
220224
* getcfilters requests compact filters for a range of blocks.
221225
* Only available with service bit NODE_COMPACT_FILTERS as described by
@@ -303,6 +307,8 @@ inline const std::array ALL_NET_MESSAGE_TYPES{std::to_array<std::string>({
303307
NetMsgType::CFCHECKPT,
304308
NetMsgType::WTXIDRELAY,
305309
NetMsgType::SENDTXRCNCL,
310+
NetMsgType::BLOCKUNDO,
311+
NetMsgType::GETBLOCKUNDO,
306312
})};
307313

308314
/** nServices flags */
@@ -336,6 +342,7 @@ enum ServiceFlags : uint64_t {
336342
// collisions and other cases where nodes may be advertising a service they
337343
// do not actually support. Other service bits should be allocated via the
338344
// BIP process.
345+
NODE_BLOCK_UNDO = (1 << 21),
339346
};
340347

341348
/**

src/test/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,7 @@ add_executable(test_bitcoin
120120
txvalidation_tests.cpp
121121
txvalidationcache_tests.cpp
122122
uint256_tests.cpp
123+
undo_tests.cpp
123124
util_check_tests.cpp
124125
util_expected_tests.cpp
125126
util_string_tests.cpp

0 commit comments

Comments
 (0)