Skip to content

Commit

Permalink
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
hash: added dogecoin_hashwriter_free
Browse files Browse the repository at this point in the history
auxpow: updated check_merkle_branch iterator to size_t and hash parameters
block: updated dogecoin_block_header_free to clear version and removed debug print
headersdb_file: updated dogecoin_headers_db_free to free chaintip to chainbottom
headersdb_file: updated dogecoin_headers_db_connect_hdr to free blockindex
spv: updated dogecoin_spv_client_free to check for headers_db_ctx and dogecoin_net_spv_post_cmd to recover after invalid blocks
spv: updated dogecoin_net_spv_periodic_statecheck to continue after full block sync
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 unspent and spends vector/rbtrees
wallet: updated dogecoin_wallet_new frees and dogecoin_wallet_free to call dogecoin_hdnode_free and dogecoin_btree_tdestroy with NULL/free
wallet: updated dogecoin_wallet_create to check for open wallet file
edtubbs committed Dec 1, 2023
1 parent 93d8f3b commit 06a6a2a
Showing 12 changed files with 196 additions and 160 deletions.
6 changes: 6 additions & 0 deletions include/dogecoin/hash.h
Original file line number Diff line number Diff line change
@@ -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 {
1 change: 0 additions & 1 deletion include/dogecoin/wallet.h
Original file line number Diff line number Diff line change
@@ -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);
6 changes: 3 additions & 3 deletions src/auxpow.c
Original file line number Diff line number Diff line change
@@ -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
7 changes: 3 additions & 4 deletions src/block.c
Original file line number Diff line number Diff line change
@@ -173,10 +173,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 +194,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;
@@ -419,7 +419,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;
}

32 changes: 24 additions & 8 deletions src/headersdb_file.c
Original file line number Diff line number Diff line change
@@ -121,6 +121,19 @@ void dogecoin_headers_db_free(dogecoin_headers_db* db) {
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;
}
}

db->chaintip = NULL;
db->chainbottom = NULL;

dogecoin_free(db);
}

@@ -261,7 +274,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);

@@ -340,14 +358,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;
}

/**
99 changes: 55 additions & 44 deletions src/spv.c
Original file line number Diff line number Diff line change
@@ -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.
*/
@@ -242,21 +245,25 @@ 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 +280,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 +305,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 +319,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 +352,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)
@@ -406,7 +413,7 @@ dogecoin_bool dogecoin_net_spv_request_headers(dogecoin_spv_client *client)

/**
* 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 +423,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 +477,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 +513,12 @@ 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);
dogecoin_net_spv_request_headers(client);
return;
}

if (dogecoin_hash_equal(node->last_requested_inv, pindex->hash)) {
// last requested block reached, consider stop syncing
@@ -540,7 +551,7 @@ void dogecoin_net_spv_post_cmd(dogecoin_node *node, dogecoin_p2p_msg_hdr *hdr, s
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);
109 changes: 56 additions & 53 deletions src/transaction.c
Original file line number Diff line number Diff line change
@@ -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,20 +679,23 @@ 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;
}

/**
* @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) {
1 change: 1 addition & 0 deletions src/tx.c
Original file line number Diff line number Diff line change
@@ -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;
}

82 changes: 40 additions & 42 deletions src/wallet.c
Original file line number Diff line number Diff line change
@@ -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;
}
3 changes: 1 addition & 2 deletions test/bip44_tests.c
Original file line number Diff line number Diff line change
@@ -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);

4 changes: 1 addition & 3 deletions test/hash_tests.c
Original file line number Diff line number Diff line change
@@ -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);
}
6 changes: 6 additions & 0 deletions test/wallet_tests.c
Original file line number Diff line number Diff line change
@@ -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);

0 comments on commit 06a6a2a

Please sign in to comment.