difficulty calculation, move from randomx to autolykos2

This commit is contained in:
2026-03-30 15:42:28 +02:00
parent c358115af4
commit b47ff30bc7
18 changed files with 1163 additions and 224 deletions

View File

@@ -8,7 +8,6 @@
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <randomx/librx_wrapper.h>
#include <signal.h>
#include <constants.h>
@@ -19,56 +18,11 @@
void handle_sigint(int sig) {
printf("Caught signal %d, exiting...\n", sig);
RandomX_Destroy();
Block_ShutdownPowContext();
exit(0);
}
static double MonotonicSeconds(void) {
struct timespec ts;
clock_gettime(CLOCK_MONOTONIC, &ts);
return (double)ts.tv_sec + ((double)ts.tv_nsec / 1000000000.0);
}
static double MeasureRandomXHashrate(void) {
uint8_t input[80] = {0};
uint8_t outHash[32];
uint64_t counter = 0;
const double start = MonotonicSeconds();
double now = start;
do {
memcpy(input, &counter, sizeof(counter));
RandomX_CalculateHash(input, sizeof(input), outHash);
counter++;
now = MonotonicSeconds();
} while ((now - start) < 0.75); // short local benchmark window
const double elapsed = now - start;
if (elapsed <= 0.0 || counter == 0) {
return 0.0;
}
return (double)counter / elapsed;
}
static uint32_t CompactTargetForExpectedHashes(double expectedHashes) {
if (expectedHashes < 1.0) {
expectedHashes = 1.0;
}
// For exponent 0x1f: target = mantissa * 2^(8*(0x1f-3)) = mantissa * 2^224
// So expected hashes ~= 2^256 / target = 2^32 / mantissa.
double mantissaF = 4294967296.0 / expectedHashes;
if (mantissaF < 1.0) {
mantissaF = 1.0;
}
if (mantissaF > 8388607.0) {
mantissaF = 8388607.0; // 0x007fffff
}
const uint32_t mantissa = (uint32_t)mantissaF;
return (0x1fU << 24) | (mantissa & 0x007fffffU);
}
uint32_t difficultyTarget = INITIAL_DIFFICULTY;
static bool MineBlock(block_t* block) {
if (!block) {
@@ -91,24 +45,18 @@ int main(int argc, char* argv[]) {
signal(SIGINT, handle_sigint);
const char* chainDataDir = CHAIN_DATA_DIR;
const uint64_t blocksToMine = 10;
const uint64_t blocksToMine = 1000;
const double targetSeconds = TARGET_BLOCK_TIME;
uint256_t currentSupply = uint256_from_u64(0);
// Init RandomX
if (!RandomX_Init("minicoin", false)) { // TODO: Use a key that is not hardcoded; E.g. hash of the last block, every thousand blocks, difficulty recalibration, etc.
fprintf(stderr, "failed to initialize RandomX\n");
return 1;
}
blockchain_t* chain = Chain_Create();
if (!chain) {
fprintf(stderr, "failed to create chain\n");
return 1;
}
if (!Chain_LoadFromFile(chain, chainDataDir, &currentSupply)) {
if (!Chain_LoadFromFile(chain, chainDataDir, &currentSupply, &difficultyTarget)) {
printf("No existing chain loaded from %s\n", chainDataDir);
}
@@ -138,17 +86,6 @@ int main(int argc, char* argv[]) {
if (argc > 1 && strcmp(argv[1], "-mine") == 0) {
printf("Mining %llu blocks with target time %.0fs...\n", (unsigned long long)blocksToMine, targetSeconds);
const double hps = MeasureRandomXHashrate();
const double expectedHashes = (hps > 0.0) ? (hps * targetSeconds) : 65536.0;
const uint32_t calibratedBits = CompactTargetForExpectedHashes(expectedHashes);
//const uint32_t calibratedBits = 0xffffffff; // Absurdly low diff for testing
printf("RandomX benchmark: %.2f H/s, target %.0fs, nBits=0x%08x, diff=%.2f\n",
hps,
targetSeconds,
calibratedBits,
(double)(1.f / calibratedBits) * 4294967296.0); // Basic representation as a big number for now
uint8_t minerAddress[32];
SHA256((const unsigned char*)"minicoin-miner-1", strlen("minicoin-miner-1"), minerAddress);
@@ -157,7 +94,7 @@ int main(int argc, char* argv[]) {
if (!block) {
fprintf(stderr, "failed to create block\n");
Chain_Destroy(chain);
RandomX_Destroy();
Block_ShutdownPowContext();
return 1;
}
@@ -174,7 +111,7 @@ int main(int argc, char* argv[]) {
memset(block->header.prevHash, 0, sizeof(block->header.prevHash));
}
block->header.timestamp = (uint64_t)time(NULL);
block->header.difficultyTarget = calibratedBits;
block->header.difficultyTarget = difficultyTarget;
block->header.nonce = 0;
signed_transaction_t coinbaseTx;
@@ -195,7 +132,7 @@ int main(int argc, char* argv[]) {
fprintf(stderr, "failed to mine block within nonce range\n");
Block_Destroy(block);
Chain_Destroy(chain);
RandomX_Destroy();
Block_ShutdownPowContext();
return 1;
}
@@ -203,28 +140,36 @@ int main(int argc, char* argv[]) {
fprintf(stderr, "failed to append block to chain\n");
Block_Destroy(block);
Chain_Destroy(chain);
RandomX_Destroy();
Block_ShutdownPowContext();
return 1;
}
(void)uint256_add_u64(&currentSupply, coinbaseTx.transaction.amount);
uint8_t blockHash[32];
Block_CalculateHash(block, blockHash);
printf("Mined block %llu/%llu (height=%llu) nonce=%llu reward=%llu supply=%llu merkle=%02x%02x%02x%02x... hash=%02x%02x%02x%02x...\n",
uint8_t canonicalHash[32];
uint8_t powHash[32];
Block_CalculateHash(block, canonicalHash);
Block_CalculateAutolykos2Hash(block, powHash);
printf("Mined block %llu/%llu (height=%llu) nonce=%llu reward=%llu supply=%llu diff=%#x merkle=%02x%02x%02x%02x... pow=%02x%02x%02x%02x... canonical=%02x%02x%02x%02x...\n",
(unsigned long long)(mined + 1),
(unsigned long long)blocksToMine,
(unsigned long long)block->header.blockNumber,
(unsigned long long)block->header.nonce,
(unsigned long long)coinbaseTx.transaction.amount,
(unsigned long long)currentSupply.limbs[0],
(unsigned int)block->header.difficultyTarget,
block->header.merkleRoot[0], block->header.merkleRoot[1], block->header.merkleRoot[2], block->header.merkleRoot[3],
blockHash[0], blockHash[1], blockHash[2], blockHash[3]);
powHash[0], powHash[1], powHash[2], powHash[3],
canonicalHash[0], canonicalHash[1], canonicalHash[2], canonicalHash[3]);
free(block); // chain stores blocks by value; transactions are owned by chain copy
// Save chain after each mined block
Chain_SaveToFile(chain, chainDataDir, currentSupply);
if (Chain_Size(chain) % DIFFICULTY_ADJUSTMENT_INTERVAL == 0) {
difficultyTarget = Chain_ComputeNextTarget(chain, difficultyTarget);
}
}
if (!Chain_SaveToFile(chain, chainDataDir, currentSupply)) {
@@ -248,6 +193,6 @@ int main(int argc, char* argv[]) {
}
Chain_Destroy(chain);
RandomX_Destroy();
Block_ShutdownPowContext();
return 0;
}