diff --git a/proxy_docker/app/script/blockchainrpc.sh b/proxy_docker/app/script/blockchainrpc.sh index b9783ba..bc24ffc 100644 --- a/proxy_docker/app/script/blockchainrpc.sh +++ b/proxy_docker/app/script/blockchainrpc.sh @@ -5,75 +5,65 @@ get_best_block_hash() { - trace "Entering get_best_block_hash()..." + trace "Entering get_best_block_hash()..." - local data='{"method":"getbestblockhash"}' - send_to_watcher_node "${data}" - return $? + local data='{"method":"getbestblockhash"}' + send_to_watcher_node "${data}" + return $? } getestimatesmartfee() { - trace "Entering getestimatesmartfee()..." + trace "Entering getestimatesmartfee()..." - local nb_blocks=${1} - trace "[getestimatesmartfee] nb_blocks=${nb_blocks}" - send_to_watcher_node "{\"method\":\"estimatesmartfee\",\"params\":[${nb_blocks}]}" | jq ".result.feerate" | awk '{ printf "%.8f", $0 }' - return $? + local nb_blocks=${1} + trace "[getestimatesmartfee] nb_blocks=${nb_blocks}" + send_to_watcher_node "{\"method\":\"estimatesmartfee\",\"params\":[${nb_blocks}]}" | jq ".result.feerate" | awk '{ printf "%.8f", $0 }' + return $? } get_block_info() { - trace "Entering get_block_info()..." + trace "Entering get_block_info()..." - local block_hash=${1} - trace "[get_block_info] block_hash=${block_hash}" - local data="{\"method\":\"getblock\",\"params\":[\"${block_hash}\"]}" - trace "[get_block_info] data=${data}" - send_to_watcher_node "${data}" - return $? + local block_hash=${1} + trace "[get_block_info] block_hash=${block_hash}" + local data="{\"method\":\"getblock\",\"params\":[\"${block_hash}\"]}" + trace "[get_block_info] data=${data}" + send_to_watcher_node "${data}" + return $? } get_best_block_info() { - trace "Entering get_best_block_info()..." + trace "Entering get_best_block_info()..." - local block_hash=$(echo "$(get_best_block_hash)" | jq ".result" | tr -d '"') - trace "[get_best_block_info] block_hash=${block_hash}" - get_block_info ${block_hash} - return $? + local block_hash=$(echo "$(get_best_block_hash)" | jq ".result" | tr -d '"') + trace "[get_best_block_info] block_hash=${block_hash}" + get_block_info ${block_hash} + return $? } get_rawtransaction() { - trace "Entering get_rawtransaction()..." + trace "Entering get_rawtransaction()..." - local txid=${1} - trace "[get_rawtransaction] txid=${txid}" - - local rawtx - rawtx=$(sql "SELECT raw_tx FROM tx WHERE txid=\"${txid}\"") - if [ -z ${rawtx} ]; then - trace "[get_rawtransaction] rawtx not found in DB, let's fetch the Bitcoin node" - local data="{\"method\":\"getrawtransaction\",\"params\":[\"${txid}\",true]}" - trace "[get_rawtransaction] data=${data}" - send_to_watcher_node "${data}" - return $? - else - trace "[get_rawtransaction] rawtx found in DB, no need to fetch the Bitcoin node" - echo ${rawtx} - return 0 - fi + local txid=${1} + trace "[get_rawtransaction] txid=${txid}" + local data="{\"method\":\"getrawtransaction\",\"params\":[\"${txid}\",true]}" + trace "[get_rawtransaction] data=${data}" + send_to_watcher_node "${data}" + return $? } get_transaction() { - trace "Entering get_transaction()..." + trace "Entering get_transaction()..." - local txid=${1} - trace "[get_transaction] txid=${txid}" - local data="{\"method\":\"gettransaction\",\"params\":[\"${txid}\",true]}" - trace "[get_transaction] data=${data}" - send_to_watcher_node "${data}" - return $? + local txid=${1} + trace "[get_transaction] txid=${txid}" + local data="{\"method\":\"gettransaction\",\"params\":[\"${txid}\",true]}" + trace "[get_transaction] data=${data}" + send_to_watcher_node "${data}" + return $? } diff --git a/proxy_docker/app/script/callbacks_job.sh b/proxy_docker/app/script/callbacks_job.sh index bcf3f9f..c31ed8d 100644 --- a/proxy_docker/app/script/callbacks_job.sh +++ b/proxy_docker/app/script/callbacks_job.sh @@ -123,7 +123,7 @@ build_callback() else data="${data}\"blocktime\":\"$(date -Is -d @${blocktime})\"," fi - data="${data}\"blockheight\":\"${blockheight}\"}" + data="${data}\"blockheight\":${blockheight}}" trace "[build_callback] data=${data}" curl_callback "${url}" "${data}" diff --git a/proxy_docker/app/script/confirmation.sh b/proxy_docker/app/script/confirmation.sh index 1f34753..ab37340 100644 --- a/proxy_docker/app/script/confirmation.sh +++ b/proxy_docker/app/script/confirmation.sh @@ -10,150 +10,160 @@ confirmation_request() { - # We are receiving a HTTP request, let's find the TXID from it + # We are receiving a HTTP request, let's find the TXID from it - trace "Entering confirmation_request()..." + trace "Entering confirmation_request()..." - local request=${1} - local txid=$(echo "${request}" | cut -d ' ' -f2 | cut -d '/' -f3) + local request=${1} + local txid=$(echo "${request}" | cut -d ' ' -f2 | cut -d '/' -f3) - confirmation "${txid}" - return $? + confirmation "${txid}" + return $? } confirmation() { - trace "Entering confirmation()..." + trace "Entering confirmation()..." - local returncode - local txid=${1} - local tx_details - tx_details=$(get_transaction ${txid}) - returncode=$? - trace_rc ${returncode} - trace "[confirmation] tx_details=${tx_details}" - if [ "${returncode}" -ne "0" ]; then - trace "[confirmation] Transaction not in watcher, exiting." - return 0 - fi + local returncode + local txid=${1} + local tx_details + tx_details=$(get_transaction ${txid}) + returncode=$? + trace_rc ${returncode} + trace "[confirmation] tx_details=${tx_details}" + if [ "${returncode}" -ne "0" ]; then + trace "[confirmation] Transaction not in watcher, exiting." + return 0 + fi - ######################################################################################################## - # First of all, let's make sure we're working on watched addresses... - local address - local addresseswhere - local addresses=$(echo ${tx_details} | jq ".result.details[].address") + ######################################################################################################## + # First of all, let's make sure we're working on watched addresses... + local address + local addresseswhere + local addresses=$(echo ${tx_details} | jq ".result.details[].address") - local notfirst=false - local IFS=$'\n' - for address in ${addresses} - do - trace "[confirmation] address=${address}" + local notfirst=false + local IFS=$'\n' + for address in ${addresses} + do + trace "[confirmation] address=${address}" - if ${notfirst}; then - addresseswhere="${addresseswhere},${address}" - else - addresseswhere="${address}" - notfirst=true - fi - done - local rows=$(sql "SELECT id, address FROM watching WHERE address IN (${addresseswhere}) AND watching") - if [ ${#rows} -eq 0 ]; then - trace "[confirmation] No watched address in this tx!" - return 0 - fi - ######################################################################################################## + if ${notfirst}; then + addresseswhere="${addresseswhere},${address}" + else + addresseswhere="${address}" + notfirst=true + fi + done + local rows=$(sql "SELECT id, address FROM watching WHERE address IN (${addresseswhere}) AND watching") + if [ ${#rows} -eq 0 ]; then + trace "[confirmation] No watched address in this tx!" + return 0 + fi + ######################################################################################################## - local tx=$(sql "SELECT id FROM tx WHERE txid=\"${txid}\"") - local id_inserted - local tx_raw_details=$(get_rawtransaction ${txid}) - local tx_nb_conf=$(echo ${tx_details} | jq '.result.confirmations') + local tx=$(sql "SELECT id FROM tx WHERE txid=\"${txid}\"") + local id_inserted + local tx_raw_details=$(get_rawtransaction ${txid}) + local tx_nb_conf=$(echo ${tx_details} | jq '.result.confirmations') - # Sometimes raw tx are too long to be passed as paramater, so let's write - # it to a temp file for it to be read by sqlite3 and then delete the file - echo "${tx_raw_details}" > rawtx-${txid}.blob + # Sometimes raw tx are too long to be passed as paramater, so let's write + # it to a temp file for it to be read by sqlite3 and then delete the file + echo "${tx_raw_details}" > rawtx-${txid}.blob - if [ -z ${tx} ]; then - # TX not found in our DB. - # 0-conf or missed conf (managed or while spending) or spending an unconfirmed - # (note: spending an unconfirmed TX must be avoided or we'll get here spending an unprocessed watching) + if [ -z ${tx} ]; then + # TX not found in our DB. + # 0-conf or missed conf (managed or while spending) or spending an unconfirmed + # (note: spending an unconfirmed TX must be avoided or we'll get here spending an unprocessed watching) - # Let's first insert the tx in our DB + # Let's first insert the tx in our DB - local tx_hash=$(echo ${tx_raw_details} | jq '.result.hash') - local tx_ts_firstseen=$(echo ${tx_details} | jq '.result.timereceived') - local tx_amount=$(echo ${tx_details} | jq '.result.amount') + local tx_hash=$(echo ${tx_raw_details} | jq '.result.hash') + local tx_ts_firstseen=$(echo ${tx_details} | jq '.result.timereceived') + local tx_amount=$(echo ${tx_details} | jq '.result.amount') - local tx_size=$(echo ${tx_raw_details} | jq '.result.size') - local tx_vsize=$(echo ${tx_raw_details} | jq '.result.vsize') - local tx_replaceable=$(echo ${tx_details} | jq '.result."bip125-replaceable"') - tx_replaceable=$([ ${tx_replaceable} = "yes" ] && echo 1 || echo 0) + local tx_size=$(echo ${tx_raw_details} | jq '.result.size') + local tx_vsize=$(echo ${tx_raw_details} | jq '.result.vsize') + local tx_replaceable=$(echo ${tx_details} | jq '.result."bip125-replaceable"') + tx_replaceable=$([ ${tx_replaceable} = "yes" ] && echo 1 || echo 0) - local fees=$(compute_fees "${txid}") - trace "[confirmation] fees=${fees}" + local fees=$(compute_fees "${txid}") + trace "[confirmation] fees=${fees}" - # If we missed 0-conf... - local tx_blockhash=$(echo ${tx_details} | jq '.result.blockhash') - local tx_blockheight=$(echo ${tx_details} | jq '.result.blockheight') - local tx_blocktime=$(echo ${tx_details} | jq '.result.blocktime') + # If we missed 0-conf... + local tx_blockhash=null + local tx_blockheight=null + local tx_blocktime=null + if [ "${tx_nb_conf}" -gt "0" ]; then + trace "[confirmation] tx_nb_conf=${tx_nb_conf}" + tx_blockhash=$(echo ${tx_details} | jq '.result.blockhash') + tx_blockheight=$(get_block_info $(echo ${tx_blockhash} | tr -d '"') | jq '.result.height') + tx_blocktime=$(echo ${tx_details} | jq '.result.blocktime') + fi - sql "INSERT OR IGNORE INTO tx (txid, hash, confirmations, timereceived, fee, size, vsize, is_replaceable, blockhash, blockheight, blocktime, raw_tx) VALUES (\"${txid}\", ${tx_hash}, ${tx_nb_conf}, ${tx_ts_firstseen}, ${fees}, ${tx_size}, ${tx_vsize}, ${tx_replaceable}, ${tx_blockhash}, ${tx_blockheight}, ${tx_blocktime}, readfile('rawtx-${txid}.blob'))" - trace_rc $? + sql "INSERT OR IGNORE INTO tx (txid, hash, confirmations, timereceived, fee, size, vsize, is_replaceable, blockhash, blockheight, blocktime, raw_tx) VALUES (\"${txid}\", ${tx_hash}, ${tx_nb_conf}, ${tx_ts_firstseen}, ${fees}, ${tx_size}, ${tx_vsize}, ${tx_replaceable}, ${tx_blockhash}, ${tx_blockheight}, ${tx_blocktime}, readfile('rawtx-${txid}.blob'))" + trace_rc $? - id_inserted=$(sql "SELECT id FROM tx WHERE txid='${txid}'") - trace_rc $? + id_inserted=$(sql "SELECT id FROM tx WHERE txid='${txid}'") + trace_rc $? - else - # TX found in our DB. - # 1-conf or spending watched address (in this case, we probably missed conf) + else + # TX found in our DB. + # 1-conf or executecallbacks on an unconfirmed tx or spending watched address (in this case, we probably missed conf) - local tx_blockhash=$(echo ${tx_details} | jq '.result.blockhash') - local tx_blockheight=$(echo ${tx_details} | jq '.result.blockheight') - local tx_blocktime=$(echo ${tx_details} | jq '.result.blocktime') + local tx_blockhash=$(echo ${tx_details} | jq '.result.blockhash') + trace "[confirmation] tx_blockhash=${tx_blockhash}" + if [ "${tx_blockhash}" = "null" ]; then + trace "[confirmation] probably being called by executecallbacks without any confirmations since the last time we checked" + else + local tx_blockheight=$(get_block_info $(echo ${tx_blockhash} | tr -d '"') | jq '.result.height') + local tx_blocktime=$(echo ${tx_details} | jq '.result.blocktime') - sql "UPDATE tx SET - confirmations=${tx_nb_conf}, - blockhash=${tx_blockhash}, - blockheight=${tx_blockheight}, - blocktime=${tx_blocktime}, - raw_tx=readfile('rawtx-${txid}.blob') - WHERE txid=\"${txid}\"" - trace_rc $? + sql "UPDATE tx SET + confirmations=${tx_nb_conf}, + blockhash=${tx_blockhash}, + blockheight=${tx_blockheight}, + blocktime=${tx_blocktime}, + raw_tx=readfile('rawtx-${txid}.blob') + WHERE txid=\"${txid}\"" + trace_rc $? - id_inserted=${tx} + id_inserted=${tx} + fi + fi + # Delete the temp file containing the raw tx (see above) + rm rawtx-${txid}.blob - fi - # Delete the temp file containing the raw tx (see above) - rm rawtx-${txid}.blob + ######################################################################################################## + # Let's now insert in the join table if not already done + tx=$(sql "SELECT tx_id FROM watching_tx WHERE tx_id=\"${tx}\"") - ######################################################################################################## - # Let's now insert in the join table if not already done - tx=$(sql "SELECT tx_id FROM watching_tx WHERE tx_id=\"${tx}\"") + if [ -z "${tx}" ]; then + trace "[confirmation] For this tx, there's no watching_tx row, let's create" + local watching_id - if [ -z "${tx}" ]; then - trace "[confirmation] For this tx, there's no watching_tx row, let's create" - local watching_id + # If the tx is batched and pays multiple watched addresses, we have to insert + # those additional addresses in watching_tx! + for row in ${rows} + do + watching_id=$(echo "${row}" | cut -d '|' -f1) + address=$(echo "${row}" | cut -d '|' -f2) + tx_vout_n=$(echo ${tx_details} | jq ".result.details[] | select(.address==\"${address}\") | .vout") + tx_vout_amount=$(echo ${tx_details} | jq ".result.details[] | select(.address==\"${address}\") | .amount") + sql "INSERT OR IGNORE INTO watching_tx (watching_id, tx_id, vout, amount) VALUES (${watching_id}, ${id_inserted}, ${tx_vout_n}, ${tx_vout_amount})" + trace_rc $? + done + else + trace "[confirmation] For this tx, there's already watching_tx rows" + fi + ######################################################################################################## - # If the tx is batched and pays multiple watched addresses, we have to insert - # those additional addresses in watching_tx! - for row in ${rows} - do - watching_id=$(echo "${row}" | cut -d '|' -f1) - address=$(echo "${row}" | cut -d '|' -f2) - tx_vout_n=$(echo ${tx_details} | jq ".result.details[] | select(.address==\"${address}\") | .vout") - tx_vout_amount=$(echo ${tx_details} | jq ".result.details[] | select(.address==\"${address}\") | .amount") - sql "INSERT OR IGNORE INTO watching_tx (watching_id, tx_id, vout, amount) VALUES (${watching_id}, ${id_inserted}, ${tx_vout_n}, ${tx_vout_amount})" - trace_rc $? - done - else - trace "[confirmation] For this tx, there's already watching_tx rows" - fi - ######################################################################################################## + do_callbacks - do_callbacks + echo '{"result":"confirmed"}' - echo '{"result":"confirmed"}' - - return 0 + return 0 } case "${0}" in *confirmation.sh) confirmation $@;; esac