Skip to content

Commit 485c2cd

Browse files
committed
cryptonote_protocol: ignore fluffy blocks past certain depth
The node searches for the most recent main-chain ancestor of an incoming fluffy block, and ignores the incoming block if the ancestor is too old. It does not drop the connection, however, so syncing deep alt chains should still be possible during the normal sync process.
1 parent fbc242d commit 485c2cd

File tree

1 file changed

+38
-0
lines changed

1 file changed

+38
-0
lines changed

src/cryptonote_protocol/cryptonote_protocol_handler.inl

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@
7878
#define DROP_ON_SYNC_WEDGE_THRESHOLD (30 * 1000000000ull) // nanoseconds
7979
#define LAST_ACTIVITY_STALL_THRESHOLD (2.0f) // seconds
8080
#define DROP_PEERS_ON_SCORE -2
81+
#define MAX_FLUFFY_BLOCK_DEPTH (2 * CRYPTONOTE_DEFAULT_TX_SPENDABLE_AGE)
8182

8283
namespace cryptonote
8384
{
@@ -623,6 +624,43 @@ namespace cryptonote
623624
MLOG_P2P_MESSAGE(context << "Received NOTIFY_NEW_FLUFFY_BLOCK " << new_block_hash << " (height "
624625
<< arg.current_blockchain_height << ", " << arg.b.txs.size() << " txes)");
625626

627+
// Get top block
628+
uint64_t top_block_index;
629+
crypto::hash top_block_id;
630+
m_core.get_blockchain_top(top_block_index, top_block_id);
631+
632+
// Find the nominal common ancestor of this block and the main chain
633+
crypto::hash common_ancestor = new_block.prev_id;
634+
bool is_common_ancestor_known = false;
635+
uint64_t ancestor_block_index = 0;
636+
for (size_t i = 0; i < MAX_FLUFFY_BLOCK_DEPTH; ++i) // bounded loop
637+
{
638+
block prev_block;
639+
bool is_ancestor_alt = false;
640+
is_common_ancestor_known = m_core.get_block_by_hash(common_ancestor, prev_block, &is_ancestor_alt);
641+
if (is_common_ancestor_known)
642+
ancestor_block_index = get_block_height(prev_block);
643+
if (!is_common_ancestor_known || !is_ancestor_alt)
644+
break;
645+
common_ancestor = prev_block.prev_id;
646+
}
647+
648+
// Ignore the block if its common ancestor is unknown or too old
649+
if (!is_common_ancestor_known || ancestor_block_index > top_block_index)
650+
{
651+
MDEBUG("Incoming fluffy block " << new_block_hash << " is an orphan from our perspective, ignoring...");
652+
// don't drop the connection because this node may be 2 blocks ahead of us
653+
return 1;
654+
}
655+
const uint64_t ancestor_depth = top_block_index - ancestor_block_index;
656+
if (ancestor_depth > MAX_FLUFFY_BLOCK_DEPTH)
657+
{
658+
MDEBUG("Incoming fluffy block " << new_block_hash << " breaks off from our main chain at block "
659+
<< common_ancestor << ", which has a depth of " << ancestor_depth << ", ignoring...");
660+
// don't drop this connection because we may want to sync its deep alternative chain
661+
return 1;
662+
}
663+
626664
// Pause mining and resume after block verification to prevent wasted mining cycles while
627665
// validating the next block. Needs more research into if this is a DoS vector or not. Invalid
628666
// block validation will cause disconnects and bans, so it might not be that bad.

0 commit comments

Comments
 (0)