Overview
Original Bitcoin P2P sync protocol does not download blocks if advertized cumulative difficulty is lower than ours. It is no longer valid for Pop aware chains. P2P protocol should be modified to offer and accept all blocks and also should properly process ATV and VTB data.
1. Add P2P service files: p2p_sync.hpp, p2p_sync.cpp.
VeriBlock P2P service files contain interactions with Pop mempool, data filtering, misbehaving nodes protection.
P2P header: https://github.com/VeriBlock/vbk-ri-btc/blob/master/src/vbk/p2p_sync.hpp. Copy this file to your project.
P2P source: https://github.com/VeriBlock/vbk-ri-btc/blob/master/src/vbk/p2p_sync.cpp. Copy this file to your project.
2. Introduce new protocol version.
https://github.com/VeriBlock/vbk-ri-btc/blob/master/src/version.h
-static const int PROTOCOL_VERSION = 70015;
+static const int PROTOCOL_VERSION = 80000;
static const int INVALID_CB_NO_BAN_VERSION = 70015;
+
+static const int PING_BESTCHAIN_VERSION = 80000;
3. Allow node to download chain with less chainWork.
https://github.com/VeriBlock/vbk-ri-btc/blob/master/src/net_processing.h
bool GetNodeStateStats(NodeId nodeid, CNodeStateStats &stats);
+
+void Misbehaving(NodeId nodeid, int howmuch, const std::string& message="") EXCLUSIVE_LOCKS_REQUIRED(cs_main);
https://github.com/VeriBlock/vbk-ri-btc/blob/master/src/net_processing.cpp
#include <util/validation.h>
+#include <vbk/p2p_sync.hpp>
void EraseOrphansFor(NodeId peer);
-
-void Misbehaving(NodeId nodeid, int howmuch, const std::string& message="") EXCLUSIVE_LOCKS_REQUIRED(cs_main);
struct CNodeState
- const CBlockIndex *pindexBestKnownBlock;
+ const CBlockIndex *pindexBestKnownBlock = nullptr;
+
+ const CBlockIndex *pindexLastAnnouncedBlock = nullptr;
uint256 hashLastUnknownBlock;
- const CBlockIndex *pindexLastCommonBlock;
+ const CBlockIndex *pindexLastCommonBlock = nullptr;
+
+ const CBlockIndex *pindexLastCommonAnnouncedBlock = nullptr;
+
+static void UpdateBestChainTip(NodeId nodeid, const uint256 &tip) EXCLUSIVE_LOCKS_REQUIRED(cs_main) {
+ CNodeState *state = State(nodeid);
+ assert(state != nullptr);
+
+ const CBlockIndex* pindex = LookupBlockIndex(tip);
+ if (pindex && pindex->nChainWork > 0) {
+ state->pindexLastAnnouncedBlock = pindex;
+ LogPrint(BCLog::NET, "peer=%s: announced best chain %s\n", nodeid, tip.GetHex());
+
+
+ if(state->pindexBestKnownBlock == nullptr || pindex->nChainWork >= state->pindexBestKnownBlock->nChainWork) {
+ state->pindexBestKnownBlock = pindex;
+ }
+ }
+
+ ProcessBlockAvailability(nodeid);
+}
-static void FindNextBlocksToDownload(NodeId nodeid, unsigned int count, std::vector<const CBlockIndex*>& vBlocks, NodeId& nodeStaller, const Consensus::Params& consensusParams) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
+static void FindNextBlocksToDownload(NodeId nodeid, unsigned int count, std::vector<const CBlockIndex*>& vBlocks, NodeId& nodeStaller, const Consensus::Params& consensusParams,
+
+ const CBlockIndex* bestBlock,
+
+ const CBlockIndex** lastCommonBlockOut
+ ) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
{
if (count == 0)
return;
vBlocks.reserve(vBlocks.size() + count);
- CNodeState *state = State(nodeid);
- assert(state != nullptr);
-
-
- ProcessBlockAvailability(nodeid);
- if (state->pindexBestKnownBlock == nullptr || state->pindexBestKnownBlock->nChainWork < ::ChainActive().Tip()->nChainWork || state->pindexBestKnownBlock->nChainWork < nMinimumChainWork) {
+ if (bestBlock == nullptr || bestBlock->nChainWork < nMinimumChainWork) {
return;
}
- if (state->pindexLastCommonBlock == nullptr) {
+ assert(lastCommonBlockOut);
+
+ if (*lastCommonBlockOut == nullptr) {
- state->pindexLastCommonBlock = ::ChainActive()[std::min(state->pindexBestKnownBlock->nHeight, ::ChainActive().Height())];
+ *lastCommonBlockOut = ::ChainActive()[std::min(bestBlock->nHeight, ::ChainActive().Height())];
}
- state->pindexLastCommonBlock = LastCommonAncestor(state->pindexLastCommonBlock, state->pindexBestKnownBlock);
- if (state->pindexLastCommonBlock == state->pindexBestKnownBlock)
+ *lastCommonBlockOut = LastCommonAncestor(*lastCommonBlockOut, bestBlock);
+ if (*lastCommonBlockOut == bestBlock)
return;
std::vector<const CBlockIndex*> vToFetch;
- const CBlockIndex *pindexWalk = state->pindexLastCommonBlock;
+ const CBlockIndex *pindexWalk = *lastCommonBlockOut;
- int nWindowEnd = state->pindexLastCommonBlock->nHeight + BLOCK_DOWNLOAD_WINDOW;
- int nMaxHeight = std::min<int>(state->pindexBestKnownBlock->nHeight, nWindowEnd + 1);
+ int nWindowEnd = (*lastCommonBlockOut)->nHeight + BLOCK_DOWNLOAD_WINDOW;
+ int nMaxHeight = std::min<int>(bestBlock->nHeight, nWindowEnd + 1);
NodeId waitingfor = -1;
method FindNextBlocksToDownload
int nToFetch = std::min(nMaxHeight - pindexWalk->nHeight, std::max<int>(count - vBlocks.size(), 128));
vToFetch.resize(nToFetch);
- pindexWalk = state->pindexBestKnownBlock->GetAncestor(pindexWalk->nHeight + nToFetch);
+ pindexWalk = bestBlock->GetAncestor(pindexWalk->nHeight + nToFetch);
method FindNextBlocksToDownload
if (pindex->nStatus & BLOCK_HAVE_DATA || ::ChainActive().Contains(pindex)) {
if (pindex->HaveTxsDownloaded())
- state->pindexLastCommonBlock = pindex;
+ *lastCommonBlockOut = pindex;
} else if (mapBlocksInFlight.count(pindex->GetBlockHash()) == 0) {
method ProcessHeadersMessage
- if (fCanDirectFetch && pindexLast->IsValid(BLOCK_VALID_TREE) && ::ChainActive().Tip()->nChainWork <= pindexLast->nChainWork) {
+ if (fCanDirectFetch && pindexLast->IsValid(BLOCK_VALID_TREE)
+
+ ) {
std::vector<const CBlockIndex*> vToFetch;
const CBlockIndex *pindexWalk = pindexLast;
method PeerLogicValidation::SendMessages
if (!pto->fClient && ((fFetch && !pto->m_limited_node) || !::ChainstateActive().IsInitialBlockDownload()) && state.nBlocksInFlight < MAX_BLOCKS_IN_TRANSIT_PER_PEER) {
std::vector<const CBlockIndex*> vToDownload;
NodeId staller = -1;
- FindNextBlocksToDownload(pto->GetId(), MAX_BLOCKS_IN_TRANSIT_PER_PEER - state.nBlocksInFlight, vToDownload, staller, consensusParams);
+
+ ProcessBlockAvailability(pto->GetId());
+
+ if(state.pindexBestKnownBlock) {
+ FindNextBlocksToDownload(pto->GetId(), MAX_BLOCKS_IN_TRANSIT_PER_PEER - state.nBlocksInFlight, vToDownload, staller, consensusParams, state.pindexBestKnownBlock, &state.pindexLastCommonBlock);
+ }
+
+ if(state.pindexLastAnnouncedBlock && state.pindexBestKnownBlock) {
+
+ assert(state.pindexLastAnnouncedBlock->nChainWork <= state.pindexBestKnownBlock->nChainWork);
+
+
+ if (state.pindexBestKnownBlock->GetAncestor(state.pindexLastAnnouncedBlock->nHeight) != state.pindexLastAnnouncedBlock) {
+
+ LogPrint(BCLog::NET, "Requesting announced best chain %d:%s from peer=%d\n", state.pindexLastAnnouncedBlock->GetBlockHash().ToString(),
+ state.pindexLastAnnouncedBlock->nHeight, pto->GetId());
+ FindNextBlocksToDownload(pto->GetId(), MAX_BLOCKS_IN_TRANSIT_PER_PEER - state.nBlocksInFlight, vToDownload, staller, consensusParams, state.pindexLastAnnouncedBlock, &state.pindexLastCommonAnnouncedBlock);
+ }
+ }
for (const CBlockIndex *pindex : vToDownload) {
4. Update Ping and Pong calls to provide best block hash.
https://github.com/VeriBlock/vbk-ri-btc/blob/master/src/net_processing.cpp
method ProcessMessage
uint64_t nonce = 0;
vRecv >> nonce;
+
+ if(pfrom->nVersion > PING_BESTCHAIN_VERSION) {
+
+ LOCK(cs_main);
+ uint256 bestHash;
+ vRecv >> bestHash;
+ UpdateBestChainTip(pfrom->GetId(), bestHash);
+
+ connman->PushMessage(pfrom, msgMaker.Make(NetMsgType::PONG, nonce, ::ChainActive().Tip()->GetBlockHash()));
+ return true;
+ }
+
method ProcessMessage
sProblem = "Nonce zero";
}
}
+
+ if(pfrom->nVersion > PING_BESTCHAIN_VERSION) {
+ LOCK(cs_main);
+ uint256 bestHash;
+ vRecv >> bestHash;
+ UpdateBestChainTip(pfrom->GetId(), bestHash);
+ }
} else {
sProblem = "Unsolicited pong without ping";
}
method PeerLogicValidation::SendMessages
if (pto->nVersion > BIP0031_VERSION) {
pto->nPingNonceSent = nonce;
- connman->PushMessage(pto, msgMaker.Make(NetMsgType::PING, nonce));
+ if(pto->nVersion > PING_BESTCHAIN_VERSION) {
+ connman->PushMessage(pto, msgMaker.Make(NetMsgType::PING, nonce, ::ChainActive().Tip()->GetBlockHash()));
+ } else {
+ connman->PushMessage(pto, msgMaker.Make(NetMsgType::PING, nonce));
+ }
5. Offer and process Pop data.
https://github.com/VeriBlock/vbk-ri-btc/blob/master/src/net_processing.cpp
method PeerLogicValidation::FinalizeNode
assert(g_outbound_peers_with_protect_from_disconnect >= 0);
mapNodeState.erase(nodeid);
+
+ VeriBlock::p2p::erasePopDataNodeState(nodeid);
method ProcessMessage
}
+
+ int tipHeight = ChainActive().Height();
+ if (Params().isPopActive(tipHeight)) {
+ int pop_res = VeriBlock::p2p::processPopData(pfrom, strCommand, vRecv, connman);
+ if (pop_res >= 0) {
+ return pop_res;
+ }
+ }
if (!(pfrom->GetLocalServices() & NODE_BLOOM) &&
(strCommand == NetMsgType::FILTERLOAD ||
method PeerLogicValidation::SendMessages
if (!vInv.empty())
connman->PushMessage(pto, msgMaker.Make(NetMsgType::INV, vInv));
+
+ {
+ VeriBlock::p2p::offerPopData<altintegration::ATV>(pto, connman, msgMaker);
+ VeriBlock::p2p::offerPopData<altintegration::VTB>(pto, connman, msgMaker);
+ VeriBlock::p2p::offerPopData<altintegration::VbkBlock>(pto, connman, msgMaker);
+ }
+
6. Subscribe the library to the mempool events.
https://github.com/VeriBlock/vbk-ri-btc/blob/master/src/vbk/pop_service.cpp
#include <vbk/adaptors/block_provider.hpp>
+#include <vbk/p2p_sync.hpp>
#include <vbk/pop_common.hpp>
method InitPopContext
SetPop(payloads_provider);
+
+ auto& app = GetPop();
+ app.getMemPool().onAccepted<
altintegration::ATV>(VeriBlock::p2p::offerPopDataToAllNodes<altintegration::ATV>);
+ app.getMemPool().onAccepted<
altintegration::VTB>(VeriBlock::p2p::offerPopDataToAllNodes<altintegration::VTB>);
+ app.getMemPool().onAccepted<
altintegration::VbkBlock>(VeriBlock::p2p::offerPopDataToAllNodes<altintegration::VbkBlock>);
Veriblock to Bitcoin publication, committed to Veriblock blockchain in containingBlock.
7. Add P2P service to the makefile.
https://github.com/VeriBlock/vbk-ri-btc/blob/master/src/Makefile.am
libbitcoin_server_a_SOURCES = \
policy/settings.cpp \
pow.cpp \
rest.cpp \
+ vbk/p2p_sync.hpp \
+ vbk/p2p_sync.cpp \
rpc/blockchain.cpp \