From 55ca03f4ff166c10b9b357b5e4dff7dff3f1a808 Mon Sep 17 00:00:00 2001 From: DcruBro Date: Fri, 15 May 2026 18:49:49 +0200 Subject: [PATCH] orphan test --- TODO.txt | 2 ++ src/nets/net_node.c | 55 +++++++++++++++++++++++++++++---------------- 2 files changed, 38 insertions(+), 19 deletions(-) diff --git a/TODO.txt b/TODO.txt index f71653b..3098927 100644 --- a/TODO.txt +++ b/TODO.txt @@ -10,6 +10,8 @@ A potential race could occur if the P2P node receives a new block, or flushes a Maybe think about how block broadcasting works. Instead of unsolicited broadcasting, maybe only advertise a new height and have peers request the block if they want it. This would reduce bandwidth usage, but it also means that blocks won't propagate as fast, which could lead to more orphaned blocks. It's a tradeoff. +Check if Block FullVerify is actually verifying fully (not missing any conditions). + TO TEST: Implement Horizen's "Reorg Penalty" system to make it harder for the young chain to be attacked by a powerful miner. diff --git a/src/nets/net_node.c b/src/nets/net_node.c index 2172619..cbe0ab1 100644 --- a/src/nets/net_node.c +++ b/src/nets/net_node.c @@ -28,6 +28,12 @@ static uint64_t Node_GetCurrentBlockHeight(void) { return currentBlockHeight; } +typedef enum { + NODE_BLOCK_REJECTED = 0, + NODE_BLOCK_ORPHAN_QUEUED = 1, + NODE_BLOCK_ACCEPTED = 2 +} node_block_accept_result_t; + static void* Node_MaintenanceThread(void* arg) { net_node_t* n = (net_node_t*)arg; if (!n) return NULL; @@ -61,18 +67,18 @@ static int Node_DecodePacket(const tcp_connection_t* conn, packet_type_t* outTyp return 0; } -static bool Node_ParseAndAcceptBlock(const unsigned char* payload, size_t payloadLen, bool persist) { - if (!payload) { return false; } +static node_block_accept_result_t Node_ParseAndAcceptBlock(const unsigned char* payload, size_t payloadLen, bool persist) { + if (!payload) { return NODE_BLOCK_REJECTED; } size_t offset = 0; - if (payloadLen < sizeof(uint64_t) + sizeof(block_header_t) + sizeof(uint64_t)) { return false; } + if (payloadLen < sizeof(uint64_t) + sizeof(block_header_t) + sizeof(uint64_t)) { return NODE_BLOCK_REJECTED; } uint64_t blockHeight = 0; memcpy(&blockHeight, payload + offset, sizeof(blockHeight)); offset += sizeof(blockHeight); block_t* blk = (block_t*)calloc(1, sizeof(block_t)); - if (!blk) { return false; } + if (!blk) { return NODE_BLOCK_REJECTED; } memcpy(&blk->header, payload + offset, sizeof(blk->header)); blk->header.blockNumber = blockHeight; @@ -83,13 +89,13 @@ static bool Node_ParseAndAcceptBlock(const unsigned char* payload, size_t payloa offset += sizeof(txCount); blk->transactions = DYNARR_CREATE(signed_transaction_t, txCount == 0 ? 1 : (size_t)txCount); - if (!blk->transactions) { free(blk); return false; } + if (!blk->transactions) { free(blk); return NODE_BLOCK_REJECTED; } for (uint64_t i = 0; i < txCount; ++i) { if (offset + sizeof(signed_transaction_t) > payloadLen) { DynArr_destroy(blk->transactions); free(blk); - return false; + return NODE_BLOCK_REJECTED; } signed_transaction_t tx; memcpy(&tx, payload + offset, sizeof(tx)); @@ -97,7 +103,7 @@ static bool Node_ParseAndAcceptBlock(const unsigned char* payload, size_t payloa if (!DynArr_push_back(blk->transactions, &tx)) { DynArr_destroy(blk->transactions); free(blk); - return false; + return NODE_BLOCK_REJECTED; } } @@ -106,14 +112,14 @@ static bool Node_ParseAndAcceptBlock(const unsigned char* payload, size_t payloa printf("Rejected BLOCK_DATA at height %" PRIu64 " during validation\n", blockHeight); DynArr_destroy(blk->transactions); free(blk); - return false; + return NODE_BLOCK_REJECTED; } if (!currentChain) { printf("Rejected BLOCK_DATA at height %" PRIu64 ": no active chain\n", blockHeight); DynArr_destroy(blk->transactions); free(blk); - return false; + return NODE_BLOCK_REJECTED; } // If parent is missing, insert into orphan pool instead of rejecting immediately. @@ -125,7 +131,7 @@ static bool Node_ParseAndAcceptBlock(const unsigned char* payload, size_t payloa OrphanPool_Insert(blk, blockHeight); if (parentCopy) Block_Destroy(parentCopy); printf("Queued orphan BLOCK_DATA at height %" PRIu64 "\n", blockHeight); - return true; + return NODE_BLOCK_ORPHAN_QUEUED; } Block_Destroy(parentCopy); } @@ -137,7 +143,7 @@ static bool Node_ParseAndAcceptBlock(const unsigned char* payload, size_t payloa DynArr_destroy(blk->transactions); } free(blk); - return false; + return NODE_BLOCK_REJECTED; } // Persist on accept if requested @@ -156,7 +162,7 @@ static bool Node_ParseAndAcceptBlock(const unsigned char* payload, size_t payloa Chain_SaveToFile(currentChain, chainDataDir, currentSupply, currentReward); BalanceSheet_SaveToFile(chainDataDir); } - return true; + return NODE_BLOCK_ACCEPTED; } static void Node_ForwardConnect(net_node_t* node, tcp_connection_t* conn) { @@ -359,7 +365,6 @@ void Node_Server_OnConnect(tcp_connection_t* client) { // We avoid connecting if we already have an outbound to the same IP. char ipbuf[INET_ADDRSTRLEN]; if (inet_ntop(AF_INET, &client->peerAddr.sin_addr, ipbuf, sizeof(ipbuf))) { - unsigned short peerPort = (unsigned short)ntohs(client->peerAddr.sin_port); // Use LISTEN_PORT as target port for peer's listening service, not the ephemeral source port. unsigned short targetPort = LISTEN_PORT; @@ -544,12 +549,15 @@ void Node_Server_OnData(tcp_connection_t* client) { if (payloadLen >= sizeof(uint64_t)) { uint64_t blockHeight = 0; memcpy(&blockHeight, payload, sizeof(blockHeight)); - if (Node_ParseAndAcceptBlock(payload, payloadLen, true)) { + node_block_accept_result_t result = Node_ParseAndAcceptBlock(payload, payloadLen, true); + if (result == NODE_BLOCK_ACCEPTED) { printf("Accepted BROADCAST_BLOCK from node %u\n", client ? client->connectionId : 0U); net_node_t* node = Node_FromConnection(client); if (node) { Node_BroadcastChainRange(node, (size_t)blockHeight, client); } + } else if (result == NODE_BLOCK_ORPHAN_QUEUED) { + printf("Queued orphan BROADCAST_BLOCK from node %u\n", client ? client->connectionId : 0U); } else { printf("Rejected BROADCAST_BLOCK from node %u\n", client ? client->connectionId : 0U); } @@ -670,7 +678,8 @@ void Node_Client_OnData(tcp_connection_t* client) { if (payloadLen >= sizeof(uint64_t)) { uint64_t blockHeight = 0; memcpy(&blockHeight, payload, sizeof(blockHeight)); - if (Node_ParseAndAcceptBlock(payload, payloadLen, true)) { + node_block_accept_result_t result = Node_ParseAndAcceptBlock(payload, payloadLen, true); + if (result == NODE_BLOCK_ACCEPTED) { printf("Accepted BLOCK_DATA from node %u\n", client ? client->connectionId : 0U); net_node_t* node = Node_FromConnection(client); if (node) { @@ -688,6 +697,8 @@ void Node_Client_OnData(tcp_connection_t* client) { Node_BroadcastChainRange(node, (size_t)blockHeight, client); } + } else if (result == NODE_BLOCK_ORPHAN_QUEUED) { + printf("Queued orphan BLOCK_DATA from node %u\n", client ? client->connectionId : 0U); } else { printf("Rejected BLOCK_DATA from node %u\n", client ? client->connectionId : 0U); } @@ -698,7 +709,8 @@ void Node_Client_OnData(tcp_connection_t* client) { if (payloadLen >= sizeof(uint64_t)) { uint64_t blockHeight = 0; memcpy(&blockHeight, payload, sizeof(blockHeight)); - if (Node_ParseAndAcceptBlock(payload, payloadLen, true)) { + node_block_accept_result_t result = Node_ParseAndAcceptBlock(payload, payloadLen, true); + if (result == NODE_BLOCK_ACCEPTED) { printf("Accepted BROADCAST_BLOCK from node %u\n", client ? client->connectionId : 0U); net_node_t* node = Node_FromConnection(client); if (node) { @@ -716,6 +728,8 @@ void Node_Client_OnData(tcp_connection_t* client) { Node_BroadcastChainRange(node, (size_t)blockHeight, client); } + } else if (result == NODE_BLOCK_ORPHAN_QUEUED) { + printf("Queued orphan BROADCAST_BLOCK from node %u\n", client ? client->connectionId : 0U); } else { printf("Rejected BROADCAST_BLOCK from node %u\n", client ? client->connectionId : 0U); } @@ -798,20 +812,22 @@ void Node_BroadcastChainRange(net_node_t* node, size_t startHeightInclusive, tcp size_t chainSize = Chain_Size(currentChain); if (startHeightInclusive >= chainSize) return; + uint32_t sourceIp = 0; + if (sourceConn) { + sourceIp = sourceConn->peerAddr.sin_addr.s_addr; + } + for (size_t h = startHeightInclusive; h < chainSize; ++h) { block_t* blk = NULL; - bool loadedFromDisk = false; if (!Chain_GetBlockCopy(currentChain, h, &blk) || !blk) { if (!Chain_LoadBlockFromFile(chainDataDir, h, true, &blk, NULL) || !blk) { continue; } - loadedFromDisk = true; } else if (!blk->transactions) { block_t* full = NULL; if (Chain_LoadBlockFromFile(chainDataDir, h, true, &full, NULL) && full) { Block_Destroy(blk); blk = full; - loadedFromDisk = true; } } @@ -863,6 +879,7 @@ void Node_BroadcastChainRange(net_node_t* node, size_t startHeightInclusive, tcp tcp_connection_t* conn = node->outboundClients[i].connection; if (!conn) continue; if (conn == sourceConn) continue; + if (sourceIp != 0 && conn->peerAddr.sin_addr.s_addr == sourceIp) continue; Node_SendPacket(node, conn, PACKET_TYPE_BROADCAST_BLOCK, payload, off); } pthread_mutex_unlock(&node->outboundLock);