diff --git a/iguana/exchanges/LP_socket.c b/iguana/exchanges/LP_socket.c index 59fe58497..42e3c3ba2 100644 --- a/iguana/exchanges/LP_socket.c +++ b/iguana/exchanges/LP_socket.c @@ -1229,9 +1229,57 @@ int history_item_cmp(struct LP_tx_history_item *item1, struct LP_tx_history_item return(item1->time < item2->time); } +void LP_electrum_get_tx_until_success(struct iguana_info *coin, char *tx_hash, cJSON **res) { + cJSON *params = cJSON_CreateArray(); + jaddistr(params, tx_hash); + jaddi(params, cJSON_CreateBool(cJSON_True)); + while(1) { + electrum_jsonarg(coin->symbol, coin->electrum, res, "blockchain.transaction.get", params, + ELECTRUM_TIMEOUT); + if (jobj(*res, "error") != NULL) { + printf("Error getting electrum tx %s %s %s\n", coin->symbol, jstri(params, 0), jprint(*res, 1)); + *res = cJSON_CreateObject(); + sleep(5); + continue; + } else { + break; + } + } + free_json(params); +} + +char *LP_get_address_from_tx_out(cJSON *tx_out) { + cJSON *script_pub_key = jobj(tx_out, "scriptPubKey"); + if (script_pub_key == 0) { + printf("No scriptPubKey on tx_out: %s\n", jprint(tx_out, 0)); + return 0; + } + + struct cJSON *addresses = jobj(script_pub_key, "addresses"); + if (addresses == 0) { + printf("No addresses on tx_out: %s\n", jprint(tx_out, 0)); + return NULL; + } + + if (!is_cJSON_Array(addresses)) { + printf("Addresses are not array on tx out: %s\n", jprint(tx_out, 0)); + return NULL; + } + + if (cJSON_GetArraySize(addresses) > 1) { + printf("Addresses array size is > 1 on tx out: %s\n", jprint(tx_out, 0)); + return NULL; + } + return jstri(addresses, 0); +} + void LP_electrum_txhistory_loop(void *_coin) { struct iguana_info *coin = _coin; + if (strcmp(coin->symbol, "QTUM") == 0 || strcmp(coin->symbol, "CRW") == 0 || strcmp(coin->symbol, "BTX") == 0) { + printf("Tx history loop doesn't support QTUM, CRW and BTX! yet\n"); + return; + } while (coin != NULL && coin->electrum != NULL && coin->inactive == 0) { cJSON *history = cJSON_CreateObject(); if (strcmp(coin->symbol, "BCH") == 0) { @@ -1242,7 +1290,7 @@ void LP_electrum_txhistory_loop(void *_coin) ELECTRUM_TIMEOUT); } if (jobj(history, "error") != NULL) { - printf("Error getting electrum history %s\n", jprint(history, 1)); + printf("Error getting electrum history of coin %s %s\n", coin->symbol, jprint(history, 1)); sleep(10); continue; } @@ -1251,6 +1299,7 @@ void LP_electrum_txhistory_loop(void *_coin) cJSON *history_item = jitem(history, i); cJSON *tx_item = cJSON_CreateObject(); char *tx_hash = jstr(history_item, "tx_hash"); + LP_electrum_get_tx_until_success(coin, tx_hash, &tx_item); struct LP_tx_history_item *iter; int found = 0; int confirmed = 0; @@ -1277,42 +1326,47 @@ void LP_electrum_txhistory_loop(void *_coin) continue; } - cJSON *params = cJSON_CreateArray(); - jaddistr(params, tx_hash); - jaddi(params, cJSON_CreateBool(cJSON_True)); - while(1) { - electrum_jsonarg(coin->symbol, coin->electrum, &tx_item, "blockchain.transaction.get", params, - ELECTRUM_TIMEOUT); - if (jobj(tx_item, "error") != NULL) { - printf("Error getting electrum tx %s %s\n", jstri(params, 0), jprint(tx_item, 1)); - tx_item = cJSON_CreateObject(); - sleep(5); - continue; - } else { - break; - } - } - free_json(params); if (!found) { strcpy(item->txid, jstr(tx_item, "txid")); // receive by default, but if at least 1 vin contains our address the category is send strcpy(item->category, "receive"); cJSON *vin = jobj(tx_item, "vin"); + cJSON *prev_tx_item = NULL; for (int j = 0; j < cJSON_GetArraySize(vin); j++) { cJSON *vin_item = jitem(vin, j); - if (strcmp(coin->smartaddr, jstr(vin_item, "address")) == 0) { - strcpy(item->category, "send"); - break; + char *address = jstr(vin_item, "address"); + if (address != NULL) { + if (strcmp(coin->smartaddr, jstr(vin_item, "address")) == 0) { + strcpy(item->category, "send"); + break; + } + } else { + // At least BTC and LTC doesn't have an address field for Vins. + // Need to get previous tx and check the output + cJSON *params = cJSON_CreateArray(); + // some transactions use few vouts of one prev tx so we can reuse it + if (prev_tx_item == 0 || strcmp(jstr(prev_tx_item, "txid"), jstr(vin_item, "txid")) != 0) { + if (prev_tx_item != 0) { + free_json(prev_tx_item); + prev_tx_item = NULL; + } + LP_electrum_get_tx_until_success(coin, jstr(vin_item, "txid"), &prev_tx_item); + } + char *vout_address = LP_get_address_from_tx_out(jitem(jobj(prev_tx_item, "vout"), jint(vin_item, "vout"))); + if (strcmp(coin->smartaddr, vout_address) == 0) { + strcpy(item->category, "send"); + break; + } + free_json(params); } } int size = 0; cJSON *vout = jarray(&size, tx_item, "vout"); for (int k = 0; k < size; k++) { cJSON *vout_item = jitem(vout, k); - int addresses_size = 0; - cJSON *addresses = jarray(&addresses_size, jobj(vout_item, "scriptPubKey"), "addresses"); - for (int z = 0; z < addresses_size; z++) { - if (strcmp(coin->smartaddr, jstri(addresses, z)) == 0) { + char *vout_address = LP_get_address_from_tx_out(vout_item); + if (vout_address != 0) { + if (strcmp(coin->smartaddr, vout_address) == 0) { if (strcmp(item->category, "receive") == 0) { item->amount += jdouble(vout_item, "value"); } @@ -1327,7 +1381,7 @@ void LP_electrum_txhistory_loop(void *_coin) if (juint(history_item, "height") > 0) { item->time = juint(tx_item, "time"); strcpy(item->blockhash, jstr(tx_item, "blockhash")); - item->blockindex = juint(tx_item, "height"); + item->blockindex = juint(history_item, "height"); item->blocktime = juint(tx_item, "blocktime"); } else { // set current time temporary until confirmed