global externs refactor, some tcp methods
This commit is contained in:
@@ -160,21 +160,20 @@ if(SKALACOIN_ENABLE_AUTOLYKOS2_REF)
|
||||
)
|
||||
endif()
|
||||
if(TARGET CURL::libcurl)
|
||||
set(_AUTOLYKOS2_CURL_LIB CURL::libcurl)
|
||||
target_link_libraries(autolykos2_ref PRIVATE
|
||||
${CMAKE_THREAD_LIBS_INIT}
|
||||
OpenSSL::SSL
|
||||
OpenSSL::Crypto
|
||||
CURL::libcurl
|
||||
)
|
||||
elseif(DEFINED CURL_LIBRARIES AND CURL_LIBRARIES)
|
||||
set(_AUTOLYKOS2_CURL_LIB ${CURL_LIBRARIES})
|
||||
target_link_libraries(autolykos2_ref PRIVATE
|
||||
${CMAKE_THREAD_LIBS_INIT}
|
||||
OpenSSL::SSL
|
||||
OpenSSL::Crypto
|
||||
${CURL_LIBRARIES}
|
||||
)
|
||||
else()
|
||||
set(_AUTOLYKOS2_CURL_LIB "")
|
||||
endif()
|
||||
|
||||
target_link_libraries(autolykos2_ref PRIVATE
|
||||
${CMAKE_THREAD_LIBS_INIT}
|
||||
OpenSSL::SSL
|
||||
OpenSSL::Crypto
|
||||
$<$<BOOL:$_AUTOLYKOS2_CURL_LIB>:$_AUTOLYKOS2_CURL_LIB>
|
||||
)
|
||||
|
||||
if(NOT _AUTOLYKOS2_CURL_LIB)
|
||||
message(FATAL_ERROR "autolykos2_ref requires libcurl (curl/curl.h). Install libcurl devel package or allow FetchContent to build it.")
|
||||
endif()
|
||||
set(SKALACOIN_AUTOLYKOS2_REF_AVAILABLE ON)
|
||||
|
||||
@@ -36,6 +36,7 @@ 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);
|
||||
bool Block_IsFullyValid(const block_t* block);
|
||||
void Block_ShutdownPowContext(void);
|
||||
void Block_Destroy(block_t* block);
|
||||
void Block_Print(const block_t* block);
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
#include <block/chain.h>
|
||||
#include <block/block.h>
|
||||
|
||||
extern uint64_t currentBlockHeight;
|
||||
#include <runtime_state.h>
|
||||
|
||||
// Nets
|
||||
#define MAX_CONS 32 // Some baseline for now
|
||||
@@ -56,11 +56,8 @@ extern uint64_t currentBlockHeight;
|
||||
|
||||
static const uint64_t M_CAP = 18446744073709551615ULL; // Max uint64
|
||||
static const uint64_t TAIL_EMISSION = 750000000000ULL; // 0.75 coins per block floor
|
||||
static uint64_t currentReward = 750000000000ULL; // Epoch reward cache for phase 3
|
||||
// No max supply. Instead of halving, it'll follow a more gradual, Monero-like emission curve.
|
||||
|
||||
static uint256_t currentSupply = {{0, 0, 0, 0}}; // Global variable to track total supply; updated with each block mined
|
||||
|
||||
// Phase 3: update once per effective epoch and keep a fixed per-block reward for that epoch.
|
||||
static inline uint64_t GetInflationRateReward(uint256_t currentSupply, blockchain_t* chain) {
|
||||
if (!chain || !chain->blocks) { return 0x00; } // Invalid
|
||||
|
||||
@@ -15,6 +15,10 @@
|
||||
|
||||
#include <dynarr.h>
|
||||
|
||||
#include <block/block.h>
|
||||
#include <block/chain.h>
|
||||
#include <block/transaction.h>
|
||||
|
||||
typedef struct {
|
||||
tcp_server_t* server;
|
||||
tcp_client_t outboundClients[MAX_CONS];
|
||||
|
||||
17
include/runtime_state.h
Normal file
17
include/runtime_state.h
Normal file
@@ -0,0 +1,17 @@
|
||||
#ifndef RUNTIME_STATE_H
|
||||
#define RUNTIME_STATE_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <uint256.h>
|
||||
|
||||
#include <block/chain.h>
|
||||
|
||||
extern uint64_t currentBlockHeight;
|
||||
extern blockchain_t* currentChain;
|
||||
extern uint256_t currentSupply;
|
||||
extern uint64_t currentReward;
|
||||
extern uint32_t difficultyTarget;
|
||||
extern const char* chainDataDir;
|
||||
|
||||
#endif
|
||||
@@ -231,6 +231,17 @@ bool Block_AllTransactionsValid(const block_t* block) {
|
||||
return true && hasCoinbase && DynArr_size(block->transactions) > 0; // Every block must have at least one transaction (the coinbase)
|
||||
}
|
||||
|
||||
bool Block_IsFullyValid(const block_t* block) {
|
||||
bool merkleValid = false;
|
||||
uint8_t calculatedMerkleRoot[32];
|
||||
if (block && block->transactions) {
|
||||
Block_CalculateMerkleRoot(block, calculatedMerkleRoot);
|
||||
merkleValid = (memcmp(calculatedMerkleRoot, block->header.merkleRoot, 32) == 0);
|
||||
}
|
||||
|
||||
return Block_HasValidProofOfWork(block) && Block_AllTransactionsValid(block) && DynArr_size(block->transactions) > 0 && merkleValid;
|
||||
}
|
||||
|
||||
void Block_Destroy(block_t* block) {
|
||||
if (!block) return;
|
||||
DynArr_destroy(block->transactions);
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#include <block/chain.h>
|
||||
#include <constants.h>
|
||||
#include <runtime_state.h>
|
||||
#include <errno.h>
|
||||
#include <limits.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
35
src/main.c
35
src/main.c
@@ -13,6 +13,7 @@
|
||||
|
||||
|
||||
#include <constants.h>
|
||||
#include <runtime_state.h>
|
||||
#include <autolykos2/autolykos2.h>
|
||||
|
||||
#include <nets/net_node.h>
|
||||
@@ -21,6 +22,11 @@
|
||||
#define CHAIN_DATA_DIR "chain_data"
|
||||
#endif
|
||||
|
||||
blockchain_t* currentChain = NULL;
|
||||
const char* chainDataDir = CHAIN_DATA_DIR;
|
||||
uint256_t currentSupply = {{0, 0, 0, 0}};
|
||||
uint64_t currentReward = 750000000000ULL;
|
||||
|
||||
void handle_sigint(int sig) {
|
||||
printf("Caught signal %d, exiting...\n", sig);
|
||||
Block_ShutdownPowContext();
|
||||
@@ -30,9 +36,6 @@ void handle_sigint(int sig) {
|
||||
|
||||
uint32_t difficultyTarget = INITIAL_DIFFICULTY;
|
||||
|
||||
// extern the currentReward from constants.h so we can update it as we mine blocks and save it to disk
|
||||
extern uint64_t currentReward;
|
||||
|
||||
static bool MineBlock(block_t* block) {
|
||||
if (!block) {
|
||||
return false;
|
||||
@@ -471,20 +474,20 @@ int main(int argc, char* argv[]) {
|
||||
srand((unsigned int)time(NULL));
|
||||
|
||||
BalanceSheet_Init();
|
||||
const char* chainDataDir = CHAIN_DATA_DIR;
|
||||
|
||||
uint256_t currentSupply = uint256_from_u64(0);
|
||||
|
||||
net_node_t* node = Node_Create();
|
||||
if (!node) {
|
||||
BalanceSheet_Destroy();
|
||||
return 1;
|
||||
}
|
||||
|
||||
blockchain_t* chain = Chain_Create();
|
||||
if (!chain) {
|
||||
fprintf(stderr, "failed to create chain\n");
|
||||
Node_Destroy(node);
|
||||
BalanceSheet_Destroy();
|
||||
return 1;
|
||||
}
|
||||
|
||||
currentChain = chain;
|
||||
|
||||
net_node_t* node = Node_Create();
|
||||
if (!node) {
|
||||
currentChain = NULL;
|
||||
Chain_Destroy(chain);
|
||||
BalanceSheet_Destroy();
|
||||
return 1;
|
||||
}
|
||||
@@ -536,8 +539,9 @@ int main(int argc, char* argv[]) {
|
||||
uint8_t minerCompressedPubkey[33];
|
||||
if (!GenerateTestMinerIdentity(minerPrivateKey, minerCompressedPubkey, minerAddress)) {
|
||||
fprintf(stderr, "failed to generate test miner keypair\n");
|
||||
Chain_Destroy(chain);
|
||||
Node_Destroy(node);
|
||||
currentChain = NULL;
|
||||
Chain_Destroy(chain);
|
||||
Block_ShutdownPowContext();
|
||||
BalanceSheet_Destroy();
|
||||
return 1;
|
||||
@@ -867,9 +871,10 @@ int main(int argc, char* argv[]) {
|
||||
|
||||
(void)FlushChainAndSheet(chain, chainDataDir, currentSupply, currentReward);
|
||||
|
||||
Chain_Destroy(chain);
|
||||
Block_ShutdownPowContext();
|
||||
Node_Destroy(node);
|
||||
currentChain = NULL;
|
||||
Chain_Destroy(chain);
|
||||
BalanceSheet_Destroy();
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <runtime_state.h>
|
||||
|
||||
static net_node_t* Node_FromConnection(tcp_connection_t* conn) {
|
||||
if (!conn) {
|
||||
return NULL;
|
||||
@@ -12,6 +14,14 @@ static net_node_t* Node_FromConnection(tcp_connection_t* conn) {
|
||||
return (net_node_t*)conn->owner;
|
||||
}
|
||||
|
||||
static uint64_t Node_GetCurrentBlockHeight(void) {
|
||||
if (currentChain) {
|
||||
return (uint64_t)Chain_Size(currentChain);
|
||||
}
|
||||
|
||||
return currentBlockHeight;
|
||||
}
|
||||
|
||||
static int Node_DecodePacket(const tcp_connection_t* conn, packet_type_t* outType, const unsigned char** outPayload, size_t* outPayloadLen) {
|
||||
if (!conn || !outType || !outPayload || !outPayloadLen || conn->dataBufLen < 1 || !conn->dataBuf) {
|
||||
return -1;
|
||||
@@ -224,8 +234,9 @@ void Node_Server_OnData(tcp_connection_t* client) {
|
||||
size_t ackOffset = 0;
|
||||
memcpy(ackData + ackOffset, &protoVersion, sizeof(protoVersion));
|
||||
ackOffset += sizeof(protoVersion);
|
||||
memcpy(ackData + ackOffset, ¤tBlockHeight, sizeof(currentBlockHeight));
|
||||
ackOffset += sizeof(currentBlockHeight);
|
||||
uint64_t currentHeight = Node_GetCurrentBlockHeight();
|
||||
memcpy(ackData + ackOffset, ¤tHeight, sizeof(currentHeight));
|
||||
ackOffset += sizeof(currentHeight);
|
||||
|
||||
Node_SendPacket(Node_FromConnection(client), client, PACKET_TYPE_ACK_HELLO, ackData, ackOffset);
|
||||
|
||||
@@ -241,9 +252,86 @@ void Node_Server_OnData(tcp_connection_t* client) {
|
||||
TcpConnection_RequestClose(client);
|
||||
return;
|
||||
}
|
||||
case PACKET_TYPE_FETCH_BLOCK:
|
||||
case PACKET_TYPE_BLOCK_DATA:
|
||||
case PACKET_TYPE_BROADCAST_BLOCK:
|
||||
case PACKET_TYPE_FETCH_BLOCK: {
|
||||
// Decode FETCH_BLOCK - payload is the block height as uint64_t
|
||||
if (payloadLen != sizeof(uint64_t)) {
|
||||
return;
|
||||
}
|
||||
|
||||
uint64_t requestedHeight;
|
||||
memcpy(&requestedHeight, payload, sizeof(requestedHeight));
|
||||
|
||||
printf("Received FETCH_BLOCK for height %" PRIu64 " from node %u\n", requestedHeight, client ? client->connectionId : 0U);
|
||||
if (requestedHeight > Node_GetCurrentBlockHeight()) {
|
||||
printf("Requested block height %" PRIu64 " is higher than current height, ignoring\n", requestedHeight);
|
||||
|
||||
// Error the client, but don't kill
|
||||
const char* msg = "Requested block height is higher than my current height!";
|
||||
Node_SendPacket(Node_FromConnection(client), client, PACKET_TYPE_ERROR, msg, strlen(msg));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Find the block
|
||||
block_t* block = Chain_GetBlock(currentChain, (size_t)requestedHeight);
|
||||
if (!block) {
|
||||
printf("Requested block height %" PRIu64 " not found, ignoring\n", requestedHeight);
|
||||
const char* msg = "Requested block not found!";
|
||||
Node_SendPacket(Node_FromConnection(client), client, PACKET_TYPE_ERROR, msg, strlen(msg));
|
||||
return;
|
||||
}
|
||||
|
||||
if (block->transactions == NULL) {
|
||||
// Just reload from disk pure
|
||||
Chain_LoadBlockFromFile(chainDataDir, requestedHeight - 1, true, &block, NULL); // blockNumber = height - 1 because of 0-indexing
|
||||
}
|
||||
|
||||
// Serialize into a BLOCK_DATA packet [block header][tx count - 8 bytes][transactions...]
|
||||
size_t blockDataSize = sizeof(block_header_t) + sizeof(uint64_t) + (block->transactions ? block->transactions->size * sizeof(signed_transaction_t) : 0);
|
||||
unsigned char* blockData = (unsigned char*)malloc(blockDataSize);
|
||||
if (!blockData) {
|
||||
// Generic error response
|
||||
printf("Failed to allocate memory for block data response to node %u\n", client ? client->connectionId : 0U);
|
||||
const char* msg = "Generic error for block data!";
|
||||
Node_SendPacket(Node_FromConnection(client), client, PACKET_TYPE_ERROR, msg, strlen(msg));
|
||||
return;
|
||||
}
|
||||
|
||||
size_t offset = 0;
|
||||
memcpy(blockData + offset, &block->header, sizeof(block_header_t));
|
||||
offset += sizeof(block_header_t);
|
||||
uint64_t txCount = block->transactions ? (uint64_t)block->transactions->size : 0;
|
||||
memcpy(blockData + offset, &txCount, sizeof(txCount));
|
||||
offset += sizeof(txCount);
|
||||
if (block->transactions && block->transactions->size > 0) {
|
||||
memcpy(blockData + offset, block->transactions->data, block->transactions->size * sizeof(signed_transaction_t));
|
||||
offset += block->transactions->size * sizeof(signed_transaction_t);
|
||||
}
|
||||
|
||||
// Send the block data
|
||||
Node_SendPacket(Node_FromConnection(client), client, PACKET_TYPE_BLOCK_DATA, blockData, offset);
|
||||
free(blockData);
|
||||
}
|
||||
case PACKET_TYPE_BLOCK_DATA: {
|
||||
// Server can't receive these!
|
||||
printf("Received unexpected packet type %u from node %u\n", (unsigned int)packetType, client ? client->connectionId : 0U);
|
||||
|
||||
// Send the error and kill the connection
|
||||
const char* msg = "You can't send me BLOCK_DATA! I'm a server!";
|
||||
Node_SendPacket(Node_FromConnection(client), client, PACKET_TYPE_ERROR, msg, strlen(msg));
|
||||
TcpConnection_RequestClose(client);
|
||||
return;
|
||||
}
|
||||
case PACKET_TYPE_BROADCAST_BLOCK: {
|
||||
// Server cannot receive these either.
|
||||
printf("Received unexpected BROADCAST_BLOCK packet from node %u\n", client ? client->connectionId : 0U);
|
||||
|
||||
// Send the error and kill the connection
|
||||
const char* msg = "You can't send me BROADCAST_BLOCK! I'm a server!";
|
||||
Node_SendPacket(Node_FromConnection(client), client, PACKET_TYPE_ERROR, msg, strlen(msg));
|
||||
TcpConnection_RequestClose(client);
|
||||
return;
|
||||
}
|
||||
case PACKET_TYPE_ACK_BLOCK:
|
||||
case PACKET_TYPE_BROADCAST_TX:
|
||||
case PACKET_TYPE_ACK_TX:
|
||||
@@ -287,7 +375,7 @@ void Node_Client_OnConnect(tcp_connection_t* client) {
|
||||
|
||||
size_t offset = 0;
|
||||
uint32_t protoVersion = 1; // little-endian
|
||||
uint64_t blockHeight = currentBlockHeight;
|
||||
uint64_t blockHeight = Node_GetCurrentBlockHeight();
|
||||
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));
|
||||
@@ -331,9 +419,73 @@ void Node_Client_OnData(tcp_connection_t* client) {
|
||||
printf("Received ACK_HELLO from node %u with protoVersion %u and blockHeight %lu\n", client ? client->connectionId : 0U, protoVersion, (unsigned long)blockHeight);
|
||||
break;
|
||||
}
|
||||
case PACKET_TYPE_FETCH_BLOCK:
|
||||
case PACKET_TYPE_BLOCK_DATA:
|
||||
case PACKET_TYPE_BROADCAST_BLOCK:
|
||||
case PACKET_TYPE_FETCH_BLOCK: {
|
||||
// A client can't serve a block!
|
||||
printf("Received unexpected FETCH_BLOCK packet from node %u\n", client ? client->connectionId : 0U);
|
||||
|
||||
// Send the error and kill the connection (this might be too aggressive)
|
||||
const char* msg = "You can't FETCH_BLOCK from me! I'm a client!";
|
||||
Node_SendPacket(Node_FromConnection(client), client, PACKET_TYPE_ERROR, msg, strlen(msg));
|
||||
TcpConnection_RequestClose(client);
|
||||
return;
|
||||
}
|
||||
case PACKET_TYPE_BLOCK_DATA: {
|
||||
// TODO
|
||||
break;
|
||||
}
|
||||
case PACKET_TYPE_BROADCAST_BLOCK: {
|
||||
// TODO: Handle based on the current block height of the node; if for n + 1, ignore it for now, since we're probably syncing.
|
||||
// If higher than n + 1, request missing blocks.
|
||||
// We just assume n + 1 for now.
|
||||
|
||||
// Decode - [1 byte packet type][8 byte block height][block header][8 byte transation count][remaining bytes block data]; TODO: This is just for v1 transactions right now.
|
||||
if (payloadLen < 1 + sizeof(uint64_t) + sizeof(uint64_t)) {
|
||||
return;
|
||||
}
|
||||
|
||||
char* ptr = (char*)payload;
|
||||
ptr += 1; // skip packet type, we already know it
|
||||
|
||||
uint64_t blockHeight;
|
||||
memcpy(&blockHeight, ptr, sizeof(blockHeight));
|
||||
ptr += sizeof(blockHeight);
|
||||
|
||||
block_t blockHeader;
|
||||
memcpy(&blockHeader, ptr, sizeof(blockHeader));
|
||||
ptr += sizeof(blockHeader);
|
||||
|
||||
uint64_t txCount;
|
||||
memcpy(&txCount, ptr, sizeof(txCount));
|
||||
ptr += sizeof(txCount);
|
||||
|
||||
DynArr* transactions = DYNARR_CREATE(sizeof(signed_transaction_t), 0);
|
||||
for (uint64_t i = 0; i < txCount; ++i) {
|
||||
if (ptr + sizeof(signed_transaction_t) > (char*)payload + payloadLen) {
|
||||
// Malformed packet - TODO: Error the sender
|
||||
DynArr_destroy(transactions);
|
||||
return;
|
||||
}
|
||||
signed_transaction_t tx;
|
||||
memcpy(&tx, ptr, sizeof(tx));
|
||||
ptr += sizeof(tx);
|
||||
DynArr_push_back(transactions, &tx);
|
||||
}
|
||||
|
||||
blockHeader.transactions = transactions;
|
||||
|
||||
// Verify
|
||||
if (!Block_IsFullyValid(&blockHeader)) {
|
||||
// Invalid block
|
||||
DynArr_destroy(transactions);
|
||||
return;
|
||||
}
|
||||
|
||||
// Push to chain - TODO: Handle orphans, reorgs, etc.
|
||||
if (currentChain) {
|
||||
Chain_AddBlock(currentChain, &blockHeader);
|
||||
Chain_SaveToFile(currentChain, chainDataDir, currentSupply, currentReward); // Note: this destroy the transactions inside the block automatically, so we don't have to worry about that here.
|
||||
}
|
||||
}
|
||||
case PACKET_TYPE_ACK_BLOCK:
|
||||
case PACKET_TYPE_BROADCAST_TX:
|
||||
case PACKET_TYPE_ACK_TX:
|
||||
|
||||
Reference in New Issue
Block a user