Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

closingd: configurable closing fee negotiation step #3390

Merged
merged 2 commits into from
Apr 7, 2020

Conversation

vasild
Copy link
Contributor

@vasild vasild commented Jan 3, 2020

When negotiating the transaction fee for closing a channel [1], we used
to always pick the middle of the range between our proposal and the
peer's proposal.

Introduce a new option fee_negotiation_step to the close command, so
the peer who initiates the close can choose his back off step.

Partially resolves #3270

[1] https://github.com/lightningnetwork/lightning-rfc/blob/master/02-peer-protocol.md#closing-negotiation-closing_signed

Changelog-Added: New optional parameter to the close command to control the closing transaction fee negotiation back off step

@vasild
Copy link
Contributor Author

vasild commented Jan 3, 2020

To complete this PR:

  • Make this behavior configurable (replace the if (true)). Maybe add a global config option --stubborn-closing-fee-negotiation? What about setting this behavior per channel?
  • Add tests - how much of this code is covered by existent tests? Maybe this change warrants adding more tests.
  • [ ] Add a way to manually specify the starting fee for the negotiation. Maybe extend the close command. This is going to be done in a separate PR.

Specifying the negotiation step and starting fee if we are not the side that initiated the channel close is left away from this PR.

@ZmnSCPxj
Copy link
Collaborator

ZmnSCPxj commented Jan 4, 2020

Maybe add a global config option --stubborn-closing-fee-negotiation? What about setting this behavior per channel?

Would not an option to the close command be better?

Also, what about specifying the fee if we are not the side that initiated the channel close?

Given that the closing fee is paid for by the side which opened the channel ("initiator pays" principle which closes some active griefing attacks), perhaps it should only matter for such channels where I opened but the other side wants to close? In such a case perhaps it should be stubborn as well.

Detecting the stubborn closing behavior from the closing peer might also be an option to trigger stubborn closing behavior on our side when we are not the one initiating the close.

@vasild
Copy link
Contributor Author

vasild commented Jan 4, 2020

@ZmnSCPxj yes, an option to the close command would be better, but it would be best if both sides can specify the negotiation strategy and the starting fee.

We have two new config options (per channel): 1. closing negotiation step (as % or satoshi) and 2. closing negotiation starting fee.

What about this:

  • When opening a channel one can specify 1. and 2. They are saved somewhere in the database and used during channel close. If the saved fee turns out to be too high during close, then it is lowered to "the base fee of the final commitment transaction". The default values, if not specified would be "strategy=bisect" and "fee=derive from bitcoind during close".
  • During channel lifetime 1. and 2. can be updated by the user - in case he changed his mind or forgot to specify them during channel open or he was not the one who created the channel. Those two items are left away from this PR because they will increase the complexity of the code a lot. They can be added later on top of this PR.
  • It is possible to also specify 1. and 2. to the close command in which case the provided values override the ones from the database. -- 1. is being done in this PR, 2. in another PR.

@vasild
Copy link
Contributor Author

vasild commented Feb 26, 2020

@ZmnSCPxj, What would be the best way to pass an option of the close command to the fee negotiating code?

That is - adding a new option to the close command would mean that json_close() will receive it and then it needs to pass it somehow down the call chain, through the daemons towards closingd.

@ZmnSCPxj
Copy link
Collaborator

ZmnSCPxj commented Mar 3, 2020

Not sure, maybe add a field to struct channel in lightningd (which you would initialize from options, then override if the close command provides it)? Then send it over to closingd in peer_start_closingd. Note there are multiple different struct channel because hysterical raisins, make sure to add to the one in lightning/channel.h. @rustyrussell @cdecker @niftynei opinions?

@vasild
Copy link
Contributor Author

vasild commented Mar 3, 2020

Yes, I did exactly that after some staring at the code! Need to clean up the patch and will push it here.

I am not yet sure what would happen if lightningd gets restarted during the close fee negotiation. I guess the newly added option telling it how to negotiate would be lost.

@vasild
Copy link
Contributor Author

vasild commented Mar 10, 2020

Need to clean up the patch and will push it here.

Done, ready for review.

The first commit (mocks re-record) belongs to a separate PR, but then this PR would depend on it. Should I create a separate PR for it?

@vasild vasild marked this pull request as ready for review March 10, 2020 17:27
@vasild vasild requested a review from cdecker as a code owner March 10, 2020 17:27
Copy link
Collaborator

@darosior darosior left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I find it really cool to be able to greed on closing fees, could it be made to directly set the step for even more customability ?

contrib/pyln-client/pyln/client/__init__.py Outdated Show resolved Hide resolved
@vasild
Copy link
Contributor Author

vasild commented Mar 16, 2020

I find it really cool to be able to greed on closing fees, could it be made to directly set the step for even more customability ?

Yes, this would be even more flexible.

So we have an interval, lets say [x, y] and our next closing fee proposal must be a number from that interval. We also know if we started higher than the peer or lower - that is, if we would prefer to be closer to y or x.

The current code chooses (x + y) / 2.

This PR adds an option to pick x (if we started lower, ie prefer lower fee than the peer) or y (if we started higher, ie prefer higher fee than the peer).

What about instead of adding a close parameter fee_negotiation_strategy=(bisect|stubborn) to add fee_negotiation_step=(N|N%) which would give up "N satoshi" or "N% from the interval" on each negotiation step? Then

  • fee_negotiation_step=50% would be the default and equivalent to the current behavior (bisect)
  • fee_negotiation_step=1 would be equivalent to "stubborn" negotiation strategy where we give up just 1 satoshi at a time
  • fee_negotiation_step=100% would be to just accept peer's proposal and finish with negotiation as quickly as possible.

@vasild vasild changed the title closingd: negotiate closing fee one sat at a time closingd: configurable closing fee negotiation step Mar 17, 2020
Copy link
Collaborator

@darosior darosior left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looking forward to test it along with https://github.com/darosior/lightning/tree/set_closing_fees !

Fwiw I opted for another command in the above for the we-don't-initiated-the-close case.

* one from our previous proposal. So, if the user requested a
* step of 1 satoshi at a time we should just return our end of
* the range from this function. */
step = (struct amount_sat){fee_negotiation_step - 1};
Copy link
Collaborator

@darosior darosior Mar 18, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

amount_sat_from_u64() ? :)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you mean to add a new function amount_sat_from_u64()? Are there other places in the code that would benefit from it?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok I confused with msat_from_u64()...

void amount_msat_from_u64(struct amount_msat *msat, u64 millisatoshis)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That can still be used, but I think would be too cumbersome:

struct amount_msat step_msat;
...
amount_msat_from_u64(&step_msat, (fee_negotiation_step - 1) * MSAT_PER_SAT);
step = amount_msat_to_sat_round_down(step_msat);

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done that way with amount_msat_from_u64() because the typecast was upsetting make check-amount-access.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you are still better off adding the helper for sat, but it can be done in a follow up cleanup, I think?

@vasild vasild force-pushed the closure_fee branch 2 times, most recently from 662c351 to 9ab236a Compare March 24, 2020 11:26
tests/test_closing.py Outdated Show resolved Hide resolved
@vasild vasild force-pushed the closure_fee branch 5 times, most recently from 7b99bd8 to 6cb74f8 Compare March 27, 2020 10:36
Copy link
Collaborator

@darosior darosior left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ACK 6cb74f8

tests/test_closing.py Outdated Show resolved Hide resolved
@vasild vasild force-pushed the closure_fee branch 2 times, most recently from 1202797 to 45d9d9f Compare April 1, 2020 09:33
Copy link
Collaborator

@darosior darosior left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

re-ACK 45d9d9f

Use `LC_ALL=C sort` instead of `sort` so that mocks get sorted in
the same way on all developers' environments.

Re-record the result of `make update-mocks`.

Changelog-None
When negotiating the transaction fee for closing a channel [1], we used
to always pick the middle of the range between our proposal and the
peer's proposal.

Introduce a new option `fee_negotiation_step` to the close command, so
the peer who initiates the close can choose his back off step.

Partially resolves ElementsProject#3270

[1] https://github.com/lightningnetwork/lightning-rfc/blob/master/02-peer-protocol.md#closing-negotiation-closing_signed

Changelog-Added: New optional parameter to the `close` command to control the closing transaction fee negotiation back off step
@vasild
Copy link
Contributor Author

vasild commented Apr 6, 2020

Rebased due to conflicts with master.

Copy link
Contributor

@rustyrussell rustyrussell left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ack 26c25ca

Minor nits which can be fixed after, IMHO.

CLOSING_FEE_NEGOTIATION_STEP_UNIT_PERCENTAGE
? "%"
: "sat");

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

tal_fmt() is generally safer than snprintf, BTW.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It was using tal_fmt() in a previous incarnation of this PR. However, that ended up with an obscure use-after-free:

  • create the string with tal_fmt() from tmpctx
  • print the string with status_debug()
  • call do_reconnect() which calls closing_read_peer_msg() which calls clean_tmpctx() which frees tmpctx
  • try to print the string with peer_billboard(), but it is already freed

different than our estimate. On every negotiation step we must give up
some amount from our proposal towards the peer's proposal. This parameter
can be an integer in which case it is interpreted as number of satoshis
to step at a time. Or it can be an integer followed by "%s" to designate
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"%s"? Not sure where the 's' came from?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in a followup PR. I must have been in C-mode-autopilot when writing the .md file.


if (!param(cmd, buffer, params,
p_req("id", param_tok, &idtok),
p_opt_def("unilateraltimeout", param_number, &timeout,
48 * 3600),
p_opt("destination", param_bitcoin_address, &close_to_script),
p_opt("fee_negotiation_step", param_string,
&fee_negotiation_step_str),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Generally better to write a param handler for this: that way "check" calls it and does more checking for the caller.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Something like this:

patch
commit ef31b2b4
Parent: 48fa053f
Author:     Vasil Dimov <vd@FreeBSD.org>
AuthorDate: Tue Apr 7 12:03:24 2020 +0200
Commit:     Vasil Dimov <vd@FreeBSD.org>
CommitDate: Tue Apr 7 12:04:43 2020 +0200
gpg: Signature made Tue Apr  7 12:04:43 2020 CEST
gpg:                using RSA key E64D8D45614DB07545D9CCC154DF06F64B55CBBF
gpg: Good signature from "Vasil Dimov <vd@myforest.net>" [ultimate]
gpg:                 aka "Vasil Dimov <vd@FreeBSD.org>" [ultimate]
gpg:                 aka "Vasil Dimov <vasild@gmail.com>" [ultimate]


    json: add JSON handler for num or num%
    
    Add a generic handler that accepts either a bare number or a bare number
    followed by "%". Use that one when taking the "close fee negotiation
    step" argument of the close command.
    
    Changelog-None

diff --git a/common/json.c b/common/json.c
index b5af5e06..e1671622 100644
--- a/common/json.c
+++ b/common/json.c
@@ -76,12 +76,27 @@ bool json_to_u64(const char *buffer, const jsmntok_t *tok,
 	if (*num != l)
 		return false;
 
 	return true;
 }
 
+bool json_to_u64_or_u64pct(const char *buffer, const jsmntok_t *tok,
+			   struct u64_or_u64pct *result)
+{
+	jsmntok_t tok_copy = *tok;
+
+	if (buffer[tok_copy.end - 1] == '%') {
+		tok_copy.end--;
+		result->is_pct = true;
+	} else {
+		result->is_pct = false;
+	}
+
+	return json_to_u64(buffer, &tok_copy, &result->n);
+}
+
 bool json_to_s64(const char *buffer, const jsmntok_t *tok, s64 *num)
 {
 	char *end;
 	long long l;
 
 	l = strtoll(buffer + tok->start, &end, 0);
diff --git a/common/json.h b/common/json.h
index f92a634d..10c33e51 100644
--- a/common/json.h
+++ b/common/json.h
@@ -1,12 +1,13 @@
 #ifndef LIGHTNING_COMMON_JSON_H
 #define LIGHTNING_COMMON_JSON_H
 #include "config.h"
 #include <ccan/short_types/short_types.h>
 #include <ccan/tal/tal.h>
 #include <common/errcode.h>
+#include <common/utils.h>
 #include <stdbool.h>
 #include <stdint.h>
 #include <stdlib.h>
 
 #define JSMN_STRICT 1
 # include <external/jsmn/jsmn.h>
@@ -55,12 +56,17 @@ bool json_to_number(const char *buffer, const jsmntok_t *tok,
 		    unsigned int *num);
 
 /* Extract number from this (may be a string, or a number literal) */
 bool json_to_u64(const char *buffer, const jsmntok_t *tok,
 		 uint64_t *num);
 
+/* Extract a non-negative integer or an integer percentage (an integer in
+ * [0, 100] followed by "%"). */
+bool json_to_u64_or_u64pct(const char *buffer, const jsmntok_t *tok,
+			   struct u64_or_u64pct *result);
+
 /* Extract signed 64 bit integer from this (may be a string, or a number literal) */
 bool json_to_s64(const char *buffer, const jsmntok_t *tok, s64 *num);
 
 /* Extract number from this (may be a string, or a number literal) */
 bool json_to_u32(const char *buffer, const jsmntok_t *tok,
 		 uint32_t *num);
diff --git a/common/json_tok.c b/common/json_tok.c
index a08de9e0..e33f933d 100644
--- a/common/json_tok.c
+++ b/common/json_tok.c
@@ -5,12 +5,13 @@
 #include <common/amount.h>
 #include <common/json_command.h>
 #include <common/json_helpers.h>
 #include <common/json_tok.h>
 #include <common/jsonrpc_errors.h>
 #include <common/param.h>
+#include <common/utils.h>
 
 struct command_result *param_array(struct command *cmd, const char *name,
 				   const char *buffer, const jsmntok_t *tok,
 				   const jsmntok_t **arr)
 {
 	if (tok->type == JSMN_ARRAY) {
@@ -139,12 +140,28 @@ struct command_result *param_u64(struct command *cmd, const char *name,
 
 	return command_fail(cmd, JSONRPC2_INVALID_PARAMS,
 			    "'%s' should be an unsigned 64 bit integer, not '%.*s'",
 			    name, tok->end - tok->start, buffer + tok->start);
 }
 
+struct command_result *param_u64_or_u64pct(struct command *cmd,
+					   const char *name, const char *buffer,
+					   const jsmntok_t *tok,
+					   struct u64_or_u64pct **result)
+{
+	*result = tal(cmd, struct u64_or_u64pct);
+
+	if (json_to_u64_or_u64pct(buffer, tok, *result))
+		return NULL;
+
+	return command_fail(cmd, JSONRPC2_INVALID_PARAMS,
+			    "'%s' should be an unsigned 64 bit integer "
+			    "optionally followed by %%, not '%.*s'",
+			    name, tok->end - tok->start, buffer + tok->start);
+}
+
 struct command_result *param_tok(struct command *cmd, const char *name,
 				 const char *buffer, const jsmntok_t * tok,
 				 const jsmntok_t **out)
 {
 	*out = tok;
 	return NULL;
diff --git a/common/json_tok.h b/common/json_tok.h
index 038015a8..ef811b37 100644
--- a/common/json_tok.h
+++ b/common/json_tok.h
@@ -3,12 +3,13 @@
 #define LIGHTNING_COMMON_JSON_TOK_H
 #include "config.h"
 #include <ccan/short_types/short_types.h>
 #include <common/json.h>
 #include <common/node_id.h>
 #include <common/sphinx.h>
+#include <common/utils.h>
 #include <wire/wire.h>
 
 struct amount_msat;
 struct amount_sat;
 struct command;
 struct command_result;
@@ -63,12 +64,19 @@ struct command_result *param_sha256(struct command *cmd, const char *name,
 
 /* Extract number from this (may be a string, or a number literal) */
 struct command_result *param_u64(struct command *cmd, const char *name,
 				 const char *buffer, const jsmntok_t *tok,
 				 uint64_t **num);
 
+/* Extract a non-negative integer or an integer percentage (an integer in
+ * [0, 100] followed by "%"). */
+struct command_result *param_u64_or_u64pct(struct command *cmd,
+					   const char *name, const char *buffer,
+					   const jsmntok_t *tok,
+					   struct u64_or_u64pct **result);
+
 /* Extract msatoshi amount from this string */
 struct command_result *param_msat(struct command *cmd, const char *name,
 				  const char *buffer, const jsmntok_t *tok,
 				  struct amount_msat **msat);
 
 /* Extract satoshi amount from this string */
diff --git a/common/utils.h b/common/utils.h
index 484da8ea..0510c952 100644
--- a/common/utils.h
+++ b/common/utils.h
@@ -5,12 +5,17 @@
 #include <ccan/crypto/sha256/sha256.h>
 #include <ccan/short_types/short_types.h>
 #include <ccan/structeq/structeq.h>
 #include <ccan/tal/tal.h>
 #include <secp256k1.h>
 
+struct u64_or_u64pct {
+	u64 n;
+	bool is_pct;
+};
+
 extern secp256k1_context *secp256k1_ctx;
 
 extern const struct chainparams *chainparams;
 
 /* Simple accessor function for our own dependencies to use, in order to avoid
  * circular dependencies (should only be used in `bitcoin/y`). */
diff --git a/lightningd/peer_control.c b/lightningd/peer_control.c
index ae7d4ae5..619b93a0 100644
--- a/lightningd/peer_control.c
+++ b/lightningd/peer_control.c
@@ -1285,22 +1285,24 @@ static struct command_result *json_close(struct command *cmd,
 	struct channel *channel COMPILER_WANTS_INIT("gcc 7.3.0 fails, 8.3 OK");
 	unsigned int *timeout = NULL;
 	bool force = true;
 	bool do_timeout;
 	const u8 *close_to_script = NULL;
 	bool close_script_set;
-	const char *fee_negotiation_step_str;
-	char* end;
+	struct u64_or_u64pct *fee_negotiation_step;
+	struct u64_or_u64pct fee_negotiation_step_default = {.n = 50,
+							     .is_pct = true};
 
 	if (!param(cmd, buffer, params,
 		   p_req("id", param_tok, &idtok),
 		   p_opt_def("unilateraltimeout", param_number, &timeout,
 			     48 * 3600),
 		   p_opt("destination", param_bitcoin_address, &close_to_script),
-		   p_opt("fee_negotiation_step", param_string,
-			 &fee_negotiation_step_str),
+		   p_opt_def("fee_negotiation_step", param_u64_or_u64pct,
+			     &fee_negotiation_step,
+			     fee_negotiation_step_default),
 		   NULL))
 		return command_param_failed();
 
 	do_timeout = (*timeout != 0);
 
 	peer = peer_from_json(cmd->ld, buffer, idtok);
@@ -1360,48 +1362,34 @@ static struct command_result *json_close(struct command *cmd,
 			= p2wpkh_for_keyidx(channel, cmd->ld, channel->final_key_idx);
 		/* We don't save the default to disk */
 		close_script_set = false;
 	} else
 		close_script_set = false;
 
-	if (fee_negotiation_step_str == NULL) {
-		channel->closing_fee_negotiation_step = 50;
-		channel->closing_fee_negotiation_step_unit =
-		    CLOSING_FEE_NEGOTIATION_STEP_UNIT_PERCENTAGE;
-	} else {
-		channel->closing_fee_negotiation_step =
-		    strtoull(fee_negotiation_step_str, &end, 10);
-
-		if (channel->closing_fee_negotiation_step == 0)
-			return command_fail(
-			    cmd, JSONRPC2_INVALID_PARAMS,
-			    "Wrong value given for fee_negotiation_step: "
-			    "\"%s\", must be positive",
-			    fee_negotiation_step_str);
-		else if (*end == '%') {
-			if (channel->closing_fee_negotiation_step > 100)
-				return command_fail(
-				    cmd, JSONRPC2_INVALID_PARAMS,
-				    "Wrong value given for "
-				    "fee_negotiation_step: \"%s\", the "
-				    "percentage should be between 1 and 100",
-				    fee_negotiation_step_str);
-			channel->closing_fee_negotiation_step_unit =
-			    CLOSING_FEE_NEGOTIATION_STEP_UNIT_PERCENTAGE;
-		} else if (*end == '\0')
-			channel->closing_fee_negotiation_step_unit =
-			    CLOSING_FEE_NEGOTIATION_STEP_UNIT_SATOSHI;
-		else
-			return command_fail(
-			    cmd, JSONRPC2_INVALID_PARAMS,
-			    "Wrong value given for fee_negotiation_step: "
-			    "\"%s\", should be an integer or an integer "
-			    "followed by %%",
-			    fee_negotiation_step_str);
+	if (fee_negotiation_step->n == 0) {
+		return command_fail(
+		    cmd, JSONRPC2_INVALID_PARAMS,
+		    "Wrong value given for fee_negotiation_step: \"%" PRIu64
+		    "\", it should be a positive number",
+		    fee_negotiation_step->n);
+	}
+
+	if (fee_negotiation_step->is_pct && fee_negotiation_step->n > 100) {
+		return command_fail(
+		    cmd, JSONRPC2_INVALID_PARAMS,
+		    "Wrong value given for fee_negotiation_step: \"%" PRIu64
+		    "\", the percentage should be between 1 and 100",
+		    fee_negotiation_step->n);
 	}
 
+	channel->closing_fee_negotiation_step = fee_negotiation_step->n;
+	channel->closing_fee_negotiation_step_unit =
+	    fee_negotiation_step->is_pct
+		? CLOSING_FEE_NEGOTIATION_STEP_UNIT_PERCENTAGE
+		: CLOSING_FEE_NEGOTIATION_STEP_UNIT_SATOSHI;
+
 	/* Normal case.
 	 * We allow states shutting down and sigexchange; a previous
 	 * close command may have timed out, and this current command
 	 * will continue waiting for the effects of the previous
 	 * close command. */
 
diff --git a/common/test/run-sphinx.c b/common/test/run-sphinx.c
index f73bc74e..a75dae8e 100644
--- a/common/test/run-sphinx.c
+++ b/common/test/run-sphinx.c
@@ -44,15 +44,12 @@ bool amount_sat_eq(struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED)
 /* Generated stub for bigsize_get */
 size_t bigsize_get(const u8 *p UNNEEDED, size_t max UNNEEDED, bigsize_t *val UNNEEDED)
 { fprintf(stderr, "bigsize_get called!\n"); abort(); }
 /* Generated stub for bigsize_put */
 size_t bigsize_put(u8 buf[BIGSIZE_MAX_LEN] UNNEEDED, bigsize_t v UNNEEDED)
 { fprintf(stderr, "bigsize_put called!\n"); abort(); }
-/* Generated stub for ecdh */
-void ecdh(const struct pubkey *point UNNEEDED, struct secret *ss UNNEEDED)
-{ fprintf(stderr, "ecdh called!\n"); abort(); }
 /* Generated stub for pubkey_from_node_id */
 bool pubkey_from_node_id(struct pubkey *key UNNEEDED, const struct node_id *id UNNEEDED)
 { fprintf(stderr, "pubkey_from_node_id called!\n"); abort(); }
 /* AUTOGENERATED MOCKS END */
 
 extern secp256k1_context *secp256k1_ctx;
diff --git a/connectd/test/run-responder-success.c b/connectd/test/run-responder-success.c
index cd9410cb..5657d178 100644
--- a/connectd/test/run-responder-success.c
+++ b/connectd/test/run-responder-success.c
@@ -37,15 +37,12 @@ const void *fromwire_fail(const u8 **cursor UNNEEDED, size_t *max UNNEEDED)
 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 notleak_ */
-void *notleak_(const void *ptr UNNEEDED, bool plus_children UNNEEDED)
-{ fprintf(stderr, "notleak_ 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_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(); }
diff --git a/lightningd/test/run-invoice-select-inchan.c b/lightningd/test/run-invoice-select-inchan.c
index 2392f76f..6f054ae9 100644
--- a/lightningd/test/run-invoice-select-inchan.c
+++ b/lightningd/test/run-invoice-select-inchan.c
@@ -20,13 +20,13 @@ void bitcoind_getutxout_(struct bitcoind *bitcoind UNNEEDED,
 				    const struct bitcoin_tx_output *txout UNNEEDED,
 				    void *arg) UNNEEDED,
 			 void *arg UNNEEDED)
 { fprintf(stderr, "bitcoind_getutxout_ called!\n"); abort(); }
 /* Generated stub for bolt11_decode */
 struct bolt11 *bolt11_decode(const tal_t *ctx UNNEEDED, const char *str UNNEEDED,
-			     const struct feature_set *fset UNNEEDED,
+			     const struct feature_set *our_features UNNEEDED,
 			     const char *description UNNEEDED, char **fail UNNEEDED)
 { fprintf(stderr, "bolt11_decode called!\n"); abort(); }
 /* Generated stub for bolt11_encode_ */
 char *bolt11_encode_(const tal_t *ctx UNNEEDED,
 		     const struct bolt11 *b11 UNNEEDED, bool n_field UNNEEDED,
 		     bool (*sign)(const u5 *u5bytes UNNEEDED,
@@ -45,15 +45,12 @@ void broadcast_tx(struct chain_topology *topo UNNEEDED,
 /* Generated stub for channel_tell_depth */
 bool channel_tell_depth(struct lightningd *ld UNNEEDED,
 				 struct channel *channel UNNEEDED,
 				 const struct bitcoin_txid *txid UNNEEDED,
 				 u32 depth UNNEEDED)
 { fprintf(stderr, "channel_tell_depth called!\n"); abort(); }
-/* Generated stub for command_check_only */
-bool command_check_only(const struct command *cmd UNNEEDED)
-{ fprintf(stderr, "command_check_only called!\n"); abort(); }
 /* Generated stub for command_fail */
 struct command_result *command_fail(struct command *cmd UNNEEDED, errcode_t code UNNEEDED,
 				    const char *fmt UNNEEDED, ...)
 
 { fprintf(stderr, "command_fail called!\n"); abort(); }
 /* Generated stub for command_failed */
@@ -100,18 +97,12 @@ const u8 *failmsg_incorrect_or_unknown(const tal_t *ctx UNNEEDED,
 /* Generated stub for fatal */
 void   fatal(const char *fmt UNNEEDED, ...)
 { fprintf(stderr, "fatal called!\n"); abort(); }
 /* Generated stub for feature_is_set */
 bool feature_is_set(const u8 *features UNNEEDED, size_t bit UNNEEDED)
 { fprintf(stderr, "feature_is_set called!\n"); abort(); }
-/* Generated stub for featurebits_or */
-u8 *featurebits_or(const tal_t *ctx UNNEEDED, const u8 *f1 TAKES UNNEEDED, const u8 *f2 TAKES UNNEEDED)
-{ fprintf(stderr, "featurebits_or called!\n"); abort(); }
-/* Generated stub for fixup_htlcs_out */
-void fixup_htlcs_out(struct lightningd *ld UNNEEDED)
-{ fprintf(stderr, "fixup_htlcs_out called!\n"); abort(); }
 /* Generated stub for fmt_wireaddr_without_port */
 char *fmt_wireaddr_without_port(const tal_t *ctx UNNEEDED, const struct wireaddr *a UNNEEDED)
 { fprintf(stderr, "fmt_wireaddr_without_port called!\n"); abort(); }
 /* Generated stub for fromwire_channel_dev_memleak_reply */
 bool fromwire_channel_dev_memleak_reply(const void *p UNNEEDED, bool *leak UNNEEDED)
 { fprintf(stderr, "fromwire_channel_dev_memleak_reply called!\n"); abort(); }
@@ -348,12 +339,18 @@ struct command_result *param_tok(struct command *cmd UNNEEDED, const char *name
 { fprintf(stderr, "param_tok called!\n"); abort(); }
 /* Generated stub for param_u64 */
 struct command_result *param_u64(struct command *cmd UNNEEDED, const char *name UNNEEDED,
 				 const char *buffer UNNEEDED, const jsmntok_t *tok UNNEEDED,
 				 uint64_t **num UNNEEDED)
 { fprintf(stderr, "param_u64 called!\n"); abort(); }
+/* Generated stub for param_u64_or_u64pct */
+struct command_result *param_u64_or_u64pct(struct command *cmd UNNEEDED,
+					   const char *name UNNEEDED, const char *buffer UNNEEDED,
+					   const jsmntok_t *tok UNNEEDED,
+					   struct u64_or_u64pct **result UNNEEDED)
+{ fprintf(stderr, "param_u64_or_u64pct called!\n"); abort(); }
 /* Generated stub for peer_get_owning_subd */
 struct subd *peer_get_owning_subd(struct peer *peer UNNEEDED)
 { fprintf(stderr, "peer_get_owning_subd called!\n"); abort(); }
 /* Generated stub for peer_memleak_done */
 void peer_memleak_done(struct command *cmd UNNEEDED, struct subd *leaker UNNEEDED)
 { fprintf(stderr, "peer_memleak_done called!\n"); abort(); }
diff --git a/wallet/test/run-wallet.c b/wallet/test/run-wallet.c
index 5d71b7be..62d838b8 100644
--- a/wallet/test/run-wallet.c
+++ b/wallet/test/run-wallet.c
@@ -55,15 +55,12 @@ void broadcast_tx(struct chain_topology *topo UNNEEDED,
 /* Generated stub for channel_tell_depth */
 bool channel_tell_depth(struct lightningd *ld UNNEEDED,
 				 struct channel *channel UNNEEDED,
 				 const struct bitcoin_txid *txid UNNEEDED,
 				 u32 depth UNNEEDED)
 { fprintf(stderr, "channel_tell_depth called!\n"); abort(); }
-/* Generated stub for command_check_only */
-bool command_check_only(const struct command *cmd UNNEEDED)
-{ fprintf(stderr, "command_check_only called!\n"); abort(); }
 /* Generated stub for command_fail */
 struct command_result *command_fail(struct command *cmd UNNEEDED, errcode_t code UNNEEDED,
 				    const char *fmt UNNEEDED, ...)
 
 { fprintf(stderr, "command_fail called!\n"); abort(); }
 /* Generated stub for command_param_failed */
@@ -339,21 +336,12 @@ void json_object_start(struct json_stream *ks UNNEEDED, const char *fieldname UN
 /* Generated stub for json_strdup */
 char *json_strdup(const tal_t *ctx UNNEEDED, const char *buffer UNNEEDED, const jsmntok_t *tok UNNEEDED)
 { fprintf(stderr, "json_strdup called!\n"); abort(); }
 /* Generated stub for json_stream_success */
 struct json_stream *json_stream_success(struct command *cmd UNNEEDED)
 { fprintf(stderr, "json_stream_success called!\n"); abort(); }
-/* Generated stub for json_to_address_scriptpubkey */
-enum address_parse_result json_to_address_scriptpubkey(const tal_t *ctx UNNEEDED,
-			     const struct chainparams *chainparams UNNEEDED,
-			     const char *buffer UNNEEDED,
-			     const jsmntok_t *tok UNNEEDED, const u8 **scriptpubkey UNNEEDED)
-{ fprintf(stderr, "json_to_address_scriptpubkey called!\n"); abort(); }
-/* Generated stub for json_to_bool */
-bool json_to_bool(const char *buffer UNNEEDED, const jsmntok_t *tok UNNEEDED, bool *b UNNEEDED)
-{ fprintf(stderr, "json_to_bool called!\n"); abort(); }
 /* Generated stub for json_to_node_id */
 bool json_to_node_id(const char *buffer UNNEEDED, const jsmntok_t *tok UNNEEDED,
 			       struct node_id *id UNNEEDED)
 { fprintf(stderr, "json_to_node_id called!\n"); abort(); }
 /* Generated stub for json_to_number */
 bool json_to_number(const char *buffer UNNEEDED, const jsmntok_t *tok UNNEEDED,
@@ -489,22 +477,23 @@ struct command_result *param_number(struct command *cmd UNNEEDED, const char *na
 struct command_result *param_short_channel_id(struct command *cmd UNNEEDED,
 					      const char *name UNNEEDED,
 					      const char *buffer UNNEEDED,
 					      const jsmntok_t *tok UNNEEDED,
 					      struct short_channel_id **scid UNNEEDED)
 { fprintf(stderr, "param_short_channel_id called!\n"); abort(); }
-/* Generated stub for param_string */
-struct command_result *param_string(struct command *cmd UNNEEDED, const char *name UNNEEDED,
-				    const char * buffer UNNEEDED, const jsmntok_t *tok UNNEEDED,
-				    const char **str UNNEEDED)
-{ fprintf(stderr, "param_string called!\n"); abort(); }
 /* Generated stub for param_tok */
 struct command_result *param_tok(struct command *cmd UNNEEDED, const char *name UNNEEDED,
 				 const char *buffer UNNEEDED, const jsmntok_t * tok UNNEEDED,
 				 const jsmntok_t **out UNNEEDED)
 { fprintf(stderr, "param_tok called!\n"); abort(); }
+/* Generated stub for param_u64_or_u64pct */
+struct command_result *param_u64_or_u64pct(struct command *cmd UNNEEDED,
+					   const char *name UNNEEDED, const char *buffer UNNEEDED,
+					   const jsmntok_t *tok UNNEEDED,
+					   struct u64_or_u64pct **result UNNEEDED)
+{ fprintf(stderr, "param_u64_or_u64pct called!\n"); abort(); }
 /* Generated stub for parse_onionpacket */
 enum onion_type parse_onionpacket(const u8 *src UNNEEDED,
 				  const size_t srclen UNNEEDED,
 				  struct onionpacket *dest UNNEEDED)
 { fprintf(stderr, "parse_onionpacket called!\n"); abort(); }
 /* Generated stub for payment_failed */

If that does not look like too much code, then I can append it to #3629.

@rustyrussell rustyrussell merged commit 158d221 into ElementsProject:master Apr 7, 2020
@vasild vasild deleted the closure_fee branch April 7, 2020 06:28
@vasild vasild mentioned this pull request Apr 7, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Setting manual channel closure fee (question)
4 participants