channel-lease: validate accepter's sig on lease terms

This commit is contained in:
niftynei 2021-06-14 14:22:46 -05:00 committed by neil saitug
parent 89f210fcd6
commit 9dd0a2c2e5
10 changed files with 343 additions and 26 deletions

View File

@ -1,4 +1,6 @@
#include "config.h"
#include <bitcoin/pubkey.h>
#include <ccan/ccan/crypto/sha256/sha256.h>
#include <ccan/ccan/mem/mem.h>
#include <common/amount.h>
#include <common/lease_rates.h>
@ -17,6 +19,32 @@ bool lease_rates_empty(struct lease_rates *rates)
&& rates->lease_fee_basis == 0;
}
void lease_rates_get_commitment(struct pubkey *pubkey,
u32 lease_expiry,
u32 chan_fee_msat,
u16 chan_fee_ppt,
struct sha256 *sha)
{
struct sha256_ctx sctx = SHA256_INIT;
u8 der[PUBKEY_CMPR_LEN];
/* BOLT- #2:
* - MUST set `signature` to the ECDSA signature of
* SHA256("option_will_fund"
* || `funding_pubkey`
* || `blockheight` + 4032
* || `channel_fee_max_base_msat`
* || `channel_fee_max_proportional_thousandths`)
* using the node_id key.
*/
pubkey_to_der(der, pubkey);
sha256_update(&sctx, "option_will_fund", strlen("option_will_fund"));
sha256_update(&sctx, der, PUBKEY_CMPR_LEN);
sha256_be32(&sctx, lease_expiry);
sha256_be32(&sctx, chan_fee_msat);
sha256_be16(&sctx, chan_fee_ppt);
sha256_done(&sctx, sha);
}
bool lease_rates_set_chan_fee_base_msat(struct lease_rates *rates,
struct amount_msat amt)
{

View File

@ -6,9 +6,19 @@
struct amount_msat;
struct amount_sat;
struct lease_rates;
struct pubkey;
struct sha256;
#define LEASE_RATE_DURATION 4032
bool lease_rates_empty(struct lease_rates *rates);
void lease_rates_get_commitment(struct pubkey *pubkey,
u32 lease_expiry,
u32 chan_fee_msat,
u16 chan_fee_ppt,
struct sha256 *sha);
WARN_UNUSED_RESULT bool lease_rates_set_chan_fee_base_msat(struct lease_rates *rates, struct amount_msat amt);
WARN_UNUSED_RESULT bool lease_rates_set_lease_fee_sat(struct lease_rates *rates, struct amount_sat amt);

View File

@ -0,0 +1,105 @@
#include "../amount.c"
#include "../lease_rates.c"
#include <assert.h>
#include <ccan/ccan/crypto/sha256/sha256.h>
#include <bitcoin/pubkey.h>
#include <common/setup.h>
#include <common/utils.h>
#include <stdio.h>
#include <wire/wire.h>
/* AUTOGENERATED MOCKS START */
/* Generated stub for fromwire */
const u8 *fromwire(const u8 **cursor UNNEEDED, size_t *max UNNEEDED, void *copy UNNEEDED, size_t n UNNEEDED)
{ fprintf(stderr, "fromwire called!\n"); abort(); }
/* Generated stub for fromwire_bool */
bool fromwire_bool(const u8 **cursor UNNEEDED, size_t *max UNNEEDED)
{ fprintf(stderr, "fromwire_bool called!\n"); abort(); }
/* Generated stub for fromwire_fail */
void *fromwire_fail(const u8 **cursor UNNEEDED, size_t *max UNNEEDED)
{ fprintf(stderr, "fromwire_fail called!\n"); abort(); }
/* Generated stub for fromwire_secp256k1_ecdsa_signature */
void fromwire_secp256k1_ecdsa_signature(const u8 **cursor UNNEEDED, size_t *max UNNEEDED,
secp256k1_ecdsa_signature *signature UNNEEDED)
{ fprintf(stderr, "fromwire_secp256k1_ecdsa_signature called!\n"); abort(); }
/* Generated stub for fromwire_sha256 */
void fromwire_sha256(const u8 **cursor UNNEEDED, size_t *max UNNEEDED, struct sha256 *sha256 UNNEEDED)
{ fprintf(stderr, "fromwire_sha256 called!\n"); abort(); }
/* Generated stub for fromwire_tal_arrn */
u8 *fromwire_tal_arrn(const tal_t *ctx UNNEEDED,
const u8 **cursor UNNEEDED, size_t *max UNNEEDED, size_t num UNNEEDED)
{ fprintf(stderr, "fromwire_tal_arrn called!\n"); abort(); }
/* Generated stub for fromwire_u16 */
u16 fromwire_u16(const u8 **cursor UNNEEDED, size_t *max UNNEEDED)
{ fprintf(stderr, "fromwire_u16 called!\n"); abort(); }
/* Generated stub for fromwire_u32 */
u32 fromwire_u32(const u8 **cursor UNNEEDED, size_t *max UNNEEDED)
{ fprintf(stderr, "fromwire_u32 called!\n"); abort(); }
/* Generated stub for fromwire_u64 */
u64 fromwire_u64(const u8 **cursor UNNEEDED, size_t *max UNNEEDED)
{ fprintf(stderr, "fromwire_u64 called!\n"); abort(); }
/* Generated stub for fromwire_u8 */
u8 fromwire_u8(const u8 **cursor UNNEEDED, size_t *max UNNEEDED)
{ fprintf(stderr, "fromwire_u8 called!\n"); abort(); }
/* Generated stub for fromwire_u8_array */
void fromwire_u8_array(const u8 **cursor UNNEEDED, size_t *max UNNEEDED, u8 *arr UNNEEDED, size_t num UNNEEDED)
{ fprintf(stderr, "fromwire_u8_array called!\n"); abort(); }
/* Generated stub for towire */
void towire(u8 **pptr UNNEEDED, const void *data UNNEEDED, size_t len UNNEEDED)
{ fprintf(stderr, "towire called!\n"); abort(); }
/* Generated stub for towire_bool */
void towire_bool(u8 **pptr UNNEEDED, bool v UNNEEDED)
{ fprintf(stderr, "towire_bool called!\n"); abort(); }
/* Generated stub for towire_secp256k1_ecdsa_signature */
void towire_secp256k1_ecdsa_signature(u8 **pptr UNNEEDED,
const secp256k1_ecdsa_signature *signature UNNEEDED)
{ fprintf(stderr, "towire_secp256k1_ecdsa_signature called!\n"); abort(); }
/* Generated stub for towire_sha256 */
void towire_sha256(u8 **pptr UNNEEDED, const struct sha256 *sha256 UNNEEDED)
{ fprintf(stderr, "towire_sha256 called!\n"); abort(); }
/* Generated stub for towire_u16 */
void towire_u16(u8 **pptr UNNEEDED, u16 v UNNEEDED)
{ fprintf(stderr, "towire_u16 called!\n"); abort(); }
/* Generated stub for towire_u32 */
void towire_u32(u8 **pptr UNNEEDED, u32 v UNNEEDED)
{ fprintf(stderr, "towire_u32 called!\n"); abort(); }
/* Generated stub for towire_u64 */
void towire_u64(u8 **pptr UNNEEDED, u64 v UNNEEDED)
{ fprintf(stderr, "towire_u64 called!\n"); abort(); }
/* Generated stub for towire_u8 */
void towire_u8(u8 **pptr UNNEEDED, u8 v UNNEEDED)
{ fprintf(stderr, "towire_u8 called!\n"); abort(); }
/* Generated stub for towire_u8_array */
void towire_u8_array(u8 **pptr UNNEEDED, const u8 *arr UNNEEDED, size_t num UNNEEDED)
{ fprintf(stderr, "towire_u8_array called!\n"); abort(); }
/* AUTOGENERATED MOCKS END */
static void check_lease_rate_commitment_hash(void)
{
struct pubkey p;
struct sha256 sha;
u8 *expected;
assert(pubkey_from_hexstr("032cf15d1ad9c4a08d26eab1918f732d8ef8fdc6abb9640bf3db174372c491304e", strlen("032cf15d1ad9c4a08d26eab1918f732d8ef8fdc6abb9640bf3db174372c491304e"), &p));
lease_rates_get_commitment(&p, 0, 0, 0, &sha);
expected = tal_hexdata(tmpctx, "adc2973c151fecf212019dc3228a6765277cec6ab958959923839238a01cc1ce", strlen("adc2973c151fecf212019dc3228a6765277cec6ab958959923839238a01cc1ce"));
assert(memeq(expected, tal_bytelen(expected),
&sha.u.u8, sizeof(sha.u.u8)));
lease_rates_get_commitment(&p, 255, 100, 50, &sha);
expected = tal_hexdata(tmpctx, "d363b338db30a4abd184e576773befb6a05ba61cec4169998ccbf546a720e421", strlen("d363b338db30a4abd184e576773befb6a05ba61cec4169998ccbf546a720e421"));
assert(memeq(expected, tal_bytelen(expected),
&sha.u.u8, sizeof(sha.u.u8)));
}
int main(int argc, char *argv[])
{
common_setup(argv[0]);
check_lease_rate_commitment_hash();
common_shutdown();
}

View File

@ -31,6 +31,7 @@ HSMD_COMMON_OBJS := \
common/hash_u5.o \
common/hsm_encryption.o \
common/key_derive.o \
common/lease_rates.o \
common/memleak.o \
common/msg_queue.o \
common/node_id.o \

View File

@ -3,6 +3,7 @@
#include <common/bolt12_merkle.h>
#include <common/hash_u5.h>
#include <common/key_derive.h>
#include <common/lease_rates.h>
#include <common/type_to_string.h>
#include <hsmd/capabilities.h>
#include <hsmd/libhsmd.h>
@ -477,35 +478,23 @@ static u8 *handle_sign_option_will_fund_offer(struct hsmd_client *c,
const u8 *msg_in)
{
struct pubkey funding_pubkey;
u32 blockheight, channel_fee_base_max_msat;
u16 channel_fee_proportional_basis_max;
struct sha256_ctx sctx = SHA256_INIT;
u32 lease_expiry, channel_fee_base_max_msat;
u16 channel_fee_max_ppt;
struct sha256 sha;
secp256k1_ecdsa_signature sig;
struct privkey node_pkey;
if (!fromwire_hsmd_sign_option_will_fund_offer(msg_in,
&funding_pubkey,
&blockheight,
&lease_expiry,
&channel_fee_base_max_msat,
&channel_fee_proportional_basis_max))
&channel_fee_max_ppt))
return hsmd_status_malformed_request(c, msg_in);
/* BOLT- #2:
* - MUST set `signature` to the ECDSA signature of
* SHA256("option_will_fund" || `funding_pubkey`|| `blockheight` ||
* `channel_fee_base_max_msat` ||
* `channel_fee_proportional_basis_max`)
*/
sha256_update(&sctx, "option_will_fund",
strlen("option_will_fund"));
sha256_update(&sctx, &funding_pubkey, sizeof(funding_pubkey));
sha256_update(&sctx, &blockheight, sizeof(blockheight));
sha256_update(&sctx, &channel_fee_base_max_msat,
sizeof(channel_fee_base_max_msat));
sha256_update(&sctx, &channel_fee_base_max_msat,
sizeof(channel_fee_base_max_msat));
sha256_done(&sctx, &sha);
lease_rates_get_commitment(&funding_pubkey, lease_expiry,
channel_fee_base_max_msat,
channel_fee_max_ppt,
&sha);
node_key(&node_pkey, NULL);

View File

@ -1913,6 +1913,72 @@ static void handle_peer_tx_sigs_msg(struct subd *dualopend,
inflight->funding_psbt);
}
static bool verify_option_will_fund_signature(struct peer *peer,
struct pubkey *funding_pubkey,
u32 lease_expiry,
u32 chan_fee_msat,
u16 chan_fee_ppt,
const secp256k1_ecdsa_signature *sig)
{
struct pubkey their_pubkey;
struct sha256 sha;
int ret;
lease_rates_get_commitment(funding_pubkey, lease_expiry,
chan_fee_msat, chan_fee_ppt,
&sha);
if (!pubkey_from_node_id(&their_pubkey, &peer->id)) {
log_broken(peer->ld->log,
"Unable to extract pubkey from peer's node id %s",
type_to_string(tmpctx, struct node_id, &peer->id));
return false;
}
ret = secp256k1_ecdsa_verify(secp256k1_ctx, sig, sha.u.u8,
&their_pubkey.pubkey);
return ret == 1;
}
static void handle_validate_lease(struct subd *dualopend,
const u8 *msg)
{
const secp256k1_ecdsa_signature sig;
u16 chan_fee_max_ppt;
u32 chan_fee_max_base_msat, lease_expiry;
struct pubkey their_pubkey;
struct channel *chan;
char *err_msg;
if (!fromwire_dualopend_validate_lease(msg,
cast_const(secp256k1_ecdsa_signature *, &sig),
&lease_expiry,
&chan_fee_max_base_msat,
&chan_fee_max_ppt,
&their_pubkey)) {
channel_internal_error(dualopend->channel,
"Bad DUALOPEND_VALIDATE_LEASE: %s",
tal_hex(tmpctx, msg));
return;
}
assert(dualopend->channel);
chan = dualopend->channel;
if (!verify_option_will_fund_signature(chan->peer, &their_pubkey,
lease_expiry,
chan_fee_max_base_msat,
chan_fee_max_ppt,
&sig))
err_msg = "Unable to verify sig";
else
err_msg = NULL;
subd_send_msg(dualopend,
take(towire_dualopend_validate_lease_reply(NULL, err_msg)));
}
static void handle_validate_rbf(struct subd *dualopend,
const u8 *msg)
{
@ -2929,6 +2995,9 @@ static unsigned int dual_opend_msg(struct subd *dualopend,
case WIRE_DUALOPEND_RBF_VALIDATE:
handle_validate_rbf(dualopend, msg);
return 0;
case WIRE_DUALOPEND_VALIDATE_LEASE:
handle_validate_lease(dualopend, msg);
return 0;
case WIRE_DUALOPEND_FUNDING_SIGS:
handle_peer_tx_sigs_msg(dualopend, msg);
return 0;
@ -2967,6 +3036,7 @@ static unsigned int dual_opend_msg(struct subd *dualopend,
case WIRE_DUALOPEND_GOT_OFFER_REPLY:
case WIRE_DUALOPEND_GOT_RBF_OFFER_REPLY:
case WIRE_DUALOPEND_RBF_VALID:
case WIRE_DUALOPEND_VALIDATE_LEASE_REPLY:
case WIRE_DUALOPEND_FAIL:
case WIRE_DUALOPEND_PSBT_UPDATED:
case WIRE_DUALOPEND_SEND_TX_SIGS:

View File

@ -33,6 +33,7 @@
#include <common/gossip_store.h>
#include <common/htlc.h>
#include <common/initial_channel.h>
#include <common/lease_rates.h>
#include <common/memleak.h>
#include <common/peer_billboard.h>
#include <common/peer_failed.h>
@ -2182,7 +2183,7 @@ static void accepter_start(struct state *state, const u8 *oc2_msg)
if (open_tlv->request_funds && tx_state->rates)
accept_tlv_add_offer(a_tlv, tx_state->rates,
state->our_funding_pubkey,
lease_blockheight_start);
lease_blockheight_start + LEASE_RATE_DURATION);
msg = towire_accept_channel2(tmpctx, &state->channel_id,
tx_state->accepter_funding,
@ -2490,7 +2491,7 @@ static void opener_start(struct state *state, u8 *msg)
struct channel_id cid;
char *err_reason;
struct amount_sat total, requested_sats;
u32 current_blockheight;
u32 current_blockheight, lease_expiry;
bool dry_run;
struct tx_state *tx_state = state->tx_state;
@ -2643,8 +2644,30 @@ static void opener_start(struct state *state, u8 *msg)
/* FIXME: BOLT QUOTE */
if (open_tlv->request_funds && a_tlv->will_fund) {
/* OK! lease mode activated */
}
char *err_msg;
struct lease_rates *rates = &a_tlv->will_fund->lease_rates;
lease_expiry = current_blockheight + LEASE_RATE_DURATION;
msg = towire_dualopend_validate_lease(NULL,
&a_tlv->will_fund->signature,
lease_expiry,
rates->channel_fee_max_base_msat,
rates->channel_fee_max_proportional_thousandths,
&state->their_funding_pubkey);
wire_sync_write(REQ_FD, take(msg));
msg = wire_sync_read(tmpctx, REQ_FD);
if (!fromwire_dualopend_validate_lease_reply(tmpctx, msg,
&err_msg))
master_badmsg(WIRE_DUALOPEND_VALIDATE_LEASE_REPLY, msg);
if (err_msg)
open_err_warn(state, "%s", err_msg);
} else
lease_expiry = 0;
/* Check that total funding doesn't overflow */
if (!amount_sat_add(&total, tx_state->opener_funding,
@ -3399,6 +3422,7 @@ static u8 *handle_master_in(struct state *state)
case WIRE_DUALOPEND_GOT_OFFER_REPLY:
case WIRE_DUALOPEND_GOT_RBF_OFFER_REPLY:
case WIRE_DUALOPEND_RBF_VALID:
case WIRE_DUALOPEND_VALIDATE_LEASE_REPLY:
/* Messages we send */
case WIRE_DUALOPEND_GOT_OFFER:
@ -3414,6 +3438,7 @@ static u8 *handle_master_in(struct state *state)
case WIRE_DUALOPEND_SHUTDOWN_COMPLETE:
case WIRE_DUALOPEND_FAIL_FALLEN_BEHIND:
case WIRE_DUALOPEND_DRY_RUN:
case WIRE_DUALOPEND_VALIDATE_LEASE:
break;
}

View File

@ -9,6 +9,7 @@
#include <common/htlc_wire.h>
#include <common/penalty_base.h>
#include <common/per_peer_state.h>
#include <secp256k1.h>
#include <wire/peer_wire.h>
msgtype,dualopend_init,7000
@ -221,3 +222,14 @@ msgdata,dualopend_dry_run,channel_id,channel_id,
msgdata,dualopend_dry_run,our_funding,amount_sat,
msgdata,dualopend_dry_run,their_funding,amount_sat,
msgdata,dualopend_dry_run,lease_rates,?lease_rates,
# dualopend -> master: validate liqudity offer sig
msgtype,dualopend_validate_lease,7027
msgdata,dualopend_validate_lease,sig,secp256k1_ecdsa_signature,
msgdata,dualopend_validate_lease,lease_expiry,u32,
msgdata,dualopend_validate_lease,chan_fee_max_base_msat,u32,
msgdata,dualopend_validate_lease,chan_fee_max_ppt,u16,
msgdata,dualopend_validate_lease,their_pubkey,pubkey,
msgtype,dualopend_validate_lease_reply,7127
msgdata,dualopend_validate_lease_reply,err_msg,?wirestring,

Can't render this file because it has a wrong number of fields in line 15.

View File

@ -47,6 +47,8 @@ const char *dualopend_wire_name(int e)
case WIRE_DUALOPEND_DEV_MEMLEAK: return "WIRE_DUALOPEND_DEV_MEMLEAK";
case WIRE_DUALOPEND_DEV_MEMLEAK_REPLY: return "WIRE_DUALOPEND_DEV_MEMLEAK_REPLY";
case WIRE_DUALOPEND_DRY_RUN: return "WIRE_DUALOPEND_DRY_RUN";
case WIRE_DUALOPEND_VALIDATE_LEASE: return "WIRE_DUALOPEND_VALIDATE_LEASE";
case WIRE_DUALOPEND_VALIDATE_LEASE_REPLY: return "WIRE_DUALOPEND_VALIDATE_LEASE_REPLY";
}
snprintf(invalidbuf, sizeof(invalidbuf), "INVALID %i", e);
@ -83,6 +85,8 @@ bool dualopend_wire_is_defined(u16 type)
case WIRE_DUALOPEND_DEV_MEMLEAK:;
case WIRE_DUALOPEND_DEV_MEMLEAK_REPLY:;
case WIRE_DUALOPEND_DRY_RUN:;
case WIRE_DUALOPEND_VALIDATE_LEASE:;
case WIRE_DUALOPEND_VALIDATE_LEASE_REPLY:;
return true;
}
return false;
@ -974,4 +978,64 @@ bool fromwire_dualopend_dry_run(const tal_t *ctx, const void *p, struct channel_
}
return cursor != NULL;
}
// SHA256STAMP:a0ce1d5dfc6518a35d2e346c770754c498558ac426e3040526e10bbbc237db6f
/* WIRE: DUALOPEND_VALIDATE_LEASE */
/* dualopend -> master: validate liqudity offer sig */
u8 *towire_dualopend_validate_lease(const tal_t *ctx, const secp256k1_ecdsa_signature *sig, u32 lease_expiry, u32 chan_fee_max_base_msat, u16 chan_fee_max_ppt, const struct pubkey *their_pubkey)
{
u8 *p = tal_arr(ctx, u8, 0);
towire_u16(&p, WIRE_DUALOPEND_VALIDATE_LEASE);
towire_secp256k1_ecdsa_signature(&p, sig);
towire_u32(&p, lease_expiry);
towire_u32(&p, chan_fee_max_base_msat);
towire_u16(&p, chan_fee_max_ppt);
towire_pubkey(&p, their_pubkey);
return memcheck(p, tal_count(p));
}
bool fromwire_dualopend_validate_lease(const void *p, secp256k1_ecdsa_signature *sig, u32 *lease_expiry, u32 *chan_fee_max_base_msat, u16 *chan_fee_max_ppt, struct pubkey *their_pubkey)
{
const u8 *cursor = p;
size_t plen = tal_count(p);
if (fromwire_u16(&cursor, &plen) != WIRE_DUALOPEND_VALIDATE_LEASE)
return false;
fromwire_secp256k1_ecdsa_signature(&cursor, &plen, sig);
*lease_expiry = fromwire_u32(&cursor, &plen);
*chan_fee_max_base_msat = fromwire_u32(&cursor, &plen);
*chan_fee_max_ppt = fromwire_u16(&cursor, &plen);
fromwire_pubkey(&cursor, &plen, their_pubkey);
return cursor != NULL;
}
/* WIRE: DUALOPEND_VALIDATE_LEASE_REPLY */
u8 *towire_dualopend_validate_lease_reply(const tal_t *ctx, const wirestring *err_msg)
{
u8 *p = tal_arr(ctx, u8, 0);
towire_u16(&p, WIRE_DUALOPEND_VALIDATE_LEASE_REPLY);
if (!err_msg)
towire_bool(&p, false);
else {
towire_bool(&p, true);
towire_wirestring(&p, err_msg);
}
return memcheck(p, tal_count(p));
}
bool fromwire_dualopend_validate_lease_reply(const tal_t *ctx, const void *p, wirestring **err_msg)
{
const u8 *cursor = p;
size_t plen = tal_count(p);
if (fromwire_u16(&cursor, &plen) != WIRE_DUALOPEND_VALIDATE_LEASE_REPLY)
return false;
if (!fromwire_bool(&cursor, &plen))
*err_msg = NULL;
else {
*err_msg = fromwire_wirestring(ctx, &cursor, &plen);
}
return cursor != NULL;
}
// SHA256STAMP:41650a0d42866067279024744de6ef7e52ff0ef5a406c4be3b702f1ecf11e556

View File

@ -18,6 +18,7 @@
#include <common/htlc_wire.h>
#include <common/penalty_base.h>
#include <common/per_peer_state.h>
#include <secp256k1.h>
#include <wire/peer_wire.h>
enum dualopend_wire {
@ -74,6 +75,9 @@ enum dualopend_wire {
WIRE_DUALOPEND_DEV_MEMLEAK_REPLY = 7133,
/* dualopend -> master: this was a dry run */
WIRE_DUALOPEND_DRY_RUN = 7026,
/* dualopend -> master: validate liqudity offer sig */
WIRE_DUALOPEND_VALIDATE_LEASE = 7027,
WIRE_DUALOPEND_VALIDATE_LEASE_REPLY = 7127,
};
const char *dualopend_wire_name(int e);
@ -222,6 +226,15 @@ bool fromwire_dualopend_dev_memleak_reply(const void *p, bool *leak);
u8 *towire_dualopend_dry_run(const tal_t *ctx, const struct channel_id *channel_id, struct amount_sat our_funding, struct amount_sat their_funding, const struct lease_rates *lease_rates);
bool fromwire_dualopend_dry_run(const tal_t *ctx, const void *p, struct channel_id *channel_id, struct amount_sat *our_funding, struct amount_sat *their_funding, struct lease_rates **lease_rates);
/* WIRE: DUALOPEND_VALIDATE_LEASE */
/* dualopend -> master: validate liqudity offer sig */
u8 *towire_dualopend_validate_lease(const tal_t *ctx, const secp256k1_ecdsa_signature *sig, u32 lease_expiry, u32 chan_fee_max_base_msat, u16 chan_fee_max_ppt, const struct pubkey *their_pubkey);
bool fromwire_dualopend_validate_lease(const void *p, secp256k1_ecdsa_signature *sig, u32 *lease_expiry, u32 *chan_fee_max_base_msat, u16 *chan_fee_max_ppt, struct pubkey *their_pubkey);
/* WIRE: DUALOPEND_VALIDATE_LEASE_REPLY */
u8 *towire_dualopend_validate_lease_reply(const tal_t *ctx, const wirestring *err_msg);
bool fromwire_dualopend_validate_lease_reply(const tal_t *ctx, const void *p, wirestring **err_msg);
#endif /* LIGHTNING_OPENINGD_DUALOPEND_WIREGEN_H */
// SHA256STAMP:a0ce1d5dfc6518a35d2e346c770754c498558ac426e3040526e10bbbc237db6f
// SHA256STAMP:41650a0d42866067279024744de6ef7e52ff0ef5a406c4be3b702f1ecf11e556