tx mempool start, hello packet

This commit is contained in:
2026-04-24 17:14:40 +02:00
parent accdeebee8
commit 32b9a57366
12 changed files with 193 additions and 25 deletions

View File

@@ -12,29 +12,12 @@
#include <utils.h>
#include <uint256.h>
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;

View File

@@ -7,6 +7,8 @@
#include <block/chain.h>
#include <block/block.h>
extern uint64_t currentBlockHeight;
// Nets
#define MAX_CONS 32 // Some baseline for now
#define LISTEN_PORT 9393

View File

@@ -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

View File

@@ -13,6 +13,8 @@
#include <stddef.h>
#include <dynarr.h>
typedef struct {
tcp_server_t* server;
tcp_client_t outboundClients[MAX_CONS];

View File

@@ -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) {

18
include/txmempool.h Normal file
View File

@@ -0,0 +1,18 @@
#ifndef TXMEMPOOL_H
#define TXMEMPOOL_H
#include <block/transaction.h>
#include <khash/khash.h>
#include <utils.h>
#include <uint256.h>
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

View File

@@ -6,6 +6,23 @@
#include <string.h>
#include <stdbool.h>
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;

View File

@@ -3,6 +3,8 @@
#include <errno.h>
#include <sys/stat.h>
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) {

View File

@@ -173,3 +173,7 @@ void DynArr_destroy(DynArr* p) {
free(p->data);
free(p);
}
void* DynArr_c_arr(DynArr* p) {
return p->data;
}

View File

@@ -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");

View File

@@ -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);

71
src/txmempool.c Normal file
View File

@@ -0,0 +1,71 @@
#include <txmempool.h>
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);
}
}