Copied TCP impl from other project, basic Block implementation, randomx pow, signing via secp256k1

This commit is contained in:
2026-03-29 17:18:23 +02:00
commit 57bfe61c13
26 changed files with 1775 additions and 0 deletions

11
include/balance_sheet.h Normal file
View File

@@ -0,0 +1,11 @@
#ifndef BALANCE_SHEET_H
#define BALANCE_SHEET_H
#include <stdint.h>
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
uint64_t balance;
} balance_sheet_entry_t;
#endif

36
include/block/block.h Normal file
View File

@@ -0,0 +1,36 @@
#ifndef BLOCK_H
#define BLOCK_H
#include <stdint.h>
#include <openssl/sha.h>
#include <dynarr.h>
#include <block/transaction.h>
#include <stdbool.h>
#include <string.h>
#include <randomx/librx_wrapper.h>
typedef struct {
uint8_t version;
uint32_t blockNumber;
uint8_t prevHash[32];
uint8_t merkleRoot[32];
uint64_t timestamp;
uint32_t difficultyTarget; // Encoding: [1 byte exponent][3 byte coefficient]; Target = coefficient * 256^(exponent-3)
uint64_t nonce; // Higher nonce for RandomX
} block_header_t;
typedef struct {
block_header_t header;
DynArr* transactions; // Array of signed_transaction_t
} block_t;
block_t* Block_Create();
void Block_CalculateHash(const block_t* block, uint8_t* outHash);
void Block_CalculateRandomXHash(const block_t* block, uint8_t* outHash);
void Block_AddTransaction(block_t* block, signed_transaction_t* tx);
void Block_RemoveTransaction(block_t* block, uint8_t* txHash);
bool Block_HasValidProofOfWork(const block_t* block);
bool Block_AllTransactionsValid(const block_t* block);
void Block_Destroy(block_t* block);
#endif

20
include/block/chain.h Normal file
View File

@@ -0,0 +1,20 @@
#ifndef CHAIN_H
#define CHAIN_H
#include <block/block.h>
#include <dynarr.h>
#include <stdlib.h>
typedef struct {
DynArr* blocks;
size_t size;
} blockchain_t;
blockchain_t* Chain_Create();
void Chain_Destroy(blockchain_t* chain);
bool Chain_AddBlock(blockchain_t* chain, block_t* block);
block_t* Chain_GetBlock(blockchain_t* chain, size_t index);
size_t Chain_Size(blockchain_t* chain);
bool Chain_IsValid(blockchain_t* chain);
#endif

View File

@@ -0,0 +1,48 @@
#ifndef TRANSACTION_H
#define TRANSACTION_H
#include <stdint.h>
#include <stdbool.h>
#include <crypto/crypto.h>
// Special sender/recipient address marker for coinbase logic: 32 bytes of 0xFF.
static inline bool Address_IsCoinbase(const uint8_t address[32]) {
if (!address) {
return false;
}
for (size_t i = 0; i < 32; ++i) {
if (address[i] != 0xFF) {
return false;
}
}
return true;
}
// 178 bytes total for v1
typedef struct {
uint8_t version;
uint8_t senderAddress[32];
uint8_t recipientAddress[32];
uint64_t amount;
uint64_t fee; // Rewarded to the miner; can be zero, but the miner may choose to ignore transactions with very low fees
uint8_t compressedPublicKey[33];
// Timestamp is dictated by the block
} transaction_t;
typedef struct {
uint8_t txHash[32];
uint8_t signature[64]; // Signature of the hash
} transaction_sig_t;
typedef struct {
transaction_t transaction;
transaction_sig_t signature;
} signed_transaction_t;
void Transaction_CalculateHash(const signed_transaction_t* tx, uint8_t* outHash);
void Transaction_Sign(signed_transaction_t* tx, const uint8_t* privateKey);
bool Transaction_Verify(const signed_transaction_t* tx);
#endif

13
include/crypto/crypto.h Normal file
View File

@@ -0,0 +1,13 @@
#ifndef CRYPTO_H
#define CRYPTO_H
#include <stdint.h>
#include <stddef.h>
#include <stdbool.h>
#include <openssl/sha.h>
#include <secp256k1.h>
bool Crypto_VerifySignature(const uint8_t* data, size_t len, const uint8_t* signature, const uint8_t* publicKey);
void Crypto_SignData(const uint8_t* data, size_t len, const uint8_t* privateKey, uint8_t* outSignature);
#endif

60
include/dynarr.h Normal file
View File

@@ -0,0 +1,60 @@
#ifndef DYNARR_H
#define DYNARR_H
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#define DYNARR_MAX_CAPACITY ((size_t)0x7FFFFFFF)
typedef struct {
size_t size;
size_t elemSize;
size_t capacity;
void* data;
} DynArr;
// Do not use; Use DYNARR_CREATE macro instead.
DynArr* DynArr_create(size_t elemSize, size_t capacity);
// Reserve n blocks in arary; New size will be n, NOT size + n; Reserving less memory that current will fail, use prune instead.
void DynArr_reserve(DynArr* p, size_t n);
// Push data into a new block at the end of the array
void* DynArr_push_back(DynArr* p, void* value);
// Remove the last block in the array.
void DynArr_pop_back(DynArr* p);
// Remove first block from array.
void DynArr_pop_front(DynArr* p);
// Remove index from array. This moves all blocks after the index block.
void DynArr_remove(DynArr* p, size_t index);
// Erase the array. This will not free unused blocks.
void DynArr_erase(DynArr* p);
// Prune and free unused blocks. If pruning to zero, ensure to reserve after.
void DynArr_prune(DynArr* p);
// Get a pointer to a block by index
void* DynArr_at(DynArr* p, size_t index);
// Get the index by block pointer
size_t DynArr_at_ptr(DynArr* p, void* ptr);
// Get size
size_t DynArr_size(DynArr* p);
// Get element size
size_t DynArr_elemSize(DynArr* p);
// Get capacity
size_t DynArr_capacity(DynArr* p);
void DynArr_destroy(DynArr* p);
#define DYNARR_CREATE(T, initialCapacity) DynArr_create(sizeof(T), initialCapacity)
#endif

20
include/dynset.h Normal file
View File

@@ -0,0 +1,20 @@
#ifndef DYNSET_H
#define DYNSET_H
#include <dynarr.h>
// Dynamic Set structure - basically DynArr with uniqueness enforced
typedef struct {
DynArr* arr;
} DynSet;
// Function prototypes
DynSet* DynSet_Create(size_t elemSize);
void DynSet_Destroy(DynSet* set);
int DynSet_Insert(DynSet* set, const void* element);
int DynSet_Contains(DynSet* set, const void* element);
size_t DynSet_Size(DynSet* set);
void* DynSet_Get(DynSet* set, size_t index);
void DynSet_Remove(DynSet* set, const void* element);
#endif

14
include/numgen.h Normal file
View File

@@ -0,0 +1,14 @@
#ifndef NUMGEN_H
#define NUMGEN_H
#include <stdlib.h>
#include <time.h>
#include <stdint.h>
#include <string.h>
unsigned char random_byte(void);
uint16_t random_two_byte(void);
uint32_t random_four_byte(void);
uint64_t random_eight_byte(void);
#endif

18
include/packettype.h Normal file
View File

@@ -0,0 +1,18 @@
#ifndef PACKETTYPE_H
#define PACKETTYPE_H
typedef enum {
PACKET_TYPE_NONE = 0,
PACKET_TYPE_HELLO = 1,
PACKET_TYPE_TASK_ASSIGN = 2,
PACKET_TYPE_TASK_RESULT = 3,
PACKET_TYPE_STATUS_UPDATE = 4,
PACKET_TYPE_CLIENT_CAPABILITIES = 5,
PACKET_TYPE_TASK_REQUEST = 6,
PACKET_TYPE_MISSING_INFO = 7,
PACKET_TYPE_ACKNOWLEDGE = 8,
PACKET_TYPE_TASK_REJECT = 9,
PACKET_TYPE_TASK_NONE_AVAILABLE = 10
} PacketType;
#endif

View File

@@ -0,0 +1,21 @@
#ifndef LIBRX_WRAPPER_H
#define LIBRX_WRAPPER_H
#include <stddef.h>
#include <stdint.h>
#include <randomx.h>
#include <stdbool.h>
#ifdef __cplusplus
extern "C" {
#endif
bool RandomX_Init(const char* key);
void RandomX_Destroy();
void RandomX_CalculateHash(const uint8_t* input, size_t inputLen, uint8_t* output);
#ifdef __cplusplus
}
#endif
#endif

29
include/tcpd/tcpclient.h Normal file
View File

@@ -0,0 +1,29 @@
#ifndef TCPCLIENT_H
#define TCPCLIENT_H
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <pthread.h>
#include <stdint.h>
#include <dynarr.h>
#define MTU 1500
struct TcpClient {
int clientFd;
struct sockaddr_in clientAddr;
uint32_t clientId;
unsigned char dataBuf[MTU];
ssize_t dataBufLen;
void (*on_data)(struct TcpClient* client);
void (*on_disconnect)(struct TcpClient* client);
pthread_t clientThread;
};
typedef struct TcpClient TcpClient;
#endif

56
include/tcpd/tcpserver.h Normal file
View File

@@ -0,0 +1,56 @@
#ifndef TCPSERVER_H
#define TCPSERVER_H
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <pthread.h>
#include <stdint.h>
#include <tcpd/tcpclient.h>
#include <numgen.h>
#include <dynarr.h>
typedef struct {
int sockFd;
struct sockaddr_in addr;
int opt;
// Called before the client thread runs
void (*on_connect)(TcpClient* client);
// Called when data is received
void (*on_data)(TcpClient* client);
// Called before the socket and client thread are killed; Do NOT free client manually
void (*on_disconnect)(TcpClient* client);
// max clients
size_t clients;
TcpClient** clientsArrPtr;
pthread_t svrThread;
} TcpServer;
struct tcpclient_thread_args {
TcpClient* clientPtr;
TcpServer* serverPtr;
};
typedef struct tcpclient_thread_args tcpclient_thread_args;
TcpServer* TcpServer_Create();
void TcpServer_Destroy(TcpServer* ptr);
void TcpServer_Init(TcpServer* ptr, unsigned short port, const char* addr);
void TcpServer_Start(TcpServer* ptr, int maxcons);
void TcpServer_Stop(TcpServer* ptr);
void TcpServer_Send(TcpServer* ptr, TcpClient* cli, void* data, size_t len);
void Generic_SendSocket(int sock, void* data, size_t len);
void TcpServer_Disconnect(TcpServer* ptr, TcpClient* cli);
void TcpServer_KillClient(TcpServer* ptr, TcpClient* cli);
size_t Generic_FindClientInArrayByPtr(TcpClient** arr, TcpClient* ptr, size_t len);
#endif