@ -1,6 +1,7 @@
# include <ccan/array_size/array_size.h>
# include <ccan/cast/cast.h>
# include <ccan/intmap/intmap.h>
# include <ccan/json_out/json_out.h>
# include <ccan/tal/str/str.h>
# include <ccan/time/time.h>
# include <common/amount.h>
@ -136,12 +137,38 @@ static void attempt_failed_tok(struct pay_command *pc, const char *method,
buf + msg - > start ) ;
else
attempt_failed_fmt ( pc ,
" { 'message': 'Call to %s failed' , %.*s " ,
" { \" message \" : \" Call to %s failed \" , %.*s " ,
method ,
errtok - > end - errtok - > start - 1 ,
buf + errtok - > start + 1 ) ;
}
/* Helper to copy JSON object directly into a json_out */
static void json_out_add_raw_len ( struct json_out * jout ,
const char * fieldname ,
const char * jsonstr , size_t len )
{
char * p ;
p = json_out_member_direct ( jout , fieldname , len ) ;
memcpy ( p , jsonstr , len ) ;
}
static void json_out_add_raw ( struct json_out * jout ,
const char * fieldname ,
const char * jsonstr )
{
json_out_add_raw_len ( jout , fieldname , jsonstr , strlen ( jsonstr ) ) ;
}
/* Helper to add a u64. */
static void json_out_add_u64 ( struct json_out * jout ,
const char * fieldname ,
u64 val )
{
json_out_add ( jout , fieldname , false , " % " PRIu64 , val ) ;
}
static struct command_result * start_pay_attempt ( struct command * cmd ,
struct pay_command * pc ,
const char * fmt , . . . ) ;
@ -178,24 +205,23 @@ static size_t count_sendpays(const struct pay_attempt *attempts)
static struct command_result * waitsendpay_expired ( struct command * cmd ,
struct pay_command * pc )
{
char * errmsg , * data ;
char * errmsg ;
struct json_out * data ;
size_t num_attempts = count_sendpays ( pc - > ps - > attempts ) ;
errmsg = tal_fmt ( pc , " Gave up after %zu attempt%s: see paystatus " ,
num_attempts , num_attempts = = 1 ? " " : " s " ) ;
data = tal_strdup ( pc , " { 'attempts': [ " ) ;
data = json_out_new ( NULL ) ;
json_out_start ( data , NULL , ' { ' ) ;
json_out_start ( data , " attempts " , ' [ ' ) ;
for ( size_t i = 0 ; i < tal_count ( pc - > ps - > attempts ) ; i + + ) {
if ( pc - > ps - > attempts [ i ] . route )
tal_append_fmt ( & data , " %s { 'route': %s, \n 'failure': %s \n } " ,
i = = 0 ? " " : " , " ,
pc - > ps - > attempts [ i ] . route ,
pc - > ps - > attempts [ i ] . failure ) ;
else
tal_append_fmt ( & data , " %s { 'failure': %s \n } " ,
i = = 0 ? " " : " , " ,
pc - > ps - > attempts [ i ] . failure ) ;
json_out_add_raw ( data , " route " ,
pc - > ps - > attempts [ i ] . route ) ;
json_out_add_raw ( data , " failure " , pc - > ps - > attempts [ i ] . failure ) ;
}
tal_append_fmt ( & data , " ] } " ) ;
json_out_end ( data , ' ] ' ) ;
json_out_end ( data , ' } ' ) ;
return command_done_err ( cmd , PAY_STOPPED_RETRYING , errmsg , data ) ;
}
@ -315,8 +341,8 @@ static struct command_result *sendpay_done(struct command *cmd,
{
return send_outreq ( cmd , " waitsendpay " ,
waitsendpay_done , waitsendpay_error , pc ,
" ' payment_hash': '%s' " ,
pc - > payment_hash ) ;
take ( json_out_obj ( NULL , " payment_hash " ,
pc - > payment_hash ) ) ) ;
}
/* Calculate how many millisatoshi we need at the start of this route
@ -375,10 +401,10 @@ static const char *join_routehint(const tal_t *ctx,
return tal_free ( ret ) ;
tal_append_fmt ( & ret , " , { "
" 'id': '%s' , "
" 'channel': '%s' , "
" 'msatoshi': '%s' , "
" 'delay' : %u } " ,
" \" id \" : \" %s \" , "
" \" channel \" : \" %s \" , "
" \" msatoshi \" : \" %s \" , "
" \" delay \" : %u } " ,
/* pubkey of *destination* */
route_pubkey ( tmpctx , pc , routehint , i + 1 ) ,
type_to_string ( tmpctx , struct short_channel_id ,
@ -455,10 +481,10 @@ static struct command_result *getroute_done(struct command *cmd,
{
struct pay_attempt * attempt = current_attempt ( pc ) ;
const jsmntok_t * t = json_get_member ( buf , result , " route " ) ;
char * json_desc ;
struct amount_msat fee ;
u32 delay ;
double feepercent ;
struct json_out * params ;
if ( ! t )
plugin_err ( " getroute gave no 'route'? '%.*s' " ,
@ -469,7 +495,7 @@ static struct command_result *getroute_done(struct command *cmd,
pc , pc - > current_routehint ) ;
if ( ! attempt - > route ) {
attempt_failed_fmt ( pc ,
" { 'message': 'Joining routehint gave absurd fee' } " ) ;
" { \" message \" : \" Joining routehint gave absurd fee \" } " ) ;
return next_routehint ( cmd , pc ) ;
}
} else
@ -497,7 +523,7 @@ static struct command_result *getroute_done(struct command *cmd,
& & feepercent > pc - > maxfeepercent ) {
const jsmntok_t * charger ;
attempt_failed_fmt ( pc , " { 'message': 'Route wanted fee of %s' } " ,
attempt_failed_fmt ( pc , " { \" message \" : \" Route wanted fee of %s \" } " ,
type_to_string ( tmpctx , struct amount_msat ,
& fee ) ) ;
@ -526,7 +552,7 @@ static struct command_result *getroute_done(struct command *cmd,
const jsmntok_t * delayer ;
attempt_failed_fmt ( pc ,
" { 'message': 'Route wanted delay of %u blocks' } " ,
" { \" message \" : \" Route wanted delay of %u blocks \" } " ,
delay ) ;
/* Remember this if we eliminating this causes us to have no
@ -549,18 +575,18 @@ static struct command_result *getroute_done(struct command *cmd,
return next_routehint ( cmd , pc ) ;
}
attempt - > sendpay = true ;
params = json_out_new ( NULL ) ;
json_out_start ( params , NULL , ' { ' ) ;
json_out_add_raw ( params , " route " , attempt - > route ) ;
json_out_add ( params , " payment_hash " , true , " %s " , pc - > payment_hash ) ;
json_out_add ( params , " bolt11 " , true , " %s " , pc - > ps - > bolt11 ) ;
if ( pc - > label )
json_desc = tal_fmt ( pc , " , 'label': '%s' " , pc - > label ) ;
else
json_desc = " " ;
json_out_add ( params , " label " , true , " %s " , pc - > label ) ;
json_out_end ( params , ' } ' ) ;
attempt - > sendpay = true ;
return send_outreq ( cmd , " sendpay " , sendpay_done , sendpay_error , pc ,
" 'route': %s, 'payment_hash': '%s', 'bolt11': '%s'%s " ,
attempt - > route ,
pc - > payment_hash ,
pc - > ps - > bolt11 ,
json_desc ) ;
take ( params ) ) ;
}
@ -600,7 +626,6 @@ static struct command_result *start_pay_attempt(struct command *cmd,
struct pay_command * pc ,
const char * fmt , . . . )
{
char * exclude ;
struct amount_msat msat ;
const char * dest ;
size_t max_hops = ROUTING_MAX_HOPS ;
@ -608,6 +633,7 @@ static struct command_result *start_pay_attempt(struct command *cmd,
struct pay_attempt * attempt ;
va_list ap ;
size_t n ;
struct json_out * params ;
n = tal_count ( pc - > ps - > attempts ) ;
tal_resize ( & pc - > ps - > attempts , n + 1 ) ;
@ -627,17 +653,6 @@ static struct command_result *start_pay_attempt(struct command *cmd,
/* routehint set below. */
if ( tal_count ( pc - > excludes ) ! = 0 ) {
exclude = tal_strdup ( tmpctx , " ,'exclude': [ " ) ;
for ( size_t i = 0 ; i < tal_count ( pc - > excludes ) ; i + + )
/* JSON.org grammar doesn't allow trailing , */
tal_append_fmt ( & exclude , " %s %s " ,
i = = 0 ? " " : " , " ,
pc - > excludes [ i ] ) ;
tal_append_fmt ( & exclude , " ] " ) ;
} else
exclude = " " ;
/* If we have a routehint, try that first; we need to do extra
* checks that it meets our criteria though . */
if ( pc - > current_routehint ) {
@ -646,7 +661,7 @@ static struct command_result *start_pay_attempt(struct command *cmd,
attempt - > routehint ,
tal_count ( attempt - > routehint ) ) ) {
attempt_failed_fmt ( pc ,
" { 'message': 'Routehint absurd fee' } " ) ;
" { \" message \" : \" Routehint absurd fee \" } " ) ;
return next_routehint ( cmd , pc ) ;
}
dest = type_to_string ( tmpctx , struct node_id ,
@ -663,15 +678,24 @@ static struct command_result *start_pay_attempt(struct command *cmd,
}
/* OK, ask for route to destination */
params = json_out_new ( NULL ) ;
json_out_start ( params , NULL , ' { ' ) ;
json_out_addstr ( params , " id " , dest ) ;
json_out_addstr ( params , " msatoshi " ,
type_to_string ( tmpctx , struct amount_msat , & msat ) ) ;
json_out_add_u64 ( params , " cltv " , cltv ) ;
json_out_add_u64 ( params , " maxhops " , max_hops ) ;
json_out_add ( params , " riskfactor " , false , " %f " , pc - > riskfactor ) ;
if ( tal_count ( pc - > excludes ) ! = 0 ) {
json_out_start ( params , " exclude " , ' [ ' ) ;
for ( size_t i = 0 ; i < tal_count ( pc - > excludes ) ; i + + )
json_out_addstr ( params , NULL , pc - > excludes [ i ] ) ;
json_out_end ( params , ' ] ' ) ;
}
json_out_end ( params , ' } ' ) ;
return send_outreq ( cmd , " getroute " , getroute_done , getroute_error , pc ,
" 'id': '%s', "
" 'msatoshi': '%s', "
" 'cltv': %u, "
" 'maxhops': %zu, "
" 'riskfactor': %f%s " ,
dest ,
type_to_string ( tmpctx , struct amount_msat , & msat ) ,
cltv , max_hops , pc - > riskfactor , exclude ) ;
take ( params ) ) ;
}
/* BOLT #7:
@ -751,7 +775,7 @@ static struct command_result *shadow_route(struct command *cmd,
return send_outreq ( cmd , " listchannels " ,
add_shadow_route , forward_error , pc ,
" ' source' : '%s' " , pc - > shadow_dest ) ;
take ( json_out_obj ( NULL , " source " , pc - > shadow_dest ) ) ) ;
}
/* gossipd doesn't know much about the current state of channels; here we
@ -996,10 +1020,9 @@ static struct command_result *json_pay(struct command *cmd,
pc - > routehints = filter_routehints ( pc , b11 - > routes ) ;
pc - > expensive_route = NULL ;
/* Get capacities of local channels. */
/* Get capacities of local channels (no parameters) */
return send_outreq ( cmd , " listpeers " , listpeers_done , forward_error , pc ,
/* gcc doesn't like zero-length format strings! */
" " ) ;
take ( json_out_obj ( NULL , NULL , NULL ) ) ) ;
}
/* FIXME: Add this to ccan/time? */
@ -1014,7 +1037,7 @@ static void utc_timestring(const struct timeabs *time, char str[UTC_TIMELEN])
( int ) time - > ts . tv_nsec / 1000000 ) ;
}
static void add_attempt ( char * * ret ,
static void add_attempt ( struct json_out * ret ,
const struct pay_status * ps ,
const struct pay_attempt * attempt )
{
@ -1022,62 +1045,56 @@ static void add_attempt(char **ret,
utc_timestring ( & attempt - > start , timestr ) ;
tal_append_fmt ( ret , " { 'strategy': '%s', "
" 'start_time': '%s', "
" 'age_in_seconds': % " PRIu64 ,
attempt - > why ,
timestr ,
time_to_sec ( time_between ( time_now ( ) , attempt - > start ) ) ) ;
json_out_start ( ret , NULL , ' { ' ) ;
json_out_addstr ( ret , " strategy " , attempt - > why ) ;
json_out_addstr ( ret , " start_time " , timestr ) ;
json_out_add_u64 ( ret , " age_in_seconds " ,
time_to_sec ( time_between ( time_now ( ) , attempt - > start ) ) ) ;
if ( attempt - > result | | attempt - > failure ) {
utc_timestring ( & attempt - > end , timestr ) ;
tal_append_fmt ( ret , " , 'end_time': '%s' "
" , 'duration_in_seconds': % " PRIu64 ,
timestr ,
time_to_sec ( time_between ( attempt - > end ,
attempt - > start ) ) ) ;
json_out_addstr ( ret , " end_time " , timestr ) ;
json_out_add_u64 ( ret , " duration_in_seconds " ,
time_to_sec ( time_between ( attempt - > end ,
attempt - > start ) ) ) ;
}
if ( tal_count ( attempt - > routehint ) ) {
tal_append_fm t( ret , " , 'routehint': [ " ) ;
json_out_star t( ret , " routehint " , ' [ ' ) ;
for ( size_t i = 0 ; i < tal_count ( attempt - > routehint ) ; i + + ) {
tal_append_fmt ( ret , " %s{ "
" ' id': '%s', "
" 'channel': '%s', "
" 'fee_base_msat': %u, "
" 'fee_proportional_millionths': %u, "
" 'cltv_expiry_delta': %u } " ,
i = = 0 ? " " : " , " ,
type_to_string ( tmpctx , struct node_id ,
& attempt - > routehint [ i ] . pubkey ) ,
type_to_string ( tmpctx ,
struct short_channel_id ,
& attempt - > routehint [ i ] . short_channel_id ) ,
attempt - > routehint [ i ] . fee_base_msat ,
attempt - > routehint [ i ] . fee_proportional_millionths ,
attempt - > routehint [ i ] . cltv_expiry_delta ) ;
json_out_start ( ret , NULL , ' { ' ) ;
json_out_addstr ( ret , " id " ,
type_to_string ( tmpctx , struct node_id ,
& attempt - > routehint [ i ] . pubkey ) ) ;
json_out_addstr ( ret , " channel " ,
type_to_string ( tmpctx ,
struct short_channel_id ,
& attempt - > routehint [ i ] . short_channel_id ) ) ;
json_out_add_u64 ( ret , " fee_base_msat " ,
attempt - > routehint [ i ] . fee_base_msat ) ;
json_out_add_u64 ( ret , " fee_proportional_millionths " ,
attempt - > routehint [ i ] . fee_proportional_millionths ) ;
json_out_add_u64 ( ret , " cltv_expiry_delta " ,
attempt - > routehint [ i ] . cltv_expiry_delta ) ;
json_out_end ( ret , ' } ' ) ;
}
tal _app end_fmt ( ret , " ] " ) ;
json_ou t_end( ret , ' ] ' ) ;
}
if ( tal_count ( attempt - > excludes ) ) {
for ( size_t i = 0 ; i < tal_count ( attempt - > excludes ) ; i + + ) {
if ( i = = 0 )
tal_append_fmt ( ret , " , 'excluded_channels': [ " ) ;
else
tal_append_fmt ( ret , " , " ) ;
tal_append_fmt ( ret , " '%s' " , attempt - > excludes [ i ] ) ;
}
tal_append_fmt ( ret , " ] " ) ;
json_out_start ( ret , " excluded_channels " , ' [ ' ) ;
for ( size_t i = 0 ; i < tal_count ( attempt - > excludes ) ; i + + )
json_out_addstr ( ret , NULL , attempt - > excludes [ i ] ) ;
json_out_end ( ret , ' ] ' ) ;
}
if ( attempt - > route )
tal_append_fmt ( ret , " , ' route': %s " , attempt - > route ) ;
json_out_add_raw ( ret , " route " , attempt - > route ) ;
if ( attempt - > failure )
tal_append_fmt ( ret , " , ' failure': %s " , attempt - > failure ) ;
json_out_add_raw ( ret , " failure " , attempt - > failure ) ;
if ( attempt - > result )
tal_append_fmt ( ret , " , ' success': % s" , attempt - > result ) ;
json_out_add_raw ( ret , " success " , attempt - > result ) ;
tal _app end_fmt ( ret , " } " ) ;
json_ou t_end( ret , ' } ' ) ;
}
static struct command_result * json_paystatus ( struct command * cmd ,
@ -1086,71 +1103,65 @@ static struct command_result *json_paystatus(struct command *cmd,
{
struct pay_status * ps ;
const char * b11str ;
char * ret ;
bool some = false ;
struct json_out * ret ;
if ( ! param ( cmd , buf , params ,
p_opt ( " bolt11 " , param_string , & b11str ) ,
NULL ) )
return NULL ;
ret = tal_fmt ( cmd , " { 'pay': [ " ) ;
ret = json_out_new ( NULL ) ;
json_out_start ( ret , NULL , ' { ' ) ;
json_out_start ( ret , " pay " , ' [ ' ) ;
/* FIXME: Index by bolt11 string! */
list_for_each ( & pay_status , ps , list ) {
if ( b11str & & ! streq ( b11str , ps - > bolt11 ) )
continue ;
if ( some )
tal_append_fmt ( & ret , " , \n " ) ;
some = true ;
tal_append_fmt ( & ret , " { 'bolt11': '%s', "
" 'msatoshi': % " PRIu64 " , "
" 'amount_msat': '%s', "
" 'destination': '%s' " ,
ps - > bolt11 ,
ps - > msat . millisatoshis , /* Raw: JSON */
json_out_start ( ret , NULL , ' { ' ) ;
json_out_addstr ( ret , " bolt11 " , ps - > bolt11 ) ;
json_out_add_u64 ( ret , " msatoshi " ,
ps - > msat . millisatoshis ) ; /* Raw: JSON */
json_out_addstr ( ret , " amount_msat " ,
type_to_string ( tmpctx , struct amount_msat ,
& ps - > msat ) , ps - > dest ) ;
& ps - > msat ) ) ;
json_out_addstr ( ret , " destination " , ps - > dest ) ;
if ( ps - > label )
tal_append_fmt ( & ret , " , ' label': '%s' " , ps - > label ) ;
json_out_addstr ( ret , " label " , ps - > label ) ;
if ( ps - > routehint_modifications )
tal_append_fmt ( & ret , " , ' routehint_modifications': '%s' " ,
ps - > routehint_modifications ) ;
json_out_addstr ( ret , " routehint_modifications " ,
ps - > routehint_modifications ) ;
if ( ps - > shadow & & ! streq ( ps - > shadow , " " ) )
tal_append_fmt ( & ret , " , ' shadow': '%s' " , ps - > shadow ) ;
json_out_addstr ( ret , " shadow " , ps - > shadow ) ;
if ( ps - > exclusions )
tal_append_fmt ( & ret , " , 'local_exclusions': '%s' " ,
ps - > exclusions ) ;
json_out_addstr ( ret , " local_exclusions " , ps - > exclusions ) ;
assert ( tal_count ( ps - > attempts ) ) ;
for ( size_t i = 0 ; i < tal_count ( ps - > attempts ) ; i + + ) {
if ( i = = 0 )
tal_append_fmt ( & ret , " , 'attempts': [ " ) ;
else
tal_append_fmt ( & ret , " , " ) ;
add_attempt ( & ret , ps , & ps - > attempts [ i ] ) ;
}
tal_append_fmt ( & ret , " ] } " ) ;
json_out_start ( ret , " attempts " , ' [ ' ) ;
for ( size_t i = 0 ; i < tal_count ( ps - > attempts ) ; i + + )
add_attempt ( ret , ps , & ps - > attempts [ i ] ) ;
json_out_end ( ret , ' ] ' ) ;
json_out_end ( ret , ' } ' ) ;
}
tal_append_fmt ( & ret , " ] } " ) ;
json_out_end ( ret , ' ] ' ) ;
json_out_end ( ret , ' } ' ) ;
return command_success ( cmd , ret ) ;
}
static const jsmntok_t * copy_member ( char * * ret ,
const char * buf ,
const jsmntok_t * result ,
const char * membername ,
const char * term )
/* Copy field and member to output, if it exists: return member */
static const jsmntok_t * copy_member ( struct json_out * ret ,
const char * buf , const jsmntok_t * obj ,
const char * membername )
{
const jsmntok_t * m = json_get_member ( buf , result , membername ) ;
if ( m )
tal_append_fmt ( ret , " '%s': %.*s%s " ,
membername ,
json_tok_full_len ( m ) , json_tok_full ( buf , m ) ,
term ) ;
const jsmntok_t * m = json_get_member ( buf , obj , membername ) ;
if ( ! m )
return NULL ;
/* Literal copy: it's already JSON escaped, and may be a string. */
json_out_add_raw_len ( ret , membername ,
json_tok_full ( buf , m ) , json_tok_full_len ( m ) ) ;
return m ;
}
@ -1175,33 +1186,30 @@ static struct command_result *listsendpays_done(struct command *cmd,
{
size_t i ;
const jsmntok_t * t , * arr ;
char * ret ;
bool some = false ;
struct json_out * ret ;
arr = json_get_member ( buf , result , " payments " ) ;
if ( ! arr | | arr - > type ! = JSMN_ARRAY )
return command_fail ( cmd , LIGHTNINGD ,
" Unexpected non-array result from listsendpays " ) ;
ret = tal_fmt ( cmd , " { 'pays': [ " ) ;
ret = json_out_new ( NULL ) ;
json_out_start ( ret , NULL , ' { ' ) ;
json_out_start ( ret , " pays " , ' [ ' ) ;
json_for_each_arr ( i , t , arr ) {
const jsmntok_t * status , * b11 ;
if ( some )
tal_append_fmt ( & ret , " , \n " ) ;
some = true ;
tal_append_fmt ( & ret , " { " ) ;
json_out_start ( ret , NULL , ' { ' ) ;
/* Old payments didn't have bolt11 field */
b11 = copy_member ( & ret , buf , t , " bolt11 " , " , " ) ;
b11 = copy_member ( ret , buf , t , " bolt11 " ) ;
if ( ! b11 ) {
if ( b11str ) {
/* If it's a single query, we can fake it */
tal_append_fmt ( & ret , " ' bolt11': '%s', " , b11str ) ;
json_out_addstr ( ret , " bolt11 " , b11str ) ;
} else {
copy_member ( & ret , buf , t , " payment_hash " , " , " ) ;
copy_member ( & ret , buf , t , " destination " , " , " ) ;
copy_member ( & ret , buf , t , " amount_msat " , " , " ) ;
copy_member ( ret , buf , t , " payment_hash " ) ;
copy_member ( ret , buf , t , " destination " ) ;
copy_member ( ret , buf , t , " amount_msat " ) ;
}
}
@ -1210,19 +1218,20 @@ static struct command_result *listsendpays_done(struct command *cmd,
if ( status ) {
if ( json_tok_streq ( buf , status , " failed " )
& & attempt_ongoing ( buf , b11 ) ) {
tal_append_fmt ( & ret , " 'status': 'pending', " ) ;
json_out_addstr ( ret , " status " , " pending " ) ;
} else {
copy_member ( & ret , buf , t , " status " , " , " ) ;
copy_member ( ret , buf , t , " status " ) ;
if ( json_tok_streq ( buf , status , " complete " ) )
copy_member ( & ret , buf , t ,
" payment_preimage " , " , " ) ;
copy_member ( ret , buf , t ,
" payment_preimage " ) ;
}
}
copy_member ( & ret , buf , t , " label " , " , " ) ;
copy_member ( & ret , buf , t , " amount_sent_msat " , " " ) ;
tal _app end_fmt ( & ret , " } " ) ;
copy_member ( ret , buf , t , " label " ) ;
copy_member ( ret , buf , t , " amount_sent_msat " ) ;
json_ou t_end( ret , ' } ' ) ;
}
tal_append_fmt ( & ret , " ] } " ) ;
json_out_end ( ret , ' ] ' ) ;
json_out_end ( ret , ' } ' ) ;
return command_success ( cmd , ret ) ;
}
@ -1230,7 +1239,7 @@ static struct command_result *json_listpays(struct command *cmd,
const char * buf ,
const jsmntok_t * params )
{
const char * b11str , * paramstr ;
const char * b11str ;
/* FIXME: would be nice to parse as a bolt11 so check worked in future */
if ( ! param ( cmd , buf , params ,
@ -1238,26 +1247,25 @@ static struct command_result *json_listpays(struct command *cmd,
NULL ) )
return NULL ;
if ( b11str )
paramstr = tal_fmt ( tmpctx , " 'bolt11' : '%s' " , b11str ) ;
else
paramstr = " " ;
return send_outreq ( cmd , " listsendpays " ,
listsendpays_done , forward_error ,
cast_const ( char * , b11str ) ,
" %s " , paramstr ) ;
/* Neatly returns empty object if b11str is NULL */
take ( json_out_obj ( NULL , " bolt11 " , b11str ) ) ) ;
}
static void init ( struct plugin_conn * rpc )
{
const char * field ;
field = rpc_delve ( tmpctx , " getinfo " , " " , rpc , " .id " ) ;
field = rpc_delve ( tmpctx , " getinfo " ,
take ( json_out_obj ( NULL , NULL , NULL ) ) , rpc , " .id " ) ;
if ( ! node_id_from_hexstr ( field , strlen ( field ) , & my_id ) )
plugin_err ( " getinfo didn't contain valid id: '%s' " , field ) ;
field = rpc_delve ( tmpctx , " listconfigs " ,
" 'config': 'max-locktime-blocks' " ,
take ( json_out_obj ( NULL ,
" config " , " max-locktime-blocks " ) ) ,
rpc , " .max-locktime-blocks " ) ;
maxdelay_default = atoi ( field ) ;
}