First push from Satoshi Portal's own cyphernode

This commit is contained in:
kexkey
2018-09-22 14:49:26 -04:00
commit c39f81f683
47 changed files with 3517 additions and 0 deletions

View File

@@ -0,0 +1,46 @@
#!/bin/sh
. ./trace.sh
. ./utils.sh
deriveindex()
{
trace "Entering deriveindex()..."
local index=${1}
trace "[deriveindex] index=${index}"
local pub32=$(get_prop "derivation.pub32")
local path=$(get_prop "derivation.path" | sed -En "s/n/${index}/p")
# pub32=$(grep "derivation.pub32" config.properties | cut -d'=' -f2)
# path=$(grep "derivation.path" config.properties | cut -d'=' -f2 | sed -En "s/n/${index}/p")
local data="{\"pub32\":\"${pub32}\",\"path\":\"${path}\"}"
trace "[deriveindex] data=${data}"
send_to_pycoin "${data}"
return $?
}
send_to_pycoin()
{
trace "Entering send_to_pycoin()..."
local data=${1}
local result
local returncode
trace "[send_to_pycoin] curl -s -H \"Content-Type: application/json\" -d \"${data}\" ${PYCOIN_CONTAINER}/derive"
result=$(curl -s -H "Content-Type: application/json" -d "${data}" ${PYCOIN_CONTAINER}/derive)
returncode=$?
trace_rc ${returncode}
trace "[send_to_pycoin] result=${result}"
# Output response to stdout before exiting with return code
echo "${result}"
trace_rc ${returncode}
return ${returncode}
}

View File

@@ -0,0 +1,79 @@
#!/bin/sh
. ./trace.sh
. ./sendtobitcoinnode.sh
get_best_block_hash()
{
trace "Entering get_best_block_hash()..."
local data='{"method":"getbestblockhash"}'
send_to_watcher_node "${data}"
return $?
}
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 $?
}
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 $?
}
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 $?
}
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
}
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 $?
}

View File

@@ -0,0 +1,102 @@
#!/bin/sh
. ./trace.sh
ln_create_invoice()
{
trace "Entering ln_create_invoice()..."
local result
local request=${1}
local msatoshi=$(echo "${request}" | jq ".msatoshi" | tr -d '"')
trace "[ln_create_invoice] msatoshi=${msatoshi}"
local label=$(echo "${request}" | jq ".label")
trace "[ln_create_invoice] label=${label}"
local description=$(echo "${request}" | jq ".description")
trace "[ln_create_invoice] description=${description}"
local expiry=$(echo "${request}" | jq ".expiry" | tr -d '"')
trace "[ln_create_invoice] expiry=${expiry}"
result=$(./lightning-cli invoice ${msatoshi} "${label}" "${description}" ${expiry})
returncode=$?
trace_rc ${returncode}
trace "[ln_create_invoice] result=${result}"
echo "${result}"
return ${returncode}
}
ln_getinfo()
{
trace "Entering ln_get_info()..."
local result
result=$(./lightning-cli getinfo)
returncode=$?
trace_rc ${returncode}
trace "[ln_getinfo] result=${result}"
echo "${result}"
return ${returncode}
}
ln_pay() {
trace "Entering ln_pay()..."
local result
local request=${1}
local bolt11=$(echo "${request}" | jq ".bolt11" | tr -d '"')
trace "[ln_pay] bolt11=${bolt11}"
local expected_msatoshi=$(echo "${request}" | jq ".expected_msatoshi")
trace "[ln_pay] expected_msatoshi=${expected_msatoshi}"
local expected_description=$(echo "${request}" | jq ".expected_description")
trace "[ln_pay] expected_description=${expected_description}"
result=$(./lightning-cli decodepay ${bolt11})
local invoice_msatoshi=$(echo "${result}" | jq ".msatoshi")
trace "[ln_pay] invoice_msatoshi=${invoice_msatoshi}"
local invoice_description=$(echo "${result}" | jq ".description")
trace "[ln_pay] invoice_description=${invoice_description}"
if [ "${expected_msatoshi}" != "${invoice_msatoshi}" ]; then
result="{\"result\":\"error\",\"expected_msatoshi\":${expected_msatoshi},\"invoice_msatoshi\":${invoice_msatoshi}}"
returncode=1
elif [ "${expected_description}" != "${invoice_description}" ]; then
result="{\"result\":\"error\",\"expected_description\":${expected_description},\"invoice_description\":${invoice_description}}"
returncode=1
else
result=$(./lightning-cli pay ${bolt11})
returncode=$?
trace_rc ${returncode}
fi
trace "[ln_pay] result=${result}"
echo "${result}"
return ${returncode}
}
ln_newaddr()
{
trace "Entering ln_newaddr()..."
local result
call_lightningd newaddr
result=$(./lightning-cli newaddr)
returncode=$?
trace_rc ${returncode}
trace "[ln_newaddr] result=${result}"
echo "${result}"
return ${returncode}
}
case "${0}" in *call_lightningd.sh) call_lightningd $@;; esac

View File

@@ -0,0 +1,148 @@
#!/bin/sh
. ./trace.sh
. ./sql.sh
do_callbacks()
{
(
flock -x 200 || return 0
trace "Entering do_callbacks()..."
# Let's fetch all the watching addresses still being watched but not called back
local callbacks=$(sql 'SELECT DISTINCT callback0conf, address, txid, vout, amount, confirmations, timereceived, fee, size, vsize, blockhash, blockheight, blocktime, w.id, is_replaceable FROM watching w LEFT JOIN watching_tx ON w.id = watching_id LEFT JOIN tx ON tx.id = tx_id WHERE NOT calledback0conf and watching_id NOT NULL and callback0conf NOT NULL and watching')
trace "[do_callbacks] callbacks0conf=${callbacks}"
local returncode
local address
local IFS=$'\n'
for row in ${callbacks}
do
build_callback ${row}
returncode=$?
trace_rc ${returncode}
if [ "${returncode}" -eq 0 ]; then
address=$(echo "${row}" | cut -d '|' -f2)
sql "UPDATE watching SET calledback0conf=1 WHERE address=\"${address}\""
trace_rc $?
fi
done
callbacks=$(sql 'SELECT DISTINCT callback1conf, address, txid, vout, amount, confirmations, timereceived, fee, size, vsize, blockhash, blockheight, blocktime, w.id, is_replaceable FROM watching w, watching_tx wt, tx t WHERE w.id = watching_id AND tx_id = t.id AND NOT calledback1conf and confirmations>0 and callback1conf NOT NULL and watching')
trace "[do_callbacks] callbacks1conf=${callbacks}"
for row in ${callbacks}
do
build_callback ${row}
returncode=$?
if [ "${returncode}" -eq 0 ]; then
address=$(echo "${row}" | cut -d '|' -f2)
sql "UPDATE watching SET calledback1conf=1, watching=0 WHERE address=\"${address}\""
trace_rc $?
fi
done
) 200>./.callbacks.lock
}
build_callback()
{
trace "Entering build_callback()..."
local row=$@
local id
local url
local data
local address
local txid
local vout_n
local sent_amount
local confirmations
local ts_firstseen
local fee
local size
local vsize
local blockhash
local blocktime
local blockheight
# callback0conf, address, txid, vout, amount, confirmations, timereceived, fee, size, vsize, blockhash, blockheight, blocktime, w.id
trace "[build_callback] row=${row}"
id=$(echo "${row}" | cut -d '|' -f14)
trace "[build_callback] id=${id}"
url=$(echo "${row}" | cut -d '|' -f1)
trace "[build_callback] url=${url}"
address=$(echo "${row}" | cut -d '|' -f2)
trace "[build_callback] address=${address}"
txid=$(echo "${row}" | cut -d '|' -f3)
trace "[build_callback] txid=${txid}"
vout_n=$(echo "${row}" | cut -d '|' -f4)
trace "[build_callback] vout_n=${vout_n}"
sent_amount=$(echo "${row}" | cut -d '|' -f5)
trace "[build_callback] sent_amount=${sent_amount}"
confirmations=$(echo "${row}" | cut -d '|' -f6)
trace "[build_callback] confirmations=${confirmations}"
ts_firstseen=$(echo "${row}" | cut -d '|' -f7)
trace "[build_callback] ts_firstseen=${ts_firstseen}"
# If node in pruned mode, we can't calculate the fees and then we don't want
# to send 0.00000000 as fees but empty string to distinguish.
fee=$(echo "${row}" | cut -d '|' -f8)
if [ -n "${fee}" ]; then
fee=$(echo "${fee}" | awk '{ printf "%.8f", $0 }')
fi
trace "[build_callback] fee=${fee}"
size=$(echo "${row}" | cut -d '|' -f9)
trace "[build_callback] size=${size}"
vsize=$(echo "${row}" | cut -d '|' -f10)
trace "[build_callback] vsize=${vsize}"
is_replaceable=$(echo "${row}" | cut -d '|' -f15)
trace "[build_callback] is_replaceable=${is_replaceable}"
blockhash=$(echo "${row}" | cut -d '|' -f11)
trace "[build_callback] blockhash=${blockhash}"
blockheight=$(echo "${row}" | cut -d '|' -f12)
trace "[build_callback] blockheight=${blockheight}"
blocktime=$(echo "${row}" | cut -d '|' -f13)
trace "[build_callback] blocktime=${blocktime}"
data="{\"id\":\"${id}\","
data="${data}\"address\":\"${address}\","
data="${data}\"hash\":\"${txid}\","
data="${data}\"vout_n\":${vout_n},"
data="${data}\"sent_amount\":${sent_amount},"
data="${data}\"confirmations\":${confirmations},"
data="${data}\"received\":\"$(date -Is -d @${ts_firstseen})\","
data="${data}\"size\":${size},"
data="${data}\"vsize\":${vsize},"
data="${data}\"fees\":${fee},"
data="${data}\"is_replaceable\":${is_replaceable},"
data="${data}\"blockhash\":\"${blockhash}\","
if [ -z ${blocktime} ]; then
data="${data}\"blocktime\":\"\","
else
data="${data}\"blocktime\":\"$(date -Is -d @${blocktime})\","
fi
data="${data}\"blockheight\":\"${blockheight}\"}"
trace "[build_callback] data=${data}"
curl_callback "${url}" "${data}"
return $?
}
curl_callback()
{
trace "Entering curl_callback()..."
local url=${1}
local data=${2}
trace "[curl_callback] curl -H \"Content-Type: application/json\" -d \"${data}\" ${url}"
curl -H "Content-Type: application/json" -H "X-Forwarded-Proto: https" -d "${data}" ${url}
local returncode=$?
trace_rc ${returncode}
return ${returncode}
}
case "${0}" in *callbacks_job.sh) do_callbacks $@;; esac

View File

@@ -0,0 +1,112 @@
#!/bin/sh
. ./trace.sh
. ./sendtobitcoinnode.sh
. ./sql.sh
. ./blockchainrpc.sh
compute_fees()
{
local pruned=$(get_prop "watchingnode.pruned")
if [ "${pruned}" = "true" ]; then
trace "[compute_fees] pruned=${pruned}"
# We want null instead of 0.00000000 in this case.
echo "null"
exit 0
fi
local txid=${1}
local tx_raw_details=$(cat rawtx-${txid}.blob)
trace "[compute_fees] tx_raw_details=${tx_raw_details}"
local vin_total_amount=$(compute_vin_total_amount "${tx_raw_details}")
local vout_total_amount=0
local vout_value
local vout_values=$(echo "${tx_raw_details}" | jq ".result.vout[].value")
for vout_value in ${vout_values}
do
vout_total_amount=$(awk "BEGIN { printf(\"%.8f\", ${vout_total_amount}+${vout_value}); exit }")
done
trace "[compute_fees] vin total amount=${vin_total_amount}"
trace "[compute_fees] vout total amount=${vout_total_amount}"
local fees=$(awk "BEGIN { printf(\"%.8f\", ${vin_total_amount}-${vout_total_amount}); exit }")
trace "[compute_fees] fees=${fees}"
echo ${fees}
}
compute_vin_total_amount()
{
trace "Entering compute_vin_total_amount()..."
local main_tx=${1}
# local vin_txids=$(echo ${main_tx} | jq '.result.vin[].txid')
local vin_txids_vout=$(echo ${main_tx} | jq '.result.vin[] | ((.txid + "-") + (.vout | tostring))')
trace "[compute_vin_total_amount] vin_txids_vout=${vin_txids_vout}"
local returncode
local vin_txid_vout
local vin_txid
local vin_raw_tx
local vin_vout_amount=0
local vout
local vin_total_amount=0
local vin_hash
local vin_confirmations
local vin_timereceived
local vin_vsize
local vin_blockhash
local vin_blockheight
local vin_blocktime
local txid_already_inserted=true
for vin_txid_vout in ${vin_txids_vout}
do
# vin_txid=$(echo ${vin_txid} | tr -d '"')
vin_txid=$(echo ${vin_txid_vout} | tr -d '"' | cut -d '-' -f1)
# Check if we already have the tx in our DB
vin_raw_tx=$(sql "SELECT raw_tx FROM tx WHERE txid=\"${vin_txid}\"")
if [ -z "${vin_raw_tx}" ]; then
txid_already_inserted=false
vin_raw_tx=$(get_rawtransaction "${vin_txid}")
returncode=$?
if [ "${returncode}" -ne 0 ]; then
return ${returncode}
fi
fi
# vout=$(echo ${main_tx} | jq ".result.vin[] | select(.txid == \"${vin_txid}\") | .vout")
vout=$(echo ${vin_txid_vout} | tr -d '"' | cut -d '-' -f2)
trace "[compute_vin_total_amount] vout=${vout}"
vin_vout_amount=$(echo ${vin_raw_tx} | jq ".result.vout[] | select(.n == ${vout}) | .value" | awk '{ printf "%.8f", $0 }')
trace "[compute_vin_total_amount] vin_vout_amount=${vin_vout_amount}"
vin_total_amount=$(awk "BEGIN { printf(\"%.8f\", ${vin_total_amount}+${vin_vout_amount}); exit}")
trace "[compute_vin_total_amount] vin_total_amount=${vin_total_amount}"
vin_hash=$(echo ${vin_raw_tx} | jq ".result.hash")
vin_confirmations=$(echo ${vin_raw_tx} | jq ".result.confirmations")
vin_timereceived=$(echo ${vin_raw_tx} | jq ".result.time")
vin_size=$(echo ${vin_raw_tx} | jq ".result.size")
vin_vsize=$(echo ${vin_raw_tx} | jq ".result.vsize")
vin_blockhash=$(echo ${vin_raw_tx} | jq ".result.blockhash")
vin_blockheight=$(echo ${vin_raw_tx} | jq ".result.blockheight")
vin_blocktime=$(echo ${vin_raw_tx} | jq ".result.blocktime")
# Let's insert the vin tx in the DB just in case it would be useful
if ! ${txid_already_inserted}; then
# 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 "${vin_raw_tx}" > rawtx-${vin_txid}.blob
sql "INSERT OR IGNORE INTO tx (txid, hash, confirmations, timereceived, size, vsize, blockhash, blockheight, blocktime, raw_tx) VALUES (\"${vin_txid}\", ${vin_hash}, ${vin_confirmations}, ${vin_timereceived}, ${vin_size}, ${vin_vsize}, ${vin_blockhash}, ${vin_blockheight}, ${vin_blocktime}, readfile('rawtx-${vin_txid}.blob'))"
trace_rc $?
rm rawtx-${vin_txid}.blob
txid_already_inserted=true
fi
done
echo ${vin_total_amount}
return 0
}
case "${0}" in *computefees.sh) compute_vin_total_amount $@;; esac

View File

@@ -0,0 +1,150 @@
#!/bin/sh
. ./trace.sh
. ./sql.sh
. ./callbacks_job.sh
. ./sendtobitcoinnode.sh
. ./responsetoclient.sh
. ./computefees.sh
. ./blockchainrpc.sh
confirmation_request()
{
# We are receiving a HTTP request, let's find the TXID from it
trace "Entering confirmation_request()..."
local request=${1}
local txid=$(echo "${request}" | cut -d ' ' -f2 | cut -d '/' -f3)
confirmation "${txid}"
return $?
}
confirmation()
{
trace "Entering confirmation()..."
local txid=${1}
local tx_details=$(get_transaction ${txid})
########################################################################################################
# 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}"
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')
# 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)
# 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_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}"
# 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')
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 $?
else
# TX found in our DB.
# 1-conf 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')
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}
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}\"")
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
########################################################################################################
do_callbacks
echo '{"result":"confirmed"}'
return 0
}
case "${0}" in *confirmation.sh) confirmation $@;; esac

View File

@@ -0,0 +1,64 @@
#!/bin/sh
. ./trace.sh
. ./sql.sh
getactivewatches()
{
trace "Entering getactivewatches()..."
local watches
watches=$(sql "SELECT id, address, imported, callback0conf, callback1conf, inserted_ts FROM watching WHERE watching AND NOT calledback1conf")
returncode=$?
trace_rc ${returncode}
local id
local address
local imported
local inserted
local cb0conf_url
local cb1conf_url
local timestamp
local notfirst=false
echo -n "{\"watches\":["
local IFS=$'\n'
for row in ${watches}
do
if ${notfirst}; then
echo ","
else
notfirst=true
fi
trace "[getactivewatches] row=${row}"
id=$(echo "${row}" | cut -d '|' -f1)
trace "[getactivewatches] id=${id}"
address=$(echo "${row}" | cut -d '|' -f2)
trace "[getactivewatches] address=${address}"
imported=$(echo "${row}" | cut -d '|' -f3)
trace "[getactivewatches] imported=${imported}"
cb0conf_url=$(echo "${row}" | cut -d '|' -f4)
trace "[getactivewatches] cb0conf_url=${cb0conf_url}"
cb1conf_url=$(echo "${row}" | cut -d '|' -f5)
trace "[getactivewatches] cb1conf_url=${cb1conf_url}"
timestamp=$(echo "${row}" | cut -d '|' -f6)
trace "[getactivewatches] timestamp=${timestamp}"
data="{\"id\":\"${id}\","
data="${data}\"address\":\"${address}\","
data="${data}\"imported\":\"${imported}\","
data="${data}\"unconfirmedCallbackURL\":\"${cb0conf_url}\","
data="${data}\"confirmedCallbackURL\":\"${cb1conf_url}\","
data="${data}\"watching_since\":\"${timestamp}\"}"
trace "[getactivewatches] data=${data}"
echo -n "${data}"
done
echo "]}"
return ${returncode}
}
case "${0}" in *getactivewatches.sh) getactivewatches;; esac

View File

@@ -0,0 +1,21 @@
#!/bin/sh
. ./trace.sh
. ./sendtobitcoinnode.sh
importaddress_rpc()
{
trace "[Entering importaddress_rpc()]"
local address=${1}
local data="{\"method\":\"importaddress\",\"params\":[\"${address}\",\"\",false]}"
local result
result=$(send_to_watcher_node ${data})
local returncode=$?
echo "${result}"
return ${returncode}
}
case "${0}" in *importaddress.sh) importaddress_rpc $@;; esac

View File

@@ -0,0 +1,86 @@
#!/bin/sh
. ./trace.sh
. ./sql.sh
. ./importaddress.sh
. ./confirmation.sh
manage_not_imported()
{
# When we tried to import watched addresses in the watching node,
# if it didn't succeed, we try again here.
trace "[Entering manage_not_imported()]"
local watches=$(sql 'SELECT address FROM watching WHERE watching AND NOT imported')
trace "[manage_not_imported] watches=${watches}"
local result
local returncode
local IFS=$'\n'
for address in ${watches}
do
result=$(importaddress_rpc "${address}")
returncode=$?
trace_rc ${returncode}
if [ "${returncode}" -eq 0 ]; then
sql "UPDATE watching SET imported=1 WHERE address=\"${address}\""
fi
done
return 0
}
manage_missed_conf()
{
# Maybe we missed confirmations, because we were down or no network or
# whatever, so we look at what might be missed and do confirmations.
trace "[Entering manage_missed_conf()]"
# local watches=$(sql 'SELECT address FROM watching WHERE txid IS NULL AND watching AND imported')
#local watches=$(sql 'SELECT address FROM watching LEFT JOIN watching_tx ON id = watching_id WHERE watching AND imported AND tx_id IS NULL')
local watches=$(sql 'SELECT address FROM watching w LEFT JOIN watching_tx ON w.id = watching_id LEFT JOIN tx t ON t.id = tx_id WHERE watching AND imported AND (tx_id IS NULL OR t.confirmations=0)')
trace "[manage_missed_conf] watches=${watches}"
if [ ${#watches} -eq 0 ]; then
trace "[manage_missed_conf] Nothing missed!"
return 0
fi
local addresses
local data
local result
local returncode
local IFS=$'\n'
for address in ${watches}
do
if [ -z ${addresses} ]; then
addresses="[\"${address}\""
else
addresses="${addresses},\"${address}\""
fi
done
addresses="${addresses}]"
# Watching addresses with UTXO are transactions being watched that went through without us knowing it, we missed the conf
data="{\"method\":\"listunspent\",\"params\":[0, 9999999, ${addresses}]}"
local unspents
unspents=$(send_to_watcher_node ${data})
returncode=$?
trace_rc ${returncode}
if [ "${returncode}" -ne 0 ]; then
return ${returncode}
fi
# | tr -d '"'
local txids=$(echo ${unspents} | jq ".result[].txid" | tr -d '"')
for txid in ${txids}
do
confirmation "${txid}"
done
return 0
}
case "${0}" in *manage_missed_conf.sh) manage_not_imported $@; manage_missed_conf $@;; esac

View File

@@ -0,0 +1,238 @@
#!/bin/sh
#
#
#
#
. ./sendtobitcoinnode.sh
. ./callbacks_job.sh
. ./watchrequest.sh
. ./unwatchrequest.sh
. ./getactivewatches.sh
. ./confirmation.sh
. ./blockchainrpc.sh
. ./responsetoclient.sh
. ./trace.sh
. ./manage_missed_conf.sh
. ./walletoperations.sh
. ./bitcoin.sh
. ./call_lightningd.sh
main()
{
trace "Entering main()..."
local step=0
local cmd
local http_method
local line
local content_length
local response
local returncode
while read line; do
line=$(echo "${line}" | tr -d '\r\n')
trace "[main] line=${line}"
if [ "${cmd}" = "" ]; then
# First line!
# Looking for something like:
# GET /cmd/params HTTP/1.1
# POST / HTTP/1.1
cmd=$(echo "${line}" | cut -d '/' -f2 | cut -d ' ' -f1)
trace "[main] cmd=${cmd}"
http_method=$(echo "${line}" | cut -d ' ' -f1)
trace "[main] http_method=${http_method}"
if [ "${http_method}" = "GET" ]; then
step=1
fi
fi
if [ "${line}" = "" ]; then
trace "[main] empty line"
if [ ${step} -eq 1 ]; then
trace "[main] body part finished, disconnecting"
break
else
trace "[main] headers part finished, body incoming"
step=1
fi
fi
# line=content-length: 406
case "${line}" in *[cC][oO][nN][tT][eE][nN][tT]-[lL][eE][nN][gG][tT][hH]*)
content_length=$(echo ${line} | cut -d ':' -f2)
trace "[main] content_length=${content_length}";
;;
esac
if [ ${step} -eq 1 ]; then
trace "[main] step=${step}"
if [ "${http_method}" = "POST" ]; then
read -n ${content_length} line
trace "[main] line=${line}"
fi
case "${cmd}" in
watch)
# POST http://192.168.111.152:8080/watch
# BODY {"address":"2N8DcqzfkYi8CkYzvNNS5amoq3SbAcQNXKp","unconfirmedCallbackURL":"192.168.111.233:1111/callback0conf","confirmedCallbackURL":"192.168.111.233:1111/callback1conf"}
response=$(watchrequest "${line}")
response_to_client "${response}" ${?}
break
;;
unwatch)
# curl (GET) 192.168.111.152:8080/unwatch/2N8DcqzfkYi8CkYzvNNS5amoq3SbAcQNXKp
response=$(unwatchrequest "${line}")
response_to_client "${response}" ${?}
break
;;
getactivewatches)
# curl (GET) 192.168.111.152:8080/getactivewatches
response=$(getactivewatches)
response_to_client "${response}" ${?}
break
;;
conf)
# curl (GET) 192.168.111.152:8080/conf/b081ca7724386f549cf0c16f71db6affeb52ff7a0d9b606fb2e5c43faffd3387
response=$(confirmation_request "${line}")
response_to_client "${response}" ${?}
break
;;
getbestblockhash)
# curl (GET) http://192.168.111.152:8080/getbestblockhash
response=$(get_best_block_hash)
response_to_client "${response}" ${?}
break
;;
getblockinfo)
# curl (GET) http://192.168.111.152:8080/getblockinfo/000000006f82a384c208ecfa04d05beea02d420f3f398ddda5c7f900de5718ea
response=$(get_block_info $(echo "${line}" | cut -d ' ' -f2 | cut -d '/' -f3))
response_to_client "${response}" ${?}
break
;;
gettransaction)
# curl (GET) http://192.168.111.152:8080/gettransaction/af867c86000da76df7ddb1054b273ca9e034e8c89d049b5b2795f9f590f67648
response=$(get_rawtransaction $(echo "${line}" | cut -d ' ' -f2 | cut -d '/' -f3))
response_to_client "${response}" ${?}
break
;;
getbestblockinfo)
# curl (GET) http://192.168.111.152:8080/getbestblockinfo
response=$(get_best_block_info)
response_to_client "${response}" ${?}
break
;;
executecallbacks)
# curl (GET) http://192.168.111.152:8080/executecallbacks
manage_not_imported
manage_missed_conf
response=$(do_callbacks)
response_to_client "${response}" ${?}
break
;;
getbalance)
# curl (GET) http://192.168.111.152:8080/getbalance
response=$(getbalance)
response_to_client "${response}" ${?}
break
;;
getnewaddress)
# curl (GET) http://192.168.111.152:8080/getnewaddress
response=$(getnewaddress)
response_to_client "${response}" ${?}
break
;;
spend)
# POST http://192.168.111.152:8080/spend
# BODY {"address":"2N8DcqzfkYi8CkYzvNNS5amoq3SbAcQNXKp","amount":0.00233}
response=$(spend "${line}")
response_to_client "${response}" ${?}
break
;;
addtobatch)
# POST http://192.168.111.152:8080/addtobatch
# BODY {"address":"2N8DcqzfkYi8CkYzvNNS5amoq3SbAcQNXKp","amount":0.00233}
response=$(addtobatching $(echo "${line}" | jq ".address" | tr -d '"') $(echo "${line}" | jq ".amount"))
response_to_client "${response}" ${?}
break
;;
batchspend)
# GET http://192.168.111.152:8080/batchspend
response=$(batchspend "${line}")
response_to_client "${response}" ${?}
break
;;
deriveindex)
# curl GET http://192.168.111.152:8080/deriveindex/25-30
# curl GET http://192.168.111.152:8080/deriveindex/34
response=$(deriveindex $(echo "${line}" | cut -d ' ' -f2 | cut -d '/' -f3))
response_to_client "${response}" ${?}
break
;;
derivepubpath)
# POST http://192.168.111.152:8080/derivepubpath
# BODY {"pub32":"tpubD6NzVbkrYhZ4YR3QK2tyfMMvBghAvqtNaNK1LTyDWcRHLcMUm3ZN2cGm5BS3MhCRCeCkXQkTXXjiJgqxpqXK7PeUSp86DTTgkLpcjMtpKWk","path":"0/25-30"}
# BODY {"pub32":"upub5GtUcgGed1aGH4HKQ3vMYrsmLXwmHhS1AeX33ZvDgZiyvkGhNTvGd2TA5Lr4v239Fzjj4ZY48t6wTtXUy2yRgapf37QHgt6KWEZ6bgsCLpb","path":"0/25-30"}
# BODY {"pub32":"vpub5SLqN2bLY4WeZF3kL4VqiWF1itbf3A6oRrq9aPf16AZMVWYCuN9TxpAZwCzVgW94TNzZPNc9XAHD4As6pdnExBtCDGYRmNJrcJ4eV9hNqcv","path":"0/25-30"}
response=$(send_to_pycoin "${line}")
response_to_client "${response}" ${?}
break
;;
ln_getinfo)
# GET http://192.168.111.152:8080/ln_getinfo
response=$(ln_getinfo)
response_to_client "${response}" ${?}
break
;;
ln_create_invoice)
# POST http://192.168.111.152:8080/ln_create_invoice
# BODY {"msatoshi":"10000","label":"koNCcrSvhX3dmyFhW","description":"Bylls order #10649","expiry":"900"}
response=$(ln_create_invoice "${line}")
response_to_client "${response}" ${?}
break
;;
ln_pay)
# POST http://192.168.111.152:8080/ln_pay
# BODY {"bolt11":"lntb1pdca82tpp5gv8mn5jqlj6xztpnt4r472zcyrwf3y2c3cvm4uzg2gqcnj90f83qdp2gf5hgcm0d9hzqnm4w3kx2apqdaexgetjyq3nwvpcxgcqp2g3d86wwdfvyxcz7kce7d3n26d2rw3wf5tzpm2m5fl2z3mm8msa3xk8nv2y32gmzlhwjved980mcmkgq83u9wafq9n4w28amnmwzujgqpmapcr3","expected_msatoshi":"10000","expected_description":"Bitcoin Outlet order #7082"}
response=$(ln_pay "${line}")
response_to_client "${response}" ${?}
break
;;
ln_newaddr)
# GET http://192.168.111.152:8080/ln_newaddr
response=$(ln_newaddr)
response_to_client "${response}" ${?}
break
;;
esac
break
fi
done
trace "[main] exiting"
return 0
}
export NODE_RPC_URL=$BTC_NODE_RPC_URL
export TRACING
export DB_PATH
export DB_FILE
main
exit $?

View File

@@ -0,0 +1,21 @@
#!/bin/sh
. ./trace.sh
response_to_client()
{
trace "Entering response_to_client()..."
local response=${1}
local returncode=${2}
([ -z "${returncode}" ] || [ "${returncode}" -eq "0" ]) && echo -ne "HTTP/1.1 200 OK\r\n"
[ -n "${returncode}" ] && [ "${returncode}" -ne "0" ] && echo -ne "HTTP/1.1 400 Bad Request\r\n"
echo -e "Content-Type: application/json\r\nContent-Length: ${#response}\r\n\r\n${response}"
# Small delay needed for the data to be processed correctly by peer
sleep 0.2s
}
case "${0}" in *responsetoclient.sh) response_to_client $@;; esac

View File

@@ -0,0 +1,59 @@
#!/bin/sh
. ./trace.sh
send_to_watcher_node()
{
trace "Entering send_to_watcher_node()..."
send_to_bitcoin_node ${WATCHER_NODE_RPC_URL} watcher_btcnode_curlcfg.properties $@
local returncode=$?
trace_rc ${returncode}
return ${returncode}
}
send_to_spender_node()
{
trace "Entering send_to_spender_node()..."
send_to_bitcoin_node ${SPENDER_NODE_RPC_URL} spender_btcnode_curlcfg.properties $@
local returncode=$?
trace_rc ${returncode}
return ${returncode}
}
send_to_bitcoin_node()
{
trace "Entering send_to_bitcoin_node()..."
local returncode
local result
local errorstring
local node_url=${1}
local configfile=${2}
local data=${3}
trace "[send_to_bitcoin_node] curl -s --config ${configfile} -H \"Content-Type: application/json\" -d \"${data}\" ${node_url}"
result=$(curl -s --config ${configfile} -H "Content-Type: application/json" -d "${data}" ${node_url})
returncode=$?
trace_rc ${returncode}
trace "[send_to_bitcoin_node] result=${result}"
if [ "${returncode}" -eq 0 ]; then
# Node responded, let's see if we got an error message from the node
# jq -e will have a return code of 1 if the supplied tag is null.
errorstring=$(echo "${result}" | jq -e ".error")
if [ "$?" -eq "0" ]; then
# Error tag not null, so there's an error
trace "[send_to_bitcoin_node] Node responded, error found in response: ${errorstring}"
returncode=1
else
trace "[send_to_bitcoin_node] Node responded, no error found in response, yayy!"
fi
fi
# Output response to stdout before exiting with return code
echo "${result}"
trace_rc ${returncode}
return ${returncode}
}
case "${0}" in *sendtobitcoinnode.sh) send_to_bitcoin_node $@;; esac

View File

@@ -0,0 +1,12 @@
#!/bin/sh
. ./trace.sh
sql()
{
trace "sqlite3 ${DB_FILE} '${1}'"
sqlite3 -cmd ".timeout 20000" ${DB_FILE} "${1}"
return $?
}
case "${0}" in *sql.sh) sql $@;; esac

View File

@@ -0,0 +1,15 @@
#!/bin/sh
export PROXY_LISTENING_PORT
export WATCHER_NODE_RPC_URL=$WATCHER_BTC_NODE_RPC_URL
export SPENDER_NODE_RPC_URL=$SPENDER_BTC_NODE_RPC_URL
export TRACING
export DB_PATH
export DB_FILE
if [ ! -e ${DB_FILE} ]; then
echo "DB not found, creating..." > /dev/stderr
cat watching.sql | sqlite3 $DB_FILE
fi
nc -vlkp${PROXY_LISTENING_PORT} -e ./requesthandler.sh

View File

@@ -0,0 +1,9 @@
#!/bin/sh
read line
echo ${line} > /dev/stderr
echo -ne "HTTP/1.1 200 OK\r\n"
echo -e "Content-Type: application/json\r\nContent-Length: 0\r\n\r\n"
# Small delay needed for the data to be processed correctly by peer
sleep 0.5s

View File

@@ -0,0 +1,322 @@
#!/bin/sh
tests()
{
local address
local address1
local address2
local address3
local response
# getbestblockhash
# (GET) http://cyphernode:8888/getbestblockhash
echo "Testing getbestblockhash..."
response=$(curl -s cyphernode:8888/getbestblockhash)
echo "response=${response}"
local blockhash=$(echo ${response} | jq ".result" | tr -d '\"')
echo "blockhash=${blockhash}"
if [ -z "${blockhash}" ]; then
exit 2
fi
echo "Tested getbestblockhash."
# getbestblockinfo
# curl (GET) http://cyphernode:8888/getbestblockinfo
echo "Testing getbestblockinfo..."
response=$(curl -s cyphernode:8888/getbestblockinfo)
echo "response=${response}"
local blockhash2=$(echo ${response} | jq ".result.hash" | tr -d '\"')
echo "blockhash2=${blockhash2}"
if [ "${blockhash2}" != "${blockhash}" ]; then
exit 4
fi
echo "Tested getbestblockinfo."
# getblockinfo
# (GET) http://cyphernode:8888/getblockinfo/000000006f82a384c208ecfa04d05beea02d420f3f398ddda5c7f900de5718ea
echo "Testing getblockinfo..."
response=$(curl -s cyphernode:8888/getblockinfo/${blockhash})
echo "response=${response}"
blockhash2=$(echo ${response} | jq ".result.hash" | tr -d '\"')
echo "blockhash2=${blockhash2}"
if [ "${blockhash2}" != "${blockhash}" ]; then
exit 6
fi
echo "Tested getblockinfo."
# gettransaction
# (GET) http://cyphernode:8888/gettransaction/af867c86000da76df7ddb1054b273ca9e034e8c89d049b5b2795f9f590f67648
echo "Testing gettransaction..."
response=$(curl -s cyphernode:8888/gettransaction/af867c86000da76df7ddb1054b273ca9e034e8c89d049b5b2795f9f590f67648)
echo "response=${response}"
local txid=$(echo ${response} | jq ".result.txid" | tr -d '\"')
echo "txid=${txid}"
if [ "${txid}" != "af867c86000da76df7ddb1054b273ca9e034e8c89d049b5b2795f9f590f67648" ]; then
exit 8
fi
echo "Tested gettransaction."
# getnewaddress
# (GET) http://cyphernode:8888/getnewaddress
# returns {"address":"2MuiUu8AyuByAGYRDAqqhdYxt8gXcsQ1Ymw"}
echo "Testing getnewaddress..."
response=$(curl -s cyphernode:8888/getnewaddress)
echo "response=${response}"
address1=$(echo ${response} | jq ".address" | tr -d '\"')
echo "address1=${address1}"
if [ -z "${address1}" ]; then
exit 10
fi
address2=$(curl -s cyphernode:8888/getnewaddress | jq ".address" | tr -d '\"')
echo "address2=${address2}"
echo "Tested getnewaddress."
# getbalance
# (GET) http://cyphernode:8888/getbalance
echo "Testing getbalance..."
response=$(curl -s cyphernode:8888/getbalance)
echo "response=${response}"
local balance=$(echo ${response} | jq ".balance")
echo "balance=${balance}"
if [ -z "${balance}" ]; then
exit 12
fi
echo "Tested getbalance."
# watch
# POST http://cyphernode:8888/watch
# BODY {"address":"2N8DcqzfkYi8CkYzvNNS5amoq3SbAcQNXKp","unconfirmedCallbackURL":"192.168.122.233:1111/callback0conf","confirmedCallbackURL":"192.168.122.233:1111/callback1conf"}
echo "Testing watch..."
local url1="$(hostname):1111/callback0conf"
local url2="$(hostname):1111/callback1conf"
echo "url1=${url1}"
echo "url2=${url2}"
response=$(curl -s -H "Content-Type: application/json" -d "{\"address\":\"${address1}\",\"unconfirmedCallbackURL\":\"${url1}\",\"confirmedCallbackURL\":\"${url2}\"}" cyphernode:8888/watch)
echo "response=${response}"
local id=$(echo "${response}" | jq ".id" | tr -d '\"')
echo "id=${id}"
local event=$(echo "${response}" | jq ".event" | tr -d '\"')
echo "event=${event}"
if [ "${event}" != "watch" ]; then
exit 15
fi
address=$(echo "${response}" | jq ".address" | tr -d '\"')
echo "address=${address}"
if [ "${address}" != "${address1}" ]; then
exit 20
fi
local imported=$(echo "${response}" | jq ".imported" | tr -d '\"')
echo "imported=${imported}"
if [ "${imported}" != "1" ]; then
exit 30
fi
local inserted=$(echo "${response}" | jq ".inserted" | tr -d '\"')
echo "inserted=${inserted}"
if [ "${inserted}" != "1" ]; then
exit 40
fi
local unconfirmedCallbackURL=$(echo "${response}" | jq ".unconfirmedCallbackURL" | tr -d '\"')
echo "unconfirmedCallbackURL=${unconfirmedCallbackURL}"
if [ "${unconfirmedCallbackURL}" != "${url1}" ]; then
exit 60
fi
local confirmedCallbackURL=$(echo "${response}" | jq ".confirmedCallbackURL" | tr -d '\"')
echo "confirmedCallbackURL=${confirmedCallbackURL}"
if [ "${confirmedCallbackURL}" != "${url2}" ]; then
exit 70
fi
# Let's watch another address just to be able to test unwatch later and test if found in getactivewatches
response=$(curl -s -H "Content-Type: application/json" -d "{\"address\":\"${address2}\",\"unconfirmedCallbackURL\":\"${url1}2\",\"confirmedCallbackURL\":\"${url2}2\"}" cyphernode:8888/watch)
echo "response=${response}"
echo "Tested watch."
# getactivewatches
# (GET) http://cyphernode:8888/getactivewatches
echo "Testing getactivewatches..."
response=$(curl -s cyphernode:8888/getactivewatches)
echo "response=${response}"
response=$(echo ${response} | jq ".watches[]")
echo "response=${response}"
local id2=$(echo ${response} | jq "select(.address == \"${address1}\") | .id" | tr -d '\"')
echo "id2=${id2}"
if [ "${id2}" != "${id}" ]; then
exit 80
fi
id2=$(echo ${response} | jq "select(.address == \"${address2}\") | .id" | tr -d '\"')
echo "id2=${id2}"
if [ -z "${id2}" ]; then
exit 90
fi
echo "Tested getactivewatches."
# unwatch
# (GET) http://cyphernode:8888/unwatch/2N8DcqzfkYi8CkYzvNNS5amoq3SbAcQNXKp
echo "Testing unwatch..."
response=$(curl -s cyphernode:8888/unwatch/${address2})
echo "response=${response}"
event=$(echo "${response}" | jq ".event" | tr -d '\"')
echo "event=${event}"
if [ "${event}" != "unwatch" ]; then
exit 100
fi
address=$(echo "${response}" | jq ".address" | tr -d '\"')
echo "address=${address}"
if [ "${address}" != "${address2}" ]; then
exit 110
fi
response=$(curl -s cyphernode:8888/getactivewatches)
echo "response=${response}"
response=$(echo "${response}" | jq ".watches[]")
echo "response=${response}"
id2=$(echo ${response} | jq "select(.address == \"${address2}\") | .id" | tr -d '\"')
echo "id2=${id2}"
if [ -n "${id2}" ]; then
exit 120
fi
echo "Tested unwatch."
# deriveindex
# (GET) http://cyphernode:8888/deriveindex/25-30
# {"addresses":[{"address":"2N6Q9kBcLtNswgMSLSQ5oduhbctk7hxEJW8"},{"address":"2NFLhFghAPKEPuZCKoeXYYxuaBxhKXbmhBV"},{"address":"2N7gepbQtRM5Hm4PTjvGadj9wAwEwnAsKiP"},{"address":"2Mth8XDZpXkY9d95tort8HYEAuEesow2tF6"},{"address":"2MwqEmAXhUw6H7bJwMhD13HGWVEj2HgFiNH"},{"address":"2N2Y4BVRdrRFhweub2ehHXveGZC3nryMEJw"}]}
echo "Testing deriveindex..."
response=$(curl -v cyphernode:8888/deriveindex/25-30)
echo "response=${response}"
local nbaddr=$(echo "${response}" | jq ".addresses | length")
if [ "${nbaddr}" -ne "6" ]; then
exit 130
fi
address=$(echo "${response}" | jq ".addresses[2].address" | tr -d '\"')
if [ "${address}" != "2N7gepbQtRM5Hm4PTjvGadj9wAwEwnAsKiP" ]; then
exit 140
fi
echo "Tested deriveindex."
# derivepubpath
# (GET) http://cyphernode:8888/derivepubpath
# BODY {"pub32":"upub5GtUcgGed1aGH4HKQ3vMYrsmLXwmHhS1AeX33ZvDgZiyvkGhNTvGd2TA5Lr4v239Fzjj4ZY48t6wTtXUy2yRgapf37QHgt6KWEZ6bgsCLpb","path":"0/25-30"}
# {"addresses":[{"address":"2N6Q9kBcLtNswgMSLSQ5oduhbctk7hxEJW8"},{"address":"2NFLhFghAPKEPuZCKoeXYYxuaBxhKXbmhBV"},{"address":"2N7gepbQtRM5Hm4PTjvGadj9wAwEwnAsKiP"},{"address":"2Mth8XDZpXkY9d95tort8HYEAuEesow2tF6"},{"address":"2MwqEmAXhUw6H7bJwMhD13HGWVEj2HgFiNH"},{"address":"2N2Y4BVRdrRFhweub2ehHXveGZC3nryMEJw"}]}
echo "Testing derivepubpath..."
response=$(curl -v -H "Content-Type: application/json" -d "{\"pub32\":\"upub5GtUcgGed1aGH4HKQ3vMYrsmLXwmHhS1AeX33ZvDgZiyvkGhNTvGd2TA5Lr4v239Fzjj4ZY48t6wTtXUy2yRgapf37QHgt6KWEZ6bgsCLpb\",\"path\":\"0/25-30\"}" cyphernode:8888/derivepubpath)
echo "response=${response}"
local nbaddr=$(echo "${response}" | jq ".addresses | length")
if [ "${nbaddr}" -ne "6" ]; then
exit 150
fi
address=$(echo "${response}" | jq ".addresses[2].address" | tr -d '\"')
if [ "${address}" != "2N7gepbQtRM5Hm4PTjvGadj9wAwEwnAsKiP" ]; then
exit 160
fi
echo "Tested derivepubpath."
# spend
# POST http://cyphernode:8888/spend
# BODY {"address":"2N8DcqzfkYi8CkYzvNNS5amoq3SbAcQNXKp","amount":0.00233}
# By spending to a watched address, we will test the spending feature and trigger the confirmation to test
# confirmations of watched addresses... Cleva!!!
echo "Testing spend, conf and callbacks..."
response=$(curl -v -H "Content-Type: application/json" -d "{\"address\":\"${address1}\",\"amount\":0.00001}" cyphernode:8888/spend)
echo "response=${response}"
wait_for_callbacks
echo "Tested spend, conf and callbacks."
# addtobatch
# POST http://cyphernode:8888/addtobatch
# BODY {"address":"2N8DcqzfkYi8CkYzvNNS5amoq3SbAcQNXKp","amount":0.00233}
# By spending to a watched address, we will test the spending feature and trigger the confirmation to test
# confirmations of watched addresses... Cleva!!!
# echo "Testing addtobatch..."
# response=$(curl -v -H "Content-Type: application/json" -d "{\"address\":\"${address1}\",\"amount\":0.00001}" cyphernode:8888/spend)
# echo "response=${response}"
# wait_for_callbacks
# echo "Tested addtobatch ."
# conf
# (GET) http://cyphernode:8888/conf/b081ca7724386f549cf0c16f71db6affeb52ff7a0d9b606fb2e5c43faffd3387
# Let's trigger tx confirmation even if not confirmed. Will be funny. Should take care of
# multiple confirmations of the same state.
# executecallbacks
# (GET) http://cyphernode::8080/executecallbacks
#echo "GET /getbestblockinfo" | nc cyphernode:8888 - | sed -En "s/^(\{.*)/\1/p" | jq
# spend
# POST http://cyphernode:8888/spend
# BODY {"address":"2N8DcqzfkYi8CkYzvNNS5amoq3SbAcQNXKp","amount":0.00233}
#curl -v -H "Content-Type: application/json" -d '{"address":"2MsWyaQ8APbnqasFpWopqUKqsdpiVY3EwLE","amount":0.0001}' cyphernode:8888/spend
# ln_getinfo
# (GET) http://cyphernode:8888/ln_getinfo
echo "Testing ln_getinfo..."
response=$(curl -s cyphernode:8888/ln_getinfo)
echo "response=${response}"
local port=$(echo ${response} | jq ".binding[] | select(.type == \"ipv4\") | .port")
echo "port=${port}"
if [ "${port}" != "9735" ]; then
exit 170
fi
echo "Tested ln_getinfo."
# ln_newaddr
# (GET) http://cyphernode:8888/ln_newaddr
echo "Testing ln_newaddr..."
response=$(curl -s cyphernode:8888/ln_newaddr)
echo "response=${response}"
address=$(echo ${response} | jq ".address")
echo "address=${address}"
if [ -z "${address}" ]; then
exit 180
fi
echo "Tested ln_newaddr."
# ln_create_invoice
# POST http://cyphernode:8888/ln_create_invoice
# BODY {"msatoshi":"10000","label":"koNCcrSvhX3dmyFhW","description":"Bylls order #10649","expiry":"10"}
#echo "Testing ln_create_invoice..."
#response=$(curl -v -H "Content-Type: application/json" -d "{\"msatoshi\":10000,\"label\":\"koNCcrSvhX3dmyFhW\",\"description\":\"Bylls order #10649\",\"expiry\":10}" cyphernode:8888/ln_create_invoice)
#echo "response=${response}"
#echo "Tested ln_create_invoice."
# ln_pay
}
wait_for_callbacks()
{
nc -vlp1111 -e ./tests-cb.sh
nc -vlp1111 -e ./tests-cb.sh
}
tests

View File

@@ -0,0 +1,15 @@
#!/bin/sh
trace()
{
if [ -n "${TRACING}" ]; then
echo "$(date -Is) ${1}" > /dev/stderr
fi
}
trace_rc()
{
if [ -n "${TRACING}" ]; then
echo "$(date -Is) Last return code: ${1}" > /dev/stderr
fi
}

View File

@@ -0,0 +1,27 @@
#!/bin/sh
. ./trace.sh
. ./sql.sh
unwatchrequest()
{
trace "Entering unwatchrequest()..."
local request=${1}
local address=$(echo "${request}" | cut -d ' ' -f2 | cut -d '/' -f3)
local returncode
trace "[unwatchrequest] Unwatch request on address ${address})"
sql "UPDATE watching SET watching=0 WHERE address=\"${address}\""
returncode=$?
trace_rc ${returncode}
data="{\"event\":\"unwatch\",\"address\":\"${address}\"}"
trace "[unwatchrequest] responding=${data}"
echo "${data}"
return ${returncode}
}
case "${0}" in *unwatchrequest.sh) unwatchrequest $@;; esac

View File

@@ -0,0 +1,17 @@
#!/bin/sh
. ./trace.sh
get_prop()
{
trace "Entering get_prop()..."
local property=${1}
trace "[get_prop] property=${property}"
local value=$(grep "${property}" config.properties | cut -d'=' -f2)
trace "[get_prop] value=${value}"
echo ${value}
}

View File

@@ -0,0 +1,193 @@
#!/bin/sh
. ./trace.sh
. ./sendtobitcoinnode.sh
spend()
{
trace "Entering spend()..."
local data
local request=${1}
local address=$(echo "${request}" | jq ".address" | tr -d '"')
trace "[spend] address=${address}"
local amount=$(echo "${request}" | jq ".amount" | awk '{ printf "%.8f", $0 }')
trace "[spend] amount=${amount}"
local response
local id_inserted
response=$(send_to_spender_node "{\"method\":\"sendtoaddress\",\"params\":[\"${address}\",${amount}]}")
local returncode=$?
trace_rc ${returncode}
trace "[spend] response=${response}"
if [ "${returncode}" -eq 0 ]; then
local txid=$(echo ${response} | jq ".result" | tr -d '"')
trace "[spend] txid=${txid}"
# Let's insert the txid in our little DB to manage the confirmation and tell it's not a watching address
# sql "INSERT OR IGNORE INTO watching (watching, txid) VALUES (0, ${txid})"
sql "INSERT OR IGNORE INTO tx (txid) VALUES (\"${txid}\")"
trace_rc $?
id_inserted=$(sql "SELECT id FROM tx WHERE txid=\"${txid}\"")
trace_rc $?
sql "INSERT OR IGNORE INTO recipient (address, amount, tx_id) VALUES (\"${address}\", ${amount}, ${id_inserted})"
trace_rc $?
data="{\"status\":\"accepted\""
data="${data},\"hash\":\"${txid}\"}"
else
local message=$(echo "${response}" | jq -e ".error.message")
data="{\"message\":${message}}"
fi
trace "[spend] responding=${data}"
echo "${data}"
return ${returncode}
}
getbalance()
{
trace "Entering getbalance()..."
local response
local data='{"method":"getbalance"}'
response=$(send_to_spender_node "${data}")
local returncode=$?
trace_rc ${returncode}
trace "[getbalance] response=${response}"
if [ "${returncode}" -eq 0 ]; then
local balance=$(echo ${response} | jq ".result")
trace "[getbalance] balance=${balance}"
data="{\"balance\":${balance}}"
else
trace "[getbalance] Coudn't get balance!"
data=""
fi
trace "[getbalance] responding=${data}"
echo "${data}"
return ${returncode}
}
getnewaddress()
{
trace "Entering getnewaddress()..."
local response
local data='{"method":"getnewaddress"}'
response=$(send_to_spender_node "${data}")
local returncode=$?
trace_rc ${returncode}
trace "[getnewaddress] response=${response}"
if [ "${returncode}" -eq 0 ]; then
local address=$(echo ${response} | jq ".result")
trace "[getnewaddress] address=${address}"
data="{\"address\":${address}}"
else
trace "[getnewaddress] Coudn't get a new address!"
data=""
fi
trace "[getnewaddress] responding=${data}"
echo "${data}"
return ${returncode}
}
addtobatching()
{
trace "Entering addtobatching()..."
local address=${1}
trace "[addtobatching] address=${address}"
local amount=${2}
trace "[addtobatching] amount=${amount}"
sql "INSERT OR IGNORE INTO recipient (address, amount) VALUES (\"${address}\", ${amount})"
returncode=$?
trace_rc ${returncode}
return ${returncode}
}
batchspend()
{
trace "Entering batchspend()..."
local data
local response
local recipientswhere
local recipientsjson
local id_inserted
# We will batch all the addresses in DB without a TXID
local batching=$(sql 'SELECT address, amount FROM recipient WHERE tx_id IS NULL')
trace "[batchspend] batching=${batching}"
local returncode
local address
local amount
local notfirst=false
local IFS=$'\n'
for row in ${batching}
do
trace "[batchspend] row=${row}"
address=$(echo "${row}" | cut -d '|' -f1)
trace "[batchspend] address=${address}"
amount=$(echo "${row}" | cut -d '|' -f2)
trace "[batchspend] amount=${amount}"
if ${notfirst}; then
recipientswhere="${recipientswhere},"
recipientsjson="${recipientsjson},"
else
notfirst=true
fi
recipientswhere="${recipientswhere}\"${address}\""
recipientsjson="${recipientsjson}\"${address}\":${amount}"
done
response=$(send_to_spender_node "{\"method\":\"sendmany\",\"params\":[\"\", {${recipientsjson}}]}")
returncode=$?
trace_rc ${returncode}
trace "[batchspend] response=${response}"
if [ "${returncode}" -eq 0 ]; then
local txid=$(echo ${response} | jq ".result" | tr -d '"')
trace "[batchspend] txid=${txid}"
# Let's insert the txid in our little DB to manage the confirmation and tell it's not a watching address
# sql "INSERT OR IGNORE INTO watching (watching, txid) VALUES (0, ${txid})"
# trace_rc $?
sql "INSERT OR IGNORE INTO tx (txid) VALUES (\"${txid}\")"
returncode=$?
trace_rc ${returncode}
if [ "${returncode}" -eq 0 ]; then
id_inserted=$(sql "SELECT id FROM tx WHERE txid=\"${txid}\"")
trace "[batchspend] id_inserted: ${id_inserted}"
sql "UPDATE recipient SET tx_id=${id_inserted} WHERE address IN (${recipientswhere})"
trace_rc $?
fi
data="{\"status\":\"accepted\""
data="${data},\"hash\":\"${txid}\"}"
else
local message=$(echo "${response}" | jq -e ".error.message")
data="{\"message\":${message}}"
fi
trace "[batchspend] responding=${data}"
echo "${data}"
return ${returncode}
}
#case "${0}" in *walletoperations.sh) getbalance $@;; esac

View File

@@ -0,0 +1,75 @@
#!/bin/sh
. ./trace.sh
. ./importaddress.sh
. ./sql.sh
. ./sendtobitcoinnode.sh
watchrequest()
{
trace "Entering watchrequest()..."
local returncode
local request=${1}
local address=$(echo "${request}" | jq ".address" | tr -d '"')
local cb0conf_url=$(echo "${request}" | jq ".unconfirmedCallbackURL" | tr -d '"')
local cb1conf_url=$(echo "${request}" | jq ".confirmedCallbackURL" | tr -d '"')
local imported
local inserted
local id_inserted
local result
trace "[watchrequest] Watch request on address (${address}), cb 0-conf (${cb0conf_url}), cb 1-conf (${cb1conf_url})"
result=$(importaddress_rpc "${address}")
returncode=$?
trace_rc ${returncode}
if [ "${returncode}" -eq 0 ]; then
imported=1
else
imported=0
fi
# sql "INSERT OR IGNORE INTO watching (address, watching, callback0conf, callback1conf, imported) VALUES (\"${address}\", 1, \"${cb0conf_url}\", \"${cb1conf_url}\", ${imported})"
sql "INSERT OR IGNORE INTO watching (address, watching, callback0conf, callback1conf, imported) VALUES (\"${address}\", 1, \"${cb0conf_url}\", \"${cb1conf_url}\", ${imported})"
returncode=$?
trace_rc ${returncode}
if [ "${returncode}" -eq 0 ]; then
inserted=1
id_inserted=$(sql "SELECT id FROM watching WHERE address='${address}'")
trace "[watchrequest] id_inserted: ${id_inserted}"
else
inserted=0
fi
local fees2blocks
local fees6blocks
local fees36blocks
local fees144blocks
fees2blocks=$(getestimatesmartfee 2)
trace_rc $?
fees6blocks=$(getestimatesmartfee 6)
trace_rc $?
fees36blocks=$(getestimatesmartfee 36)
trace_rc $?
fees144blocks=$(getestimatesmartfee 144)
trace_rc $?
local data="{\"id\":\"${id_inserted}\",
\"event\":\"watch\",
\"imported\":\"${imported}\",
\"inserted\":\"${inserted}\",
\"address\":\"${address}\",
\"unconfirmedCallbackURL\":\"${cb0conf_url}\",
\"confirmedCallbackURL\":\"${cb1conf_url}\",
\"estimatesmartfee2blocks\":\"${fees2blocks}\",
\"estimatesmartfee6blocks\":\"${fees6blocks}\",
\"estimatesmartfee36blocks\":\"${fees36blocks}\",
\"estimatesmartfee144blocks\":\"${fees144blocks}\"}"
trace "[watchrequest] responding=${data}"
echo "${data}"
return ${returncode}
}
case "${0}" in *watchrequest.sh) watchrequest $@;; esac