Skip to content

Commit

Permalink
wallet: use strtok_r instead of strtok for thread safety
Browse files Browse the repository at this point in the history
-adds find_needle function to utils
-move print statements from dogecoin_wallet_init to print_utxos function
-use dogecoin_wallet_init instead of dogecoin_wallet_load in dogecoin_wallet_read
-add multi address support to dogecoin_register_watch_address_with_node
  • Loading branch information
xanimo committed Jul 10, 2023
1 parent b632371 commit 9bcfdec
Show file tree
Hide file tree
Showing 5 changed files with 88 additions and 63 deletions.
1 change: 1 addition & 0 deletions include/dogecoin/utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ LIBDOGECOIN_API void utils_uint256_sethex(char* psz, uint8_t* out);
LIBDOGECOIN_API uint256* uint256S(const char *str);
LIBDOGECOIN_API unsigned char* parse_hex(const char* psz);
LIBDOGECOIN_API void swap_bytes(uint8_t *buf, int buf_size);
LIBDOGECOIN_API const char *find_needle(const char *haystack, size_t haystack_length, const char *needle, size_t needle_length);
LIBDOGECOIN_API void* safe_malloc(size_t size);
LIBDOGECOIN_API void dogecoin_cheap_random_bytes(uint8_t* buf, size_t len);
LIBDOGECOIN_API void dogecoin_get_default_datadir(cstring* path_out);
Expand Down
1 change: 1 addition & 0 deletions include/dogecoin/wallet.h
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,7 @@ LIBDOGECOIN_API void dogecoin_wallet_output_free(dogecoin_output* output);

LIBDOGECOIN_API dogecoin_wallet* dogecoin_wallet_new(const dogecoin_chainparams *params);
LIBDOGECOIN_API dogecoin_wallet* dogecoin_wallet_init(const dogecoin_chainparams* chain, const char* address, const char* mnemonic_in, const char* name);
LIBDOGECOIN_API void print_utxos(dogecoin_wallet* wallet);
LIBDOGECOIN_API void dogecoin_wallet_free(dogecoin_wallet* wallet);

/** load the wallet, sets masterkey, sets next_childindex */
Expand Down
39 changes: 15 additions & 24 deletions src/cli/spvnode.c
Original file line number Diff line number Diff line change
Expand Up @@ -327,6 +327,7 @@ int main(int argc, char* argv[]) {

#if WITH_WALLET
dogecoin_wallet* wallet = dogecoin_wallet_init(chain, address, mnemonic_in, name);
print_utxos(wallet);
client->sync_transaction = dogecoin_wallet_check_transaction;
client->sync_transaction_ctx = wallet;
#endif
Expand Down Expand Up @@ -408,34 +409,24 @@ int main(int argc, char* argv[]) {
} else if (strcmp(data, "wallet") == 0) {
#if WITH_WALLET
dogecoin_ecc_start();
dogecoin_wallet_addr* waddr;
if (address != NULL) {
char delim[] = " ";
// copy address into a new string, strtok modifies the string
char* address_copy = strdup(address);
char *ptr = strtok(address_copy, delim);
while(ptr != NULL)
{
int res = dogecoin_register_watch_address_with_node(ptr);
printf("registered: %d %s\n", res, ptr);
uint64_t amount = dogecoin_get_balance(ptr);
if (amount > 0) {
printf("amount: %s\n", dogecoin_get_balance_str(ptr));
unsigned int utxo_count = dogecoin_get_utxos_length(ptr);
if (utxo_count) {
printf("utxo count: %d\n", utxo_count);
unsigned int i = 1;
for (; i <= utxo_count; i++) {
printf("txid: %s\n", dogecoin_get_utxo_txid_str(ptr, i));
printf("vout: %d\n", dogecoin_get_utxo_vout(ptr, i));
printf("amount: %s\n", dogecoin_get_utxo_amount(ptr, i));
}
int res = dogecoin_register_watch_address_with_node(address);
printf("registered: %d %s\n", res, address);
uint64_t amount = dogecoin_get_balance(address);
if (amount > 0) {
printf("amount: %s\n", dogecoin_get_balance_str(address));
unsigned int utxo_count = dogecoin_get_utxos_length(address);
if (utxo_count) {
printf("utxo count: %d\n", utxo_count);
unsigned int i = 1;
for (; i <= utxo_count; i++) {
printf("txid: %s\n", dogecoin_get_utxo_txid_str(address, i));
printf("vout: %d\n", dogecoin_get_utxo_vout(address, i));
printf("amount: %s\n", dogecoin_get_utxo_amount(address, i));
}
}
ptr = strtok(NULL, delim);
}

int res = dogecoin_unregister_watch_address_with_node(address);
res = dogecoin_unregister_watch_address_with_node(address);
printf("unregistered: %s\n", res ? "true" : "false");
}
dogecoin_ecc_stop();
Expand Down
25 changes: 25 additions & 0 deletions src/utils.c
Original file line number Diff line number Diff line change
Expand Up @@ -369,6 +369,31 @@ void swap_bytes(uint8_t *buf, int buf_size) {
}
}

const char *find_needle(const char *haystack, size_t haystack_length, const char *needle, size_t needle_length) {
size_t haystack_index = 0;
for (; haystack_index < haystack_length; haystack_index++) {

bool needle_found = true;
size_t needle_index = 0;
for (; needle_index < needle_length; needle_index++) {
const auto haystack_character = haystack[haystack_index + needle_index];
const auto needle_character = needle[needle_index];
if (haystack_character == needle_character) {
continue;
} else {
needle_found = false;
break;
}
}

if (needle_found) {
return &haystack[haystack_index];
}
}

return NULL;
}

/**
* @brief This function executes malloc() but exits the
* program if unsuccessful.
Expand Down
85 changes: 46 additions & 39 deletions src/wallet.c
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
#include <stddef.h>
#include <stdint.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
Expand Down Expand Up @@ -407,7 +408,10 @@ dogecoin_wallet* dogecoin_wallet_init(const dogecoin_chainparams* chain, const c
waddr = dogecoin_wallet_next_addr(wallet);
}
#endif
return wallet;
}

void print_utxos(dogecoin_wallet* wallet) {
/* Creating a vector of addresses and storing them in the wallet. */
vector* addrs = vector_new(1, free);
dogecoin_wallet_get_addresses(wallet, addrs);
Expand Down Expand Up @@ -460,7 +464,6 @@ dogecoin_wallet* dogecoin_wallet_init(const dogecoin_chainparams* chain, const c
printf("Unspent Balance: %s\n", wallet_total);
}
vector_free(unspent, true);
return wallet;
}

void dogecoin_wallet_free(dogecoin_wallet* wallet)
Expand Down Expand Up @@ -1255,31 +1258,33 @@ void dogecoin_wallet_check_transaction(void *ctx, dogecoin_tx *tx, unsigned int

dogecoin_wallet* dogecoin_wallet_read(char* address) {
dogecoin_chainparams* chain = (dogecoin_chainparams*)chain_from_b58_prefix(address);
int error;
dogecoin_bool created;
// prefix chain to wallet file name:
char* wallet_suffix = "_wallet.db";
char* wallet_prefix = (char*)chain->chainname;
char* walletfile = concat(wallet_prefix, wallet_suffix);
dogecoin_wallet* wallet = dogecoin_wallet_new(chain);
dogecoin_wallet* wallet = dogecoin_wallet_init(chain, address, 0, walletfile);
wallet->filename = concat(wallet_prefix, wallet_suffix);
dogecoin_bool res = dogecoin_wallet_load(wallet, walletfile, &error, &created);
dogecoin_free(walletfile);
if (!res) {
printf("Loading wallet failed: %d\n", error);
exit(EXIT_FAILURE);
}
return wallet;
}

int dogecoin_register_watch_address_with_node(char* address) {
if (!address) return false;
dogecoin_wallet* wallet = dogecoin_wallet_read(address);
dogecoin_wallet_addr* waddr = dogecoin_wallet_addr_new();
if (!dogecoin_p2pkh_address_to_wallet_pubkeyhash(address, waddr, wallet)) {
return false;
}
dogecoin_wallet_free(wallet);
if (address != NULL) {
printf("address: %s\n", address);
char delim[] = " ";
// 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)))
{
dogecoin_wallet* wallet = dogecoin_wallet_read(address);
dogecoin_wallet_addr* waddr = dogecoin_wallet_addr_new();
if (!dogecoin_p2pkh_address_to_wallet_pubkeyhash(address, waddr, wallet)) {
return false;
}
dogecoin_wallet_free(wallet);
}
} else return false;
return true;
}

Expand All @@ -1288,30 +1293,30 @@ 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 *ptr = strtok(address_copy, delim);

while(ptr != NULL)
{
char *ptr;
while((ptr = strtok_r(address_copy, delim, &address_copy)))
{
dogecoin_wallet* wallet = dogecoin_wallet_read(ptr);

char* wallet_suffix = "_wallet.db";
char* wallet_prefix = (char*)wallet->chain->chainname;
char* walletfile = concat(wallet_prefix, wallet_suffix);
unsigned int i = 0;
char* addresses = dogecoin_char_vla(strlen(address));
dogecoin_mem_zero(addresses, strlen(address));
for (; i < wallet->waddr_vector->len; i++) {
char* address_inner = vector_idx(wallet->waddr_vector, i);
for (; i <= wallet->waddr_vector->len; i++) {
dogecoin_wallet_addr* waddr_to_del = vector_idx(wallet->waddr_vector, i);
char p2pkh_tmp[35];
dogecoin_p2pkh_addr_from_hash160((const uint8_t*)address_inner, wallet->chain, p2pkh_tmp, 35);
if (strcmp(ptr, p2pkh_tmp)==0) {
dogecoin_p2pkh_addr_from_hash160(waddr_to_del->pubkeyhash, wallet->chain, p2pkh_tmp, 35);
const char* match = find_needle(address, strlen(address), p2pkh_tmp, strlen(p2pkh_tmp));
if (match != NULL) {
dogecoin_wallet_addr* waddr_del = vector_idx(wallet->waddr_vector, i);
dogecoin_btree_tdelete(waddr_del, &wallet->waddr_rbtree, dogecoin_wallet_addr_compare);
vector_remove_idx(wallet->waddr_vector, i);
} else {
addresses = concat(addresses, p2pkh_tmp);
addresses = concat(addresses, delim);
}
}
int found = 0;
// set up new wallet to store everything except our soon to be unregistered watch address:
dogecoin_wallet* wallet_new = dogecoin_wallet_init(wallet->chain, addresses, 0, "temp.bin");
dogecoin_wallet* wallet_new = dogecoin_wallet_init(wallet->chain, address, 0, "temp.bin");
dogecoin_free(addresses);
wallet_new->filename = "temp.bin";
dogecoin_wallet_addr* waddr_check = dogecoin_wallet_addr_new();
Expand Down Expand Up @@ -1390,12 +1395,15 @@ int dogecoin_unregister_watch_address_with_node(char* address) {
} else {
dogecoin_wallet_addr_deserialize(waddr, wallet_new->chain, &cbuf);
char p2pkh[35];
dogecoin_p2pkh_addr_from_hash160(waddr_check->pubkeyhash, wallet->chain, p2pkh, 35);
if (!dogecoin_p2pkh_address_to_wallet_pubkeyhash(p2pkh, waddr_check, wallet_new)) return false;
// add the node to the binary tree
dogecoin_btree_tsearch(waddr, &wallet_new->waddr_rbtree, dogecoin_wallet_addr_compare);
vector_add(wallet_new->waddr_vector, waddr);
wallet_new->next_childindex = waddr->childindex+1;
dogecoin_p2pkh_addr_from_hash160(waddr->pubkeyhash, wallet->chain, p2pkh, 35);
const char* addr_match = find_needle(address, strlen(address), p2pkh, 35);
if (!addr_match) {
if (!dogecoin_p2pkh_address_to_wallet_pubkeyhash(p2pkh, waddr, wallet_new)) return false;
// add the node to the binary tree
dogecoin_btree_tsearch(waddr, &wallet_new->waddr_rbtree, dogecoin_wallet_addr_compare);
vector_add(wallet_new->waddr_vector, waddr);
wallet_new->next_childindex = waddr->childindex+1;
}
}
} else if (rectype == WALLET_DB_REC_TYPE_TX) {
unsigned char* buf = dogecoin_uchar_vla(reclen);
Expand Down Expand Up @@ -1431,9 +1439,8 @@ int dogecoin_unregister_watch_address_with_node(char* address) {
rename("temp.bin", wallet->filename);
} else remove("temp.bin");
dogecoin_wallet_flush(wallet);
dogecoin_wallet_free(wallet);
dogecoin_wallet_free(wallet_new);
ptr = strtok(NULL, delim);
dogecoin_free(wallet);
dogecoin_free(wallet_new);
}
} else return false;
return true;
Expand Down

0 comments on commit 9bcfdec

Please sign in to comment.