@@ -351,7 +351,16 @@ struct CNodeState {
351
351
352
352
TxDownloadState m_tx_download;
353
353
354
- CNodeState (CAddress addrIn, std::string addrNameIn) : address(addrIn), name(addrNameIn) {
354
+ // ! Whether this peer is an inbound connection
355
+ bool m_is_inbound;
356
+
357
+ // ! Whether this peer is a manual connection
358
+ bool m_is_manual_connection;
359
+
360
+ CNodeState (CAddress addrIn, std::string addrNameIn, bool is_inbound, bool is_manual) :
361
+ address (addrIn), name(std::move(addrNameIn)), m_is_inbound(is_inbound),
362
+ m_is_manual_connection (is_manual)
363
+ {
355
364
fCurrentlyConnected = false ;
356
365
nMisbehavior = 0 ;
357
366
fShouldBan = false ;
@@ -747,7 +756,7 @@ void PeerLogicValidation::InitializeNode(CNode *pnode) {
747
756
NodeId nodeid = pnode->GetId ();
748
757
{
749
758
LOCK (cs_main);
750
- mapNodeState.emplace_hint (mapNodeState.end (), std::piecewise_construct, std::forward_as_tuple (nodeid), std::forward_as_tuple (addr, std::move (addrName)));
759
+ mapNodeState.emplace_hint (mapNodeState.end (), std::piecewise_construct, std::forward_as_tuple (nodeid), std::forward_as_tuple (addr, std::move (addrName), pnode-> fInbound , pnode-> m_manual_connection ));
751
760
}
752
761
if (!pnode->fInbound )
753
762
PushNodeVersion (pnode, connman, GetTime ());
@@ -994,9 +1003,22 @@ static bool MaybePunishNode(NodeId nodeid, const CValidationState& state, bool v
994
1003
return true ;
995
1004
}
996
1005
break ;
997
- // Handled elsewhere for now
998
1006
case ValidationInvalidReason::CACHED_INVALID:
999
- break ;
1007
+ {
1008
+ LOCK (cs_main);
1009
+ CNodeState *node_state = State (nodeid);
1010
+ if (node_state == nullptr ) {
1011
+ break ;
1012
+ }
1013
+
1014
+ // Ban outbound (but not inbound) peers if on an invalid chain.
1015
+ // Exempt HB compact block peers and manual connections.
1016
+ if (!via_compact_block && !node_state->m_is_inbound && !node_state->m_is_manual_connection ) {
1017
+ Misbehaving (nodeid, 100 , message);
1018
+ return true ;
1019
+ }
1020
+ break ;
1021
+ }
1000
1022
case ValidationInvalidReason::BLOCK_INVALID_HEADER:
1001
1023
case ValidationInvalidReason::BLOCK_CHECKPOINT:
1002
1024
case ValidationInvalidReason::BLOCK_INVALID_PREV:
@@ -1556,7 +1578,7 @@ inline void static SendBlockTransactions(const CBlock& block, const BlockTransac
1556
1578
connman->PushMessage (pfrom, msgMaker.Make (nSendFlags, NetMsgType::BLOCKTXN, resp));
1557
1579
}
1558
1580
1559
- bool static ProcessHeadersMessage (CNode *pfrom, CConnman *connman, const std::vector<CBlockHeader>& headers, const CChainParams& chainparams, bool punish_duplicate_invalid )
1581
+ bool static ProcessHeadersMessage (CNode *pfrom, CConnman *connman, const std::vector<CBlockHeader>& headers, const CChainParams& chainparams, bool via_compact_block )
1560
1582
{
1561
1583
const CNetMsgMaker msgMaker (pfrom->GetSendVersion ());
1562
1584
size_t nCount = headers.size ();
@@ -1619,41 +1641,7 @@ bool static ProcessHeadersMessage(CNode *pfrom, CConnman *connman, const std::ve
1619
1641
CBlockHeader first_invalid_header;
1620
1642
if (!ProcessNewBlockHeaders (headers, state, chainparams, &pindexLast, &first_invalid_header)) {
1621
1643
if (state.IsInvalid ()) {
1622
- if (punish_duplicate_invalid && state.GetReason () == ValidationInvalidReason::CACHED_INVALID) {
1623
- // Goal: don't allow outbound peers to use up our outbound
1624
- // connection slots if they are on incompatible chains.
1625
- //
1626
- // We ask the caller to set punish_invalid appropriately based
1627
- // on the peer and the method of header delivery (compact
1628
- // blocks are allowed to be invalid in some circumstances,
1629
- // under BIP 152).
1630
- // Here, we try to detect the narrow situation that we have a
1631
- // valid block header (ie it was valid at the time the header
1632
- // was received, and hence stored in mapBlockIndex) but know the
1633
- // block is invalid, and that a peer has announced that same
1634
- // block as being on its active chain.
1635
- // Disconnect the peer in such a situation.
1636
- //
1637
- // Note: if the header that is invalid was not accepted to our
1638
- // mapBlockIndex at all, that may also be grounds for
1639
- // disconnecting the peer, as the chain they are on is likely
1640
- // to be incompatible. However, there is a circumstance where
1641
- // that does not hold: if the header's timestamp is more than
1642
- // 2 hours ahead of our current time. In that case, the header
1643
- // may become valid in the future, and we don't want to
1644
- // disconnect a peer merely for serving us one too-far-ahead
1645
- // block header, to prevent an attacker from splitting the
1646
- // network by mining a block right at the 2 hour boundary.
1647
- //
1648
- // TODO: update the DoS logic (or, rather, rewrite the
1649
- // DoS-interface between validation and net_processing) so that
1650
- // the interface is cleaner, and so that we disconnect on all the
1651
- // reasons that a peer's headers chain is incompatible
1652
- // with ours (eg block->nVersion softforks, MTP violations,
1653
- // etc), and not just the duplicate-invalid case.
1654
- pfrom->fDisconnect = true ;
1655
- }
1656
- MaybePunishNode (pfrom->GetId (), state, /* via_compact_block*/ false , " invalid header received" );
1644
+ MaybePunishNode (pfrom->GetId (), state, via_compact_block, " invalid header received" );
1657
1645
return false ;
1658
1646
}
1659
1647
}
@@ -2781,7 +2769,7 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
2781
2769
// the peer if the header turns out to be for an invalid block.
2782
2770
// Note that if a peer tries to build on an invalid chain, that
2783
2771
// will be detected and the peer will be banned.
2784
- return ProcessHeadersMessage (pfrom, connman, {cmpctblock.header }, chainparams, /* punish_duplicate_invalid =*/ false );
2772
+ return ProcessHeadersMessage (pfrom, connman, {cmpctblock.header }, chainparams, /* via_compact_block =*/ true );
2785
2773
}
2786
2774
2787
2775
if (fBlockReconstructed ) {
@@ -2924,12 +2912,7 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
2924
2912
ReadCompactSize (vRecv); // ignore tx count; assume it is 0.
2925
2913
}
2926
2914
2927
- // Headers received via a HEADERS message should be valid, and reflect
2928
- // the chain the peer is on. If we receive a known-invalid header,
2929
- // disconnect the peer if it is using one of our outbound connection
2930
- // slots.
2931
- bool should_punish = !pfrom->fInbound && !pfrom->m_manual_connection ;
2932
- return ProcessHeadersMessage (pfrom, connman, headers, chainparams, should_punish);
2915
+ return ProcessHeadersMessage (pfrom, connman, headers, chainparams, /* via_compact_block=*/ false );
2933
2916
}
2934
2917
2935
2918
if (strCommand == NetMsgType::BLOCK)
0 commit comments