mirror of
https://github.com/aljazceru/cyphernode.git
synced 2025-12-17 04:35:14 +01:00
Support for Bitcoin Core labels for watched and new addresses
This commit is contained in:
@@ -9,7 +9,7 @@ Inserts the address, webhook URLs and eventMessage in the DB and imports the add
|
||||
```http
|
||||
POST http://cyphernode:8888/watch
|
||||
with body...
|
||||
{"address":"2N8DcqzfkYi8CkYzvNNS5amoq3SbAcQNXKp","unconfirmedCallbackURL":"192.168.111.233:1111/callback0conf","confirmedCallbackURL":"192.168.111.233:1111/callback1conf","eventMessage":"eyJib3VuY2VfYWRkcmVzcyI6IjJNdkEzeHIzOHIxNXRRZWhGblBKMVhBdXJDUFR2ZTZOamNGIiwibmJfY29uZiI6MH0K"}
|
||||
{"address":"2N8DcqzfkYi8CkYzvNNS5amoq3SbAcQNXKp","unconfirmedCallbackURL":"192.168.111.233:1111/callback0conf","confirmedCallbackURL":"192.168.111.233:1111/callback1conf","eventMessage":"eyJib3VuY2VfYWRkcmVzcyI6IjJNdkEzeHIzOHIxNXRRZWhGblBKMVhBdXJDUFR2ZTZOamNGIiwibmJfY29uZiI6MH0K","label":"myLabel"}
|
||||
```
|
||||
|
||||
Proxy response:
|
||||
@@ -23,6 +23,7 @@ Proxy response:
|
||||
"address": "2N8DcqzfkYi8CkYzvNNS5amoq3SbAcQNXKp",
|
||||
"unconfirmedCallbackURL": "192.168.133.233:1111/callback0conf",
|
||||
"confirmedCallbackURL": "192.168.133.233:1111/callback1conf",
|
||||
"label": "myLabel",
|
||||
"estimatesmartfee2blocks": "0.000010",
|
||||
"estimatesmartfee6blocks": "0.000010",
|
||||
"estimatesmartfee36blocks": "0.000010",
|
||||
@@ -721,6 +722,20 @@ GET http://cyphernode:8888/getnewaddress/legacy
|
||||
GET http://cyphernode:8888/getnewaddress/p2sh-segwit
|
||||
```
|
||||
|
||||
or
|
||||
|
||||
```http
|
||||
POST http://cyphernode:8888/getnewaddress
|
||||
with body...
|
||||
{"address_type":"bech32","label":"myLabel"}
|
||||
or
|
||||
{"label":"myLabel"}
|
||||
or
|
||||
{"address_type":"p2sh-segwit"}
|
||||
or
|
||||
{}
|
||||
```
|
||||
|
||||
Proxy response:
|
||||
|
||||
```json
|
||||
@@ -731,7 +746,9 @@ Proxy response:
|
||||
|
||||
```json
|
||||
{
|
||||
"address":"tb1ql7yvh3lmajxmaljsnsu3w8lhwczu963tvjfzpj"
|
||||
"address":"tb1ql7yvh3lmajxmaljsnsu3w8lhwczu963tvjfzpj",
|
||||
"label":"myLabel",
|
||||
"address_type":"bech32"
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
@@ -62,6 +62,9 @@ paths:
|
||||
eventMessage:
|
||||
description: "Will be part of the published message on confirmations"
|
||||
type: "string"
|
||||
label:
|
||||
description: "Label for this address that will be imported in Bitcoin Core"
|
||||
type: "string"
|
||||
responses:
|
||||
'200':
|
||||
description: "successfully created"
|
||||
@@ -1096,8 +1099,16 @@ paths:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/ApiResponseTemporarilyUnavailable'
|
||||
/getnewaddress:
|
||||
/getnewaddress/{address_type}:
|
||||
get:
|
||||
parameters:
|
||||
- in: "path"
|
||||
name: "address_type"
|
||||
description: "Address type"
|
||||
required: false
|
||||
schema:
|
||||
type: "string"
|
||||
enum: ["legacy", "p2sh-segwit", "bech32"]
|
||||
tags:
|
||||
- "spending wallet"
|
||||
- "core features"
|
||||
@@ -1114,6 +1125,57 @@ paths:
|
||||
properties:
|
||||
address:
|
||||
$ref: '#/components/schemas/TypeAddressString'
|
||||
address_type:
|
||||
type: "string"
|
||||
enum: ["legacy", "p2sh-segwit", "bech32"]
|
||||
'403':
|
||||
$ref: '#/components/schemas/ApiResponseNotAllowed'
|
||||
'503':
|
||||
description: "Resource temporarily unavailable"
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/ApiResponseTemporarilyUnavailable'
|
||||
/getnewaddress:
|
||||
post:
|
||||
tags:
|
||||
- "spending wallet"
|
||||
- "core features"
|
||||
summary: "Generates a new address on the spending wallet"
|
||||
description: "Generates a new address on the spending wallet. Useful to refill the spending wallet from cold wallet (ie Trezor)."
|
||||
operationId: "getSpendingWalletNewAddress"
|
||||
requestBody:
|
||||
description: "Bitcoin address properties"
|
||||
required: false
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: "object"
|
||||
properties:
|
||||
address_type:
|
||||
type: "string"
|
||||
enum: ["legacy", "p2sh-segwit", "bech32"]
|
||||
label:
|
||||
type: "string"
|
||||
responses:
|
||||
'200':
|
||||
description: "successfully got an address"
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: "object"
|
||||
required:
|
||||
- "address"
|
||||
properties:
|
||||
address:
|
||||
$ref: '#/components/schemas/TypeAddressString'
|
||||
address_type:
|
||||
type: "string"
|
||||
enum: ["legacy", "p2sh-segwit", "bech32"]
|
||||
label:
|
||||
type: "string"
|
||||
'400':
|
||||
$ref: '#/components/schemas/ApiResponseInvalidInput'
|
||||
'403':
|
||||
$ref: '#/components/schemas/ApiResponseNotAllowed'
|
||||
'503':
|
||||
@@ -2491,6 +2553,7 @@ components:
|
||||
- "unconfirmedCallbackURL"
|
||||
- "confirmedCallbackURL"
|
||||
- "eventMessage"
|
||||
- "label"
|
||||
properties:
|
||||
id:
|
||||
type: "string"
|
||||
@@ -2512,6 +2575,9 @@ components:
|
||||
description: "Async callback in case of activity on address"
|
||||
type: "string"
|
||||
format: "url"
|
||||
label:
|
||||
description: "Label for this address that will be imported in Bitcoin Core"
|
||||
type: "string"
|
||||
estimatesmartfee2blocks:
|
||||
type: "string"
|
||||
estimatesmartfee6blocks:
|
||||
|
||||
14
proxy_docker/app/data/sqlmigrate20210808_0.7.0-0.8.0.sh
Normal file
14
proxy_docker/app/data/sqlmigrate20210808_0.7.0-0.8.0.sh
Normal file
@@ -0,0 +1,14 @@
|
||||
#!/bin/sh
|
||||
|
||||
echo "Checking for labels for watched addresses support in DB..."
|
||||
count=$(sqlite3 $DB_FILE "select count(*) from pragma_table_info('watching') where name='label'")
|
||||
if [ "${count}" -eq "0" ]; then
|
||||
# label not there, we have to migrate
|
||||
echo "Migrating database for labels for watched addresses support..."
|
||||
echo "Backing up current DB..."
|
||||
cp $DB_FILE $DB_FILE-sqlmigrate20210808_0.7.0-0.8.0
|
||||
echo "Altering DB..."
|
||||
cat sqlmigrate20210808_0.7.0-0.8.0.sql | sqlite3 $DB_FILE
|
||||
else
|
||||
echo "Database labels for watched addresses support migration already done, skipping!"
|
||||
fi
|
||||
9
proxy_docker/app/data/sqlmigrate20210808_0.7.0-0.8.0.sql
Normal file
9
proxy_docker/app/data/sqlmigrate20210808_0.7.0-0.8.0.sql
Normal file
@@ -0,0 +1,9 @@
|
||||
PRAGMA foreign_keys=off;
|
||||
|
||||
BEGIN TRANSACTION;
|
||||
|
||||
ALTER TABLE watching ADD COLUMN label TEXT;
|
||||
|
||||
COMMIT;
|
||||
|
||||
PRAGMA foreign_keys=on;
|
||||
@@ -67,7 +67,7 @@ getactivewatches() {
|
||||
local watches
|
||||
# Let's build the string directly with sqlite instead of manipulating multiple strings afterwards, it's faster.
|
||||
# {"id":"${id}","address":"${address}","imported":"${imported}","unconfirmedCallbackURL":"${cb0conf_url}","confirmedCallbackURL":"${cb1conf_url}","watching_since":"${timestamp}"}
|
||||
watches=$(sql "SELECT '{\"id\":' || id || ',\"address\":\"' || address || '\",\"imported\":' || imported || ',\"unconfirmedCallbackURL\":\"' || COALESCE(callback0conf, '') || '\",\"confirmedCallbackURL\":\"' || COALESCE(callback1conf, '') || '\",\"watching_since\":\"' || inserted_ts || '\"}' FROM watching WHERE watching AND NOT calledback1conf")
|
||||
watches=$(sql "SELECT '{\"id\":' || id || ',\"address\":\"' || address || '\",\"imported\":' || imported || ',\"unconfirmedCallbackURL\":\"' || COALESCE(callback0conf, '') || '\",\"confirmedCallbackURL\":\"' || COALESCE(callback1conf, '') || '\",\"label\":\"' || COALESCE(label, '') || '\",\"watching_since\":\"' || inserted_ts || '\"}' FROM watching WHERE watching AND NOT calledback1conf")
|
||||
returncode=$?
|
||||
trace_rc ${returncode}
|
||||
|
||||
|
||||
@@ -7,7 +7,12 @@ importaddress_rpc() {
|
||||
trace "[Entering importaddress_rpc()]"
|
||||
|
||||
local address=${1}
|
||||
local data="{\"method\":\"importaddress\",\"params\":[\"${address}\",\"\",false]}"
|
||||
local label=${2}
|
||||
if [ -z "${label}" ]; then
|
||||
label="null"
|
||||
fi
|
||||
local data='{"method":"importaddress","params":{"address":"'${address}'","label":'${label}',"rescan":false}}'
|
||||
# local data="{\"method\":\"importaddress\",\"params\":[\"${address}\",\"\",false]}"
|
||||
local result
|
||||
result=$(send_to_watcher_node ${data})
|
||||
local returncode=$?
|
||||
|
||||
@@ -11,15 +11,17 @@ manage_not_imported() {
|
||||
|
||||
trace "[Entering manage_not_imported()]"
|
||||
|
||||
local watches=$(sql 'SELECT address FROM watching WHERE watching AND NOT imported')
|
||||
local watches=$(sql 'SELECT address, label FROM watching WHERE watching AND NOT imported')
|
||||
trace "[manage_not_imported] watches=${watches}"
|
||||
|
||||
local result
|
||||
local returncode
|
||||
local IFS=$'\n'
|
||||
for address in ${watches}
|
||||
for row in ${watches}
|
||||
do
|
||||
result=$(importaddress_rpc "${address}")
|
||||
address=$(echo "${row}" | cut -d '|' -f1)
|
||||
label=$(echo "${row}" | cut -d '|' -f2)
|
||||
result=$(importaddress_rpc "${address}" "${label}")
|
||||
returncode=$?
|
||||
trace_rc ${returncode}
|
||||
if [ "${returncode}" -eq 0 ]; then
|
||||
|
||||
@@ -93,6 +93,7 @@ main() {
|
||||
# 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"}
|
||||
# BODY {"address":"2N8DcqzfkYi8CkYzvNNS5amoq3SbAcQNXKp","confirmedCallbackURL":"192.168.111.233:1111/callback1conf","eventMessage":"eyJib3VuY2VfYWRkcmVzcyI6IjJNdkEzeHIzOHIxNXRRZWhGblBKMVhBdXJDUFR2ZTZOamNGIiwibmJfY29uZiI6MH0K"}
|
||||
# BODY {"address":"2N8DcqzfkYi8CkYzvNNS5amoq3SbAcQNXKp","confirmedCallbackURL":"192.168.111.233:1111/callback1conf","eventMessage":"eyJib3VuY2VfYWRkcmVzcyI6IjJNdkEzeHIzOHIxNXRRZWhGblBKMVhBdXJDUFR2ZTZOamNGIiwibmJfY29uZiI6MH0K","label":"myLabel"}
|
||||
|
||||
response=$(watchrequest "${line}")
|
||||
response_to_client "${response}" ${?}
|
||||
@@ -328,8 +329,23 @@ main() {
|
||||
getnewaddress)
|
||||
# curl (GET) http://192.168.111.152:8080/getnewaddress
|
||||
# curl (GET) http://192.168.111.152:8080/getnewaddress/bech32
|
||||
#
|
||||
# or...
|
||||
# POST http://192.168.111.152:8080/getnewaddress
|
||||
# BODY {"address_type":"bech32","label":"myLabel"}
|
||||
# BODY {"label":"myLabel"}
|
||||
# BODY {"address_type":"p2sh-segwit"}
|
||||
# BODY {}
|
||||
|
||||
response=$(getnewaddress "$(echo "${line}" | cut -d ' ' -f2 | cut -d '/' -f3)")
|
||||
# Let's make it work even for a GET request (equivalent to a POST with empty json object body)
|
||||
if [ "$http_method" = "POST" ]; then
|
||||
address_type=$(echo "${line}" | jq -er ".addressType // empty")
|
||||
label=$(echo "${line}" | jq -er ".label // empty")
|
||||
else
|
||||
address_type=$(echo "${line}" | cut -d ' ' -f2 | cut -d '/' -f3)
|
||||
fi
|
||||
|
||||
response=$(getnewaddress "${address_type}" "${label}")
|
||||
response_to_client "${response}" ${?}
|
||||
break
|
||||
;;
|
||||
|
||||
@@ -270,13 +270,29 @@ getnewaddress() {
|
||||
local address_type=${1}
|
||||
trace "[getnewaddress] address_type=${address_type}"
|
||||
|
||||
local label=${2}
|
||||
trace "[getnewaddress] label=${label}"
|
||||
|
||||
local response
|
||||
local data
|
||||
if [ -z "${address_type}" ]; then
|
||||
data='{"method":"getnewaddress"}'
|
||||
else
|
||||
data="{\"method\":\"getnewaddress\",\"params\":[\"\",\"${address_type}\"]}"
|
||||
local jqop
|
||||
local addedfields
|
||||
local data='{"method":"getnewaddress"}'
|
||||
if [ -n "${address_type}" ] || [ -n "${label}" ]; then
|
||||
jqop='. += {"params":{}}'
|
||||
if [ -n "${label}" ]; then
|
||||
jqop=${jqop}' | .params += {"label":"'${label}'"}'
|
||||
addedfields=' | . += {"label":"'${label}'"}'
|
||||
fi
|
||||
if [ -n "${address_type}" ]; then
|
||||
jqop=${jqop}' | .params += {"address_type":"'${address_type}'"}'
|
||||
addedfields=' | . += {"address_type":"'${address_type}'"}'
|
||||
fi
|
||||
trace "[getnewaddress] jqop=${jqop}"
|
||||
|
||||
data=$(echo "${data}" | jq -rc "${jqop}")
|
||||
fi
|
||||
trace "[getnewaddress] data=${data}"
|
||||
|
||||
response=$(send_to_spender_node "${data}")
|
||||
local returncode=$?
|
||||
trace_rc ${returncode}
|
||||
@@ -286,7 +302,11 @@ getnewaddress() {
|
||||
local address=$(echo ${response} | jq ".result")
|
||||
trace "[getnewaddress] address=${address}"
|
||||
|
||||
data="{\"address\":${address}}"
|
||||
data='{"address":'${address}'}'
|
||||
if [ -n "${jqop}" ]; then
|
||||
data=$(echo "${data}" | jq -rc "${data}${addedfields}")
|
||||
trace "[getnewaddress] data=${data}"
|
||||
fi
|
||||
else
|
||||
trace "[getnewaddress] Coudn't get a new address!"
|
||||
data=""
|
||||
|
||||
@@ -15,6 +15,7 @@ watchrequest() {
|
||||
local cb0conf_url=$(echo "${request}" | jq ".unconfirmedCallbackURL")
|
||||
local cb1conf_url=$(echo "${request}" | jq ".confirmedCallbackURL")
|
||||
local event_message=$(echo "${request}" | jq ".eventMessage")
|
||||
local label=$(echo "${request}" | jq ".label")
|
||||
local imported
|
||||
local inserted
|
||||
local id_inserted
|
||||
@@ -23,7 +24,7 @@ watchrequest() {
|
||||
# Let's lowercase bech32 addresses
|
||||
address=$(lowercase_if_bech32 "${address}")
|
||||
|
||||
trace "[watchrequest] Watch request on address (\"${address}\"), cb 0-conf (${cb0conf_url}), cb 1-conf (${cb1conf_url}) with event_message=${event_message}"
|
||||
trace "[watchrequest] Watch request on address (\"${address}\"), cb 0-conf (${cb0conf_url}), cb 1-conf (${cb1conf_url}) with event_message=${event_message} and label=${label}"
|
||||
|
||||
local isvalid
|
||||
isvalid=$(validateaddress "${address}" | jq ".result.isvalid")
|
||||
@@ -38,6 +39,7 @@ watchrequest() {
|
||||
\"address\":\"${address}\",
|
||||
\"unconfirmedCallbackURL\":${cb0conf_url},
|
||||
\"confirmedCallbackURL\":${cb1conf_url},
|
||||
\"label\":${label},
|
||||
\"eventMessage\":${event_message}}}}"
|
||||
trace "[watchrequest] Invalid address"
|
||||
trace "[watchrequest] responding=${result}"
|
||||
@@ -47,7 +49,7 @@ watchrequest() {
|
||||
return 1
|
||||
fi
|
||||
|
||||
result=$(importaddress_rpc ${address})
|
||||
result=$(importaddress_rpc "${address}" "${label}")
|
||||
returncode=$?
|
||||
trace_rc ${returncode}
|
||||
if [ "${returncode}" -eq 0 ]; then
|
||||
@@ -56,7 +58,7 @@ watchrequest() {
|
||||
imported=0
|
||||
fi
|
||||
|
||||
sql "INSERT INTO watching (address, watching, callback0conf, callback1conf, imported, event_message) VALUES (\"${address}\", 1, ${cb0conf_url}, ${cb1conf_url}, ${imported}, ${event_message}) ON CONFLICT(address,callback0conf,callback1conf) DO UPDATE SET watching=1, event_message=${event_message}, calledback0conf=0, calledback1conf=0"
|
||||
sql "INSERT INTO watching (address, watching, callback0conf, callback1conf, imported, event_message, label) VALUES (\"${address}\", 1, ${cb0conf_url}, ${cb1conf_url}, ${imported}, ${event_message}, ${label}) ON CONFLICT(address,callback0conf,callback1conf) DO UPDATE SET watching=1, event_message=${event_message}, calledback0conf=0, calledback1conf=0, label=${label}"
|
||||
returncode=$?
|
||||
trace_rc ${returncode}
|
||||
|
||||
@@ -88,6 +90,7 @@ watchrequest() {
|
||||
\"address\":\"${address}\",
|
||||
\"unconfirmedCallbackURL\":${cb0conf_url},
|
||||
\"confirmedCallbackURL\":${cb1conf_url},
|
||||
\"label\":${label},
|
||||
\"estimatesmartfee2blocks\":${fees2blocks},
|
||||
\"estimatesmartfee6blocks\":${fees6blocks},
|
||||
\"estimatesmartfee36blocks\":${fees36blocks},
|
||||
|
||||
Reference in New Issue
Block a user