Skip to content

Add KeysInterface trait to handle keys management, first part: when C… #214

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
wants to merge 6 commits into from

Conversation

ariard
Copy link

@ariard ariard commented Oct 19, 2018

…hannelMonitor

detects a spendable outputs onchain it will notify back the user wallet
with needed data to spend it with register_spendable_outputs

@ariard
Copy link
Author

ariard commented Oct 19, 2018

Early work, just to agree on the general KeysInterface thing. I don't follow the event model we talked previously on irc as it doesn't fit well with ChannelMonitor, I've more thought to something like ChainWatchInterface.
I think we have two cases of keys, the ones static, as found in justice tx or preimage tx witness, and the others dynamic, generated from per_commitment_point. For the last ones, we send back the local per_commitment_secret from which the user wallet can derive the priv_key, we assume it keeps knowledge of the basepoint_privatekey.

(note I commented an assert in test_utils, because of hanging of ChannelMonintor serialization, which could be changed with ongoing #61, before I'm done here )

writer.write_all(&[0;32])?;

}

Copy link
Contributor

Choose a reason for hiding this comment

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

you don't want to persist secret? also, seems it's better to re-sign local_commitment_tx can when it's loaded onto the memory and strip off signature when it's stored into hard disk.

Copy link
Author

Choose a reason for hiding this comment

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

If I get derivation scheme right you can't do nothing with a per_commitment_point, you still need basepoint and basepoint_secret? ChannelMonitor handling current per_commitment_point is to avoid KeysManager or whatsever having to remember the per_commitment_point for each new commitment, without knowing if it's gonna be useful.
Hard disk storage thing is under revision, so here it's temporary.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Definitely do want to persist, but you should only do it in case of for_local_storage.

@TheBlueMatt
Copy link
Collaborator

Thanks for the quick work on this one! The nice thing about Events is that they are inherintly asynchronous and we don't have to worry about lock inversions between rust-lightning bits and client bits. Making a callback for something that is asynchronous just feels like asking for more complexity than we need there. What about just making SimpleManyChannelMonitor an EventsProvider?

@TheBlueMatt TheBlueMatt added this to the 0.0.6 milestone Oct 20, 2018
@ariard ariard force-pushed the 81-key-management branch from 83d8947 to 96567d8 Compare October 23, 2018 02:09
@ariard
Copy link
Author

ariard commented Oct 23, 2018

Rebased, with EventsProvider model, with two Interfaces: ln --> wallet and wallet --> ln, still WIP.

@ariard ariard force-pushed the 81-key-management branch from 96567d8 to 4c53b79 Compare October 23, 2018 15:43
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.

High-level interface looks good!


if let Some(ref per_commitment_point) = *per_commitment_point {
spendable_outputs.push((Some(per_commitment_point.clone()), redeemscript, BitcoinOutPoint { txid: htlc_success_tx.txid(), vout: 0 }));
Copy link
Collaborator

Choose a reason for hiding this comment

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

The script here is a bit confused - sometimes its the redeemscript sometimes its the script itself. Also, a script isn't really the best way to tell a user how to spend an output - I think an enum (that might contain data, eg a redeemscript) may be more useful.

Copy link
Author

Choose a reason for hiding this comment

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

Hmm something like output script descriptor seems to be the right solution ? But it's still not into rust-bitcoin..

Copy link
Collaborator

Choose a reason for hiding this comment

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

Indeed, though I dont think the descriptor stuff is always sufficiently expressive for custom scripts. A simple enum with clear docs that explain what you have to put in the witness stack for the spend to succeed should be sufficient.

@@ -226,6 +246,9 @@ pub struct ChannelMonitor {
prev_local_signed_commitment_tx: Option<LocalSignedTx>,
current_local_signed_commitment_tx: Option<LocalSignedTx>,

prev_latest_per_commitment_point: Option<SecretKey>,
Copy link
Collaborator

Choose a reason for hiding this comment

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

I dont think we actually need these right now? They are only used for the local htlc tx case, but I think we actually want the delayed_payment_key there, which we derive.

Copy link
Author

Choose a reason for hiding this comment

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

The user wallet has to have access to local_delay key. We can derive this one from delayed_payment_basepoint and local per_commitment_point, but actually ChannelMonitor doesn't have any of them ? So I think we need them and also add delayed_payment_basepoint in KeyStorage ? If so it's nice for the user wallet because it hasn't to be aware of LN derivation scheme, it just gets the right key

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 need more than the local_delayedkey anywhere? Maybe only store that?

Copy link
Author

@ariard ariard Oct 26, 2018

Choose a reason for hiding this comment

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

Nop right only need local_delayedkey for dynamic outputs, we store it only in PrivMode ? How a user will be able to spend if watchtower's channel monitor only send him back local_delayedpubkey ?

@ariard
Copy link
Author

ariard commented Oct 24, 2018

Hmm still working on it, should we provide destination_script as a P2WPKH with a key derive from seed or let the user provide us destination_script (multisig, ...) ? Seems 2nd is better.

For shutdown_scriptpubkey, following BOLT 2, there is 4 forms, we pick one by default for user ?

@TheBlueMatt
Copy link
Collaborator

I think ideally for shutdown_scriptpubkey and destination_script we'd derive something from a user-provided secret (eg just do an HD derivation from a user-provided HD master key). If we double-derive on accident and reuse them we'll just have slightly less privacy but that's OK cause we already exposed a persistent identifier via our node_id.

@ariard ariard force-pushed the 81-key-management branch 5 times, most recently from a1ea971 to 7b4d1f2 Compare October 25, 2018 02:04
@ariard
Copy link
Author

ariard commented Oct 25, 2018

Okay rebased with addition of CustomOutputScriptDescriptor. Still lack some integrations of KeysManager in other places and maybe tests to be finished.

Still open : #214 (comment) ? which conditions writer/reader of per_commitment_point and some TODO in ChannelMonitor

@@ -490,6 +519,13 @@ impl ChannelMonitor {
self.payment_preimages.insert(payment_hash.clone(), payment_preimage.clone());
}

/// Provides latest local per_commitment_point secret. Useful to derive private key for protocol exit points based
/// on local commitment tx.
pub(super) fn provide_latest_per_commitment_point(&mut self, per_commitment_point: SecretKey) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

This is currently never called, but I think you should be able to add the info to provide_latest_local_commitment_tx_info and move the fields into LocalTx, no?

writer.write_all(&[0;32])?;

}

Copy link
Collaborator

Choose a reason for hiding this comment

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

Definitely do want to persist, but you should only do it in case of for_local_storage.

pub enum CustomOutputScriptDescriptor {
/// Outpoint commits to a P2PWKH, should be spend by the following witness :
/// <signature> <pubkey> OP_CHECKSIG
StaticOutput {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Shouldn't this include the publickey so that the user knows which pubkey to use?

Copy link
Author

Choose a reason for hiding this comment

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

Yes updated with "With pubkey being bip32 /1' from HMAC-Sha512 of user-provided seed as master private key" ?

Copy link
Collaborator

Choose a reason for hiding this comment

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

Well KeysInterface is just an interface so would have to specify it as "get_destination_script() return value", but I was thinking more because a user might find it easier to see the pubkey here as it would allow them to claim the output without having to go look up the output on-chain - they could just create a transaction from only the data in the event.

@@ -1446,6 +1518,9 @@ impl<R: ::std::io::Read> Readable<R> for ChannelMonitor {
_ => return Err(DecodeError::InvalidValue),
};

let prev_latest_per_commitment_point = Some(unwrap_obj!(SecretKey::from_slice(&secp_ctx, read_bytes!(32))));
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 unwrap_obj! if it was optional at write-time.

@@ -55,7 +55,7 @@ impl channelmonitor::ManyChannelMonitor for TestChannelMonitor {
// to a watchtower and disk...
let mut w = VecWriter(Vec::new());
monitor.write_for_disk(&mut w).unwrap();
assert!(channelmonitor::ChannelMonitor::read(&mut ::std::io::Cursor::new(&w.0)).unwrap() == monitor);
//assert!(channelmonitor::ChannelMonitor::read(&mut ::std::io::Cursor::new(&w.0)).unwrap() == monitor);
Copy link
Collaborator

Choose a reason for hiding this comment

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

I dont think you need this anymore with the current code (at least if you remove the unwrap_obj that I flagged)?

@ariard ariard force-pushed the 81-key-management branch 2 times, most recently from 177956e to 8e7ec6d Compare October 26, 2018 02:55
… ChannelMonitor

detects a spendable outputs onchain it will send back an Event to user
wallet with needed data to be at disposal

Add CustomOutputScriptDescriptor to ease user wallet spending of onchain
lightning outputs

Extend KeyStorage with delayed_payment_base_key and per_commitment_point
to derive local_delayed private key
@ariard ariard force-pushed the 81-key-management branch from 8e7ec6d to 981a9ed Compare October 26, 2018 03:30
Antoine Riard added 3 commits October 26, 2018 12:16
componenents, responsible to get seed from the former and derive
appropriate keyring materials

Move ChannelKeys into keysinterface for generate a set of it from
master_seed
@ariard ariard force-pushed the 81-key-management branch from 981a9ed to 3a8c01a Compare October 26, 2018 13:05
Antoine Riard added 2 commits October 26, 2018 13:31
ChannelManager/Channel

Drop channel_monitor_claim_key from ChannelKeys
let router = Arc::new(Router::new(PublicKey::from_secret_key(&secp_ctx, &our_network_key), watch.clone(), Arc::clone(&logger)));
let mut seed = [0; 32];
let mut rng = thread_rng();
rng.fill_bytes(&mut seed);
Copy link
Collaborator

Choose a reason for hiding this comment

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

fuzz targets must be fully deterministic - if you need to read bytes, read them from the input buffer, though ideally you'd keep consistency with the existing input data.

@TheBlueMatt
Copy link
Collaborator

Will take as #225.

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.

3 participants