From 5f1c77d249c0a8f03c375035048b3dffb8ec2938 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Tue, 3 Apr 2018 16:49:42 +0930 Subject: [PATCH] test_lightning.py: add test for onchain with different feerates. Signed-off-by: Rusty Russell --- lightningd/peer_control.c | 4 +++ lightningd/peer_control.h | 5 ++++ lightningd/peer_htlcs.c | 45 ++++++++++++++++++++++++++++++++++ onchaind/onchain.c | 3 ++- tests/test_lightningd.py | 51 +++++++++++++++++++++++++++++++++++++++ 5 files changed, 107 insertions(+), 1 deletion(-) diff --git a/lightningd/peer_control.c b/lightningd/peer_control.c index 50c21b921..126e83f7b 100644 --- a/lightningd/peer_control.c +++ b/lightningd/peer_control.c @@ -84,6 +84,10 @@ struct peer *new_peer(struct lightningd *ld, u64 dbid, list_head_init(&peer->channels); peer->direction = get_channel_direction(&peer->ld->id, &peer->id); +#if DEVELOPER + peer->ignore_htlcs = false; +#endif + /* Max 128k per peer. */ peer->log_book = new_log_book(128*1024, get_log_level(ld->log_book)); set_log_outfn(peer->log_book, copy_to_parent_log, ld->log); diff --git a/lightningd/peer_control.h b/lightningd/peer_control.h index c0b385f8b..44adc202a 100644 --- a/lightningd/peer_control.h +++ b/lightningd/peer_control.h @@ -45,6 +45,11 @@ struct peer { /* If we open a channel our direction will be this */ u8 direction; + +#if DEVELOPER + /* Swallow incoming HTLCs (for testing) */ + bool ignore_htlcs; +#endif }; struct peer *find_peer_by_dbid(struct lightningd *ld, u64 dbid); diff --git a/lightningd/peer_htlcs.c b/lightningd/peer_htlcs.c index 502af9932..c8c1d97a5 100644 --- a/lightningd/peer_htlcs.c +++ b/lightningd/peer_htlcs.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -576,6 +577,13 @@ static bool peer_accepted_htlc(struct channel *channel, if (!htlc_in_update_state(channel, hin, RCVD_ADD_ACK_REVOCATION)) return false; +#if DEVELOPER + if (channel->peer->ignore_htlcs) { + log_debug(channel->log, "their htlc %"PRIu64" dev_ignore_htlcs", + id); + return true; + } +#endif /* BOLT #2: * * A sending node SHOULD fail to route any HTLC added after it @@ -1618,3 +1626,40 @@ void notify_feerate_change(struct lightningd *ld) subd_send_msg(channel->owner, take(msg)); } } + +#if DEVELOPER +static void json_dev_ignore_htlcs(struct command *cmd, const char *buffer, + const jsmntok_t *params) +{ + jsmntok_t *nodeidtok, *ignoretok; + struct peer *peer; + + if (!json_get_params(cmd, buffer, params, + "id", &nodeidtok, + "ignore", &ignoretok, + NULL)) { + return; + } + + peer = peer_from_json(cmd->ld, buffer, nodeidtok); + if (!peer) { + command_fail(cmd, "Could not find channel with that peer"); + return; + } + + if (!json_tok_bool(buffer, ignoretok, &peer->ignore_htlcs)) { + command_fail(cmd, "Invalid boolean '%.*s'", + ignoretok->end - ignoretok->start, + buffer + ignoretok->start); + return; + } + command_success(cmd, null_response(cmd)); +} + +static const struct json_command dev_ignore_htlcs = { + "dev-ignore-htlcs", json_dev_ignore_htlcs, + "Set ignoring incoming HTLCs for peer {id} to {ignore}", false, + "Set/unset ignoring of all incoming HTLCs. For testing only." +}; +AUTODATA(json_command, &dev_ignore_htlcs); +#endif /* DEVELOPER */ diff --git a/onchaind/onchain.c b/onchaind/onchain.c index a080f0be3..84b4c4552 100644 --- a/onchaind/onchain.c +++ b/onchaind/onchain.c @@ -129,9 +129,10 @@ static u64 grind_htlc_tx_fee(struct bitcoin_tx *tx, } status_failed(STATUS_FAIL_INTERNAL_ERROR, "grind_fee failed from %u - %u" - " for tx %s, signature %s, wscript %s, multiplier %"PRIu64, + " for tx %s, inputamount %"PRIu64", signature %s, wscript %s, multiplier %"PRIu64, min_possible_feerate, max_possible_feerate, type_to_string(tmpctx, struct bitcoin_tx, tx), + input_amount, type_to_string(tmpctx, secp256k1_ecdsa_signature, remotesig), tal_hex(tmpctx, wscript), multiplier); diff --git a/tests/test_lightningd.py b/tests/test_lightningd.py index 754c231c0..0525b57df 100644 --- a/tests/test_lightningd.py +++ b/tests/test_lightningd.py @@ -1939,6 +1939,57 @@ class LightningDTests(BaseLightningDTests): bitcoind.generate_block(1) l1.daemon.wait_for_log('onchaind complete, forgetting peer') + @unittest.skipIf(not DEVELOPER, "needs DEVELOPER=1 for dev_fail") + def test_onchain_different_fees(self): + """Onchain handling when we've had a range of fees""" + + l1, l2 = self.connect() + self.fund_channel(l1, l2, 10**7) + + l2.rpc.dev_ignore_htlcs(id=l1.info['id'], ignore=True) + p1 = self.pay(l1, l2, 1000000000, async=True) + l1.daemon.wait_for_log('htlc 0: RCVD_ADD_ACK_COMMIT->SENT_ADD_ACK_REVOCATION') + + l1.rpc.dev_setfees('14000') + p2 = self.pay(l1, l2, 900000000, async=True) + l1.daemon.wait_for_log('htlc 1: RCVD_ADD_ACK_COMMIT->SENT_ADD_ACK_REVOCATION') + + l1.rpc.dev_setfees('5000') + p3 = self.pay(l1, l2, 800000000, async=True) + l1.daemon.wait_for_log('htlc 2: RCVD_ADD_ACK_COMMIT->SENT_ADD_ACK_REVOCATION') + + # Drop to chain + l1.rpc.dev_fail(l2.info['id']) + l1.daemon.wait_for_log('sendrawtx exit 0') + + bitcoind.generate_block(1) + l1.daemon.wait_for_log(' to ONCHAIN') + l2.daemon.wait_for_log(' to ONCHAIN') + + # Both sides should have correct feerate + assert l1.db_query('SELECT min_possible_feerate, max_possible_feerate FROM channels;') == [{'min_possible_feerate': 5000, 'max_possible_feerate': 14000}] + assert l2.db_query('SELECT min_possible_feerate, max_possible_feerate FROM channels;') == [{'min_possible_feerate': 5000, 'max_possible_feerate': 14000}] + + bitcoind.generate_block(5) + # Three HTLCs, and one for the to-us output. + l1.daemon.wait_for_logs(['sendrawtx exit 0'] * 4) + + # We use 3 blocks for "reasonable depth" + bitcoind.generate_block(3) + + self.assertRaises(TimeoutError, p1.result, 10) + self.assertRaises(TimeoutError, p2.result, 10) + self.assertRaises(TimeoutError, p3.result, 10) + + # Two more for HTLC timeout tx to be spent. + bitcoind.generate_block(2) + l1.daemon.wait_for_logs(['sendrawtx exit 0'] * 3) + + # Now, 100 blocks it should be done. + bitcoind.generate_block(100) + wait_forget_channels(l1) + wait_forget_channels(l2) + @unittest.skipIf(not DEVELOPER, "needs DEVELOPER=1") def test_permfail_new_commit(self): # Test case where we have two possible commits: it will use new one.