diff --git a/common/lease_rates.c b/common/lease_rates.c index cd70734a0..eb8434737 100644 --- a/common/lease_rates.c +++ b/common/lease_rates.c @@ -1,4 +1,6 @@ #include "config.h" +#include +#include #include #include #include @@ -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) { diff --git a/common/lease_rates.h b/common/lease_rates.h index 2c4a82002..cc7bc7aaf 100644 --- a/common/lease_rates.h +++ b/common/lease_rates.h @@ -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); diff --git a/common/test/run-lease_rates.c b/common/test/run-lease_rates.c new file mode 100644 index 000000000..45c2b5027 --- /dev/null +++ b/common/test/run-lease_rates.c @@ -0,0 +1,105 @@ +#include "../amount.c" +#include "../lease_rates.c" +#include +#include +#include +#include +#include +#include +#include + +/* 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(); +} diff --git a/hsmd/Makefile b/hsmd/Makefile index 6e1870524..afd120d64 100644 --- a/hsmd/Makefile +++ b/hsmd/Makefile @@ -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 \ diff --git a/hsmd/libhsmd.c b/hsmd/libhsmd.c index 0f2cacdcf..944982f1d 100644 --- a/hsmd/libhsmd.c +++ b/hsmd/libhsmd.c @@ -3,6 +3,7 @@ #include #include #include +#include #include #include #include @@ -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); diff --git a/lightningd/dual_open_control.c b/lightningd/dual_open_control.c index d84817d67..3019ca97c 100644 --- a/lightningd/dual_open_control.c +++ b/lightningd/dual_open_control.c @@ -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: diff --git a/openingd/dualopend.c b/openingd/dualopend.c index 2dc6eaac2..26be290b9 100644 --- a/openingd/dualopend.c +++ b/openingd/dualopend.c @@ -33,6 +33,7 @@ #include #include #include +#include #include #include #include @@ -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; } diff --git a/openingd/dualopend_wire.csv b/openingd/dualopend_wire.csv index 2cf80caa9..36846061a 100644 --- a/openingd/dualopend_wire.csv +++ b/openingd/dualopend_wire.csv @@ -9,6 +9,7 @@ #include #include #include +#include #include 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, diff --git a/openingd/dualopend_wiregen.c b/openingd/dualopend_wiregen.c index 97ed07980..3fe527a87 100644 --- a/openingd/dualopend_wiregen.c +++ b/openingd/dualopend_wiregen.c @@ -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 diff --git a/openingd/dualopend_wiregen.h b/openingd/dualopend_wiregen.h index 66bb3de80..35263d206 100644 --- a/openingd/dualopend_wiregen.h +++ b/openingd/dualopend_wiregen.h @@ -18,6 +18,7 @@ #include #include #include +#include #include 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