Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

elements peg in endpoints #331

Open
wants to merge 6 commits into
base: features/liquid2
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions api_auth_docker/api-sample.properties
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ action_ln_withdraw=spender
action_elements_deriveindex=spender
action_elements_derivepubpath=spender
action_elements_get_txns_spending=spender
action_elements_getbalance=spender
action_elements_getnewaddress=spender
action_elements_getwalletinfo=spender
action_elements_spend=spender
Expand All @@ -94,6 +95,9 @@ action_listbatchers=spender
action_getbatcher=spender
action_getbatchdetails=spender
action_bitcoin_generatetoaddress=spender
action_elements_getpeginaddress=spender
action_elements_claimpegin=spender
action_elements_sendtomainchain=spender

# Admin can do what the spender can do, plus:

Expand Down
4 changes: 4 additions & 0 deletions cyphernodeconf_docker/templates/gatekeeper/api.properties
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ action_ln_withdraw=spender
action_elements_deriveindex=spender
action_elements_derivepubpath=spender
action_elements_get_txns_spending=spender
action_elements_getbalance=spender
action_elements_getnewaddress=spender
action_elements_getwalletinfo=spender
action_elements_spend=spender
Expand All @@ -88,6 +89,9 @@ action_listbatchers=spender
action_getbatcher=spender
action_getbatchdetails=spender
action_bitcoin_generatetoaddress=spender
action_elements_getpeginaddress=spender
action_elements_claimpegin=spender
action_elements_sendtomainchain=spender

# Admin can do what the spender can do, plus:

Expand Down
44 changes: 44 additions & 0 deletions proxy_docker/app/script/elements_pegin.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
#!/bin/sh

. ./trace.sh
. ./sendtoelementsnode.sh

elements_getpeginaddress() {
trace "Entering elements_getpeginaddress()..."

local response
response=$(send_to_elements_spender_node "{\"method\":\"getpeginaddress\"}")

returncode=$?
trace_rc ${returncode}
trace "[elements_getpeginaddress] response=${response}"

echo "${response}"

return ${returncode}
}

elements_claimpegin() {
trace "Entering elements_claimpegin()..."

local request=${1}
local rawtx=$(echo "${request}" | jq -r ".rawtx")
trace "[elements_claimpegin] rawtx=${rawtx}"
local proof=$(echo "${request}" | jq -r ".proof")
trace "[elements_claimpegin] proof=${proof}"
local claim_script=$(echo "${request}" | jq -r ".claim_script")
trace "[elements_claimpegin] claim_script=${claim_script}"

local response
local returncode

response=$(send_to_elements_spender_node "{\"method\":\"claimpegin\",\"params\":[\"${rawtx}\",\"${proof}\",\"${claim_script}\"]}")
returncode=$?

trace_rc ${returncode}
trace "[elements_claimpegin] response=${response}"

echo "${response}"

return ${returncode}
}
27 changes: 27 additions & 0 deletions proxy_docker/app/script/elements_pegout.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
#!/bin/sh

. ./trace.sh
. ./sendtoelementsnode.sh

elements_sendtomainchain() {
trace "Entering elements_sendtomainchain()..."

local request=${1}
local address=$(echo "${request}" | jq -r ".address")
trace "[elements_sendtomainchain] address=${address}"
local amount=$(echo "${request}" | jq -r ".amount")
trace "[elements_sendtomainchain] amount=${amount}"
local subtractfeefromamount=$(echo "${request}" | jq -r ".subtractfeefromamount // false")
trace "[elements_sendtomainchain] subtractfeefromamount=${subtractfeefromamount}"

local response
response=$(send_to_elements_spender_node "{\"method\":\"sendtomainchain\",\"params\":[\"${address}\",${amount},${subtractfeefromamount}]}")

returncode=$?
trace_rc ${returncode}
trace "[elements_sendtomainchain] response=${response}"

echo "${response}"

return ${returncode}
}
28 changes: 28 additions & 0 deletions proxy_docker/app/script/requesthandler.sh
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@
. ./elements_walletoperations.sh
. ./elements_newblock.sh
. ./elements_getactivewatches.sh
. ./elements_pegin.sh
. ./elements_pegout.sh

main() {
trace "Entering main()..."
Expand Down Expand Up @@ -881,6 +883,12 @@ main() {
response=$(elements_newblock "${line}")
returncode=$?
;;
elements_getbalance)
# curl (GET) http://192.168.111.152:8080/elements_getbalance

response=$(elements_getbalance)
returncode=$?
;;
elements_gettransaction)
# curl (GET) http://192.168.111.152:8080/elements_gettransaction/7a45ba9de1f6fbd17e123762cd5b27f18a02a72d581d019abf1030e6a5677178

Expand Down Expand Up @@ -943,6 +951,26 @@ main() {
response=$(elements_get_mempool_info)
returncode=$?
;;
elements_getpeginaddress)
# curl GET http://192.168.111.152:8080/elements_getpeginaddress

response=$(elements_getpeginaddress)
returncode=$?
;;
elements_claimpegin)
# curl POST http://192.168.111.152:8080/elements_claimpegin
# BODY {"rawtx": "020000000...", "proof": "0080da266ad8...","claim_script":"0014857769bab984f1070e038930f8a6e2142d809f71"}

response=$(elements_claimpegin "${line}")
returncode=$?
;;
elements_sendtomainchain)
# curl POST http://192.168.111.152:8080/elements_sendtomainchain
# BODY {"address":"bc1qar0srrr7xfkvy5l643lydnw9re59gtzzwf5mdq","amount":0.001,"subtractfeefromamount":true}

response=$(elements_sendtomainchain "${line}")
returncode=$?
;;
*)
response='{"error": {"code": -32601, "message": "Method not found"}, "id": "1"}'
returncode=1
Expand Down
209 changes: 209 additions & 0 deletions proxy_docker/app/tests/test-elements-peg-in.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,209 @@
#!/bin/bash

DIR="$( dirname -- "${BASH_SOURCE[0]}"; )";
. $DIR/colors.sh
. $DIR/mine.sh

# This needs to be run in regtest
# You need jq installed for these tests to run correctly
#
# Something like rpcworkqueue=1000 in bitcoin.conf is recommended due to the number of blocks we mine

# This will test the elements peg in and claim functionality
#
# - getpeginaddress
# - watchtx
# - executecallbacks
# - claimpegin
#

trace() {
if [ "${1}" -le "${TRACING}" ]; then
echo -e "$(date -u +%FT%TZ) ${2}" 1>&2
fi
}

create_cb_server() {
trace 1 "\n\n[create_cb_server] ${BCyan}Creating cb-server.sh...${Color_Off}\n"

local cbserver_b64
cbserver_b64=$(echo '#!/bin/sh

lookingfor=$1
returncode=0

a=$(timeout 1 tee)

echo -en "\033[40m\033[0;37m" >&2
date >&2
echo "$a" >&2

case "$a" in
*$lookingfor*)
echo -e "\033[42m\033[0;30m Found \"$lookingfor\" in request! \033[40m" >&2
found=true
;;
esac

echo -e "\033[0m" >&2

if [ "$found" = "true" ]; then
echo -en "HTTP/1.1 200 OK\r\n\r\n"
else
echo -en "HTTP/1.1 404 NOT FOUND\r\n\r\n"
returncode=1
fi
echo -en "$a"

return ${returncode}
' | base64)

local execcmd=("sh" "-c" "echo \"${cbserver_b64}\" | base64 -d > cb-server.sh && chmod +x cb-server.sh")
exec_in_test_container "${execcmd[@]}"

trace 1 "\n\n[create_cb_server] ${BCyan}Created cb-server.sh...${Color_Off}\n"
}

start_test_container() {
docker run -d --rm -t --name tests-elements-peg-in --network=cyphernodenet alpine:3.15.4
}

stop_test_container() {
trace 1 "\n\n[stop_test_container] ${BCyan}Stopping existing containers if they are running...${Color_Off}\n"

# docker stop tests-elements-peg-in
local containers=$(docker ps -q -f "name=tests-elements-peg-in")
if [ -n "${containers}" ]; then
docker stop ${containers}
fi
}

exec_in_test_container() {
docker exec -it tests-elements-peg-in "$@"
}

exec_in_test_container_nonint() {
docker exec -t tests-elements-peg-in "$@"
}

wait_for_broker() {
trace 1 "\n\n[wait_for_broker] ${BCyan}Waiting for the broker to be ready...${Color_Off}\n"

# First ping the containers to make sure they're up...
docker exec -t tests-elements-peg-in sh -c 'while true ; do ping -c 1 broker ; [ "$?" -eq "0" ] && break ; sleep 5; done'
}

test_elements_peg_in() {
# 1. (elements) Get new peg in address
# 2. (bitcoin) sendtoaddress
# 3. (bitcoin) Watch txid for 102 confirmations
# 4. (bitcoin) Mine 102 blocks
# 5. (elements) Claim peg in
# 6. (elements) Mine a new block
# 7. (elements) Check balance

trace 2 "[test_elements_peg_in] Check initial balance..."
response=$(exec_in_test_container curl proxy:8888/elements_getbalance)
trace 3 "[test_elements_peg_in] response=${response}"

local startbalance=$(echo "${response}" | jq -r ".balance.bitcoin")
trace 3 "[test_elements_peg_in] startbalance=${startbalance}"

local id0=$RANDOM
local id1=$RANDOM

local port0=${id0}
local port1=${id1}

local callbackurl1conf="http://${callbackservername}:${port1}/callbackurl1conf"
local callbackurlnconf="http://${callbackservername}:${port1}/callbackurlnconf"

trace 1 "\n[test_elements_peg_in] ${BCyan}Let's peg in!...${Color_Off}"

# 1. (elements) Get new peg in address
trace 2 "[test_elements_peg_in] getpeginaddress..."
local response=$(exec_in_test_container curl proxy:8888/elements_getpeginaddress)
trace 3 "[test_elements_peg_in] response=${response}"
local mainchain_address=$(echo "${response}" | jq -r ".result.mainchain_address")
trace 3 "[test_elements_peg_in] mainchain_address=${mainchain_address}"
local claim_script=$(echo "${response}" | jq -r ".result.claim_script")
trace 3 "[test_elements_peg_in] claim_script=${claim_script}"

mine 101 > /dev/null 2>&1

# 2. (bitcoin) sendtoaddress
trace 2 "[test_elements_peg_in] Sending coins to peg in address..."
txid=$(docker exec -it $(docker ps -q -f "name=cyphernode.bitcoin") bitcoin-cli -rpcwallet=spending01.dat sendtoaddress ${mainchain_address} 0.1 | tr -d "\r\n")
trace 3 "[test_elements_peg_in] txid=${txid}"

# 3. (bitcoin) Watch txid for 102 confirmations
trace 2 "[test_elements_peg_in] watch it..."
local data='{"txid":"'${txid}'","confirmedCallbackURL":"'${callbackurl1conf}'","xconfCallbackURL":"'${callbackurlnconf}'","nbxconf":102}'
trace 3 "[test_elements_peg_in] data=${data}"
response=$(exec_in_test_container curl -d "${data}" proxy:8888/watchtxid)
trace 3 "[test_elements_peg_in] response=${response}"

# 4. (bitcoin) Mine 102 blocks
trace 3 "[test_elements_peg_in] Mine 102 blocks..."
mine 102 > /dev/null 2>&1

trace 2 "[test_elements_peg_in] Start callback server for 102-conf webhook..."
start_callback_server $port1 "102"

trace 3 "[test_elements_peg_in] Waiting for 102-conf callbacks on txid..."

# 5. (elements) Claim peg in
local txoutproof=$(docker exec -it $(docker ps -q -f "name=cyphernode.bitcoin") bitcoin-cli -rpcwallet=spending01.dat gettxoutproof '["'${txid}'"]' | tr -d "\r\n")
trace 3 "[test_elements_peg_in] txoutproof=${txoutproof}"

local txhex=$(docker exec -it $(docker ps -q -f "name=cyphernode.bitcoin") bitcoin-cli -rpcwallet=spending01.dat getrawtransaction ${txid} | tr -d "\r\n")
trace 3 "[test_elements_peg_in] txhex=${txhex}"

trace 2 "[test_elements_peg_in] claimpegin..."
local data='{"proof":"'${txoutproof}'","rawtx":"'${txhex}'","claim_script":"'${claim_script}'"}'
trace 3 "[test_elements_peg_in] data=${data}"
response=$(exec_in_test_container curl -d "${data}" proxy:8888/elements_claimpegin)
trace 3 "[test_elements_peg_in] response=${response}"

# 6. (elements) Mine a new block
trace 2 "[test_elements_peg_in] Mine a block..."
elements_mine

# 7. (elements) Check balance
trace 2 "[test_elements_peg_in] Check balance..."
response=$(exec_in_test_container curl proxy:8888/elements_getbalance)
trace 3 "[test_elements_peg_in] response=${response}"

local balance=$(echo "${response}" | jq -r ".balance.bitcoin")
if [ $(echo "${balance} > ${startbalance}" | bc -l) -eq 1 ]; then
trace 1 "\n\n[test_elements_peg_in] ${On_IGreen}${BBlack} 1. elements_getbalance success! ${Color_Off}\n"
return 0
else
trace 1 "\n\n[test_elements_peg_in] ${On_Red}${BBlack} 1. elements_getbalance failed! ${Color_Off}\n"
return 10
fi
}

start_callback_server() {
trace 1 "\n\n[start_callback_server] ${BCyan}Let's start a callback server!...${Color_Off}\n"

local port expected_text
port=${1:-${callbackserverport}}
expected_text=$2

exec_in_test_container_nonint sh -c 'nc -vlp'${port}' -e ./cb-server.sh '${expected_text}' ; echo "::$?::"'
}

TRACING=3

stop_test_container
start_test_container

exec_in_test_container apk add --update curl

create_cb_server
callbackservername="tests-elements-peg-in"

test_elements_peg_in

stop_test_container