From 32b9a5736697b225467c409dabd4650b46795c51 Mon Sep 17 00:00:00 2001 From: DcruBro Date: Fri, 24 Apr 2026 17:14:40 +0200 Subject: [PATCH] tx mempool start, hello packet --- include/balance_sheet.h | 17 ---------- include/constants.h | 2 ++ include/dynarr.h | 3 ++ include/nets/net_node.h | 2 ++ include/packettype.h | 11 +++++-- include/txmempool.h | 18 +++++++++++ include/utils.h | 17 ++++++++++ src/block/chain.c | 4 +++ src/dynarr.c | 4 +++ src/main.c | 7 ++++ src/nets/net_node.c | 62 ++++++++++++++++++++++++++++++++--- src/txmempool.c | 71 +++++++++++++++++++++++++++++++++++++++++ 12 files changed, 193 insertions(+), 25 deletions(-) create mode 100644 include/txmempool.h create mode 100644 src/txmempool.c diff --git a/include/balance_sheet.h b/include/balance_sheet.h index 20ca117..c83784b 100644 --- a/include/balance_sheet.h +++ b/include/balance_sheet.h @@ -12,29 +12,12 @@ #include #include -typedef struct { - uint8_t bytes[32]; -} key32_t; - typedef struct { uint8_t address[32]; // For now just the SHA-256 of the public key; allows representation in different encodings (base58, bech32, etc) without changing the underlying data structure uint256_t balance; // TODO: Additional things } balance_sheet_entry_t; -static inline uint32_t hash_key32(key32_t k) { - uint32_t hash = 2166136261u; - for (int i = 0; i < 32; i++) { - hash ^= k.bytes[i]; - hash *= 16777619; - } - return hash; -} - -static inline int eq_key32(key32_t a, key32_t b) { - return memcmp(a.bytes, b.bytes, 32) == 0; -} - KHASH_INIT(balance_sheet_map_m, key32_t, balance_sheet_entry_t, 1, hash_key32, eq_key32) extern khash_t(balance_sheet_map_m)* sheetMap; diff --git a/include/constants.h b/include/constants.h index 1ebf243..6e7405b 100644 --- a/include/constants.h +++ b/include/constants.h @@ -7,6 +7,8 @@ #include #include +extern uint64_t currentBlockHeight; + // Nets #define MAX_CONS 32 // Some baseline for now #define LISTEN_PORT 9393 diff --git a/include/dynarr.h b/include/dynarr.h index cb6c20b..b58e7b7 100644 --- a/include/dynarr.h +++ b/include/dynarr.h @@ -55,6 +55,9 @@ size_t DynArr_capacity(DynArr* p); void DynArr_destroy(DynArr* p); +// Note: Make sure to not overread or overwrite +void* DynArr_c_arr(DynArr* p); + #define DYNARR_CREATE(T, initialCapacity) DynArr_create(sizeof(T), initialCapacity) #endif diff --git a/include/nets/net_node.h b/include/nets/net_node.h index ad1baf0..29a1e43 100644 --- a/include/nets/net_node.h +++ b/include/nets/net_node.h @@ -13,6 +13,8 @@ #include +#include + typedef struct { tcp_server_t* server; tcp_client_t outboundClients[MAX_CONS]; diff --git a/include/packettype.h b/include/packettype.h index 95c7b4d..fab9e21 100644 --- a/include/packettype.h +++ b/include/packettype.h @@ -5,9 +5,14 @@ typedef enum { PACKET_TYPE_NONE = 0, - PACKET_TYPE_REQUEST = 1, - PACKET_TYPE_RESPONSE = 2, - PACKET_TYPE_MAX = 3 + PACKET_TYPE_HELLO = 1, // Hello, let's connect! Here's who I am, and what I have! + PACKET_TYPE_FETCH_BLOCK = 2, // I want a Block + PACKET_TYPE_BLOCK_DATA = 3, // Here's a Block (response to fetch) - I don't care what you do with it, but you wanted it, so here it is! + PACKET_TYPE_BROADCAST_BLOCK = 4, // Here's a new Block I want to share with the network (unsolicited - e.g. just mined it) + PACKET_TYPE_ACK_BLOCK = 5, // I have received your block, here's what I did with it (response to broadcast) + PACKET_TYPE_BROADCAST_TX = 6, // Here's a new transaction I want to share with the network + PACKET_TYPE_ACK_TX = 7, // I have received your transaction, here's what I did with it (response to broadcast) + PACKET_TYPE_MAX = 9 } packet_type_t; static inline int PacketType_IsValid(uint8_t packetType) { diff --git a/include/txmempool.h b/include/txmempool.h new file mode 100644 index 0000000..f92c5ec --- /dev/null +++ b/include/txmempool.h @@ -0,0 +1,18 @@ +#ifndef TXMEMPOOL_H +#define TXMEMPOOL_H + +#include +#include +#include +#include + +KHASH_INIT(tx_mempool_map_m, key32_t, signed_transaction_t, 1, hash_key32, eq_key32) +extern khash_t(tx_mempool_map_m)* txMempool; + +void TxMempool_Init(); +int TxMempool_Insert(signed_transaction_t tx); +bool TxMempool_Lookup(uint8_t* txHash, signed_transaction_t* out); +void TxMempool_Print(); +void TxMempool_Destroy(); + +#endif diff --git a/include/utils.h b/include/utils.h index b50fe98..9a0cadf 100644 --- a/include/utils.h +++ b/include/utils.h @@ -6,6 +6,23 @@ #include #include +typedef struct { + uint8_t bytes[32]; +} key32_t; + +static inline uint32_t hash_key32(key32_t k) { + uint32_t hash = 2166136261u; + for (int i = 0; i < 32; i++) { + hash ^= k.bytes[i]; + hash *= 16777619; + } + return hash; +} + +static inline int eq_key32(key32_t a, key32_t b) { + return memcmp(a.bytes, b.bytes, 32) == 0; +} + static inline void AddressToHexString(const uint8_t address[32], char out[65]) { if (!address || !out) { return; diff --git a/src/block/chain.c b/src/block/chain.c index e7aacf6..1937028 100644 --- a/src/block/chain.c +++ b/src/block/chain.c @@ -3,6 +3,8 @@ #include #include +uint64_t currentBlockHeight = 0; + static bool EnsureDirectoryExists(const char* dirpath) { if (!dirpath || dirpath[0] == '\0') { return false; @@ -176,6 +178,7 @@ bool Chain_AddBlock(blockchain_t* chain, block_t* block) { return false; } chain->size++; + currentBlockHeight = (uint64_t)(chain->size - 1); // Second pass: apply the ledger changes. if (blk->transactions) { @@ -269,6 +272,7 @@ bool Chain_IsValid(blockchain_t* chain) { void Chain_Wipe(blockchain_t* chain) { Chain_ClearBlocks(chain); + currentBlockHeight = 0; } bool Chain_SaveToFile(blockchain_t* chain, const char* dirpath, uint256_t currentSupply, uint64_t currentReward) { diff --git a/src/dynarr.c b/src/dynarr.c index 5055d70..894703d 100644 --- a/src/dynarr.c +++ b/src/dynarr.c @@ -173,3 +173,7 @@ void DynArr_destroy(DynArr* p) { free(p->data); free(p); } + +void* DynArr_c_arr(DynArr* p) { + return p->data; +} diff --git a/src/main.c b/src/main.c index a3d797e..891295f 100644 --- a/src/main.c +++ b/src/main.c @@ -561,8 +561,15 @@ int main(int argc, char* argv[]) { } free(block); // Chain stores block by value and owns copied transaction array. + + if (i % 1000 == 0) { + // Mid-mine flush + (void)FlushChainAndSheet(chain, chainDataDir, currentSupply, currentReward); + } } + + if (minedAll) { (void)FlushChainAndSheet(chain, chainDataDir, currentSupply, currentReward); printf("mine finished and chain flushed\n"); diff --git a/src/nets/net_node.c b/src/nets/net_node.c index 38b6c9a..212fc22 100644 --- a/src/nets/net_node.c +++ b/src/nets/net_node.c @@ -160,6 +160,7 @@ int Node_SendPacket(net_node_t* node, tcp_connection_t* conn, packet_type_t pack return -1; } + /* if (conn->role == TCP_CONNECTION_ROLE_INBOUND && packetType != PACKET_TYPE_RESPONSE) { return -1; } @@ -167,6 +168,7 @@ int Node_SendPacket(net_node_t* node, tcp_connection_t* conn, packet_type_t pack if (conn->role == TCP_CONNECTION_ROLE_OUTBOUND && packetType != PACKET_TYPE_REQUEST) { return -1; } + */ size_t framePayloadLen = payloadLen + 1; unsigned char* framed = (unsigned char*)malloc(framePayloadLen); @@ -200,9 +202,34 @@ void Node_Server_OnData(tcp_connection_t* client) { return; } - if (packetType != PACKET_TYPE_REQUEST) { - return; - } + switch (packetType) { + case PACKET_TYPE_HELLO: { + // Decode HELLO + if (payloadLen < sizeof(uint32_t) + sizeof(uint64_t)) { + return; + } + + uint32_t protoVersion; + uint64_t blockHeight; + memcpy(&protoVersion, payload, sizeof(protoVersion)); + memcpy(&blockHeight, payload + sizeof(protoVersion), sizeof(blockHeight)); + + // TODO: Save these somewhere and maybe respond + printf("Received HELLO from node %u: protoVersion=%u, blockHeight=%" PRIu64 "\n", + client ? client->connectionId : 0U, protoVersion, blockHeight); + + break; + } + case PACKET_TYPE_FETCH_BLOCK: + case PACKET_TYPE_BLOCK_DATA: + case PACKET_TYPE_BROADCAST_BLOCK: + case PACKET_TYPE_ACK_BLOCK: + case PACKET_TYPE_BROADCAST_TX: + case PACKET_TYPE_ACK_TX: + break; + default: + return; + } net_node_t* node = Node_FromConnection(client); Node_ForwardData(node, client, payload, payloadLen); @@ -218,6 +245,22 @@ void Node_Client_OnConnect(tcp_connection_t* client) { net_node_t* node = Node_FromConnection(client); Node_ForwardConnect(node, client); printf("Outbound node connected: %u\n", client ? client->connectionId : 0U); + + // Construct and send HELLO + if (node) { + uint8_t buf[100]; + uint8_t* data = buf; + + size_t offset = 0; + uint32_t protoVersion = 1; // little-endian + uint64_t blockHeight = currentBlockHeight; + memcpy((unsigned char*)data + offset, &protoVersion, sizeof(protoVersion)); // This is technically "unsafe", but I honestly just don't give a shit at this point + offset += sizeof(protoVersion); + memcpy((unsigned char*)data + offset, &blockHeight, sizeof(blockHeight)); + offset += sizeof(blockHeight); + + Node_SendPacket(node, client, PACKET_TYPE_HELLO, data, offset); + } } void Node_Client_OnData(tcp_connection_t* client) { @@ -229,8 +272,17 @@ void Node_Client_OnData(tcp_connection_t* client) { return; } - if (packetType != PACKET_TYPE_RESPONSE) { - return; + switch (packetType) { + case PACKET_TYPE_HELLO: + case PACKET_TYPE_FETCH_BLOCK: + case PACKET_TYPE_BLOCK_DATA: + case PACKET_TYPE_BROADCAST_BLOCK: + case PACKET_TYPE_ACK_BLOCK: + case PACKET_TYPE_BROADCAST_TX: + case PACKET_TYPE_ACK_TX: + break; + default: + return; } net_node_t* node = Node_FromConnection(client); diff --git a/src/txmempool.c b/src/txmempool.c new file mode 100644 index 0000000..a3adc46 --- /dev/null +++ b/src/txmempool.c @@ -0,0 +1,71 @@ +#include + +khash_t(tx_mempool_map_m)* txMempool = NULL; + +void TxMempool_Init() { + txMempool = kh_init(tx_mempool_map_m); +} + +int TxMempool_Insert(signed_transaction_t tx) { + if (!txMempool) { return -1; } + + uint8_t txHash[32]; + Transaction_CalculateHash(&tx.transaction, txHash); + + key32_t key; + memcpy(key.bytes, txHash, 32); + + int ret; + khiter_t k = kh_put(tx_mempool_map_m, txMempool, key, &ret); + if (k == kh_end(txMempool)) { + return -1; + } + + kh_value(txMempool, k) = tx; + + return ret; +} + +bool TxMempool_Lookup(uint8_t* txHash, signed_transaction_t* out) { + if (!txMempool || !txHash || !out) { return false; } + + key32_t key; + memcpy(key.bytes, txHash, 32); + + khiter_t k = kh_get(tx_mempool_map_m, txMempool, key); + if (k != kh_end(txMempool)) { + signed_transaction_t tx = kh_value(txMempool, k); + memcpy(out, &tx, sizeof(signed_transaction_t)); + return true; + } + + return false; +} + +void TxMempool_Print() { + if (!txMempool) { return; } + + khiter_t k; + for (k = kh_begin(txMempool); k != kh_end(txMempool); ++k) { + if (kh_exist(txMempool, k)) { + signed_transaction_t tx = kh_val(txMempool, k); + char senderHex[65]; + char recipient1Hex[65]; + char recipient2Hex[65]; + AddressToHexString(tx.transaction.senderAddress, senderHex); + AddressToHexString(tx.transaction.recipientAddress1, recipient1Hex); + AddressToHexString(tx.transaction.recipientAddress2, recipient2Hex); + printf("TX in mempool: sender=%s recipient1=%s recipient2=%s amount1=%llu amount2=%llu fee=%llu\n", + senderHex, recipient1Hex, recipient2Hex, + (unsigned long long)tx.transaction.amount1, + (unsigned long long)tx.transaction.amount2, + (unsigned long long)tx.transaction.fee); + } + } +} + +void TxMempool_Destroy() { + if (txMempool) { + kh_destroy(tx_mempool_map_m, txMempool); + } +}