Skip to content

Add channel_monitor_claim_revoked_commitment_tx test #184

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

Closed

Conversation

ariard
Copy link

@ariard ariard commented Sep 16, 2018

Test htlc outputs shared claim case

Following discussion in #137 on testing htlc outputs claiming.
Note that I didn't clean the TODO in channel_monitor, I'm also gonna add this specific case here.

/// Tests that the given node has broadcast a claim transaction against the provided revoked
/// HTLC transaction.
/// Tests that the given node has broadcast a claim transaction against the provided
/// HTLC transaction issued from a revoked commitment tx
Copy link
Author

Choose a reason for hiding this comment

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

Properly speaking, does a HTLC transaction is revoked ? It's more the broadcasting of a revoked commitment tx which "nullify" the chain of following transactions, seems to me


nodes[1].chain_monitor.block_connected_with_filtering(&Block { header, txdata: vec![revoked_local_txn[0].clone()] }, 1);
let node_txn = nodes[1].tx_broadcaster.txn_broadcasted.lock().unwrap();
assert_eq!(node_txn.len(), 4); // ChannelManager is broadcasting last_local_commitment_txn.. and revocation tx is broacasted twice as block has been re-scanned.
Copy link
Author

Choose a reason for hiding this comment

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

As described in force_close, ChannelManager is also broadcasting the last_local_commitment_txn, which is normal. But revocation tx which is generated and broadcasted again due to block re-scanning seems really a performance bottleneck?

nodes[1].chain_monitor.block_connected_with_filtering(&Block { header, txdata: vec![revoked_local_txn[0].clone()] }, 1);
let node_txn = nodes[1].tx_broadcaster.txn_broadcasted.lock().unwrap();
assert_eq!(node_txn.len(), 4); // ChannelManager is broadcasting last_local_commitment_txn.. and revocation tx is broacasted twice as block has been re-scanned.
assert_eq!(node_txn[0].input.len(), 2); //TODO: really should be 4 when we implement to_local and to_remote via revocation key claiming
Copy link
Author

Choose a reason for hiding this comment

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

Still thinking to more assert, but how to identify specifically htlc input scripts?

@ariard ariard force-pushed the test_claim_revoked_htlc_outputs branch from 94235ea to 7e2fd5a Compare September 18, 2018 00:03
@ariard
Copy link
Author

ariard commented Sep 18, 2018

This 2 tests are covering claiming of htlc outputs from a revoked commitment tx, both case where they can shared a tx and case where they can't due to timeout.

Copy link
Collaborator

@TheBlueMatt TheBlueMatt left a comment

Choose a reason for hiding this comment

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

Nice! I think we should be a bit more aggressive with these tests. Better to be aggressive (with lots of comments) and change the tests later if we tweak how txn get created than have a bug in on-chain claiming.

let _payment_preimage_2 = route_payment(&nodes[1], &vec!(&nodes[0])[..], 3000000).0;

// Get the will-be-revoked local txn from node[0]
let revoked_local_txn = nodes[0].node.channel_state.lock().unwrap().by_id.iter().next().unwrap().1.last_local_commitment_txn.clone();
Copy link
Collaborator

Choose a reason for hiding this comment

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

Note that chan_1.3 is the channel_id, so you can do a get(chan_1.3).unwrap() here for a bit more readability.

Copy link
Author

Choose a reason for hiding this comment

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

Thanks, updated

let header = BlockHeader { version: 0x20000000, prev_blockhash: Default::default(), merkle_root: Default::default(), time: 42, bits: 42, nonce: 42 };

nodes[0].chain_monitor.block_connected_with_filtering(&Block { header, txdata: vec![revoked_local_txn[0].clone()] }, 1);
test_txn_broadcast(&nodes[0], &chan_1, Some(revoked_local_txn[0].clone()), HTLCType::TIMEOUT);
Copy link
Collaborator

Choose a reason for hiding this comment

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

Do we really care what nodes[0] did here? It misbehaved (broadcasted an old local commitment state, so is probably gonna lose its money on revocation claims).

Copy link
Author

Choose a reason for hiding this comment

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

Was thinking of the comment, check_spend_revoked_transaction channel_monitor l 1338, maybe we want to implement it and substitute it to check_spend_local_transaction internally for specially handling revoked tx from us.
Seems check_spend_revoked_transaction is no longer news ?

Copy link
Author

Choose a reason for hiding this comment

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

Deleted the test_txn_broadcast


nodes[1].chain_monitor.block_connected_with_filtering(&Block { header, txdata: vec![revoked_local_txn[0].clone()] }, 1);
let node_txn = nodes[1].tx_broadcaster.txn_broadcasted.lock().unwrap();
assert_eq!(node_txn.len(), 4); // ChannelManager is broadcasting 2 last_local_commitment_txn..and revocation tx is broacasted twice as block has been re-scanned.
Copy link
Collaborator

Choose a reason for hiding this comment

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

Hmm, can we test what the 4 txn look like, then to be much tighter?

Copy link
Author

Choose a reason for hiding this comment

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

Yeah, add asserts based on witness script, txid, number of inputs.

assert_eq!(nodes[0].node.list_channels().len(), 0);
assert_eq!(nodes[1].node.list_channels().len(), 0);

let chan_2 = create_announced_chan_between_nodes(&nodes, 2, 3);
Copy link
Collaborator

Choose a reason for hiding this comment

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

Hmm, if the tests are completely separate I'd prefer we make a new test. This means fewer channel_update/channel_announcement handles and also lets rust run them in paralell. I previously didn't but going forward would be nice to keep tests smaller.

Copy link
Author

@ariard ariard Sep 20, 2018

Choose a reason for hiding this comment

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

Splitted as of 080d5df

// Rebalance the network to generate htlc in the two directions
send_payment(&nodes[2], &vec!(&nodes[3])[..], 8000000);
// node[2] is gonna to revoke an old state thus node[3] should be able to claim both offered/received HTLC outputs on top of commitment tx, but this
// time as two different claim transactions as we're gonna to timeout htlc with given a high current heigh
Copy link
Collaborator

Choose a reason for hiding this comment

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

nit: heigh -> height.

Copy link
Author

Choose a reason for hiding this comment

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

thks

assert_eq!(node_txn[1].input.len(), 1);

let mut funding_tx_map = HashMap::new();
funding_tx_map.insert(revoked_local_txn[0].txid(), revoked_local_txn[0].clone());
Copy link
Collaborator

Choose a reason for hiding this comment

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

Hmm, this test looks like it would pass whether the tx here were claiming the revoked normal output or the revoked HTLC output. We should test that later txn claim a different output in the revoked_local_txn[0], at least, if not be more aggressive with what all of the txn here look like.

Copy link
Author

Choose a reason for hiding this comment

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

Yes add assert based on witness_script. Note: we can't assume which one is the htlc offered/received first as of using HashMap internally.

@ariard ariard force-pushed the test_claim_revoked_htlc_outputs branch from 7e2fd5a to 2f41481 Compare September 20, 2018 00:56
let witness_script_1 = node_txn[0].clone().input[0].witness.pop().unwrap();
let witness_script_2 = node_txn[0].clone().input[1].witness.pop().unwrap();
if witness_script_1.len() > 133 {
assert_eq!(witness_script_1.len(), 138);
Copy link
Author

@ariard ariard Sep 20, 2018

Choose a reason for hiding this comment

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

Is there any reason to get accepted HTLC script of 138 bytes instead of BOLT 3 139 bytes ?

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 it should be 139 in prod but because the block height being used as locktime here is < 2^15 (but more than 2^7) its 138.

@ariard ariard force-pushed the test_claim_revoked_htlc_outputs branch from 2f41481 to 080d5df Compare September 20, 2018 01:54
Copy link
Collaborator

@TheBlueMatt TheBlueMatt left a comment

Choose a reason for hiding this comment

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

Just re-reviewed first test for now.

assert_eq!(node_txn[3].input.len(), 2);
node_txn[3].verify(&revoked_tx_map).unwrap();

assert_eq!(node_txn[0].txid(), node_txn[3].txid()); // justice tx is duplicated due to block re-scanning
Copy link
Collaborator

Choose a reason for hiding this comment

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

Should just be able to assert node_txn[0], node_txn[3], no? The witnesses should also be identical.

let witness_script_1 = node_txn[0].clone().input[0].witness.pop().unwrap();
let witness_script_2 = node_txn[0].clone().input[1].witness.pop().unwrap();
if witness_script_1.len() > 133 {
assert_eq!(witness_script_1.len(), 138);
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 it should be 139 in prod but because the block height being used as locktime here is < 2^15 (but more than 2^7) its 138.

}

assert_eq!(node_txn[1].input.len(), 1);
let witness_script = node_txn[1].clone().input[0].witness.pop().unwrap();
Copy link
Collaborator

Choose a reason for hiding this comment

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

Why not just assert the input prevout is the funding tx?

assert_eq!(witness_script.len(), 71); // Spending funding tx unique txoutput, tx broadcasted by ChannelManager

assert_eq!(node_txn[2].input.len(), 1);
let witness_script = node_txn[2].clone().input[0].witness.pop().unwrap();
Copy link
Collaborator

Choose a reason for hiding this comment

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

Can't we check that its spending the same as revoked_tx_map (and has a unique outpoint that wasnt in one of the others)?

@ariard ariard force-pushed the test_claim_revoked_htlc_outputs branch from 622c958 to f1f9ead Compare September 21, 2018 00:22
@ariard
Copy link
Author

ariard commented Sep 21, 2018

Rebased, updated with comments, also add more asserts in remaining test based on last review pass.

@TheBlueMatt
Copy link
Collaborator

New tests look good, but found a bug that needs to be fixed first. Can you review #199 (which includes this rebased)?

TheBlueMatt added a commit that referenced this pull request Sep 30, 2018
Fix simple to_local revoked output claim and rebase #184
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.

2 participants