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

163
src/block/block.c Normal file
View File

@@ -0,0 +1,163 @@
#include <block/block.h>
#include <stdlib.h>
block_t* Block_Create() {
block_t* block = (block_t*)malloc(sizeof(block_t));
if (!block) {
return NULL;
}
memset(&block->header, 0, sizeof(block_header_t));
block->transactions = DYNARR_CREATE(signed_transaction_t, 1);
if (!block->transactions) {
free(block);
return NULL;
}
return block;
}
void Block_CalculateHash(const block_t* block, uint8_t* outHash) {
if (!block || !outHash || !block->transactions || DynArr_size(block->transactions) <= 0) {
return;
}
// Merkle root TODO
// Flatten the block header and transactions into a single buffer for hashing (assume that txs are verified - usually on receive)
uint8_t buffer[sizeof(block_header_t) + (DynArr_size(block->transactions) * DynArr_elemSize(block->transactions))];
memcpy(buffer, &block->header, sizeof(block_header_t));
for (size_t i = 0; i < DynArr_size(block->transactions); i++) {
void* txPtr = (char*)DynArr_at(block->transactions, i);
memcpy(buffer + sizeof(block_header_t) + (i * DynArr_elemSize(block->transactions)), txPtr, DynArr_elemSize(block->transactions));
}
SHA256((const unsigned char*)buffer, sizeof(buffer), outHash);
SHA256(outHash, 32, outHash); // Double-Hash
}
void Block_CalculateRandomXHash(const block_t* block, uint8_t* outHash) {
if (!block || !outHash || !block->transactions || DynArr_size(block->transactions) <= 0) {
return;
}
// Merkle root TODO
// Flatten the block header and transactions into a single buffer for hashing (assume that txs are verified - usually on receive)
uint8_t buffer[sizeof(block_header_t) + (DynArr_size(block->transactions) * DynArr_elemSize(block->transactions))];
memcpy(buffer, &block->header, sizeof(block_header_t));
for (size_t i = 0; i < DynArr_size(block->transactions); i++) {
void* txPtr = (char*)DynArr_at(block->transactions, i);
memcpy(buffer + sizeof(block_header_t) + (i * DynArr_elemSize(block->transactions)), txPtr, DynArr_elemSize(block->transactions));
}
RandomX_CalculateHash(buffer, sizeof(buffer), outHash);
}
void Block_AddTransaction(block_t* block, signed_transaction_t* tx) {
if (!block || !tx || !block->transactions) {
return;
}
DynArr_push_back(block->transactions, tx);
}
void Block_RemoveTransaction(block_t* block, uint8_t* txHash) {
if (!block || !txHash || !block->transactions) {
return;
}
for (size_t i = 0; i < DynArr_size(block->transactions); i++) {
signed_transaction_t* currentTx = (signed_transaction_t*)DynArr_at(block->transactions, i);
if (memcmp(currentTx->signature.txHash, txHash, 32) == 0) {
DynArr_remove(block->transactions, i);
return;
}
}
}
static int Uint256_CompareBE(const uint8_t a[32], const uint8_t b[32]) {
for (int i = 0; i < 32; ++i) {
if (a[i] < b[i]) return -1;
if (a[i] > b[i]) return 1;
}
return 0;
}
static bool DecodeCompactTarget(uint32_t nBits, uint8_t target[32]) {
memset(target, 0, 32);
uint32_t exponent = nBits >> 24;
uint32_t mantissa = nBits & 0x007fffff; // ignore sign bit for now
bool negative = (nBits & 0x00800000) != 0;
if (negative || mantissa == 0) {
return false;
}
// Compute: target = mantissa * 256^(exponent - 3)
if (exponent <= 3) {
mantissa >>= 8 * (3 - exponent);
target[29] = (mantissa >> 16) & 0xff;
target[30] = (mantissa >> 8) & 0xff;
target[31] = mantissa & 0xff;
} else {
uint32_t byte_index = exponent - 3; // number of zero-bytes appended on right
if (byte_index > 29) {
return false; // overflow 256 bits
}
target[32 - byte_index - 3] = (mantissa >> 16) & 0xff;
target[32 - byte_index - 2] = (mantissa >> 8) & 0xff;
target[32 - byte_index - 1] = mantissa & 0xff;
}
return true;
}
bool Block_HasValidProofOfWork(const block_t* block) {
if (!block) {
return false;
}
uint8_t target[32];
if (!DecodeCompactTarget(block->header.difficultyTarget, target)) {
return false;
}
uint8_t hash[32];
Block_CalculateRandomXHash(block, hash);
return Uint256_CompareBE(hash, target) <= 0;
}
bool Block_AllTransactionsValid(const block_t* block) {
if (!block || !block->transactions) {
return false;
}
bool hasCoinbase = false;
for (size_t i = 0; i < DynArr_size(block->transactions); i++) {
signed_transaction_t* tx = (signed_transaction_t*)DynArr_at(block->transactions, i);
if (!Transaction_Verify(tx)) {
return false;
}
if (Address_IsCoinbase(tx->transaction.senderAddress)) {
if (hasCoinbase) {
return false; // More than one coinbase transaction
}
hasCoinbase = true;
}
}
return true && hasCoinbase && DynArr_size(block->transactions) > 0; // Every block must have at least one transaction (the coinbase)
}
void Block_Destroy(block_t* block) {
if (!block) return;
DynArr_destroy(block->transactions);
free(block);
}

53
src/block/chain.c Normal file
View File

@@ -0,0 +1,53 @@
#include <block/chain.h>
blockchain_t* Chain_Create() {
blockchain_t* ptr = (blockchain_t*)malloc(sizeof(blockchain_t));
if (!ptr) {
return NULL;
}
ptr->blocks = DYNARR_CREATE(block_t, 1);
ptr->size = 0;
return ptr;
}
void Chain_Destroy(blockchain_t* chain) {
if (chain) {
if (chain->blocks) {
DynArr_destroy(chain->blocks);
}
free(chain);
}
}
bool Chain_AddBlock(blockchain_t* chain, block_t* block) {
if (chain && block && chain->blocks) {
DynArr_push_back(chain->blocks, block);
return true;
}
return false;
}
block_t* Chain_GetBlock(blockchain_t* chain, size_t index) {
if (chain) {
return DynArr_at(chain->blocks, index);
}
return NULL;
}
size_t Chain_Size(blockchain_t* chain) {
if (chain) {
return DynArr_size(chain->blocks);
}
return 0;
}
bool Chain_IsValid(blockchain_t* chain) {
if (!chain || !chain->blocks) {
return false;
}
// Add validation logic here
return true;
}

76
src/block/transaction.c Normal file
View File

@@ -0,0 +1,76 @@
#include <block/transaction.h>
#include <string.h>
void Transaction_CalculateHash(const signed_transaction_t* tx, uint8_t* outHash) {
if (!tx || !outHash) {
return;
}
uint8_t buffer[sizeof(transaction_t)];
memcpy(buffer, &tx->transaction, sizeof(transaction_t));
SHA256(buffer, sizeof(buffer), outHash);
SHA256(outHash, 32, outHash); // Double-Hash
}
void Transaction_Sign(signed_transaction_t* tx, const uint8_t* privateKey) {
if (!tx || !privateKey) {
return;
}
Transaction_CalculateHash(tx, tx->signature.txHash);
Crypto_SignData(
(const uint8_t*)&tx->transaction,
sizeof(transaction_t),
privateKey,
tx->signature.signature
);
}
bool Transaction_Verify(const signed_transaction_t* tx) {
if (!tx) {
return false;
}
if (Address_IsCoinbase(tx->transaction.senderAddress)) {
// Coinbase transactions are valid if the signature is correct for the block (handled in Block_Verify)
return true;
}
uint8_t computeAddress[32];
SHA256(tx->transaction.compressedPublicKey, 33, computeAddress); // Address is hash of public key
if (memcmp(computeAddress, tx->transaction.senderAddress, 32) != 0) {
return false; // Sender address does not match public key
}
if (tx->transaction.amount == 0) {
return false; // Zero-amount transactions are not valid
}
if (tx->transaction.fee > tx->transaction.amount) {
return false; // Fee cannot exceed amount
}
if (tx->transaction.version != 1) {
return false; // Unsupported version
}
if (Address_IsCoinbase(tx->transaction.recipientAddress)) {
return false; // Cannot send to coinbase address
}
uint8_t txHash[32];
Transaction_CalculateHash(tx, txHash);
if (memcmp(txHash, tx->signature.txHash, 32) != 0) {
return false; // Hash does not match signature hash
}
// If all checks pass, verify the signature
return Crypto_VerifySignature(
(const uint8_t*)&tx->transaction,
sizeof(transaction_t),
tx->signature.signature,
tx->transaction.compressedPublicKey
);
}