First pass of LN payment callbacks

This commit is contained in:
kexkey
2019-01-08 16:01:49 -05:00
committed by kexkey
parent ef504bb27a
commit b719992a0c
10 changed files with 228 additions and 65 deletions

View File

@@ -30,7 +30,7 @@ COPY app/data/* ./
COPY app/script/* ./ COPY app/script/* ./
COPY --from=cyphernode/clightning:v0.6.2 /usr/bin/lightning-cli ./ COPY --from=cyphernode/clightning:v0.6.2 /usr/bin/lightning-cli ./
RUN chmod +x startproxy.sh requesthandler.sh lightning-cli sqlmigrate*.sh \ RUN chmod +x startproxy.sh requesthandler.sh lightning-cli sqlmigrate*.sh waitanyinvoice.sh \
&& chmod o+w . \ && chmod o+w . \
&& mkdir db && mkdir db

View File

@@ -26,7 +26,7 @@ COPY app/data/* ./
COPY app/script/* ./ COPY app/script/* ./
COPY --from=cyphernode/clightning:v0.6.2 /usr/bin/lightning-cli ./ COPY --from=cyphernode/clightning:v0.6.2 /usr/bin/lightning-cli ./
RUN chmod +x startproxy.sh requesthandler.sh lightning-cli sqlmigrate*.sh \ RUN chmod +x startproxy.sh requesthandler.sh lightning-cli sqlmigrate*.sh waitanyinvoice.sh \
&& chmod o+w . \ && chmod o+w . \
&& mkdir db && mkdir db

View File

@@ -87,3 +87,16 @@ CREATE TABLE cyphernode_props (
CREATE INDEX idx_cp_property ON cyphernode_props (property); CREATE INDEX idx_cp_property ON cyphernode_props (property);
INSERT INTO cyphernode_props (property, value) VALUES ("version", "0.1"); INSERT INTO cyphernode_props (property, value) VALUES ("version", "0.1");
INSERT INTO cyphernode_props (property, value) VALUES ("pay_index", "0");
CREATE TABLE ln_invoice (
id INTEGER PRIMARY KEY AUTOINCREMENT,
bolt11 TEXT UNIQUE,
status TEXT,
callback_url TEXT,
calledback INTEGER DEFAULT FALSE,
callback_failed INTEGER DEFAULT FALSE,
inserted_ts INTEGER DEFAULT CURRENT_TIMESTAMP
)
CREATE INDEX idx_lninvoice_bolt11 ON ln_invoice (bolt11);
CREATE INDEX idx_lninvoice_status ON ln_invoice (status);

View File

@@ -0,0 +1,10 @@
#!/bin/sh
exists=$(sqlite3 db/proxydb "SELECT value FROM cyphernode_props WHERE property='pay_index'")
if [ -z "${exists}" ]; then
# pay_index not found, let's migrate
echo "Migrating database from v0.1 to v0.2..."
cat sqlmigrate20190104_0.1-0.2.sql | sqlite3 $DB_FILE
else
echo "Database v0.1 to v0.2 migration already done, skipping!"
fi

View File

@@ -0,0 +1,15 @@
PRAGMA foreign_keys = ON;
INSERT INTO cyphernode_props (property, value) VALUES ("pay_index", "0");
CREATE TABLE ln_invoice (
id INTEGER PRIMARY KEY AUTOINCREMENT,
bolt11 TEXT UNIQUE,
status TEXT,
callback_url TEXT,
calledback INTEGER DEFAULT FALSE,
callback_failed INTEGER DEFAULT FALSE,
inserted_ts INTEGER DEFAULT CURRENT_TIMESTAMP
);
CREATE INDEX idx_lninvoice_bolt11 ON ln_invoice (bolt11);
CREATE INDEX idx_lninvoice_status ON ln_invoice (status);

View File

@@ -4,99 +4,114 @@
ln_create_invoice() ln_create_invoice()
{ {
trace "Entering ln_create_invoice()..." trace "Entering ln_create_invoice()..."
local result local result
local request=${1} local request=${1}
local msatoshi=$(echo "${request}" | jq ".msatoshi" | tr -d '"') local msatoshi=$(echo "${request}" | jq ".msatoshi" | tr -d '"')
trace "[ln_create_invoice] msatoshi=${msatoshi}" trace "[ln_create_invoice] msatoshi=${msatoshi}"
local label=$(echo "${request}" | jq ".label") local label=$(echo "${request}" | jq ".label")
trace "[ln_create_invoice] label=${label}" trace "[ln_create_invoice] label=${label}"
local description=$(echo "${request}" | jq ".description") local description=$(echo "${request}" | jq ".description")
trace "[ln_create_invoice] description=${description}" trace "[ln_create_invoice] description=${description}"
local expiry=$(echo "${request}" | jq ".expiry" | tr -d '"') local expiry=$(echo "${request}" | jq ".expiry" | tr -d '"')
trace "[ln_create_invoice] expiry=${expiry}" trace "[ln_create_invoice] expiry=${expiry}"
local callback_url=$(echo "${request}" | jq ".callback_url" | tr -d '"')
trace "[ln_create_invoice] callback_url=${callback_url}"
result=$(./lightning-cli invoice ${msatoshi} "${label}" "${description}" ${expiry}) #/proxy $ ./lightning-cli invoice 10000 "t1" "t1d" 60
returncode=$? #{
trace_rc ${returncode} # "payment_hash": "a74e6cccb06e26bcddc32c43674f9c3cf6b018a4cb9e9ff7f835cc59b091ae06",
trace "[ln_create_invoice] result=${result}" # "expires_at": 1546648644,
# "bolt11": "lnbc100n1pwzllqgpp55a8xen9sdcntehwr93pkwnuu8nmtqx9yew0flalcxhx9nvy34crqdq9wsckgxqzpucqp2rzjqt04ll5ft3mcuy8hws4xcku2pnhma9r9mavtjtadawyrw5kgzp7g7zr745qq3mcqqyqqqqlgqqqqqzsqpcr85k33shzaxscpj29fadmjmfej6y2p380x9w4kxydqpxq87l6lshy69fry9q2yrtu037nt44x77uhzkdyn8043n5yj8tqgluvmcl69cquaxr68"
#}
echo "${result}" result=$(./lightning-cli invoice ${msatoshi} "${label}" "${description}" ${expiry})
returncode=$?
trace_rc ${returncode}
trace "[ln_create_invoice] result=${result}"
return ${returncode} local bolt11
bolt11=$(echo ${result} | jq ".bolt11" | tr -d '"')
trace "[ln_create_invoice] bolt11=${bolt11}"
sql "INSERT OR IGNORE INTO ln_invoice (bolt11, callback_url) VALUES (\"${bolt11}\", \"${callback_url}\")"
trace_rc $?
echo "${result}"
return ${returncode}
} }
ln_getinfo() ln_getinfo()
{ {
trace "Entering ln_get_info()..." trace "Entering ln_get_info()..."
local result local result
result=$(./lightning-cli getinfo) result=$(./lightning-cli getinfo)
returncode=$? returncode=$?
trace_rc ${returncode} trace_rc ${returncode}
trace "[ln_getinfo] result=${result}" trace "[ln_getinfo] result=${result}"
echo "${result}" echo "${result}"
return ${returncode} return ${returncode}
} }
ln_pay() { ln_pay() {
trace "Entering ln_pay()..." trace "Entering ln_pay()..."
local result local result
local request=${1} local request=${1}
local bolt11=$(echo "${request}" | jq ".bolt11" | tr -d '"') local bolt11=$(echo "${request}" | jq ".bolt11" | tr -d '"')
trace "[ln_pay] bolt11=${bolt11}" trace "[ln_pay] bolt11=${bolt11}"
local expected_msatoshi=$(echo "${request}" | jq ".expected_msatoshi") local expected_msatoshi=$(echo "${request}" | jq ".expected_msatoshi")
trace "[ln_pay] expected_msatoshi=${expected_msatoshi}" trace "[ln_pay] expected_msatoshi=${expected_msatoshi}"
local expected_description=$(echo "${request}" | jq ".expected_description") local expected_description=$(echo "${request}" | jq ".expected_description")
trace "[ln_pay] expected_description=${expected_description}" trace "[ln_pay] expected_description=${expected_description}"
result=$(./lightning-cli decodepay ${bolt11}) result=$(./lightning-cli decodepay ${bolt11})
local invoice_msatoshi=$(echo "${result}" | jq ".msatoshi") local invoice_msatoshi=$(echo "${result}" | jq ".msatoshi")
trace "[ln_pay] invoice_msatoshi=${invoice_msatoshi}" trace "[ln_pay] invoice_msatoshi=${invoice_msatoshi}"
local invoice_description=$(echo "${result}" | jq ".description") local invoice_description=$(echo "${result}" | jq ".description")
trace "[ln_pay] invoice_description=${invoice_description}" trace "[ln_pay] invoice_description=${invoice_description}"
if [ "${expected_msatoshi}" != "${invoice_msatoshi}" ]; then if [ "${expected_msatoshi}" != "${invoice_msatoshi}" ]; then
result="{\"result\":\"error\",\"expected_msatoshi\":${expected_msatoshi},\"invoice_msatoshi\":${invoice_msatoshi}}" result="{\"result\":\"error\",\"expected_msatoshi\":${expected_msatoshi},\"invoice_msatoshi\":${invoice_msatoshi}}"
returncode=1 returncode=1
elif [ "${expected_description}" != "${invoice_description}" ]; then elif [ "${expected_description}" != "${invoice_description}" ]; then
result="{\"result\":\"error\",\"expected_description\":${expected_description},\"invoice_description\":${invoice_description}}" result="{\"result\":\"error\",\"expected_description\":${expected_description},\"invoice_description\":${invoice_description}}"
returncode=1 returncode=1
else else
result=$(./lightning-cli pay ${bolt11}) result=$(./lightning-cli pay ${bolt11})
returncode=$? returncode=$?
trace_rc ${returncode} trace_rc ${returncode}
fi fi
trace "[ln_pay] result=${result}" trace "[ln_pay] result=${result}"
echo "${result}" echo "${result}"
return ${returncode} return ${returncode}
} }
ln_newaddr() ln_newaddr()
{ {
trace "Entering ln_newaddr()..." trace "Entering ln_newaddr()..."
local result local result
call_lightningd newaddr call_lightningd newaddr
result=$(./lightning-cli newaddr) result=$(./lightning-cli newaddr)
returncode=$? returncode=$?
trace_rc ${returncode} trace_rc ${returncode}
trace "[ln_newaddr] result=${result}" trace "[ln_newaddr] result=${result}"
echo "${result}" echo "${result}"
return ${returncode} return ${returncode}
} }
case "${0}" in *call_lightningd.sh) call_lightningd $@;; esac case "${0}" in *call_lightningd.sh) call_lightningd $@;; esac

View File

@@ -16,6 +16,7 @@ do_callbacks()
local returncode local returncode
local address local address
local url
local IFS=$'\n' local IFS=$'\n'
for row in ${callbacks} for row in ${callbacks}
do do
@@ -42,6 +43,27 @@ do_callbacks()
trace_rc $? trace_rc $?
fi fi
done done
callbacks=$(sql 'SELECT id, callback_url FROM ln_invoice WHERE NOT calledback AND callback_failed')
trace "[do_callbacks] ln_callbacks=${callbacks}"
for row in ${callbacks}
do
url=$(echo "${row}" | cut -d '|' -f2)
trace "[do_callbacks LN] url=${url}"
trace "[do_callbacks LN] curl -H \"X-Forwarded-Proto: https\" ${url}"
curl -H "X-Forwarded-Proto: https" ${url}
returncode=$?
if [ "${returncode}" -eq 0 ]; then
id=$(echo "${row}" | cut -d '|' -f1)
sql "UPDATE ln_invoice SET calledback=1,callback_failed=0 WHERE id=\"${id}\""
trace_rc $?
else
trace "[do_callbacks LN] callback failed: ${callback_url}"
fi
done
) 200>./.callbacks.lock ) 200>./.callbacks.lock
} }

View File

@@ -260,7 +260,7 @@ main()
;; ;;
ln_create_invoice) ln_create_invoice)
# POST http://192.168.111.152:8080/ln_create_invoice # POST http://192.168.111.152:8080/ln_create_invoice
# BODY {"msatoshi":"10000","label":"koNCcrSvhX3dmyFhW","description":"Bylls order #10649","expiry":"900"} # BODY {"msatoshi":"10000","label":"koNCcrSvhX3dmyFhW","description":"Bylls order #10649","expiry":"900","callback_url":"http://192.168.122.159"}
response=$(ln_create_invoice "${line}") response=$(ln_create_invoice "${line}")
response_to_client "${response}" ${?} response_to_client "${response}" ${?}

View File

@@ -45,4 +45,6 @@ chmod 0600 $DB_FILE
createCurlConfig ${WATCHER_BTC_NODE_RPC_CFG} ${WATCHER_BTC_NODE_RPC_USER} createCurlConfig ${WATCHER_BTC_NODE_RPC_CFG} ${WATCHER_BTC_NODE_RPC_USER}
createCurlConfig ${SPENDER_BTC_NODE_RPC_CFG} ${SPENDER_BTC_NODE_RPC_USER} createCurlConfig ${SPENDER_BTC_NODE_RPC_CFG} ${SPENDER_BTC_NODE_RPC_USER}
./waitanyinvoice.sh &
nc -vlkp${PROXY_LISTENING_PORT} -e ./requesthandler.sh nc -vlkp${PROXY_LISTENING_PORT} -e ./requesthandler.sh

View File

@@ -0,0 +1,86 @@
#!/bin/sh
. ./trace.sh
. ./sql.sh
ln_waitanyinvoice() {
trace "Entering ln_waitanyinvoice()..."
local lastpay_index=${1}
trace "[ln_waitanyinvoice] lastpay_index=${lastpay_index}"
local returncode
local result
local bolt11
local pay_index
local row
local id
local callback_url
#{
# "label": "Duvapk2OWvlmL3kf5GyDF",
# "bolt11": "lnbc1546230n1pwzanfspp5t5jr3rsjkh37986nzkta8kk0yyzam833l5e4an5nu6cyhjcjluwqdq9u2d2zxqr3jscqp2rzjqt04ll5ft3mcuy8hws4xcku2pnhma9r9mavtjtadawyrw5kgzp7g7zr745qq3mcqqyqqqqlgqqqqqzsqpclrjg6vtg4cmqj46przdgwp6rk0xmzfa7ga3wnm4h4evzxy3z32aqw77av65cz2mgcf02dak3vl25epq90dw289zz9x87dyjy6nqvchsq6p8nmj",
# "payment_hash": "5d24388e12b5e3e29f531597d3dacf2105dd9e31fd335ece93e6b04bcb12ff1c",
# "msatoshi": 154623000,
# "status": "paid",
# "pay_index": 12,
# "msatoshi_received": 154623000,
# "paid_at": 1546571113,
# "description": "...",
# "expires_at": 1546589056
#},
result=$(./lightning-cli waitanyinvoice ${lastpay_index})
returncode=$?
trace_rc ${returncode}
trace "[ln_waitanyinvoice] result=${result}"
bolt11=$(echo ${result} | jq ".bolt11" | tr -d '"')
pay_index=$(echo ${result} | jq ".pay_index" | tr -d '"')
row=$(sql "SELECT id, callback_url FROM ln_invoice WHERE NOT calledback AND bolt11=\"${bolt11}\"")
id=$(echo ${row} | cut -d '|' -f1)
callback_url=$(echo ${row} | cut -d '|' -f2)
if [ -z "${callback_url}" ]; then
# No callback url provided for that invoice
sql "UPDATE ln_invoice SET calledback=1 WHERE id=\"${id}\""
trace_rc $?
return
fi
ln_payment_callback ${callback_url}
returncode=$?
trace_rc ${returncode}
if [ "${returncode}" -eq 0 ]; then
sql "UPDATE ln_invoice SET calledback=1 WHERE id=\"${id}\""
trace_rc $?
else
trace "[ln_waitanyinvoice] callback failed: ${callback_url}"
sql "UPDATE ln_invoice SET callback_failed=1 WHERE id=\"${id}\""
trace_rc $?
fi
sql "UPDATE cyphernode_props SET value="${pay_index}" WHERE property=\"pay_index\""
}
ln_payment_callback() {
trace "Entering ln_payment_callback()..."
local url=${1}
trace "[ln_payment_callback] curl ${url}"
curl -H "X-Forwarded-Proto: https" ${url}
local returncode=$?
trace_rc ${returncode}
return ${returncode}
}
while :
do
pay_index=$(sql "SELECT value FROM cyphernode_props WHERE property='pay_index'")
trace "[waitanyinvoice] pay_index=${pay_index}"
ln_waitanyinvoice ${pay_index}
sleep 1
done