Skip to content

Add util fn for creating a Transaction from spendable outputs #789

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

Merged

Conversation

TheBlueMatt
Copy link
Collaborator

Based on #786, This adds a utility method, KeysManager::spend_spendable_outputs,
which constructs a Transaction from a given set of
SpendableOutputDescriptors, deriving relevant keys as needed.

It also adds methods which can sign individual inputs where
channel-specific key derivation is required to
InMemoryChannelKeys, making it easy to sign transaction inputs
when a custom KeysInterface is used with InMemoryChannelKeys.

@codecov
Copy link

codecov bot commented Feb 4, 2021

Codecov Report

Merging #789 (95d0fe9) into main (2088f4b) will increase coverage by 0.01%.
The diff coverage is 95.66%.

Impacted file tree graph

@@            Coverage Diff             @@
##             main     #789      +/-   ##
==========================================
+ Coverage   90.75%   90.77%   +0.01%     
==========================================
  Files          44       44              
  Lines       24075    24282     +207     
==========================================
+ Hits        21849    22041     +192     
- Misses       2226     2241      +15     
Impacted Files Coverage Δ
lightning/src/chain/channelmonitor.rs 95.68% <66.66%> (ø)
lightning/src/chain/keysinterface.rs 93.36% <95.20%> (+0.80%) ⬆️
lightning/src/util/transaction_utils.rs 98.06% <96.29%> (-1.94%) ⬇️
lightning/src/ln/chan_utils.rs 97.34% <100.00%> (+<0.01%) ⬆️
lightning/src/ln/functional_tests.rs 96.95% <100.00%> (-0.03%) ⬇️
lightning/src/util/macro_logger.rs 88.33% <100.00%> (ø)
lightning/src/util/test_utils.rs 83.16% <100.00%> (-1.66%) ⬇️

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 2088f4b...95d0fe9. Read the comment docs.

/// Information about a spendable output to a P2WSH script. See
/// SpendableOutputDescriptor::DynamicOutputP2WSH for more details on how to spend this.
#[derive(Clone, Debug, PartialEq)]
pub struct DynamicP2WSHOutputDescriptor {
Copy link
Member

Choose a reason for hiding this comment

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

Probably not for this PR, but maybe this can be DelayedPaymentFromHolderOutput and the one below can be StaticPaymentFromCounterpartyOutput?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Right, there are a few things in keysinterface that could use renaming, so maybe we can do it as a follow up - I'd like to rename ChanKeys to ChannelSigner (and a bunch of things downstream that use similar naming) as well.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Went ahead and did this since Val had a further naming comment.

/// script_pubkey as it appears in the output.
/// An output to a script which was provided via KeysInterface directly, either from
/// `get_destination_script()` or `get_shutdown_pubkey()`, thus you should already know how to
/// spend it. No secret keys are provided as rust-lightning was never given any key.
/// These may include outputs from a transaction punishing our counterparty or claiming an HTLC
/// on-chain using the payment preimage or after it has timed out.
StaticOutput {
Copy link
Member

@devrandom devrandom Feb 5, 2021

Choose a reason for hiding this comment

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

it would be good to have the derivation path here (and maybe channel ID - see comment nearby), even if it's not used, just so that the user / KeysManager implementation can keep track of which channel is being swept

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Note this is really in #786. It would feel awkward to tie the scripts to a channel without moving the functions to get them to the ChannelSigner? I dont really want to do that, though, as the current setup is great in that the KeysInterface implementation is trivial and gives you direct control over all the entropy used and keys used directly (that aren't fixed by the lightning protocol), and the ChannelSigner implementation is all about the lightning protocol details.

I guess we could maybe pass the channel information to the functions in KeysInterface to get the fields as a middle ground, but ultimately a user probably would just want some kind of integer id to figure out what HD derivation path they used, not channel information, and I'm not really sure how to capture that easily.

Copy link
Member

Choose a reason for hiding this comment

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

Oh, this wasn't about the scripts at all. It's about this struct (StaticOutput), which is constructed in ChannelMonitor when sweeping a payment to us. I'm just saying it would be good for the KeysManager to know which channel is being swept for housekeeping / policy controls. ChannelMonitor has the derivation ID handy, so it's easy to populate such a field in this struct.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Right, it just felt awkward that we pass an id referencing the derivation id when the script/output itself isn't in any way related to a given derivation, the KeysManager returns them directly. Best would be to pass in the derivation info to the keysmanager when we get those scripts, I think, but we don't have it yet at that point, afair.

Copy link
Member

Choose a reason for hiding this comment

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

OK, there's no rush to get into this in this PR.

@TheBlueMatt TheBlueMatt force-pushed the 2021-02-chansigner-util-fns branch from 5adddfe to 29d6c13 Compare February 5, 2021 21:53
@TheBlueMatt TheBlueMatt force-pushed the 2021-02-chansigner-util-fns branch 2 times, most recently from bfbcd4e to 84bec9b Compare February 6, 2021 20:00
/// The output which is referenced by the given outpoint
pub output: TxOut,
/// The revocation_pubkey used to derive witnessScript
pub revocation_pubkey: PublicKey,
Copy link
Member

Choose a reason for hiding this comment

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

isn't this available from ChannelKeys, so doesn't need to be replicated here?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

No, this is the revocation point for the broadcast commitment transaction. I'll clarify the docs.

Copy link
Member

@devrandom devrandom Feb 10, 2021

Choose a reason for hiding this comment

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

Ah, we can't re-derive the revocation_pubkey, because that would require the counterparty's revocation base, which we don't have because we rederived ChannelKeys from scratch and therefore it doesn't have the counterparty's pubkeys.

However, we could still make it work if we looked up the populated ChannelKeys instead of re-deriving them.

So this brings up the question - why are we using derive_channel_keys instead of looking up the existing ChannelKeys in some index?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Right. Depending on the specific KeysInterface implementation we could look up a globally-cached remote public keys object. However we should try to be as implementation-agnostic as possible, so in this case I'm not sure it's ideal. We could provide the raw data to re-derive in the event, but I'm not sure what that protects against - if they even is bogus no funds loss can occur, the client may just create an invalid transaction.

Copy link
Member

Choose a reason for hiding this comment

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

It's pretty minor, just felt a bit more "normalized" to provide just the minimum set of fields.

We previously counted 35 bytes for a length + public key, but in
reality they are never larger than 34 bytes - 33 for the key and 1
for the push length.
Both SpendableOutputDescriptor::DynamicOutputP2WSH and
SpendableOutputDescriptor::StaticOutputCounterpartyPayment are
relevant only in the context of a given channel, making them
candidates for being passed into helper functions in
`InMemoryChannelKeys`. This moves them into their own structs so
that they can later be used standalone.
@TheBlueMatt TheBlueMatt force-pushed the 2021-02-chansigner-util-fns branch from e16b8dc to 25a17d9 Compare February 16, 2021 17:40
@TheBlueMatt
Copy link
Collaborator Author

Rebased and squashed after dependent-PR merge with no other changes.

@valentinewallace valentinewallace self-requested a review February 16, 2021 17:50
Copy link
Contributor

@valentinewallace valentinewallace left a comment

Choose a reason for hiding this comment

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

Super useful utility! Seems like a big win for users.

/// Information about a spendable output to a P2WSH script. See
/// SpendableOutputDescriptor::DynamicOutputP2WSH for more details on how to spend this.
#[derive(Clone, Debug, PartialEq)]
pub struct DynamicP2WSHOutputDescriptor {
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: this could be renamed to be uniform to DynamicOutputP2WSH: i.e., rename to DynamicOutputP2WSHDescriptor (or vice versa)

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Did something more akin to devrandom's suggestion above #789 (comment)

KeyManager::new() took a bitcoin::Network parameter which needs to
be passed to the BIP 32 Extended Key constructor, but because we
never write out the BIP 32 serialization, it isn't used. Instead,
we just pass a dummy value into `ExtendedPrivKey`, dropping the
unused argument to KeysManager::new().
Previously, test_dynamic_spendable_outputs_local_htlc_success_tx
called connect_block with two identical transactions, which
resulted in duplicate SpendableOutputs Events back-to-back. This
is a test issue as such a block_connected call represents an
invalid block.
This adds a utility method, `KeysManager::spend_spendable_outputs`,
which constructs a Transaction from a given set of
`SpendableOutputDescriptor`s, deriving relevant keys as needed.

It also adds methods which can sign individual inputs where
channel-specific key derivation is required to
`InMemoryChannelKeys`, making it easy to sign transaction inputs
when a custom `KeysInterface` is used with `InMemoryChannelKeys`.
@TheBlueMatt TheBlueMatt force-pushed the 2021-02-chansigner-util-fns branch from 25a17d9 to 8dbadd1 Compare February 16, 2021 21:32
Both Miron and Val suggested naming tweaks in their reviews, so
clarifying things some would be good.
Copy link
Contributor

@valentinewallace valentinewallace left a comment

Choose a reason for hiding this comment

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

New naming + typo fixes LGTM

@TheBlueMatt TheBlueMatt merged commit 414e622 into lightningdevkit:main Feb 18, 2021
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