From bbaf8ed1ebb7bb5cd40c600901a69abfbff1725a 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 headersdb_file: updated dogecoin_headers_db_free to free chaintip to chainbottom headersdb_file: updated dogecoin_headers_db_connect_hdr to free blockindex headersdb_file: updated dogecoin_headers_db_connect_hdr with todo 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 continue after full block sync spv: updated dogecoin_net_spv_request_headers to recover after invalid headers and blocks 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 already 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 --- include/dogecoin/hash.h | 6 ++ include/dogecoin/wallet.h | 1 - src/auxpow.c | 6 +- src/block.c | 20 ++++-- src/headersdb_file.c | 42 ++++++++++--- src/spv.c | 124 +++++++++++++++++++++----------------- src/transaction.c | 109 +++++++++++++++++---------------- src/tx.c | 1 + src/wallet.c | 82 ++++++++++++------------- test/bip44_tests.c | 3 +- test/hash_tests.c | 4 +- test/wallet_tests.c | 6 ++ 12 files changed, 231 insertions(+), 173 deletions(-) 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..14f784654 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; @@ -256,7 +264,7 @@ void print_transaction(dogecoin_tx* x) { } void print_block_header(dogecoin_block_header* header) { - printf("block->header->version: %i\n", header->version); + printf("block->header->version: %u\n", header->version); printf("block->header->prev_block: %s\n", hash_to_string(header->prev_block)); printf("block->header->merkle_root: %s\n", hash_to_string(header->merkle_root)); printf("block->header->timestamp: %u\n", header->timestamp); @@ -300,6 +308,7 @@ 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. */ @@ -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; } @@ -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..cf94167e5 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; + if (scan_tip) { + dogecoin_free(scan_tip); + } + scan_tip = prev; + } + } + + // Free the chainbottom + if (db->chainbottom) { + dogecoin_free(db->chainbottom); + } + + db->chaintip = NULL; + db->chainbottom = NULL; + dogecoin_free(db); } @@ -261,7 +281,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 +338,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 +366,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..280f70522 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,10 @@ 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); + node->state &= ~NODE_BLOCKSYNC; dogecoin_node_disconnect(node); node->time_last_request = 0; dogecoin_net_spv_request_headers(client); @@ -242,21 +246,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 +282,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 +307,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 +321,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,9 +354,9 @@ 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) @@ -375,6 +384,8 @@ dogecoin_bool dogecoin_net_spv_request_headers(dogecoin_spv_client *client) } else 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, false); + new_headers_available = true; } } } @@ -385,12 +396,12 @@ dogecoin_bool dogecoin_net_spv_request_headers(dogecoin_spv_client *client) 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; + return true; } } } @@ -401,12 +412,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 +427,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 +481,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; @@ -508,6 +517,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_ERRORED; + dogecoin_node_group_connect_next_nodes(client->nodegroup); + return; + } if (dogecoin_hash_equal(node->last_requested_inv, pindex->hash)) { // last requested block reached, consider stop syncing @@ -534,19 +550,17 @@ 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); + node->state |= NODE_ERRORED; + dogecoin_node_group_connect_next_nodes(client->nodegroup); + 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..54b4a01b4 100644 --- a/src/tx.c +++ b/src/tx.c @@ -227,6 +227,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..fc0636b01 100644 --- a/src/wallet.c +++ b/src/wallet.c @@ -306,11 +306,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; } @@ -523,37 +523,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); } @@ -662,9 +669,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 +701,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 +754,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 +771,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 +953,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 +993,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 +1288,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) @@ -1602,6 +1595,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 +1650,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 +1676,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 +1694,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; } @@ -1717,6 +1714,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/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/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);