Files

492 lines
10 KiB
C
Raw Permalink Normal View History

#include "utils.h"
#include <ctype.h>
#include <math.h>
#include <openssl/bn.h>
#include <openssl/sha.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
static char to_hex_digit(unsigned int v) {
if (v < 10U) {
return (char)('0' + v);
}
return (char)('a' + (v - 10U));
}
static void format_hashrate_core(double rate_hs, char *out, size_t out_len) {
static const char *units[] = {"H/s", "kH/s", "MH/s", "GH/s", "TH/s", "PH/s", "EH/s"};
size_t unit_idx = 0;
const size_t unit_count = sizeof(units) / sizeof(units[0]);
double value;
if (out == NULL || out_len == 0) {
return;
}
if (!(rate_hs >= 0.0)) {
rate_hs = 0.0;
}
value = rate_hs;
while (value >= 999.95 && unit_idx + 1 < unit_count) {
value /= 1000.0;
unit_idx++;
}
while (value > 0.0 && value < 1.0 && unit_idx > 0) {
value *= 1000.0;
unit_idx--;
}
if (value >= 100.0) {
snprintf(out, out_len, "%.0f %s", value, units[unit_idx]);
} else if (value >= 10.0) {
snprintf(out, out_len, "%.1f %s", value, units[unit_idx]);
} else {
snprintf(out, out_len, "%.2f %s", value, units[unit_idx]);
}
}
void format_hashrate_hz(double rate_hz, char *out, size_t out_len) {
format_hashrate_core(rate_hz, out, out_len);
}
void format_hashrate_khs(double rate_khs, char *out, size_t out_len) {
format_hashrate_core(rate_khs * 1000.0, out, out_len);
}
void sb_init(StrBuf *sb) {
sb->data = NULL;
sb->len = 0;
sb->cap = 0;
}
void sb_free(StrBuf *sb) {
free(sb->data);
sb->data = NULL;
sb->len = 0;
sb->cap = 0;
}
int sb_reserve(StrBuf *sb, size_t extra) {
size_t need;
size_t new_cap;
char *p;
need = sb->len + extra + 1;
if (need <= sb->cap) {
return 1;
}
new_cap = (sb->cap == 0) ? 128 : sb->cap;
while (new_cap < need) {
new_cap *= 2;
}
p = (char *)realloc(sb->data, new_cap);
if (p == NULL) {
return 0;
}
sb->data = p;
sb->cap = new_cap;
if (sb->len == 0) {
sb->data[0] = '\0';
}
return 1;
}
int sb_append(StrBuf *sb, const char *s) {
size_t n = strlen(s);
if (sb_reserve(sb, n) == 0) {
return 0;
}
memcpy(sb->data + sb->len, s, n + 1);
sb->len += n;
return 1;
}
int sb_append_n(StrBuf *sb, const char *s, size_t n) {
if (sb_reserve(sb, n) == 0) {
return 0;
}
memcpy(sb->data + sb->len, s, n);
sb->len += n;
sb->data[sb->len] = '\0';
return 1;
}
int sb_append_byte_hex(StrBuf *sb, uint8_t b) {
char tmp[3];
tmp[0] = to_hex_digit((unsigned int)(b >> 4));
tmp[1] = to_hex_digit((unsigned int)(b & 0x0F));
tmp[2] = '\0';
return sb_append(sb, tmp);
}
char *sb_take(StrBuf *sb) {
char *out = sb->data;
sb->data = NULL;
sb->len = 0;
sb->cap = 0;
return out;
}
int hex_char_to_val(char c) {
if (c >= '0' && c <= '9') {
return c - '0';
}
if (c >= 'a' && c <= 'f') {
return 10 + (c - 'a');
}
if (c >= 'A' && c <= 'F') {
return 10 + (c - 'A');
}
return -1;
}
int hex_to_bytes(const char *hex, uint8_t **out, size_t *out_len) {
size_t n;
size_t i;
uint8_t *buf;
if (hex == NULL || out == NULL || out_len == NULL) {
return 0;
}
n = strlen(hex);
if ((n % 2) != 0) {
return 0;
}
buf = (uint8_t *)malloc(n / 2);
if (buf == NULL) {
return 0;
}
for (i = 0; i < n; i += 2) {
int hi = hex_char_to_val(hex[i]);
int lo = hex_char_to_val(hex[i + 1]);
if (hi < 0 || lo < 0) {
free(buf);
return 0;
}
buf[i / 2] = (uint8_t)((hi << 4) | lo);
}
*out = buf;
*out_len = n / 2;
return 1;
}
int hex_to_fixed_bytes(const char *hex, uint8_t *out, size_t out_len) {
size_t n;
size_t i;
if (hex == NULL || out == NULL) {
return 0;
}
n = strlen(hex);
if (n != out_len * 2) {
return 0;
}
for (i = 0; i < n; i += 2) {
int hi = hex_char_to_val(hex[i]);
int lo = hex_char_to_val(hex[i + 1]);
if (hi < 0 || lo < 0) {
return 0;
}
out[i / 2] = (uint8_t)((hi << 4) | lo);
}
return 1;
}
char *bytes_to_hex(const uint8_t *data, size_t len) {
static const char tab[] = "0123456789abcdef";
char *out;
size_t i;
out = (char *)malloc(len * 2 + 1);
if (out == NULL) {
return NULL;
}
for (i = 0; i < len; ++i) {
out[2 * i] = tab[data[i] >> 4];
out[2 * i + 1] = tab[data[i] & 0x0F];
}
out[len * 2] = '\0';
return out;
}
void reverse_bytes(uint8_t *data, size_t n) {
size_t i;
for (i = 0; i < n / 2; ++i) {
uint8_t t = data[i];
data[i] = data[n - 1 - i];
data[n - 1 - i] = t;
}
}
void double_sha256(const uint8_t *data, size_t len, uint8_t out[32]) {
uint8_t tmp[SHA256_DIGEST_LENGTH];
SHA256(data, len, tmp);
SHA256(tmp, SHA256_DIGEST_LENGTH, out);
}
int encode_varint_hex(uint64_t value, StrBuf *sb) {
uint8_t bytes[9];
size_t n = 0;
size_t i;
if (value < 0xFD) {
bytes[n++] = (uint8_t)value;
} else if (value <= 0xFFFFULL) {
bytes[n++] = 0xFD;
bytes[n++] = (uint8_t)(value & 0xFF);
bytes[n++] = (uint8_t)((value >> 8) & 0xFF);
} else if (value <= 0xFFFFFFFFULL) {
bytes[n++] = 0xFE;
bytes[n++] = (uint8_t)(value & 0xFF);
bytes[n++] = (uint8_t)((value >> 8) & 0xFF);
bytes[n++] = (uint8_t)((value >> 16) & 0xFF);
bytes[n++] = (uint8_t)((value >> 24) & 0xFF);
} else {
bytes[n++] = 0xFF;
bytes[n++] = (uint8_t)(value & 0xFF);
bytes[n++] = (uint8_t)((value >> 8) & 0xFF);
bytes[n++] = (uint8_t)((value >> 16) & 0xFF);
bytes[n++] = (uint8_t)((value >> 24) & 0xFF);
bytes[n++] = (uint8_t)((value >> 32) & 0xFF);
bytes[n++] = (uint8_t)((value >> 40) & 0xFF);
bytes[n++] = (uint8_t)((value >> 48) & 0xFF);
bytes[n++] = (uint8_t)((value >> 56) & 0xFF);
}
for (i = 0; i < n; ++i) {
if (sb_append_byte_hex(sb, bytes[i]) == 0) {
return 0;
}
}
return 1;
}
static char *bn_to_fixed_hex64(const BIGNUM *bn) {
char *tmp;
char *out;
size_t n;
size_t i;
tmp = BN_bn2hex(bn);
if (tmp == NULL) {
return NULL;
}
n = strlen(tmp);
if (n > 64) {
OPENSSL_free(tmp);
return NULL;
}
out = (char *)malloc(65);
if (out == NULL) {
OPENSSL_free(tmp);
return NULL;
}
for (i = 0; i < 64; ++i) {
out[i] = '0';
}
out[64] = '\0';
for (i = 0; i < n; ++i) {
char c = tmp[i];
if (isupper((unsigned char)c)) {
c = (char)tolower((unsigned char)c);
}
out[64 - n + i] = c;
}
OPENSSL_free(tmp);
return out;
}
char *decode_nbits_hex(uint32_t nbits) {
BN_CTX *ctx;
BIGNUM *bn;
BIGNUM *sig;
char *out;
uint32_t exponent;
uint32_t significand;
exponent = (nbits >> 24) & 0xFF;
significand = nbits & 0x007FFFFF;
ctx = BN_CTX_new();
bn = BN_new();
sig = BN_new();
if (ctx == NULL || bn == NULL || sig == NULL) {
BN_CTX_free(ctx);
BN_free(bn);
BN_free(sig);
return NULL;
}
BN_set_word(sig, significand);
BN_copy(bn, sig);
if (exponent >= 3) {
BN_lshift(bn, bn, 8 * ((int)exponent - 3));
} else {
BN_rshift(bn, bn, 8 * (3 - (int)exponent));
}
out = bn_to_fixed_hex64(bn);
BN_CTX_free(ctx);
BN_free(bn);
BN_free(sig);
return out;
}
char *calculate_target_hex(const char *bits_hex, double difficulty_factor, const char *network) {
static const char *MAX_TARGET_HEX = "00000000ffff0000000000000000000000000000000000000000000000000000";
BIGNUM *max_bn;
BIGNUM *limit_bn;
BIGNUM *num_bn;
BIGNUM *den_bn;
BIGNUM *result_bn;
BN_CTX *ctx;
char *original;
char *out;
uint64_t scaled_factor;
const uint64_t SCALE = 1000000000ULL;
uint32_t nbits;
if (bits_hex == NULL || network == NULL) {
return NULL;
}
nbits = (uint32_t)strtoul(bits_hex, NULL, 16);
original = decode_nbits_hex(nbits);
if (original == NULL) {
return NULL;
}
if (strcmp(network, "regtest") == 0) {
if (difficulty_factor < 0.0) {
difficulty_factor = 0.1;
}
} else {
difficulty_factor = 1.0;
}
if (difficulty_factor == 0.0) {
return original;
}
scaled_factor = (uint64_t)llround(difficulty_factor * (double)SCALE);
if (scaled_factor == 0ULL) {
scaled_factor = 1ULL;
}
ctx = BN_CTX_new();
max_bn = BN_new();
limit_bn = BN_new();
num_bn = BN_new();
den_bn = BN_new();
result_bn = BN_new();
if (ctx == NULL || max_bn == NULL || limit_bn == NULL || num_bn == NULL || den_bn == NULL || result_bn == NULL) {
BN_CTX_free(ctx);
BN_free(max_bn);
BN_free(limit_bn);
BN_free(num_bn);
BN_free(den_bn);
BN_free(result_bn);
free(original);
return NULL;
}
BN_hex2bn(&max_bn, MAX_TARGET_HEX);
BN_hex2bn(&limit_bn, "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff");
BN_copy(num_bn, max_bn);
BN_mul_word(num_bn, (BN_ULONG)SCALE);
BN_set_word(den_bn, (BN_ULONG)scaled_factor);
BN_div(result_bn, NULL, num_bn, den_bn, ctx);
if (BN_cmp(result_bn, limit_bn) > 0) {
BN_copy(result_bn, limit_bn);
}
out = bn_to_fixed_hex64(result_bn);
BN_CTX_free(ctx);
BN_free(max_bn);
BN_free(limit_bn);
BN_free(num_bn);
BN_free(den_bn);
BN_free(result_bn);
free(original);
return out;
}
char *hex_add_width(const char *base_hex, int add_value) {
static const char *hex_digits = "0123456789abcdef";
char *out;
size_t n;
int carry;
size_t pos;
if (base_hex == NULL || add_value < 0) {
return NULL;
}
n = strlen(base_hex);
if (n == 0) {
return NULL;
}
out = strdup(base_hex);
if (out == NULL) {
return NULL;
}
carry = add_value;
pos = n;
while (pos > 0 && carry > 0) {
int digit = hex_char_to_val(out[pos - 1]);
int sum;
if (digit < 0) {
free(out);
return NULL;
}
sum = digit + carry;
out[pos - 1] = hex_digits[sum & 0x0F];
carry = sum >> 4;
--pos;
}
return out;
}