From 4ec69f6512ad6e6402524c2da4fa8f8569c5d61d Mon Sep 17 00:00:00 2001 From: edtubbs Date: Fri, 24 Nov 2023 16:31:55 -0600 Subject: [PATCH] hash: added dogecoin_hashwriter_free auxpow: updated check_merkle_branch iterator to size_t and hash parameters block: updated dogecoin_block_header_new to initialize header block: updated dogecoin_block_header_free to clear version and removed debug print block: updated dogecoin_block_header_copy to copy auxpow block: updated header and dogecoin_block_header_serialize/deserialize to signed version headersdb_file: updated dogecoin_headers_db_free to free chaintip to chainbottom headersdb_file: updated dogecoin_headers_db_connect_hdr to free blockindex and todo headersdb_file: updated dogecoin_headers_db_load to print progress spv: updated dogecoin_spv_client_free to check for headers_db_ctx spv: updated dogecoin_net_spv_post_cmd to recover after invalid headers and blocks spv: updated dogecoin_net_spv_periodic_statecheck to request blocks in full block sync spv: updated dogecoin_net_spv_request_headers to requests blocks from node with best height transaction: updated sign_transaction_w_privkey to free script_pubkey and txtmp tx: updated dogecoin_tx_out_pubkey_hash_to_p2pkh_address to free copy of txout wallet: removed dogecoin_wallet_add_to_spent as dogecoin_wallet_scrape_utxos handles spends wallet: updated dogecoin_wallet_new frees and to call dogecoin_hdnode_free wallet: updated dogecoin_wallet_free to call dogecoin_btree_tdestroy with NULL/free wallet: updated dogecoin_wallet_create to check for open wallet file wallet: updated dogecoin_wallet_init with temp_address_copy and free address_copy wallet: updated dogecoin_wallet_init with dogecoin_wallet_addr_free if address found wallet: updated dogecoin_wallet_load_address and to free buf wallet: updated dogecoin_wallet_load_transaction to free buf wallet: updated dogecoin_wallet_next_addr to free key wallet: updated dogecoin_wallet_next_bip44_addr to free keys and waddr wallet: updated dogecoin_register_watch_address_with_node to free address_copy and wallet wallet: updated dogecoin_register_watch_address_with_node to free waddr wallet: updated dogecoin_unregister_watch_address_with_node to free address_copy and record wallet: updated dogecoin_unregister_watch_address_with_node to free waddr_check and waddr wallet: updated dogecoin_get_utxo functions and dogecoin_get_balance to free wallet/utxos wallet: updated dogecoin_wallet_utxo_new to initialize elements wallet: updated dogecoin_wallet_scrape_utxos to check pointers before memcmp address_test: updated generateHDMasterPubKeypair testnet parameter to true bip44_test: updated test_seed pointer and assignment block_test: updated to signed version hash_test: added dogecoin_hashwriter_free wallet_test: added vector_add of waddr and dogecoin_free of tx_data to test_wallet wallet_test: added dogecoin_wallet_flush and dogecoin_wallet_free to test_wallet wallet_test: added vector_free of addrs to test_wallet_basics --- include/dogecoin/block.h | 2 +- include/dogecoin/hash.h | 6 ++ include/dogecoin/wallet.h | 1 - src/auxpow.c | 6 +- src/block.c | 24 ++++-- src/headersdb_file.c | 57 +++++++++++--- src/spv.c | 152 +++++++++++++++++++++++--------------- src/transaction.c | 109 ++++++++++++++------------- src/tx.c | 2 + src/wallet.c | 132 +++++++++++++++++++-------------- test/address_tests.c | 2 +- test/bip44_tests.c | 3 +- test/block_tests.c | 4 +- test/hash_tests.c | 4 +- test/wallet_tests.c | 6 ++ 15 files changed, 313 insertions(+), 197 deletions(-) diff --git a/include/dogecoin/block.h b/include/dogecoin/block.h index 24fa28636..b31caf6a2 100644 --- a/include/dogecoin/block.h +++ b/include/dogecoin/block.h @@ -48,7 +48,7 @@ typedef struct _auxpow { } auxpow; typedef struct dogecoin_block_header_ { - uint32_t version; + int32_t version; uint256 prev_block; uint256 merkle_root; uint32_t timestamp; diff --git a/include/dogecoin/hash.h b/include/dogecoin/hash.h index de0a04b8c..f08cb8a67 100644 --- a/include/dogecoin/hash.h +++ b/include/dogecoin/hash.h @@ -189,6 +189,12 @@ static hashwriter* init_hashwriter(int n_type, int n_version) { return hw; } +static void dogecoin_hashwriter_free(hashwriter* hw) { + free(hw->ctx->sha); + free(hw->ctx); + dogecoin_free(hw->hash); + dogecoin_free(hw); +} /** SipHash 2-4 */ typedef struct siphasher { diff --git a/include/dogecoin/wallet.h b/include/dogecoin/wallet.h index 05bd8055a..e3ee2c43a 100644 --- a/include/dogecoin/wallet.h +++ b/include/dogecoin/wallet.h @@ -173,7 +173,6 @@ LIBDOGECOIN_API int64_t dogecoin_wallet_wtx_get_available_credit(dogecoin_wallet LIBDOGECOIN_API dogecoin_bool dogecoin_wallet_txout_is_mine(dogecoin_wallet* wallet, dogecoin_tx_out* tx_out); /** checks if a transaction outpoint is owned by the wallet */ -LIBDOGECOIN_API void dogecoin_wallet_add_to_spent(dogecoin_wallet* wallet, const dogecoin_wtx* wtx); LIBDOGECOIN_API dogecoin_bool dogecoin_wallet_is_spent(dogecoin_wallet* wallet, uint256 hash, uint32_t n); LIBDOGECOIN_API dogecoin_bool dogecoin_wallet_get_unspents(dogecoin_wallet* wallet, vector* unspents); LIBDOGECOIN_API dogecoin_bool dogecoin_wallet_get_unspent(dogecoin_wallet* wallet, vector* unspent); diff --git a/src/auxpow.c b/src/auxpow.c index 00ea078e3..5f1c77a83 100644 --- a/src/auxpow.c +++ b/src/auxpow.c @@ -65,14 +65,14 @@ uint256* check_merkle_branch(uint256* hash, const vector* merkle_branch, int ind 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) { + for (size_t 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); + new_hash = Hash((const uint256*) next_branch_hash, (const uint256*) current_hash); } else { - new_hash = Hash(current_hash, next_branch_hash); + new_hash = Hash((const uint256*) current_hash, (const uint256*) next_branch_hash); } memcpy(current_hash, new_hash, sizeof(uint256)); // Update the current hash diff --git a/src/block.c b/src/block.c index c03714027..fb0aaf3d0 100644 --- a/src/block.c +++ b/src/block.c @@ -159,6 +159,14 @@ dogecoin_bool check(void *ctx, uint256* hash, uint32_t chainid, dogecoin_chainpa dogecoin_block_header* dogecoin_block_header_new() { dogecoin_block_header* header; header = dogecoin_calloc(1, sizeof(*header)); + header->version = 0; + dogecoin_mem_zero(&header->prev_block, DOGECOIN_HASH_LENGTH); + dogecoin_mem_zero(&header->merkle_root, DOGECOIN_HASH_LENGTH); + header->bits = 0; + header->timestamp = 0; + header->nonce = 0; + header->auxpow->check = check; + header->auxpow->ctx = header; return header; } @@ -173,10 +181,10 @@ dogecoin_auxpow_block* dogecoin_auxpow_block_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_coinbase_merkle = NULL; block->parent_merkle_index = 0; block->aux_merkle_count = 0; - block->aux_merkle_branch; + block->aux_merkle_branch = NULL; block->aux_merkle_index = 0; block->parent_header = dogecoin_block_header_new(); block->header->auxpow->check = check; @@ -194,7 +202,7 @@ dogecoin_auxpow_block* dogecoin_auxpow_block_new() { */ void dogecoin_block_header_free(dogecoin_block_header* header) { if (!header) return; - header->version = 1; + header->version = 0; dogecoin_mem_zero(&header->prev_block, DOGECOIN_HASH_LENGTH); dogecoin_mem_zero(&header->merkle_root, DOGECOIN_HASH_LENGTH); header->bits = 0; @@ -300,12 +308,13 @@ void print_block(dogecoin_auxpow_block* block) { * * @param header The header object to be constructed. * @param buf The buffer to deserialize from. + * @param params The chain parameters. * * @return 1 if deserialization was successful, 0 otherwise. */ int dogecoin_block_header_deserialize(dogecoin_block_header* header, struct const_buffer* buf, const dogecoin_chainparams *params) { dogecoin_auxpow_block* block = dogecoin_auxpow_block_new(); - if (!deser_u32(&block->header->version, buf)) + if (!deser_s32(&block->header->version, buf)) return false; if (!deser_u256(block->header->prev_block, buf)) return false; @@ -392,7 +401,7 @@ int deserialize_dogecoin_auxpow_block(dogecoin_auxpow_block* block, struct const printf("%s:%d:%s:%s\n", __FILE__, __LINE__, __func__, strerror(errno)); return false; } - if (!deser_u32(&block->parent_header->version, buffer)) { + if (!deser_s32(&block->parent_header->version, buffer)) { printf("%s:%d:%s:%s\n", __FILE__, __LINE__, __func__, strerror(errno)); return false; } @@ -419,7 +428,6 @@ int deserialize_dogecoin_auxpow_block(dogecoin_auxpow_block* block, struct const if (!check_auxpow(block, (dogecoin_chainparams*)params)) { printf("check_auxpow failed!\n"); - print_block(block); return false; } @@ -436,7 +444,7 @@ int deserialize_dogecoin_auxpow_block(dogecoin_auxpow_block* block, struct const * @return Nothing. */ void dogecoin_block_header_serialize(cstring* s, const dogecoin_block_header* header) { - ser_u32(s, header->version); + ser_s32(s, header->version); ser_u256(s, header->prev_block); ser_u256(s, header->merkle_root); ser_u32(s, header->timestamp); @@ -460,6 +468,8 @@ void dogecoin_block_header_copy(dogecoin_block_header* dest, const dogecoin_bloc dest->timestamp = src->timestamp; dest->bits = src->bits; dest->nonce = src->nonce; + dest->auxpow->check = src->auxpow->check; + dest->auxpow->ctx = src->auxpow->ctx; } /** diff --git a/src/headersdb_file.c b/src/headersdb_file.c index 080d206c0..1fc9db4bf 100644 --- a/src/headersdb_file.c +++ b/src/headersdb_file.c @@ -117,10 +117,30 @@ void dogecoin_headers_db_free(dogecoin_headers_db* db) { } if (db->tree_root) { - dogecoin_btree_tdestroy(db->tree_root, dogecoin_free); + dogecoin_btree_tdestroy(db->tree_root, NULL); db->tree_root = NULL; } + // Free all blockindex structures starting from chaintip to chainbottom + if (db->chaintip) { + dogecoin_blockindex *scan_tip = db->chaintip; + while (scan_tip && scan_tip != db->chainbottom) { + dogecoin_blockindex *prev = scan_tip->prev; + dogecoin_free(scan_tip); + scan_tip = prev; + } +#ifndef __APPLE__ + // If scan_tip is chainbottom, free it + if (scan_tip == db->chainbottom) { + dogecoin_free(scan_tip); + db->chainbottom = NULL; + } +#endif + } + + db->chaintip = NULL; + db->chainbottom = NULL; + dogecoin_free(db); } @@ -181,8 +201,17 @@ dogecoin_bool dogecoin_headers_db_load(dogecoin_headers_db* db, const char *file size_t connected_headers_count = 0; if (db->headers_tree_file && !create) { + printf("Loading headers from disk, this may take several minutes...\n"); + while (!feof(db->headers_tree_file)) { + // print progress + if (connected_headers_count % 1000 == 0) + { + printf("\r%ld headers loaded", connected_headers_count); + fflush(stdout); + } + uint8_t buf_all[32+4+80]; if (fread(buf_all, sizeof(buf_all), 1, db->headers_tree_file) == 1) { struct const_buffer cbuf_all = {buf_all, sizeof(buf_all)}; @@ -201,7 +230,7 @@ dogecoin_bool dogecoin_headers_db_load(dogecoin_headers_db* db, const char *file if (!dogecoin_block_header_deserialize(&chainheader->header, &cbuf_all, db->params)) { dogecoin_block_header_free(&chainheader->header); dogecoin_free(chainheader); - fprintf(stderr, "Error: Invalid data found.\n"); + fprintf(stderr, "\nError: Invalid data found.\n"); return -1; } dogecoin_block_header_hash(&chainheader->header, (uint8_t *)&chainheader->hash); @@ -212,7 +241,7 @@ dogecoin_bool dogecoin_headers_db_load(dogecoin_headers_db* db, const char *file dogecoin_headers_db_connect_hdr(db, &cbuf_all, true, &connected); if (!connected) { - printf("Connecting header failed (at height: %d)\n", db->chaintip->height); + printf("\nConnecting header failed (at height: %d)\n", db->chaintip->height); } else { connected_headers_count++; @@ -221,7 +250,7 @@ dogecoin_bool dogecoin_headers_db_load(dogecoin_headers_db* db, const char *file } } } - printf("Connected %ld headers, now at height: %d\n", connected_headers_count, db->chaintip->height); + printf("\nConnected %ld headers, now at height: %d\n", connected_headers_count, db->chaintip->height); return (db->headers_tree_file != NULL); } @@ -261,7 +290,12 @@ dogecoin_blockindex * dogecoin_headers_db_connect_hdr(dogecoin_headers_db* db, s *connected = false; dogecoin_blockindex *blockindex = dogecoin_calloc(1, sizeof(dogecoin_blockindex)); - if (!dogecoin_block_header_deserialize(&blockindex->header, buf, db->params)) return NULL; + if (!dogecoin_block_header_deserialize(&blockindex->header, buf, db->params)) + { + dogecoin_free(blockindex); + fprintf(stderr, "Error deserializing block header\n"); + return NULL; + } dogecoin_block_header_hash(&blockindex->header, (uint8_t *)&blockindex->hash); @@ -313,6 +347,7 @@ dogecoin_blockindex * dogecoin_headers_db_connect_hdr(dogecoin_headers_db* db, s } } if (db->use_binary_tree) { + /* TODO: update when fork handling is implemented */ dogecoin_btree_tfind(blockindex, &db->tree_root, dogecoin_header_compare); } @@ -340,14 +375,12 @@ dogecoin_blockindex * dogecoin_headers_db_connect_hdr(dogecoin_headers_db* db, s } } *connected = true; + return blockindex; + } else { + // Connection not established, free allocated memory + dogecoin_free(blockindex); + return NULL; } - else { - //TODO, add to orphans - char hex[65] = {0}; - utils_bin_to_hex(blockindex->hash, DOGECOIN_HASH_LENGTH, hex); - } - - return blockindex; } /** diff --git a/src/spv.c b/src/spv.c index 4884f9658..8e97c6cda 100644 --- a/src/spv.c +++ b/src/spv.c @@ -68,7 +68,7 @@ void dogecoin_net_spv_node_handshake_done(dogecoin_node *node); * the nodegroup's handshake_done_cb to dogecoin_net_spv_node_handshake_done, * the nodegroup's node_connection_state_changed_cb to NULL, and the * nodegroup's periodic_timer_cb to dogecoin_net_spv_node_timer_callback - * + * * @param nodegroup The nodegroup to set the callbacks for. */ void dogecoin_net_set_spv(dogecoin_node_group *nodegroup) @@ -81,11 +81,11 @@ void dogecoin_net_set_spv(dogecoin_node_group *nodegroup) /** * The function creates a new dogecoin_spv_client object and initializes it - * + * * @param params The chainparams struct that we created earlier. * @param debug If true, the node will print out debug messages to stdout. * @param headers_memonly If true, the headers database will not be loaded from disk. - * + * * @return A pointer to a dogecoin_spv_client object. */ dogecoin_spv_client* dogecoin_spv_client_new(const dogecoin_chainparams *params, dogecoin_bool debug, dogecoin_bool headers_memonly, dogecoin_bool use_checkpoints, dogecoin_bool full_sync) @@ -128,7 +128,7 @@ dogecoin_spv_client* dogecoin_spv_client_new(const dogecoin_chainparams *params, /** * It adds peers to the nodegroup. - * + * * @param client the dogecoin_spv_client object * @param ips A comma-separated list of IPs or seeds to connect to. */ @@ -140,7 +140,7 @@ void dogecoin_spv_client_discover_peers(dogecoin_spv_client* client, const char /** * The function loops through all the nodes in the node group and connects to the next nodes in the * node group - * + * * @param client The dogecoin_spv_client object. */ void dogecoin_spv_client_runloop(dogecoin_spv_client* client) @@ -151,9 +151,9 @@ void dogecoin_spv_client_runloop(dogecoin_spv_client* client) /** * It frees the memory allocated for the client - * + * * @param client The client object to be freed. - * + * * @return Nothing. */ void dogecoin_spv_client_free(dogecoin_spv_client *client) @@ -163,7 +163,10 @@ void dogecoin_spv_client_free(dogecoin_spv_client *client) if (client->headers_db) { - client->headers_db->free(client->headers_db_ctx); + if (client->headers_db_ctx) + { + client->headers_db->free(client->headers_db_ctx); + } client->headers_db_ctx = NULL; client->headers_db = NULL; } @@ -178,10 +181,10 @@ void dogecoin_spv_client_free(dogecoin_spv_client *client) /** * Loads the headers database from a file - * + * * @param client the client object * @param file_path The path to the headers database file. - * + * * @return A boolean value. */ dogecoin_bool dogecoin_spv_client_load(dogecoin_spv_client *client, const char *file_path) @@ -198,7 +201,7 @@ dogecoin_bool dogecoin_spv_client_load(dogecoin_spv_client *client, const char * /** * If we are in the header sync state, we request headers from a random node - * + * * @param node the node that we are checking * @param now The current time in seconds. */ @@ -228,9 +231,9 @@ void dogecoin_net_spv_periodic_statecheck(dogecoin_node *node, uint64_t *now) // we are downloading blocks from this peer int64_t timedetla = *now - node->time_last_request; - client->nodegroup->log_write_cb("No block response in time (used %d) for node %d\n", timedetla, node->nodeid); if (timedetla > HEADERS_MAX_RESPONSE_TIME) { + client->nodegroup->log_write_cb("No block response in time (used %d) for node %d\n", timedetla, node->nodeid); dogecoin_node_disconnect(node); node->time_last_request = 0; dogecoin_net_spv_request_headers(client); @@ -242,21 +245,26 @@ void dogecoin_net_spv_periodic_statecheck(dogecoin_node *node, uint64_t *now) dogecoin_net_spv_request_headers(client); } + if ((client->stateflags & SPV_FULLBLOCK_SYNC_FLAG) == SPV_FULLBLOCK_SYNC_FLAG) + { + dogecoin_net_spv_request_headers(client); + } + client->last_statecheck_time = *now; } /** - * This function is called by the dogecoin_node_timer_callback function. - * - * It checks if the last_statecheck_time is greater than the minimum time delta for state checks. - * - * If it is, it calls the dogecoin_net_spv_periodic_statecheck function. - * - * The dogecoin_net_spv_periodic_statecheck function checks if the node is connected to the network. - * + * This function is called by the dogecoin_node_timer_callback function. + * + * It checks if the last_statecheck_time is greater than the minimum time delta for state checks. + * + * If it is, it calls the dogecoin_net_spv_periodic_statecheck function. + * + * The dogecoin_net_spv_periodic_statecheck function checks if the node is connected to the network. + * * @param node The node that the timer is being called on. * @param now the current time in seconds since the epoch - * + * * @return A boolean value. */ static dogecoin_bool dogecoin_net_spv_node_timer_callback(dogecoin_node *node, uint64_t *now) @@ -273,10 +281,10 @@ static dogecoin_bool dogecoin_net_spv_node_timer_callback(dogecoin_node *node, u /** * Fill up the blocklocators vector with the blocklocators from the headers database - * + * * @param client the spv client * @param blocklocators a vector of block hashes that we want to scan from - * + * * @return The blocklocators are being returned. */ void dogecoin_net_spv_fill_block_locator(dogecoin_spv_client *client, vector *blocklocators) { @@ -298,7 +306,7 @@ void dogecoin_net_spv_fill_block_locator(dogecoin_spv_client *client, vector *bl } } } - if (blocklocators->len > 0) return; // return if we could fill up the blocklocator with checkpoints + if (blocklocators->len > 0) return; // return if we could fill up the blocklocator with checkpoints } uint256 *hash = dogecoin_calloc(1, sizeof(uint256)); memcpy_safe(hash, &client->chainparams->genesisblockhash, sizeof(uint256)); @@ -312,7 +320,7 @@ void dogecoin_net_spv_fill_block_locator(dogecoin_spv_client *client, vector *bl /** * This function is called when a node is in headers sync state. It will request the next block headers * from the node - * + * * @param node The node that is requesting headers or blocks. * @param blocks boolean, true if we want to request blocks, false if we want to request headers */ @@ -345,23 +353,49 @@ void dogecoin_net_spv_node_request_headers_or_blocks(dogecoin_node *node, dogeco /** * If we have not yet reached the height of the blockchain tip, we request headers from a peer. If we * have reached the height of the blockchain tip, we request blocks from a peer - * + * * @param client the spv client - * + * * @return dogecoin_bool */ dogecoin_bool dogecoin_net_spv_request_headers(dogecoin_spv_client *client) { size_t i; + dogecoin_bool new_headers_available = false; for(i = 0; i < client->nodegroup->nodes->len; ++i) { dogecoin_node *check_node = vector_idx(client->nodegroup->nodes, i); if (((check_node->state & NODE_HEADERSYNC) == NODE_HEADERSYNC || (check_node->state & NODE_BLOCKSYNC) == NODE_BLOCKSYNC) && (check_node->state & NODE_CONNECTED) == NODE_CONNECTED) { return true; } } - dogecoin_bool new_headers_available = false; + // If in header or block sync state, request headers or blocks from the node with the longest chain + if ((client->stateflags & SPV_HEADER_SYNC_FLAG) == SPV_HEADER_SYNC_FLAG || (client->stateflags & SPV_FULLBLOCK_SYNC_FLAG) == SPV_FULLBLOCK_SYNC_FLAG) + { + dogecoin_node *node_with_longest_chain = NULL; + unsigned int longest_chain_height = 0; + for(i = 0; i < client->nodegroup->nodes->len; ++i) + { + dogecoin_node *check_node = vector_idx(client->nodegroup->nodes, i); + if (((check_node->state & NODE_CONNECTED) == NODE_CONNECTED) && check_node->version_handshake) + { + if (check_node->bestknownheight > longest_chain_height) + { + longest_chain_height = check_node->bestknownheight; + node_with_longest_chain = check_node; + } + } + } + + // Request headers or blocks from the node with the longest chain + if (node_with_longest_chain != NULL) { + dogecoin_net_spv_node_request_headers_or_blocks(node_with_longest_chain, (client->stateflags & SPV_FULLBLOCK_SYNC_FLAG) == SPV_FULLBLOCK_SYNC_FLAG); + new_headers_available = true; + } + } + + // Fallback: original logic for handling cases where no suitable node was found unsigned int nodes_at_same_height = 0; - if (client->headers_db->getchaintip(client->headers_db_ctx)->header.timestamp < client->oldest_item_of_interest - (BLOCK_GAP_TO_DEDUCT_TO_START_SCAN_FROM * BLOCKS_DELTA_IN_S) && client->stateflags == SPV_HEADER_SYNC_FLAG) + if (!new_headers_available && client->headers_db->getchaintip(client->headers_db_ctx)->header.timestamp < client->oldest_item_of_interest - (BLOCK_GAP_TO_DEDUCT_TO_START_SCAN_FROM * BLOCKS_DELTA_IN_S) && client->stateflags == SPV_HEADER_SYNC_FLAG) { for(i = 0; i < client->nodegroup->nodes->len; i++) { @@ -371,26 +405,25 @@ dogecoin_bool dogecoin_net_spv_request_headers(dogecoin_spv_client *client) if (check_node->bestknownheight > client->headers_db->getchaintip(client->headers_db_ctx)->height) { dogecoin_net_spv_node_request_headers_or_blocks(check_node, false); new_headers_available = true; - return new_headers_available; + break; } else if (check_node->bestknownheight == client->headers_db->getchaintip(client->headers_db_ctx)->height) { nodes_at_same_height++; } } } } - if (!new_headers_available && dogecoin_node_group_amount_of_connected_nodes(client->nodegroup, NODE_CONNECTED) > 0) { + if (!new_headers_available && (dogecoin_node_group_amount_of_connected_nodes(client->nodegroup, NODE_CONNECTED) > 0) && client->stateflags == SPV_FULLBLOCK_SYNC_FLAG) { // try to fetch blocks if no new headers are available but connected nodes are reachable for(i = 0; i< client->nodegroup->nodes->len; i++) { dogecoin_node *check_node = vector_idx(client->nodegroup->nodes, i); if (((check_node->state & NODE_CONNECTED) == NODE_CONNECTED) && check_node->version_handshake) { - if (check_node->bestknownheight > client->headers_db->getchaintip(client->headers_db_ctx)->height) { - dogecoin_net_spv_node_request_headers_or_blocks(check_node, true); - return true; - } else if (check_node->bestknownheight == client->headers_db->getchaintip(client->headers_db_ctx)->height) { + if (check_node->bestknownheight == client->headers_db->getchaintip(client->headers_db_ctx)->height) { nodes_at_same_height++; } + dogecoin_net_spv_node_request_headers_or_blocks(check_node, true); + new_headers_available = true; } } } @@ -401,12 +434,12 @@ dogecoin_bool dogecoin_net_spv_request_headers(dogecoin_spv_client *client) client->called_sync_completed = true; } - return false; + return new_headers_available; } /** * When the handshake is done, we request the headers - * + * * @param node The node that just completed the handshake. */ void dogecoin_net_spv_node_handshake_done(dogecoin_node *node) @@ -416,11 +449,11 @@ void dogecoin_net_spv_node_handshake_done(dogecoin_node *node) /** * The function is called when a new message is received from a peer - * + * * @param node * @param hdr * @param buf - * + * * @return Nothing. */ void dogecoin_net_spv_post_cmd(dogecoin_node *node, dogecoin_p2p_msg_hdr *hdr, struct const_buffer *buf) @@ -470,28 +503,26 @@ void dogecoin_net_spv_post_cmd(dogecoin_node *node, dogecoin_p2p_msg_hdr *hdr, s dogecoin_bool connected; dogecoin_blockindex *pindex = client->headers_db->connect_hdr(client->headers_db_ctx, buf, false, &connected); - if (!pindex) { - return; - } - - uint32_t amount_of_txs; - if (!deser_varlen(&amount_of_txs, buf)) { - return; - } - // flag off the block request stall check node->time_last_request = time(NULL); - // for now, turn of stall checks if we are near the tip - if (pindex->header.timestamp > node->time_last_request - 30*60) { - node->time_last_request = 0; - } - if (connected) { if (client->header_connected) { client->header_connected(client); } + + // for now, turn of stall checks if we are near the tip + if (pindex->header.timestamp > node->time_last_request - 30*60) { + node->time_last_request = 0; + } + time_t lasttime = pindex->header.timestamp; printf("Downloaded new block with size %d at height %d from %s\n", hdr->data_len, pindex->height, ctime(&lasttime)); uint64_t start = time(NULL); + + uint32_t amount_of_txs; + if (!deser_varlen(&amount_of_txs, buf)) { + return; + } + client->nodegroup->log_write_cb("Start parsing %d transactions...\n", (int)amount_of_txs); size_t consumedlength = 0; @@ -501,6 +532,7 @@ void dogecoin_net_spv_post_cmd(dogecoin_node *node, dogecoin_p2p_msg_hdr *hdr, s dogecoin_tx* tx = dogecoin_tx_new(); if (!dogecoin_tx_deserialize(buf->p, buf->len, tx, &consumedlength)) { client->nodegroup->log_write_cb("Error deserializing transaction\n"); + dogecoin_tx_free(tx); } deser_skip(buf, consumedlength); if (client->sync_transaction) { client->sync_transaction(client->sync_transaction_ctx, tx, i, pindex); } @@ -508,6 +540,13 @@ void dogecoin_net_spv_post_cmd(dogecoin_node *node, dogecoin_p2p_msg_hdr *hdr, s } client->nodegroup->log_write_cb("done (took %llu secs)\n", (unsigned long long)(time(NULL) - start)); } + else + { + client->nodegroup->log_write_cb("Got invalid block (not in sequence) from node %d\n", node->nodeid); + node->state &= ~NODE_BLOCKSYNC; + dogecoin_node_send(node, dogecoin_p2p_message_new(node->nodegroup->chainparams->netmagic, DOGECOIN_MSG_REJECT, NULL, 0)); + return; + } if (dogecoin_hash_equal(node->last_requested_inv, pindex->hash)) { // last requested block reached, consider stop syncing @@ -534,19 +573,16 @@ void dogecoin_net_spv_post_cmd(dogecoin_node *node, dogecoin_p2p_msg_hdr *hdr, s if (!pindex) { client->nodegroup->log_write_cb("Header deserialization failed (node %d)\n", node->nodeid); - return; } if (!deser_skip(buf, 1)) { client->nodegroup->log_write_cb("Header deserialization (tx count skip) failed (node %d)\n", node->nodeid); - return; } - + if (!connected) { client->nodegroup->log_write_cb("Got invalid headers (not in sequence) from node %d\n", node->nodeid); node->state &= ~NODE_HEADERSYNC; - dogecoin_node_misbehave(node); - dogecoin_net_spv_request_headers(client); + break; } else { if (client->header_connected) { client->header_connected(client); } connected_headers++; diff --git a/src/transaction.c b/src/transaction.c index 225f7a4cb..2f11c7683 100644 --- a/src/transaction.c +++ b/src/transaction.c @@ -36,8 +36,8 @@ /** * @brief This function instantiates a new working transaction, * but does not add it to the hash table. - * - * @return A pointer to the new working transaction. + * + * @return A pointer to the new working transaction. */ working_transaction* new_transaction() { working_transaction* working_tx = (struct working_transaction*)dogecoin_calloc(1, sizeof *working_tx); @@ -49,9 +49,9 @@ working_transaction* new_transaction() { /** * @brief This function takes a pointer to an existing working * transaction object and adds it to the hash table. - * + * * @param working_tx The pointer to the working transaction. - * + * * @return Nothing. */ void add_transaction(working_transaction *working_tx) { @@ -68,9 +68,9 @@ void add_transaction(working_transaction *working_tx) { /** * @brief This function takes an index and returns the working * transaction associated with that index in the hash table. - * + * * @param idx The index of the target working transaction. - * + * * @return The pointer to the working transaction associated with * the provided index. */ @@ -83,9 +83,9 @@ working_transaction* find_transaction(int idx) { /** * @brief This function removes the specified working transaction * from the hash table and frees the transactions in memory. - * + * * @param working_tx The pointer to the transaction to remove. - * + * * @return Nothing. */ void remove_transaction(working_transaction *working_tx) { @@ -97,8 +97,8 @@ void remove_transaction(working_transaction *working_tx) { /** * @brief This function removes all working transactions from * the hash table. - * - * @return Nothing. + * + * @return Nothing. */ void remove_all() { struct working_transaction *current_tx; @@ -112,8 +112,8 @@ void remove_all() { /** * @brief This function prints the raw hex representation of * each working transaction in the hash table. - * - * @return Nothing. + * + * @return Nothing. */ void print_transactions() { @@ -127,8 +127,8 @@ void print_transactions() /** * @brief This function counts the number of working * transactions currently in the hash table. - * - * @return Nothing. + * + * @return Nothing. */ void count_transactions() { int temp = HASH_COUNT(transactions); @@ -139,12 +139,12 @@ void count_transactions() { * @brief This function takes two working transactions * and returns the difference of their indices to aid * in sorting transactions. - * + * * @param a The pointer to the first working transaction. * @param b The pointer to the second working transaction. - * + * * @return The integer difference between the indices of - * the two provided transactions. + * the two provided transactions. */ int by_id(const struct working_transaction *a, const struct working_transaction *b) { @@ -154,10 +154,10 @@ int by_id(const struct working_transaction *a, const struct working_transaction /** * @brief This function prints a prompt and parses the user's * response for a CLI tool. - * + * * @param prompt The prompt to display to the user. - * - * @return The string containing user input. + * + * @return The string containing user input. */ const char *getl(const char *prompt) { @@ -176,9 +176,9 @@ const char *getl(const char *prompt) /** * @brief This function prompts the user to enter a raw * transaction and parses it. - * + * * @param prompt_tx The prompt to display to the user. - * + * * @return The string containing user input. */ const char *get_raw_tx(const char *prompt_tx) @@ -198,9 +198,9 @@ const char *get_raw_tx(const char *prompt_tx) /** * @brief This function prompts the user to enter a private key * and parses it. - * + * * @param prompt_tx The prompt to display to the user. - * + * * @return The string containing user input. */ const char *get_private_key(const char *prompt_key) @@ -221,7 +221,7 @@ const char *get_private_key(const char *prompt_key) * @brief This function creates a new transaction, places it in * the hash table, and returns the index of the new transaction, * starting from 1 and incrementing each subsequent call. - * + * * @return The index of the new transaction. */ int start_transaction() { @@ -235,11 +235,11 @@ int start_transaction() { * @brief This function takes a transaction represented in raw * hex and serializes it into a transaction which is then saved * in the hashtable at the specified index. - * + * * @param txindex The index to save the transaction to. * @param hexadecimal_transaction The raw hex of the transaction to serialize and save. - * - * @return 1 if the transaction was saved successfully, 0 otherwise. + * + * @return 1 if the transaction was saved successfully, 0 otherwise. */ int save_raw_transaction(int txindex, const char* hexadecimal_transaction) { debug_print("raw_hexadecimal_transaction: %s\n", hexadecimal_transaction); @@ -273,12 +273,12 @@ int save_raw_transaction(int txindex, const char* hexadecimal_transaction) { /** * @brief This function takes a transaction represented in raw * hex and adds it as an input to the specified working transaction. - * + * * @param txindex The index of the transaction to add the input to. * @param hex_utxo_txid The raw transaction hex of the input transaction. * @param vout The output index of the input transaction containing spendable funds. - * - * @return 1 if the transaction input was added successfully, 0 otherwise. + * + * @return 1 if the transaction input was added successfully, 0 otherwise. */ int add_utxo(int txindex, char* hex_utxo_txid, int vout) { // find working transaction by index and pass to funciton local variable to manipulate: @@ -311,11 +311,11 @@ int add_utxo(int txindex, char* hex_utxo_txid, int vout) { * @brief This function constructs an output sending the specified * amount to the specified address and adds it to the transaction * with the specified index. - * + * * @param txindex The index of the transaction where the output will be added. * @param destinationaddress The address to send the funds to. * @param amount The amount of dogecoin to send. - * + * * @return 1 if the transaction input was added successfully, 0 otherwise. */ int add_output(int txindex, char* destinationaddress, char* amount) { @@ -337,13 +337,13 @@ int add_output(int txindex, char* destinationaddress, char* amount) { /** * @brief This function is for internal use and constructs an extra * output which returns the change back to the sender so that all of - * the funds from inputs are spent in the current transaction. - * + * the funds from inputs are spent in the current transaction. + * * @param txindex The transaction which needs the output for returning change. * @param public_key The address of the sender for returning the change. * @param subtractedfee The amount to set aside for the mining fee. * @param amount The remaining funds after outputs have been subtracted from the inputs. - * + * * @return 1 if the additional output was created successfully, 0 otherwise. */ static int make_change(int txindex, char* public_key, uint64_t subtractedfee, uint64_t amount) { @@ -366,13 +366,13 @@ static int make_change(int txindex, char* public_key, uint64_t subtractedfee, ui /** * @brief This function 'closes the inputs' by returning change to the recipient * after the total amount and desired fee is confirmed. - * + * * @param txindex The index of the working transaction to finalize. * @param destinationaddress The address where the funds are being sent. * @param subtractedfee The amount to set aside as a fee to the miner. * @param out_dogeamount_for_verification An echo of the total amount to send. * @param changeaddress The address of the sender to receive the change. - * + * * @return The hex of the finalized transaction. */ char* finalize_transaction(int txindex, char* destinationaddress, char* subtractedfee, char* out_dogeamount_for_verification, char* changeaddress) { @@ -424,9 +424,9 @@ char* finalize_transaction(int txindex, char* destinationaddress, char* subtract /** * @brief This function takes an index of a working transaction and returns * the hex representation of it. - * + * * @param txindex The index of the working transaction. - * + * * @return The hex representation of the transaction. */ char* get_raw_transaction(int txindex) { @@ -452,9 +452,9 @@ char* get_raw_transaction(int txindex) { /** * @brief This function removes the specified working transaction * from the hash table. - * + * * @param txindex The index of the working transaction to remove. - * + * * @return Nothing. */ void clear_transaction(int txindex) { @@ -467,13 +467,13 @@ void clear_transaction(int txindex) { /** * @brief This function signs the specified input of a working transaction, * according to the signing parameters specified. - * + * * @param inputindex The index of the current transaction input to sign. * @param incomingrawtx The hex representation of the transaction to sign. * @param scripthex The hex representation of the public key script. * @param sighashtype The type of signature hash to perform. * @param privkey The private key used to sign the transaction input. - * + * * @return 1 if the raw transaction was signed successfully, 0 otherwise. */ int sign_raw_transaction(int inputindex, char* incomingrawtx, char* scripthex, int sighashtype, char* privkey) { @@ -512,7 +512,7 @@ int sign_raw_transaction(int inputindex, char* incomingrawtx, char* scripthex, i return false; } - // initialize byte array with length equal to account for byte size + // initialize byte array with length equal to account for byte size uint8_t* script_data = dogecoin_uint8_vla(strlen(scripthex)); // convert hex string to byte array utils_hex_to_bin(scripthex, script_data, strlen(scripthex), &outlength); @@ -585,14 +585,14 @@ int sign_raw_transaction(int inputindex, char* incomingrawtx, char* scripthex, i /** * @brief This function is for internal use and saves the result of * sign_raw_transaction to a working transaction in the hash table. - * + * * @param txindex The index where the signed transaction will be saved. * @param inputindex The index of the current transaction input to sign. * @param incomingrawtx The hex representation of the transaction to sign. * @param scripthex The hex representation of the public key script. * @param sighashtype The type of signature hash to perform. * @param privkey The private key used to sign the transaction input. - * + * * @return 1 if the transaction was signed successfully, 0 otherwise. */ int sign_indexed_raw_transaction(int txindex, int inputindex, char* incomingrawtx, char* scripthex, int sighashtype, char* privkey) { @@ -611,11 +611,11 @@ int sign_indexed_raw_transaction(int txindex, int inputindex, char* incomingrawt /** * @brief This function signs all of the inputs in the specified working * transaction using the provided script pubkey and private key. - * + * * @param txindex The index of the working transaction to sign. * @param script_pubkey The hex representation of the public key script. * @param privkey The private key used to sign the transaction input. - * + * * @return 1 if the transaction was signed successfully, 0 otherwise. */ int sign_transaction(int txindex, char* script_pubkey, char* privkey) { @@ -651,11 +651,11 @@ int sign_transaction(int txindex, char* script_pubkey, char* privkey) { /** * @brief This function signs a specific vin index in the specified working * transaction using the provided private key and vin index. - * + * * @param txindex The index of the working transaction to sign. * @param vout_index The index of the unspent tx output we are spending. * @param privkey The private key used to sign the transaction input. - * + * * @return 1 if the transaction was signed successfully, 0 otherwise. */ int sign_transaction_w_privkey(int txindex, int vout_index, char* privkey) { @@ -679,10 +679,13 @@ int sign_transaction_w_privkey(int txindex, int vout_index, char* privkey) { // free byte array dogecoin_free(data_bin); if (!sign_indexed_raw_transaction(txindex, vout_index, raw_hexadecimal_transaction, script_pubkey, 1, privkey)) { + dogecoin_free(script_pubkey); + dogecoin_tx_free(txtmp); printf("error signing raw transaction: %s\n", __func__); return false; } save_raw_transaction(txindex, raw_hexadecimal_transaction); + dogecoin_free(script_pubkey); dogecoin_tx_free(txtmp); return true; } @@ -690,9 +693,9 @@ int sign_transaction_w_privkey(int txindex, int vout_index, char* privkey) { /** * @brief This function stores a raw transaction to the next available * working transaction in the hash table. - * + * * @param incomingrawtx The hex of the raw transaction - * + * * @return The index of the new working transaction if stored successfully, 0 otherwise. */ int store_raw_transaction(char* incomingrawtx) { diff --git a/src/tx.c b/src/tx.c index b49b02bcc..04974f234 100644 --- a/src/tx.c +++ b/src/tx.c @@ -99,6 +99,7 @@ dogecoin_tx_in* dogecoin_tx_in_new() tx_in = dogecoin_calloc(1, sizeof(*tx_in)); dogecoin_mem_zero(&tx_in->prevout, sizeof(tx_in->prevout)); tx_in->sequence = UINT32_MAX; + tx_in->prevout.n = UINT32_MAX; return tx_in; } @@ -227,6 +228,7 @@ int dogecoin_tx_out_pubkey_hash_to_p2pkh_address(dogecoin_tx_out* txout, char* p return false; } dogecoin_free(stripped_array); + dogecoin_tx_out_free(copy); return true; } diff --git a/src/wallet.c b/src/wallet.c index 3a089f9a6..6fd9dd1a3 100644 --- a/src/wallet.c +++ b/src/wallet.c @@ -227,6 +227,12 @@ dogecoin_utxo* dogecoin_wallet_utxo_new() { utxo->confirmations = 0; utxo->spendable = true; utxo->solvable = true; + utxo->account = NULL; + dogecoin_mem_zero(&utxo->script_pubkey, sizeof(utxo->script_pubkey)); + dogecoin_mem_zero(&utxo->amount, sizeof(utxo->amount)); + dogecoin_mem_zero(&utxo->address, sizeof(utxo->address)); + dogecoin_mem_zero(&utxo->txid, sizeof(utxo->txid)); + utxo->vout = 0; return utxo; } @@ -306,11 +312,11 @@ dogecoin_wallet* dogecoin_wallet_new(const dogecoin_chainparams *params) wallet->hdkeys_rbtree = 0; wallet->unspent = vector_new(1, NULL); wallet->unspent_rbtree = 0; - wallet->spends = vector_new(10, dogecoin_free); + wallet->spends = vector_new(10, (void (*)(void *)) dogecoin_wallet_utxo_free); wallet->spends_rbtree = 0; - wallet->vec_wtxes = vector_new(10, dogecoin_free); + wallet->vec_wtxes = vector_new(10, (void (*)(void *)) dogecoin_wallet_wtx_free); wallet->wtxes_rbtree = 0; - wallet->waddr_vector = vector_new(10, dogecoin_free); + wallet->waddr_vector = vector_new(10, (void (*)(void *)) dogecoin_wallet_addr_free); wallet->waddr_rbtree = 0; return wallet; } @@ -434,15 +440,18 @@ dogecoin_wallet* dogecoin_wallet_init(const dogecoin_chainparams* chain, const c // copy address into a new string, strtok modifies the string char* address_copy = strdup(address); char *ptr; - while((ptr = strtok_r(address_copy, delim, &address_copy))) + char* temp_address_copy = address_copy; + + while((ptr = strtok_r(temp_address_copy, delim, &temp_address_copy))) { waddr = dogecoin_wallet_addr_new(); if (!waddr->ignore) { if (!dogecoin_p2pkh_address_to_wallet_pubkeyhash(ptr, waddr, wallet)) { - return NULL; + dogecoin_wallet_addr_free(waddr); } } } + dogecoin_free(address_copy); } #ifdef USE_UNISTRING else if (wallet->waddr_vector->len == 0) { @@ -523,37 +532,44 @@ void dogecoin_wallet_free(dogecoin_wallet* wallet) if (wallet->dbfile) { fclose(wallet->dbfile); + wallet->dbfile = NULL; } - if (wallet->masterkey) - dogecoin_free(wallet->masterkey); + if (wallet->masterkey) { + dogecoin_hdnode_free(wallet->masterkey); + wallet->masterkey = NULL; + } + // Note: Ensure that vector_free does not free the individual elements if they are managed elsewhere if (wallet->spends) { - vector_free(wallet->spends, true); + vector_free(wallet->spends, true); // set to 'true' if vector owns the elements wallet->spends = NULL; } if (wallet->unspent) { - vector_free(wallet->unspent, true); + vector_free(wallet->unspent, true); // set to 'true' if vector owns the elements wallet->unspent = NULL; } - dogecoin_btree_tdestroy(wallet->hdkeys_rbtree, dogecoin_free); - dogecoin_btree_tdestroy(wallet->unspent_rbtree, dogecoin_free); - dogecoin_btree_tdestroy(wallet->spends_rbtree, dogecoin_free); - dogecoin_btree_tdestroy(wallet->wtxes_rbtree, dogecoin_free); - if (wallet->waddr_vector) { - vector_free(wallet->waddr_vector, true); + vector_free(wallet->waddr_vector, true); // set to 'true' if vector owns the elements wallet->waddr_vector = NULL; } if (wallet->vec_wtxes) { - vector_free(wallet->vec_wtxes, true); + vector_free(wallet->vec_wtxes, true); // set to 'true' if vector owns the elements wallet->vec_wtxes = NULL; } wallet->chain = NULL; + + // Destroy binary trees + dogecoin_btree_tdestroy(wallet->hdkeys_rbtree, NULL); + dogecoin_btree_tdestroy(wallet->unspent_rbtree, NULL); + dogecoin_btree_tdestroy(wallet->spends_rbtree, NULL); + dogecoin_btree_tdestroy(wallet->wtxes_rbtree, (void (*)(void *)) dogecoin_wallet_wtx_free); + dogecoin_btree_tdestroy(wallet->waddr_rbtree, NULL); + dogecoin_free(wallet); } @@ -574,9 +590,10 @@ void dogecoin_wallet_scrape_utxos(dogecoin_wallet* wallet, dogecoin_wtx* wtx) { // reverse the characters: utils_reverse_hex(prevout_hash, 64); // copy back to uint8_t: - uint8_t* prevout_hash_bytes = utils_hex_to_uint8(prevout_hash); + uint8_t prevout_hash_bytes[32] = {0}; + memcpy(&prevout_hash_bytes, utils_hex_to_uint8(prevout_hash), 32); // compare wtx->tx->vin->prevout.hash and prevout.n with utxo->txid and utxo->vout: - if (memcmp(prevout_hash_bytes, utxo->txid, 32)==0 && (int)tx_in->prevout.n == utxo->vout) { + if (memcmp(&prevout_hash_bytes, utxo->txid, 32)==0 && (int)tx_in->prevout.n == utxo->vout) { size_t m = 0, n = 0; for (; m < wallet->spends->len; m++) { dogecoin_utxo* spent_utxo = vector_idx(wallet->spends, m); @@ -662,9 +679,7 @@ void dogecoin_wallet_scrape_utxos(dogecoin_wallet* wallet, dogecoin_wtx* wtx) { } void dogecoin_wallet_add_wtx_intern_move(dogecoin_wallet *wallet, const dogecoin_wtx *wtx) { - //add to spends - dogecoin_wallet_add_to_spent(wallet, wtx); - + // check if wtx already exists dogecoin_wtx* checkwtx = dogecoin_btree_tfind(wtx, &wallet->wtxes_rbtree, dogecoin_wtx_compare); if (checkwtx) { // remove existing wtx @@ -696,8 +711,11 @@ dogecoin_bool dogecoin_wallet_create(dogecoin_wallet* wallet, const char* file_p return false; } - wallet->filename = file_path; - wallet->dbfile = fopen(file_path, "a+b"); + // open wallet file if not already open + if (!wallet->dbfile) { + wallet->filename = file_path; + wallet->dbfile = fopen(file_path, "a+b"); + } // write file-header-magic if (fwrite(file_hdr_magic, 4, 1, wallet->dbfile) != 1) return false; @@ -746,6 +764,7 @@ dogecoin_bool dogecoin_wallet_load_address(dogecoin_wallet* wallet) { return false; } dogecoin_wallet_addr_deserialize(waddr, wallet->chain, &cbuf); + dogecoin_free(buf); if (!waddr->ignore) { // add the node to the binary tree dogecoin_btree_tsearch(waddr, &wallet->waddr_rbtree, dogecoin_wallet_addr_compare); @@ -762,6 +781,7 @@ dogecoin_bool dogecoin_wallet_load_transaction(dogecoin_wallet* wallet, uint32_t if (fread(buf, reclen, 1, wallet->dbfile) != 1) return false; dogecoin_wtx *wtx = dogecoin_wallet_wtx_new(); if (!dogecoin_wallet_wtx_deserialize(wtx, &cbuf)) return false; + dogecoin_free(buf); dogecoin_wallet_scrape_utxos(wallet, wtx); dogecoin_wallet_add_wtx_intern_move(wallet, wtx); // hands memory management over to the binary tree return true; @@ -943,6 +963,7 @@ dogecoin_wallet_addr* dogecoin_wallet_next_addr(dogecoin_wallet* wallet) dogecoin_hdnode *hdnode = dogecoin_hdnode_copy(wallet->masterkey); dogecoin_hdnode_public_ckd(hdnode, wallet->next_childindex); dogecoin_hdnode_get_hash160(hdnode, waddr->pubkeyhash); + dogecoin_hdnode_free(hdnode); waddr->childindex = wallet->next_childindex; //add it to the binary tree @@ -982,10 +1003,15 @@ dogecoin_wallet_addr* dogecoin_wallet_next_bip44_addr(dogecoin_wallet* wallet) /* Derive the child private key at the index */ if (derive_bip44_extended_key(hdnode, &account, &index, change, NULL, false, keypath, bip44_key) == -1) { + dogecoin_hdnode_free(hdnode); + dogecoin_hdnode_free(bip44_key); + dogecoin_wallet_addr_free(waddr); return NULL; } dogecoin_hdnode_get_hash160(bip44_key, waddr->pubkeyhash); + dogecoin_hdnode_free(hdnode); + dogecoin_hdnode_free(bip44_key); waddr->childindex = wallet->next_childindex; //add it to the binary tree @@ -1272,29 +1298,6 @@ dogecoin_bool dogecoin_wallet_is_from_me(dogecoin_wallet *wallet, const dogecoin return (dogecoin_wallet_get_debit_tx(wallet, tx) > 0); } -void dogecoin_wallet_add_to_spent(dogecoin_wallet* wallet, const dogecoin_wtx* wtx) { - if (!wallet || !wtx) - return; - - if (dogecoin_tx_is_coinbase(wtx->tx)) - return; - - unsigned int i; - if (wtx->tx->vin) { - for (i = 0; i < wtx->tx->vin->len; i++) { - dogecoin_tx_in* tx_in = vector_idx(wtx->tx->vin, i); - - // form outpoint - dogecoin_tx_outpoint* outpoint = dogecoin_calloc(1, sizeof(dogecoin_tx_outpoint)); - memcpy_safe(outpoint, &tx_in->prevout, sizeof(dogecoin_tx_outpoint)); - - // add to binary tree - // memory is managed there (will free on tdestroy - dogecoin_btree_tfind(outpoint, &wallet->spends_rbtree, dogecoin_tx_outpoint_compare); - } - } -} - dogecoin_bool dogecoin_wallet_is_spent(dogecoin_wallet* wallet, uint256 hash, uint32_t n) { if (!wallet) @@ -1391,16 +1394,19 @@ int dogecoin_register_watch_address_with_node(char* address) { char delim[] = " "; // copy address into a new string, strtok modifies the string char* address_copy = strdup(address); + char* temp_address_copy = address_copy; char *ptr; - while((ptr = strtok_r(address_copy, delim, &address_copy))) + while((ptr = strtok_r(temp_address_copy, delim, &temp_address_copy))) { dogecoin_wallet* wallet = dogecoin_wallet_read(ptr); dogecoin_wallet_addr* waddr = dogecoin_wallet_addr_new(); if (!dogecoin_p2pkh_address_to_wallet_pubkeyhash(ptr, waddr, wallet)) { + dogecoin_wallet_addr_free(waddr); + dogecoin_free(address_copy); return false; } - dogecoin_wallet_free(wallet); } + dogecoin_free(address_copy); } else return false; return true; } @@ -1410,8 +1416,9 @@ int dogecoin_unregister_watch_address_with_node(char* address) { char delim[] = " "; // copy address into a new string, strtok modifies the string char* address_copy = strdup(address); + char* temp_address_copy = address_copy; char *ptr; - while((ptr = strtok_r(address_copy, delim, &address_copy))) + while((ptr = strtok_r(temp_address_copy, delim, &temp_address_copy))) { dogecoin_wallet* wallet = dogecoin_wallet_read(ptr); int found = 0, error = 0; @@ -1438,6 +1445,7 @@ int dogecoin_unregister_watch_address_with_node(char* address) { // serialize address prior to search: cstring* record = cstr_new_sz(256); dogecoin_wallet_addr_serialize(record, wallet->chain, waddr_check); + dogecoin_free(waddr_check); // rewind db to read again: rewind(wallet->dbfile); // check file-header-magic, version and genesis @@ -1487,7 +1495,6 @@ int dogecoin_unregister_watch_address_with_node(char* address) { fprintf(stderr, "Wallet file: xpub check failed, corrupt wallet detected.\n"); return false; } - wallet->masterkey = dogecoin_hdnode_new(); dogecoin_hdnode_deserialize(strbuf, wallet->chain, wallet->masterkey); if (wallet_new->masterkey==NULL) { // copy masterkey to new wallet: @@ -1511,8 +1518,11 @@ int dogecoin_unregister_watch_address_with_node(char* address) { const char* addr_match = find_needle(ptr, strlen(ptr), p2pkh_check, P2PKHLEN); if (!addr_match) { if (!dogecoin_p2pkh_address_to_wallet_pubkeyhash(p2pkh_check, waddr, wallet_new)) return false; + } else { + dogecoin_wallet_addr_free(waddr); } } + free(buf); } else if (rectype == WALLET_DB_REC_TYPE_TX) { unsigned char* buf = dogecoin_uchar_vla(reclen); struct const_buffer cbuf = {buf, reclen}; @@ -1540,11 +1550,11 @@ int dogecoin_unregister_watch_address_with_node(char* address) { fseek(wallet->dbfile, reclen, SEEK_CUR); } } - + cstr_free(record, true); dogecoin_wallet_flush(wallet); dogecoin_wallet_free(wallet); dogecoin_wallet_flush(wallet_new); - dogecoin_free(wallet_new); + dogecoin_wallet_free(wallet_new); if (found) { /* Attempt to rename file: */ #ifdef WIN32 @@ -1574,6 +1584,8 @@ int dogecoin_unregister_watch_address_with_node(char* address) { } #endif } + dogecoin_free(oldname); + dogecoin_free(newname); } } else return false; return true; @@ -1590,7 +1602,10 @@ int dogecoin_get_utxo_vector(char* address, vector* utxos) { vector_add(utxos, utxo); } } - } else return false; + } else { + dogecoin_wallet_free(wallet); + return false; + } dogecoin_wallet_free(wallet); return true; } @@ -1602,6 +1617,7 @@ unsigned int dogecoin_get_utxos_length(char* address) { vector* utxos = vector_new(1, free); if (!dogecoin_get_utxo_vector(address, utxos)) return false; utxos_total = utxos->len; + vector_free(utxos, true); dogecoin_wallet_free(wallet); return utxos_total; } @@ -1656,6 +1672,7 @@ char* dogecoin_get_utxo_txid_str(char* address, unsigned int index) { txid = utils_uint8_to_hex((const uint8_t*)utxo->txid, DOGECOIN_HASH_LENGTH); } } + vector_free(utxos, true); dogecoin_wallet_free(wallet); return txid; } @@ -1681,6 +1698,7 @@ int dogecoin_get_utxo_vout(char* address, unsigned int index) { vout = utxo->vout; } } + vector_free(utxos, true); dogecoin_wallet_free(wallet); return vout; } @@ -1698,6 +1716,7 @@ char* dogecoin_get_utxo_amount(char* address, unsigned int index) { strcpy(amount, utxo->amount); } } + vector_free(utxos, true); dogecoin_wallet_free(wallet); return amount; } @@ -1706,7 +1725,11 @@ uint64_t dogecoin_get_balance(char* address) { if (!address) return false; dogecoin_wallet* wallet = dogecoin_wallet_read(address); vector* utxos = vector_new(1, free); - if (!dogecoin_get_utxo_vector(address, utxos)) return false; + if (!dogecoin_get_utxo_vector(address, utxos)) { + dogecoin_wallet_free(wallet); + vector_free(utxos, true); + return false; + } uint64_t wallet_total_u64 = 0; if (utxos->len) { vector* addrs = vector_new(1, free); @@ -1717,6 +1740,7 @@ uint64_t dogecoin_get_balance(char* address) { wallet_total_u64 += coins_to_koinu_str(utxo->amount); } } + vector_free(utxos, true); dogecoin_wallet_free(wallet); return wallet_total_u64; } diff --git a/test/address_tests.c b/test/address_tests.c index 5a92a0afe..7c674a287 100644 --- a/test/address_tests.c +++ b/test/address_tests.c @@ -66,7 +66,7 @@ void test_address() /* test generation ability */ u_assert_int_eq(generateHDMasterPubKeypair(masterkey_main, NULL, false), true) u_assert_int_eq(generateHDMasterPubKeypair(NULL, NULL, false), true) - u_assert_int_eq(generateHDMasterPubKeypair(NULL, NULL, NULL), true) + u_assert_int_eq(generateHDMasterPubKeypair(NULL, NULL, true), true) u_assert_int_eq(generateHDMasterPubKeypair(masterkey_main, p2pkh_master_pubkey_main, false), true); u_assert_int_eq(generateHDMasterPubKeypair(masterkey_test, p2pkh_master_pubkey_test, true), true); diff --git a/test/bip44_tests.c b/test/bip44_tests.c index b6c5c54b3..47800b8af 100644 --- a/test/bip44_tests.c +++ b/test/bip44_tests.c @@ -55,8 +55,7 @@ void test_bip44() // Convert mnemonic to seed uint8_t* seed = malloc(MAX_SEED_SIZE); memset(seed, 0, MAX_SEED_SIZE); - const uint8_t* test_seed = malloc(MAX_SEED_SIZE); - test_seed = utils_hex_to_uint8("5eb00bbddcf069084889a8ab9155568165f5c453ccb85e70811aaed6f6da5fc19a5ac40b389cd370d086206dec8aa6c43daea6690f20ad3d8d48b2d2ce9e38e4"); + uint8_t* test_seed = utils_hex_to_uint8("5eb00bbddcf069084889a8ab9155568165f5c453ccb85e70811aaed6f6da5fc19a5ac40b389cd370d086206dec8aa6c43daea6690f20ad3d8d48b2d2ce9e38e4"); dogecoin_seed_from_mnemonic (words, "", seed); u_assert_mem_eq(seed, test_seed, MAX_SEED_SIZE); diff --git a/test/block_tests.c b/test/block_tests.c index fe30ed2b6..436d68f93 100644 --- a/test/block_tests.c +++ b/test/block_tests.c @@ -23,7 +23,7 @@ struct blockheadertest { char hexheader[160]; char hexhash[64]; - uint32_t version; + int32_t version; uint32_t timestamp; uint32_t bits; uint32_t nonce; @@ -67,7 +67,7 @@ void test_block_header() // Check the serialized form matches dogecoin_block_header_serialize(serialized, header); utils_bin_to_hex((unsigned char*) serialized->str, serialized->len, hexbuf); - + assert(memcmp(hexbuf, test->hexheader, 160) == 0); // Check the block hash diff --git a/test/hash_tests.c b/test/hash_tests.c index 9ce5387a0..66c0e1c6b 100644 --- a/test/hash_tests.c +++ b/test/hash_tests.c @@ -120,8 +120,6 @@ void test_hash() dogecoin_free(hasher); dogecoin_free(hasher2); dogecoin_free(hasher3); - dogecoin_free(hw->ctx); - dogecoin_free(hw->hash); - dogecoin_free(hw); + dogecoin_hashwriter_free(hw); dogecoin_tx_free(tx); } diff --git a/test/wallet_tests.c b/test/wallet_tests.c index 95751ab6f..119ed96d8 100644 --- a/test/wallet_tests.c +++ b/test/wallet_tests.c @@ -165,6 +165,7 @@ void test_wallet() utils_hex_to_bin("e195b669de8e49f955749033fa2d79390732c435", waddr->pubkeyhash, 40, &outlen); dogecoin_btree_tsearch(waddr, &wallet->waddr_rbtree, dogecoin_wallet_addr_compare); + vector_add(wallet->waddr_vector, waddr); int64_t totalin = 0; unsigned int i; @@ -175,6 +176,7 @@ void test_wallet() dogecoin_wtx* wtx = dogecoin_wallet_wtx_new(); dogecoin_tx_deserialize(tx_data, outlen, wtx->tx, NULL); + dogecoin_free(tx_data); dogecoin_wallet_add_wtx_move(wallet, wtx); totalin += dogecoin_wallet_wtx_get_credit(wallet, wtx); @@ -183,6 +185,9 @@ void test_wallet() int64_t amount = dogecoin_wallet_get_balance(wallet); u_assert_uint32_eq(amount, 669388541); u_assert_uint32_eq(totalin, 669388541); + + dogecoin_wallet_flush(wallet); + dogecoin_wallet_free(wallet); } void test_wallet_basics() @@ -242,6 +247,7 @@ void test_wallet_basics() u_assert_str_eq(addrs->data[0],"DHprgyNMcy3Ct9zVbJCrezYywxTBDWPL3v"); u_assert_str_eq(addrs->data[1],"DMTbb3NbwAdimWDMVabwip7FjPAVx6Qeq4"); u_assert_str_eq(addrs->data[2],"DMTbb3NbwAdimWDMVabwip7FjPAVx6Qeq4"); // we have forced to regenerate this key + vector_free(addrs, true); dogecoin_wallet_flush(wallet); dogecoin_wallet_free(wallet);