2017-06-20 17:15:25 +02:00
# include <bitcoin/address.h>
# include <bitcoin/base58.h>
# include <bitcoin/script.h>
# include <ccan/tal/str/str.h>
2017-12-11 04:43:11 +01:00
# include <common/bech32.h>
2017-08-28 18:05:01 +02:00
# include <common/key_derive.h>
# include <common/status.h>
# include <common/utxo.h>
2018-04-05 21:19:47 +02:00
# include <common/wallet_tx.h>
2017-08-28 18:02:01 +02:00
# include <common/withdraw_tx.h>
2017-06-24 08:50:14 +02:00
# include <errno.h>
2017-11-30 17:07:38 +01:00
# include <hsmd/gen_hsm_client_wire.h>
2017-12-19 21:10:19 +01:00
# include <inttypes.h>
2017-08-28 18:04:01 +02:00
# include <lightningd/bitcoind.h>
# include <lightningd/chaintopology.h>
2017-06-24 08:50:23 +02:00
# include <lightningd/hsm_control.h>
2018-03-16 04:45:08 +01:00
# include <lightningd/json.h>
2017-08-28 18:04:01 +02:00
# include <lightningd/jsonrpc.h>
2018-05-24 23:40:18 +02:00
# include <lightningd/jsonrpc_errors.h>
2017-06-20 17:15:25 +02:00
# include <lightningd/lightningd.h>
2017-08-28 18:04:01 +02:00
# include <lightningd/log.h>
2018-07-20 03:14:02 +02:00
# include <lightningd/param.h>
2018-02-09 14:24:33 +01:00
# include <lightningd/peer_control.h>
2017-06-20 17:15:25 +02:00
# include <lightningd/subd.h>
# include <wally_bip32.h>
2017-06-24 08:50:14 +02:00
# include <wire/wire_sync.h>
2017-06-20 17:15:25 +02:00
struct withdrawal {
struct command * cmd ;
2018-04-05 21:19:47 +02:00
struct wallet_tx wtx ;
u8 * destination ;
2017-06-20 17:15:25 +02:00
const char * hextx ;
} ;
/**
* wallet_withdrawal_broadcast - The tx has been broadcast ( or it failed )
*
* This is the final step in the withdrawal . We either successfully
* broadcast the withdrawal transaction or it failed somehow . So we
* report success or a broadcast failure . Upon success we also mark
* the used outputs as spent , and add the change output to our pool of
* available outputs .
*/
2018-02-06 14:00:12 +01:00
static void wallet_withdrawal_broadcast ( struct bitcoind * bitcoind UNUSED ,
2017-06-20 17:15:25 +02:00
int exitstatus , const char * msg ,
struct withdrawal * withdraw )
{
struct command * cmd = withdraw - > cmd ;
2017-08-28 18:09:01 +02:00
struct lightningd * ld = withdraw - > cmd - > ld ;
2017-06-22 14:20:41 +02:00
u64 change_satoshi = 0 ;
2017-06-20 17:15:25 +02:00
/* Massage output into shape so it doesn't kill the JSON serialization */
char * output = tal_strjoin ( cmd , tal_strsplit ( cmd , msg , " \n " , STR_NO_EMPTY ) , " " , STR_NO_TRAIL ) ;
if ( exitstatus = = 0 ) {
2017-06-22 14:20:41 +02:00
/* Mark used outputs as spent */
2018-04-05 21:19:47 +02:00
wallet_confirm_utxos ( ld - > wallet , withdraw - > wtx . utxos ) ;
2017-06-22 14:20:41 +02:00
/* Parse the tx and extract the change output. We
* generated the hex tx , so this should always work */
2018-03-25 21:51:11 +02:00
struct bitcoin_tx * tx = bitcoin_tx_from_hex ( withdraw , withdraw - > hextx , strlen ( withdraw - > hextx ) ) ;
2017-06-22 14:20:41 +02:00
assert ( tx ! = NULL ) ;
2018-02-26 11:36:48 +01:00
wallet_extract_owned_outputs ( ld - > wallet , tx , NULL , & change_satoshi ) ;
2018-01-29 06:59:21 +01:00
2018-04-05 21:19:47 +02:00
/* Note normally, change_satoshi == withdraw->wtx.change, but
2018-01-29 06:59:21 +01:00
* not if we ' re actually making a payment to ourselves ! */
2018-04-05 21:19:47 +02:00
assert ( change_satoshi > = withdraw - > wtx . change ) ;
2017-06-22 14:20:41 +02:00
2017-06-20 17:15:25 +02:00
struct json_result * response = new_json_result ( cmd ) ;
json_object_start ( response , NULL ) ;
json_add_string ( response , " tx " , withdraw - > hextx ) ;
json_add_string ( response , " txid " , output ) ;
json_object_end ( response ) ;
command_success ( cmd , response ) ;
} else {
2018-05-24 23:40:18 +02:00
command_fail ( cmd , LIGHTNINGD ,
" Error broadcasting transaction: %s " , output ) ;
2017-06-20 17:15:25 +02:00
}
}
/**
* json_withdraw - Entrypoint for the withdrawal flow
*
* A user has requested a withdrawal over the JSON - RPC , parse the
* request , select coins and a change key . Then send the request to
* the HSM to generate the signatures .
*/
static void json_withdraw ( struct command * cmd ,
2018-04-20 10:09:50 +02:00
const char * buffer , const jsmntok_t * params )
2017-06-20 17:15:25 +02:00
{
2018-07-20 03:14:02 +02:00
const jsmntok_t * desttok , * sattok ;
2018-04-05 21:19:47 +02:00
struct withdrawal * withdraw = tal ( cmd , struct withdrawal ) ;
2017-12-19 21:12:41 +01:00
u32 feerate_per_kw = get_feerate ( cmd - > ld - > topology , FEERATE_NORMAL ) ;
2017-06-24 08:50:14 +02:00
struct bitcoin_tx * tx ;
2018-04-05 21:19:47 +02:00
2018-02-24 15:59:39 +01:00
enum address_parse_result addr_parse ;
2017-06-24 08:50:14 +02:00
2018-04-05 21:19:47 +02:00
withdraw - > cmd = cmd ;
wtx_init ( cmd , & withdraw - > wtx ) ;
2018-07-20 03:14:02 +02:00
if ( ! param ( cmd , buffer , params ,
2018-08-15 17:16:02 +02:00
p_req ( " destination " , json_tok_tok , & desttok ) ,
p_req ( " satoshi " , json_tok_tok , & sattok ) ,
2018-07-20 03:14:02 +02:00
NULL ) )
2017-06-20 17:15:25 +02:00
return ;
2018-07-20 03:14:02 +02:00
2018-07-29 07:51:38 +02:00
if ( ! json_tok_wtx ( & withdraw - > wtx , buffer , sattok , - 1ULL ) )
2017-06-20 17:15:25 +02:00
return ;
2017-12-10 07:49:51 +01:00
2017-12-10 12:49:46 +01:00
/* Parse address. */
2018-02-24 15:59:39 +01:00
addr_parse = json_tok_address_scriptpubkey ( cmd ,
get_chainparams ( cmd - > ld ) ,
buffer , desttok ,
( const u8 * * ) ( & withdraw - > destination ) ) ;
2017-12-10 07:49:51 +01:00
/* Check that destination address could be understood. */
2018-02-24 15:59:39 +01:00
if ( addr_parse = = ADDRESS_PARSE_UNRECOGNIZED ) {
2018-05-24 23:40:18 +02:00
command_fail ( cmd , LIGHTNINGD , " Could not parse destination address " ) ;
2017-06-20 17:15:25 +02:00
return ;
}
2017-12-09 14:08:40 +01:00
/* Check address given is compatible with the chain we are on. */
2018-02-24 15:59:39 +01:00
if ( addr_parse = = ADDRESS_PARSE_WRONG_NETWORK ) {
2018-05-24 23:40:18 +02:00
command_fail ( cmd , LIGHTNINGD ,
2018-04-05 21:19:47 +02:00
" Destination address is not on network %s " ,
get_chainparams ( cmd - > ld ) - > network_name ) ;
2017-12-09 14:08:40 +01:00
return ;
}
2018-04-05 21:19:47 +02:00
if ( ! wtx_select_utxos ( & withdraw - > wtx , feerate_per_kw ,
2018-07-28 08:00:16 +02:00
tal_count ( withdraw - > destination ) ) )
2018-04-05 21:19:47 +02:00
return ;
2017-06-20 17:15:25 +02:00
2017-11-30 17:07:38 +01:00
u8 * msg = towire_hsm_sign_withdrawal ( cmd ,
2018-04-05 21:19:47 +02:00
withdraw - > wtx . amount ,
withdraw - > wtx . change ,
withdraw - > wtx . change_key_index ,
2017-12-10 07:24:38 +01:00
withdraw - > destination ,
2018-04-05 21:19:47 +02:00
withdraw - > wtx . utxos ) ;
2017-06-24 08:50:14 +02:00
2017-08-28 18:09:01 +02:00
if ( ! wire_sync_write ( cmd - > ld - > hsm_fd , take ( msg ) ) )
2017-06-24 08:50:14 +02:00
fatal ( " Could not write sign_withdrawal to HSM: %s " ,
strerror ( errno ) ) ;
2018-07-09 13:17:59 +02:00
msg = wire_sync_read ( cmd , cmd - > ld - > hsm_fd ) ;
2017-06-24 08:50:14 +02:00
2018-02-20 21:59:09 +01:00
if ( ! fromwire_hsm_sign_withdrawal_reply ( msg , msg , & tx ) )
2017-06-24 08:50:14 +02:00
fatal ( " HSM gave bad sign_withdrawal_reply %s " ,
tal_hex ( withdraw , msg ) ) ;
/* Now broadcast the transaction */
withdraw - > hextx = tal_hex ( withdraw , linearize_tx ( cmd , tx ) ) ;
2017-08-28 18:09:01 +02:00
bitcoind_sendrawtx ( cmd - > ld - > topology - > bitcoind , withdraw - > hextx ,
2017-06-24 08:50:14 +02:00
wallet_withdrawal_broadcast , withdraw ) ;
2017-12-15 11:15:54 +01:00
command_still_pending ( cmd ) ;
2017-06-20 17:15:25 +02:00
}
static const struct json_command withdraw_command = {
" withdraw " ,
json_withdraw ,
2018-02-06 14:00:12 +01:00
" Send to {destination} address {satoshi} (or 'all') amount via Bitcoin transaction " ,
false , " Send funds from the internal wallet to the specified address. Either specify a number of satoshis to send or 'all' to sweep all funds in the internal wallet to the address. "
2017-06-20 17:15:25 +02:00
} ;
AUTODATA ( json_command , & withdraw_command ) ;
2017-06-21 17:18:55 +02:00
2018-04-21 14:24:58 +02:00
/* May return NULL if encoding error occurs. */
static char *
encode_pubkey_to_addr ( const tal_t * ctx ,
const struct lightningd * ld ,
const struct pubkey * pubkey ,
bool is_p2sh_p2wpkh ,
/* Output: redeemscript to use to redeem outputs
* paying to the address .
* May be NULL if redeemscript is do not care . */
u8 * * out_redeemscript )
{
char * out ;
const char * hrp ;
struct sha256 h ;
struct ripemd160 h160 ;
u8 * redeemscript ;
bool ok ;
if ( is_p2sh_p2wpkh ) {
redeemscript = bitcoin_redeem_p2sh_p2wpkh ( ctx , pubkey ) ;
sha256 ( & h , redeemscript , tal_count ( redeemscript ) ) ;
ripemd160 ( & h160 , h . u . u8 , sizeof ( h ) ) ;
out = p2sh_to_base58 ( ctx ,
get_chainparams ( ld ) - > testnet ,
& h160 ) ;
} else {
hrp = get_chainparams ( ld ) - > bip173_name ;
/* out buffer is 73 + strlen(human readable part),
* see common / bech32 . h */
out = tal_arr ( ctx , char , 73 + strlen ( hrp ) ) ;
pubkey_to_hash160 ( pubkey , & h160 ) ;
/* I am uncertain why this is so for direct SegWit
* outputs , but this is how listaddrs worked prior to
* this code being refactored . */
redeemscript = tal_dup_arr ( ctx , u8 ,
( u8 * ) & h160 , sizeof ( h160 ) ,
0 ) ;
ok = segwit_addr_encode ( out , hrp , 0 , h160 . u . u8 , sizeof ( h160 ) ) ;
if ( ! ok )
out = tal_free ( out ) ;
}
if ( out_redeemscript )
* out_redeemscript = redeemscript ;
else
tal_free ( redeemscript ) ;
return out ;
}
2018-08-14 19:52:42 +02:00
/* Extract a bool indicating "p2sh-segwit" or "bech32" */
static bool json_tok_newaddr ( struct command * cmd , const char * name ,
const char * buffer , const jsmntok_t * tok ,
bool * * is_p2wpkh )
{
* is_p2wpkh = tal ( cmd , bool ) ;
if ( json_tok_streq ( buffer , tok , " p2sh-segwit " ) ) {
* * is_p2wpkh = false ;
return true ;
}
if ( json_tok_streq ( buffer , tok , " bech32 " ) ) {
* * is_p2wpkh = true ;
return true ;
}
command_fail ( cmd , JSONRPC2_INVALID_PARAMS ,
" '%s' should be 'bech32' or 'p2sh-segwit', not '%.*s' " ,
name , tok - > end - tok - > start , buffer + tok - > start ) ;
return false ;
}
2018-02-06 14:00:12 +01:00
static void json_newaddr ( struct command * cmd , const char * buffer UNUSED ,
const jsmntok_t * params UNUSED )
2017-06-21 17:18:55 +02:00
{
struct json_result * response = new_json_result ( cmd ) ;
struct ext_key ext ;
struct pubkey pubkey ;
2018-08-14 19:52:42 +02:00
bool * is_p2wpkh ;
2017-06-25 04:33:13 +02:00
s64 keyidx ;
2018-01-24 08:01:21 +01:00
char * out ;
2018-07-20 03:14:02 +02:00
if ( ! param ( cmd , buffer , params ,
2018-08-15 17:16:02 +02:00
p_opt_def ( " addresstype " , json_tok_newaddr , & is_p2wpkh , true ) ,
2018-07-20 03:14:02 +02:00
NULL ) )
2018-01-24 08:01:21 +01:00
return ;
2017-06-21 17:18:55 +02:00
2017-08-28 18:09:01 +02:00
keyidx = wallet_get_newindex ( cmd - > ld ) ;
2017-06-25 04:33:13 +02:00
if ( keyidx < 0 ) {
2018-05-24 23:40:18 +02:00
command_fail ( cmd , LIGHTNINGD , " Keys exhausted " ) ;
2017-06-21 17:18:55 +02:00
return ;
}
2017-08-28 18:09:01 +02:00
if ( bip32_key_from_parent ( cmd - > ld - > wallet - > bip32_base , keyidx ,
2017-06-21 17:18:55 +02:00
BIP32_FLAG_KEY_PUBLIC , & ext ) ! = WALLY_OK ) {
2018-05-24 23:40:18 +02:00
command_fail ( cmd , LIGHTNINGD , " Keys generation failure " ) ;
2017-06-21 17:18:55 +02:00
return ;
}
if ( ! secp256k1_ec_pubkey_parse ( secp256k1_ctx , & pubkey . pubkey ,
ext . pub_key , sizeof ( ext . pub_key ) ) ) {
2018-05-24 23:40:18 +02:00
command_fail ( cmd , LIGHTNINGD , " Key parsing failure " ) ;
2017-06-21 17:18:55 +02:00
return ;
}
2017-11-27 16:20:10 +01:00
txfilter_add_derkey ( cmd - > ld - > owned_txfilter , ext . pub_key ) ;
2018-04-21 14:24:58 +02:00
out = encode_pubkey_to_addr ( cmd , cmd - > ld ,
2018-08-14 19:52:42 +02:00
& pubkey , ! * is_p2wpkh ,
2018-04-21 14:24:58 +02:00
NULL ) ;
if ( ! out ) {
2018-05-24 23:40:18 +02:00
command_fail ( cmd , LIGHTNINGD ,
" p2wpkh address encoding failure. " ) ;
2018-04-21 14:24:58 +02:00
return ;
2018-01-24 08:01:21 +01:00
}
2017-06-21 17:18:55 +02:00
json_object_start ( response , NULL ) ;
2018-01-24 08:01:21 +01:00
json_add_string ( response , " address " , out ) ;
2017-06-21 17:18:55 +02:00
json_object_end ( response ) ;
command_success ( cmd , response ) ;
}
static const struct json_command newaddr_command = {
" newaddr " ,
json_newaddr ,
2018-07-23 16:08:45 +02:00
" Get a new {bech32, p2sh-segwit} address to fund a channel (default is bech32) " , false ,
2018-02-06 14:13:57 +01:00
" Generates a new address that belongs to the internal wallet. Funds sent to these addresses will be managed by lightningd. Use `withdraw` to withdraw funds to an external wallet. "
2017-06-21 17:18:55 +02:00
} ;
AUTODATA ( json_command , & newaddr_command ) ;
2017-06-21 17:40:42 +02:00
2018-02-18 13:52:46 +01:00
static void json_listaddrs ( struct command * cmd ,
2018-04-20 10:09:50 +02:00
const char * buffer , const jsmntok_t * params )
2018-02-18 13:52:46 +01:00
{
struct json_result * response = new_json_result ( cmd ) ;
struct ext_key ext ;
struct pubkey pubkey ;
2018-08-13 18:16:41 +02:00
u64 * bip32_max_index ;
2018-02-18 13:52:46 +01:00
2018-07-20 03:14:02 +02:00
if ( ! param ( cmd , buffer , params ,
2018-08-15 17:16:02 +02:00
p_opt_def ( " bip32_max_index " , json_tok_u64 , & bip32_max_index ,
2018-08-13 18:16:41 +02:00
db_get_intvar ( cmd - > ld - > wallet - > db ,
" bip32_max_index " , 0 ) ) ,
2018-07-20 03:14:02 +02:00
NULL ) )
2018-02-18 13:52:46 +01:00
return ;
json_object_start ( response , NULL ) ;
json_array_start ( response , " addresses " ) ;
2018-08-13 18:16:41 +02:00
for ( s64 keyidx = 0 ; keyidx < = * bip32_max_index ; keyidx + + ) {
2018-02-18 13:52:46 +01:00
if ( keyidx = = BIP32_INITIAL_HARDENED_CHILD ) {
break ;
}
if ( bip32_key_from_parent ( cmd - > ld - > wallet - > bip32_base , keyidx ,
BIP32_FLAG_KEY_PUBLIC , & ext ) ! = WALLY_OK ) {
2018-05-24 23:40:18 +02:00
command_fail ( cmd , LIGHTNINGD ,
" Keys generation failure " ) ;
2018-02-18 13:52:46 +01:00
return ;
}
if ( ! secp256k1_ec_pubkey_parse ( secp256k1_ctx , & pubkey . pubkey ,
ext . pub_key , sizeof ( ext . pub_key ) ) ) {
2018-05-24 23:40:18 +02:00
command_fail ( cmd , LIGHTNINGD , " Key parsing failure " ) ;
2018-02-18 13:52:46 +01:00
return ;
}
// p2sh
2018-04-21 14:24:58 +02:00
u8 * redeemscript_p2sh ;
char * out_p2sh = encode_pubkey_to_addr ( cmd , cmd - > ld ,
& pubkey ,
true ,
& redeemscript_p2sh ) ;
2018-02-18 13:52:46 +01:00
// bech32 : p2wpkh
2018-04-21 14:24:58 +02:00
u8 * redeemscript_p2wpkh ;
char * out_p2wpkh = encode_pubkey_to_addr ( cmd , cmd - > ld ,
& pubkey ,
false ,
& redeemscript_p2wpkh ) ;
if ( ! out_p2wpkh ) {
2018-05-24 23:40:18 +02:00
command_fail ( cmd , LIGHTNINGD ,
" p2wpkh address encoding failure. " ) ;
2018-02-18 13:52:46 +01:00
return ;
}
// outputs
json_object_start ( response , NULL ) ;
json_add_u64 ( response , " keyidx " , keyidx ) ;
json_add_pubkey ( response , " pubkey " , & pubkey ) ;
json_add_string ( response , " p2sh " , out_p2sh ) ;
2018-07-28 07:53:33 +02:00
json_add_hex_talarr ( response , " p2sh_redeemscript " ,
redeemscript_p2sh ) ;
2018-02-18 13:52:46 +01:00
json_add_string ( response , " bech32 " , out_p2wpkh ) ;
2018-07-28 07:53:33 +02:00
json_add_hex_talarr ( response , " bech32_redeemscript " ,
redeemscript_p2wpkh ) ;
2018-02-18 13:52:46 +01:00
json_object_end ( response ) ;
}
json_array_end ( response ) ;
json_object_end ( response ) ;
command_success ( cmd , response ) ;
}
static const struct json_command listaddrs_command = {
" dev-listaddrs " ,
json_listaddrs ,
2018-04-20 10:09:50 +02:00
" Show addresses list up to derivation {index} (default is the last bip32 index) " ,
false ,
2018-02-18 13:52:46 +01:00
" Show addresses of your internal wallet. Use `newaddr` to generate a new address. "
} ;
AUTODATA ( json_command , & listaddrs_command ) ;
2018-02-06 14:00:12 +01:00
static void json_listfunds ( struct command * cmd , const char * buffer UNUSED ,
const jsmntok_t * params UNUSED )
2017-09-05 02:11:53 +02:00
{
struct json_result * response = new_json_result ( cmd ) ;
2018-02-09 14:24:33 +01:00
struct peer * p ;
2017-09-05 02:11:53 +02:00
struct utxo * * utxos =
wallet_get_utxos ( cmd , cmd - > ld - > wallet , output_state_available ) ;
2018-03-27 16:00:33 +02:00
char * out ;
struct pubkey funding_pubkey ;
2017-09-05 02:11:53 +02:00
json_object_start ( response , NULL ) ;
json_array_start ( response , " outputs " ) ;
2018-02-06 14:14:43 +01:00
for ( size_t i = 0 ; i < tal_count ( utxos ) ; i + + ) {
2017-09-05 02:11:53 +02:00
json_object_start ( response , NULL ) ;
2017-12-18 07:20:24 +01:00
json_add_txid ( response , " txid " , & utxos [ i ] - > txid ) ;
2017-09-05 02:11:53 +02:00
json_add_num ( response , " output " , utxos [ i ] - > outnum ) ;
json_add_u64 ( response , " value " , utxos [ i ] - > amount ) ;
2018-02-21 23:48:01 +01:00
2018-04-03 14:08:00 +02:00
/* @close_info is for outputs that are not yet claimable */
2018-03-27 16:00:33 +02:00
if ( utxos [ i ] - > close_info = = NULL ) {
bip32_pubkey ( cmd - > ld - > wallet - > bip32_base , & funding_pubkey ,
utxos [ i ] - > keyindex ) ;
2018-04-21 14:24:58 +02:00
out = encode_pubkey_to_addr ( cmd , cmd - > ld ,
& funding_pubkey ,
utxos [ i ] - > is_p2sh ,
NULL ) ;
if ( ! out ) {
2018-05-24 23:40:18 +02:00
command_fail ( cmd , LIGHTNINGD ,
" p2wpkh address encoding failure. " ) ;
2018-04-21 14:24:58 +02:00
return ;
2018-03-27 16:00:33 +02:00
}
json_add_string ( response , " address " , out ) ;
}
2018-02-21 23:48:01 +01:00
if ( utxos [ i ] - > spendheight )
json_add_string ( response , " status " , " spent " ) ;
else if ( utxos [ i ] - > blockheight )
json_add_string ( response , " status " , " confirmed " ) ;
else
json_add_string ( response , " status " , " unconfirmed " ) ;
2017-09-05 02:11:53 +02:00
json_object_end ( response ) ;
}
json_array_end ( response ) ;
2018-02-09 14:24:33 +01:00
/* Add funds that are allocated to channels */
json_array_start ( response , " channels " ) ;
list_for_each ( & cmd - > ld - > peers , p , list ) {
2018-02-12 11:12:55 +01:00
struct channel * c ;
list_for_each ( & p - > channels , c , list ) {
json_object_start ( response , NULL ) ;
json_add_pubkey ( response , " peer_id " , & p - > id ) ;
if ( c - > scid )
json_add_short_channel_id ( response ,
" short_channel_id " ,
c - > scid ) ;
/* Poor man's rounding to satoshis to match the unit for outputs */
json_add_u64 ( response , " channel_sat " ,
2018-02-19 02:06:12 +01:00
( c - > our_msatoshi + 500 ) / 1000 ) ;
2018-02-12 11:12:55 +01:00
json_add_u64 ( response , " channel_total_sat " ,
c - > funding_satoshi ) ;
2018-02-19 02:06:12 +01:00
json_add_txid ( response , " funding_txid " ,
& c - > funding_txid ) ;
2018-02-12 11:12:55 +01:00
json_object_end ( response ) ;
}
2018-02-09 14:24:33 +01:00
}
json_array_end ( response ) ;
2017-09-05 02:11:53 +02:00
json_object_end ( response ) ;
2018-02-09 14:24:33 +01:00
2017-09-05 02:11:53 +02:00
command_success ( cmd , response ) ;
}
static const struct json_command listfunds_command = {
2018-01-22 09:55:07 +01:00
" listfunds " ,
json_listfunds ,
2018-04-20 10:09:50 +02:00
" Show available funds from the internal wallet " ,
false ,
2018-02-06 14:13:57 +01:00
" Returns a list of funds (outputs) that can be used by the internal wallet to open new channels or can be withdrawn, using the `withdraw` command, to another wallet. "
2018-01-22 09:55:07 +01:00
} ;
2017-09-05 02:11:53 +02:00
AUTODATA ( json_command , & listfunds_command ) ;
2018-01-31 23:38:27 +01:00
struct txo_rescan {
struct command * cmd ;
struct utxo * * utxos ;
struct json_result * response ;
} ;
static void process_utxo_result ( struct bitcoind * bitcoind ,
const struct bitcoin_tx_output * txout ,
void * arg )
{
struct txo_rescan * rescan = arg ;
struct json_result * response = rescan - > response ;
struct utxo * u = rescan - > utxos [ 0 ] ;
enum output_status newstate =
txout = = NULL ? output_state_spent : output_state_available ;
json_object_start ( rescan - > response , NULL ) ;
json_add_txid ( response , " txid " , & u - > txid ) ;
json_add_num ( response , " output " , u - > outnum ) ;
json_add_num ( response , " oldstate " , u - > status ) ;
json_add_num ( response , " newstate " , newstate ) ;
json_object_end ( rescan - > response ) ;
wallet_update_output_status ( bitcoind - > ld - > wallet , & u - > txid , u - > outnum ,
u - > status , newstate ) ;
/* Remove the utxo we just resolved */
rescan - > utxos [ 0 ] = rescan - > utxos [ tal_count ( rescan - > utxos ) - 1 ] ;
tal_resize ( & rescan - > utxos , tal_count ( rescan - > utxos ) - 1 ) ;
if ( tal_count ( rescan - > utxos ) = = 0 ) {
/* Complete the response */
json_array_end ( rescan - > response ) ;
json_object_end ( rescan - > response ) ;
command_success ( rescan - > cmd , rescan - > response ) ;
} else {
bitcoind_gettxout (
bitcoind - > ld - > topology - > bitcoind , & rescan - > utxos [ 0 ] - > txid ,
rescan - > utxos [ 0 ] - > outnum , process_utxo_result , rescan ) ;
}
}
2018-02-06 14:00:12 +01:00
static void json_dev_rescan_outputs ( struct command * cmd ,
const char * buffer UNUSED ,
const jsmntok_t * params UNUSED )
2018-01-31 23:38:27 +01:00
{
struct txo_rescan * rescan = tal ( cmd , struct txo_rescan ) ;
rescan - > response = new_json_result ( cmd ) ;
rescan - > cmd = cmd ;
/* Open the result structure so we can incrementally add results */
json_object_start ( rescan - > response , NULL ) ;
json_array_start ( rescan - > response , " outputs " ) ;
2018-02-08 02:06:52 +01:00
rescan - > utxos = wallet_get_utxos ( rescan , cmd - > ld - > wallet , output_state_any ) ;
if ( tal_count ( rescan - > utxos ) = = 0 ) {
json_array_end ( rescan - > response ) ;
json_object_end ( rescan - > response ) ;
command_success ( cmd , rescan - > response ) ;
return ;
}
2018-01-31 23:38:27 +01:00
bitcoind_gettxout ( cmd - > ld - > topology - > bitcoind , & rescan - > utxos [ 0 ] - > txid ,
rescan - > utxos [ 0 ] - > outnum , process_utxo_result ,
rescan ) ;
command_still_pending ( cmd ) ;
}
static const struct json_command dev_rescan_output_command = {
2018-04-20 10:09:50 +02:00
" dev-rescan-outputs " ,
json_dev_rescan_outputs ,
" Synchronize the state of our funds with bitcoind " ,
false ,
" For each output stored in the internal wallet ask `bitcoind` whether we are in sync with its state (spent vs. unspent) "
2018-01-31 23:38:27 +01:00
} ;
AUTODATA ( json_command , & dev_rescan_output_command ) ;