diff --git a/include/dogecoin/auxpow.h b/include/dogecoin/auxpow.h index 60eb2c4ca..d098a4e2a 100644 --- a/include/dogecoin/auxpow.h +++ b/include/dogecoin/auxpow.h @@ -44,7 +44,7 @@ LIBDOGECOIN_BEGIN_DECL static const unsigned char pch_merged_mining_header[] = { 0xfa, 0xbe, 'm', 'm' }; int get_expected_index(uint32_t nNonce, int nChainId, unsigned h); -uint256* check_merkle_branch(uint256 hash, const vector* parent_coinbase_merkle, unsigned int n_index); +uint256* check_merkle_branch(uint256* hash, const vector* merkle_branch, int index); LIBDOGECOIN_END_DECL diff --git a/include/dogecoin/hash.h b/include/dogecoin/hash.h index 9632e4525..de0a04b8c 100644 --- a/include/dogecoin/hash.h +++ b/include/dogecoin/hash.h @@ -98,7 +98,7 @@ typedef struct _chash256 { static inline chash256* dogecoin_chash256_init() { chash256* chash = dogecoin_calloc(1, sizeof(*chash)); - sha256_context* ctx = NULL; + sha256_context* ctx = dogecoin_calloc(1, sizeof(*ctx)); sha256_init(ctx); chash->sha = ctx; chash->write = sha256_write; @@ -107,19 +107,34 @@ static inline chash256* dogecoin_chash256_init() { return chash; } -static inline uint256* Hash(const uint256 p1begin, const uint256 p1end, - const uint256 p2begin, const uint256 p2end) { - static const unsigned char pblank[1]; +// Hashes the data from two uint256 values and returns the double SHA-256 hash. +static inline uint256* Hash(const uint256* p1, const uint256* p2) { uint256* result = dogecoin_uint256_vla(1); chash256* chash = dogecoin_chash256_init(); - chash->write(chash->sha, p1begin == p1end ? pblank : (const unsigned char*)&p1begin[0], (p1end - p1begin) * sizeof(p1begin[0])); - chash->write(chash->sha, p2begin == p2end ? pblank : (const unsigned char*)&p2begin[0], (p2end - p2begin) * sizeof(p2begin[0])); + + // Write the first uint256 to the hash context + if (p1) { + chash->write(chash->sha, (const uint8_t*)p1, sizeof(uint256)); + } + + // Write the second uint256 to the hash context + if (p2) { + chash->write(chash->sha, (const uint8_t*)p2, sizeof(uint256)); + } + + // Finalize and reset for double hashing chash->finalize(chash->sha, (unsigned char*)result); chash->reset(chash->sha); + chash->write(chash->sha, (const uint8_t*)result, SHA256_DIGEST_LENGTH); + chash->finalize(chash->sha, (unsigned char*)result); + + // Cleanup + free(chash->sha); + free(chash); + return result; } - /** Hashwriter Psuedoclass */ static enum ser_type { // primary actions diff --git a/include/dogecoin/validation.h b/include/dogecoin/validation.h index 82b8c817e..c4197b294 100644 --- a/include/dogecoin/validation.h +++ b/include/dogecoin/validation.h @@ -45,7 +45,7 @@ LIBDOGECOIN_BEGIN_DECL LIBDOGECOIN_API uint32_t get_chainid(uint32_t version); LIBDOGECOIN_API dogecoin_bool is_auxpow(uint32_t version); LIBDOGECOIN_API dogecoin_bool is_legacy(uint32_t version); -LIBDOGECOIN_API dogecoin_bool check_auxpow(dogecoin_auxpow_block block, dogecoin_chainparams* params); +LIBDOGECOIN_API dogecoin_bool check_auxpow(dogecoin_auxpow_block* block, dogecoin_chainparams* params); LIBDOGECOIN_API dogecoin_bool dogecoin_block_header_scrypt_hash(cstring* s, uint256* hash); LIBDOGECOIN_END_DECL diff --git a/src/auxpow.c b/src/auxpow.c index a4eb3f9e3..00ea078e3 100644 --- a/src/auxpow.c +++ b/src/auxpow.c @@ -56,17 +56,29 @@ int get_expected_index (uint32_t nNonce, int nChainId, unsigned h) return rand % (1 << h); } -uint256* check_merkle_branch(uint256 hash, const vector* parent_coinbase_merkle, unsigned int n_index) { - if (n_index == (unsigned int)-1) return dogecoin_uint256_vla(1); - unsigned int i = n_index; - for (; i < parent_coinbase_merkle->len; ++i) { - uint256 pcm; - memcpy(pcm, vector_idx(parent_coinbase_merkle, i), 32); - if (i & 1) - hash = (uint8_t *)Hash(UBEGIN(*pcm), UEND(*pcm), UBEGIN(hash), UEND(hash)); - else - hash = (uint8_t *)Hash(UBEGIN(hash), UEND(hash), UBEGIN(*pcm), UEND(*pcm)); - i >>= 1; +// Computes the Merkle root from a given hash, Merkle branch, and index. +uint256* check_merkle_branch(uint256* hash, const vector* merkle_branch, int index) { + if (index == -1) { + return dogecoin_uint256_vla(1); // Return a zeroed-out uint256 array. } - return (uint256*)*&hash; + + uint256* current_hash = dogecoin_uint256_vla(1); + memcpy(current_hash, hash, sizeof(uint256)); // Copy the initial hash + + for (int i = 0; i < merkle_branch->len; ++i) { + uint256* next_branch_hash = (uint256*)vector_idx(merkle_branch, i); + uint256* new_hash; + + if (index & 1) { + new_hash = Hash(next_branch_hash, current_hash); + } else { + new_hash = Hash(current_hash, next_branch_hash); + } + + memcpy(current_hash, new_hash, sizeof(uint256)); // Update the current hash + dogecoin_free(new_hash); // Free the new hash memory + index >>= 1; + } + + return current_hash; } diff --git a/src/block.c b/src/block.c index 3b57220ec..3e807e503 100644 --- a/src/block.c +++ b/src/block.c @@ -53,25 +53,29 @@ dogecoin_bool check(void *ctx, uint256* hash, uint32_t chainid, dogecoin_chainpa uint32_t parent_chainid = get_chainid(block->parent_header->version); if (params->strict_id && parent_chainid == chainid) { - printf("Aux POW parent has our chain ID"); + printf("Aux POW parent has our chain ID\n"); return false; } - vector* parent_merkle = vector_new(8, NULL); - size_t p = 0; - for (; p < block->parent_merkle_count; p++) { - vector_add(parent_merkle, block->parent_coinbase_merkle[p]); + vector* chain_merkle_branch = vector_new(block->aux_merkle_count, NULL); + for (size_t p = 0; p < block->aux_merkle_count; p++) { + vector_add(chain_merkle_branch, block->aux_merkle_branch[p]); } - if (parent_merkle->len > 30) { + if (chain_merkle_branch->len > 30) { printf("Aux POW chain merkle branch too long\n"); + vector_free(chain_merkle_branch, true); return false; } - // Check that the chain merkle root is in the coinbase - uint256* n_roothash = check_merkle_branch((uint8_t*)hash, parent_merkle, parent_merkle->len); - const unsigned char* vch_roothash = (unsigned char*)hash_to_string((uint8_t*)n_roothash); // correct endian - vector_free(parent_merkle, true); + // First call to check_merkle_branch for the auxiliary blockchain's merkle branch + uint256* chain_merkle_root = check_merkle_branch(hash, chain_merkle_branch, block->aux_merkle_index); + vector_free(chain_merkle_branch, true); + + // Convert the root hash to a human-readable format (hex) + unsigned char vch_roothash[64]; // Make sure it's large enough to hold the hash + memcpy(vch_roothash, hash_to_string((uint8_t*)chain_merkle_root), 64); // Copy the data + dogecoin_free(chain_merkle_root); // Free the computed merkle root dogecoin_tx_in *tx_in = vector_idx(block->parent_coinbase->vin, 0); size_t idx = 0, count = 0; @@ -146,6 +150,13 @@ dogecoin_auxpow_block* dogecoin_auxpow_block_new() { dogecoin_auxpow_block* block = dogecoin_calloc(1, sizeof(*block)); block->header = dogecoin_block_header_new(); block->parent_coinbase = dogecoin_tx_new(); + dogecoin_mem_zero(&block->parent_hash, DOGECOIN_HASH_LENGTH); + block->parent_merkle_count = 0; + block->parent_coinbase_merkle; + block->parent_merkle_index = 0; + block->aux_merkle_count = 0; + block->aux_merkle_branch; + block->aux_merkle_index = 0; block->parent_header = dogecoin_block_header_new(); block->header->auxpow->check = check; block->header->auxpow->ctx = block; @@ -244,7 +255,7 @@ void print_parent_header(dogecoin_auxpow_block* block) { printf("block->aux_merkle_count: %d\n", block->aux_merkle_count); j = 0; for (; j < block->aux_merkle_count; j++) { - printf("block->aux_merkle_branch[%zu]: " + printf("block->aux_merkle_branch[%zu]: " "%s\n", j, hash_to_string((uint8_t*)block->aux_merkle_branch[j])); } printf("block->aux_merkle_index: %d\n", block->aux_merkle_index); @@ -328,7 +339,9 @@ int deserialize_dogecoin_auxpow_block(dogecoin_auxpow_block* block, struct const return false; } uint8_t i = 0; - block->parent_coinbase_merkle = dogecoin_calloc(block->parent_merkle_count, sizeof(uint256)); + if (block->parent_merkle_count > 0) { + block->parent_coinbase_merkle = dogecoin_calloc(block->parent_merkle_count, sizeof(uint256)); + } for (; i < block->parent_merkle_count; i++) { if (!deser_u256(block->parent_coinbase_merkle[i], buffer)) { printf("%d:%s:%d\n", __LINE__, __func__, i); @@ -344,7 +357,9 @@ int deserialize_dogecoin_auxpow_block(dogecoin_auxpow_block* block, struct const printf("%s:%d:%s:%s\n", __FILE__, __LINE__, __func__, strerror(errno)); return false; } - block->aux_merkle_branch = dogecoin_calloc(block->aux_merkle_count, sizeof(uint256)); + if (block->aux_merkle_count > 0) { + block->aux_merkle_branch = dogecoin_calloc(block->aux_merkle_count, sizeof(uint256)); + } for (i = 0; i < block->aux_merkle_count; i++) { if (!deser_u256(block->aux_merkle_branch[i], buffer)) { printf("%d:%s:%d\n", __LINE__, __func__, i); @@ -381,8 +396,9 @@ int deserialize_dogecoin_auxpow_block(dogecoin_auxpow_block* block, struct const return false; } - if (!check_auxpow(*block, (dogecoin_chainparams*)params)) { + if (!check_auxpow(block, (dogecoin_chainparams*)params)) { printf("check_auxpow failed!\n"); + print_block(block); return false; } diff --git a/src/validation.c b/src/validation.c index e662e6ec8..51302c817 100644 --- a/src/validation.c +++ b/src/validation.c @@ -42,9 +42,13 @@ */ dogecoin_bool dogecoin_block_header_scrypt_hash(cstring* s, uint256* hash) { char scratchpad[SCRYPT_SCRATCHPAD_SIZE]; +#if defined(USE_SSE2) + scrypt_1024_1_1_256_sp_sse2((const char*)s->str, (char *) hash, scratchpad); +#else scrypt_1024_1_1_256_sp_generic((const char*)s->str, (char *) hash, scratchpad); +#endif return true; - } +} uint32_t get_chainid(uint32_t version) { return version >> 16; @@ -60,29 +64,29 @@ dogecoin_bool is_legacy(uint32_t version) { || (version == 2 && get_chainid(version) == 0); } -dogecoin_bool check_auxpow(dogecoin_auxpow_block block, dogecoin_chainparams* params) { +dogecoin_bool check_auxpow(dogecoin_auxpow_block* block, dogecoin_chainparams* params) { /* Except for legacy blocks with full version 1, ensure that the chain ID is correct. Legacy blocks are not allowed since the merge-mining start, which is checked in AcceptBlockHeader where the height is known. */ - if (!is_legacy(block.header->version) && params->strict_id && get_chainid(block.header->version) != params->auxpow_id) { + if (!is_legacy(block->header->version) && params->strict_id && get_chainid(block->header->version) != params->auxpow_id) { printf("%s:%d:%s : block does not have our chain ID" " (got %d, expected %d, full nVersion %d) : %s\n", - __FILE__, __LINE__, __func__, get_chainid(block.header->version), - params->auxpow_id, block.header->version, strerror(errno)); + __FILE__, __LINE__, __func__, get_chainid(block->header->version), + params->auxpow_id, block->header->version, strerror(errno)); return false; } /* If there is no auxpow, just check the block hash. */ - if (!block.header->auxpow->is) { + if (!block->header->auxpow->is) { uint256 hash = {0}; cstring* s = cstr_new_sz(64); - dogecoin_block_header_serialize(s, block.header); + dogecoin_block_header_serialize(s, block->header); dogecoin_block_header_scrypt_hash(s, &hash); cstr_free(s, true); - if (!check_pow(&hash, block.header->bits, params)) { + if (!check_pow(&hash, block->header->bits, params)) { printf("%s:%d:%s : non-AUX proof of work failed : %s\n", __FILE__, __LINE__, __func__, strerror(errno)); return false; } @@ -92,23 +96,20 @@ dogecoin_bool check_auxpow(dogecoin_auxpow_block block, dogecoin_chainparams* pa /* We have auxpow. Check it. */ uint256 block_header_hash; - cstring* s = cstr_new_sz(64); - dogecoin_block_header_serialize(s, block.header); - dogecoin_block_header_scrypt_hash(s, &block_header_hash); - cstr_free(s, true); - uint32_t chainid = get_chainid(block.header->version); - if (!block.header->auxpow->check(&block, &block_header_hash, chainid, params)) { + dogecoin_block_header_hash(block->header, block_header_hash); + uint32_t chainid = get_chainid(block->header->version); + if (!block->header->auxpow->check(block, &block_header_hash, chainid, params)) { printf("%s:%d:%s : AUX POW is not valid : %s\n", __FILE__, __LINE__, __func__, strerror(errno)); return false; } uint256 parent_hash; cstring* s2 = cstr_new_sz(64); - dogecoin_block_header_serialize(s2, block.parent_header); + dogecoin_block_header_serialize(s2, block->parent_header); dogecoin_block_header_scrypt_hash(s2, &parent_hash); cstr_free(s2, true); - if (!check_pow(&parent_hash, block.header->bits, params)) { - printf("%s:%d:%s : check_pow failure : %s\n", __FILE__, __LINE__, __func__, strerror(errno)); + if (!check_pow(&parent_hash, block->header->bits, params)) { + printf("%s:%d:%s : AUX proof of work failed: %s\n", __FILE__, __LINE__, __func__, strerror(errno)); return false; }