Skip to content

Draft: phase-2 signer API #723

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 2 commits into from

Conversation

devrandom
Copy link
Member

This is an early sketch of a modified signer API for review of the concept.

As previously discussed, we would like to pass in the data elements describing the commitment transaction (and HTLCs) instead of the serialized transaction. This makes it easier to validate and ensure that no aspect of the transaction escaped validation.

Let me know if expanding the sketch is required for meaningful review.

@@ -244,6 +245,17 @@ pub trait ChannelKeys : Send+Clone {
// TODO: Add more input vars to enable better checking (preferably removing commitment_tx and
fn sign_holder_commitment<T: secp256k1::Signing + secp256k1::Verification>(&self, holder_commitment_tx: &HolderCommitmentTransaction, secp_ctx: &Secp256k1<T>) -> Result<Signature, ()>;

/// Create a signature for a holder's commitment transaction and attached HTLC transactions.
fn sign_holder_commitment_phase2<T: secp256k1::Signing + secp256k1::Verification>(
Copy link
Member Author

Choose a reason for hiding this comment

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

This replaces the previous function.

// We provide a dummy signature for the remote, since we don't require that sig
// to be passed in to this call. It would have been better if HolderCommitmentTransaction
// didn't require the remote sig.
let dummy_sig = Secp256k1::new().sign(
Copy link
Member Author

Choose a reason for hiding this comment

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

This awkwardness is due to HolderCommitmentTransaction holding counterparty signatures. Not sure what's the best thing here - perhaps separate the signature holding to another struct?

Copy link

Choose a reason for hiding this comment

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

I think we would like to get ride of HolderCommitmentTransaction. It's API can be enforced either by ChannelMonitor or an external signer implementation like InMemoryChannelKeys.

All dynamic state (balances, HTLCs, ...) would be stored in Channel and the rest assumed to be in signer.

Copy link
Collaborator

Choose a reason for hiding this comment

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

I don't see why? HolderCommitmentTransaction, indeed, holds too much data today (specifically, the transaction itself), but communicating things like the counterparty signatures and the per htlc values has to be done. eg here the function signature has a ton of fields, that may be usefully just shoved into a struct, and HolderCommitmentTransaction is basically that. (I assume we agree here, just noting that we may end up wanting a struct either way).

/// Returns the transaction, the HTLC descriptions with output index populated
/// and the redeem scripts for the transaction.
/// Note that the redeem scripts are returned for test purposes.
pub fn build_commitment_tx(
Copy link
Member Author

Choose a reason for hiding this comment

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

Should this be DRYed with Channel.build_commitment_transaction?

Copy link
Collaborator

Choose a reason for hiding this comment

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

Would def be nice, also so that its a separate, static function which can be used by a simple external signer to implement of the signer interface with one-line calls to pub-static functions.

}

/// Get the transaction number obscure factor
pub fn get_commitment_transaction_number_obscure_factor(
Copy link
Member Author

Choose a reason for hiding this comment

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

DRY this with Channel.get_commitment_transaction_number_obscure_factor

@codecov
Copy link

codecov bot commented Sep 29, 2020

Codecov Report

Merging #723 into main will increase coverage by 1.46%.
The diff coverage is 17.02%.

Impacted file tree graph

@@            Coverage Diff             @@
##             main     #723      +/-   ##
==========================================
+ Coverage   91.95%   93.41%   +1.46%     
==========================================
  Files          36       40       +4     
  Lines       20200    25867    +5667     
==========================================
+ Hits        18575    24164    +5589     
- Misses       1625     1703      +78     
Impacted Files Coverage Δ
lightning/src/ln/chan_utils.rs 97.37% <ø> (ø)
lightning/src/ln/transaction.rs 0.00% <0.00%> (ø)
lightning/src/util/enforcing_trait_impls.rs 98.76% <50.00%> (ø)
lightning/src/chain/keysinterface.rs 94.05% <58.82%> (-2.15%) ⬇️
lightning/src/ln/channel.rs 89.79% <100.00%> (+3.56%) ⬆️
lightning/src/chain/transaction.rs 100.00% <0.00%> (ø)
lightning/src/chain/channelmonitor.rs 95.07% <0.00%> (ø)
lightning/src/chain/mod.rs 100.00% <0.00%> (ø)
lightning/src/chain/chainmonitor.rs 100.00% <0.00%> (ø)
... and 9 more

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 8640173...05a8af6. Read the comment docs.

Copy link

@ariard ariard left a comment

Choose a reason for hiding this comment

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

Actually we have HolderCommitmentTransaction which is just a blob of channel data without clear distribution of responsibility between Signer, Channel and ChannelMonitor. I think we should reduce/kill HolderCommitmentTransaction and stick per-update state in both Channel/ChannelMonitor. Static channel data should be initialized in Signer as soon as we receive off-chain messages.

When Channel/ChannelMonitor require either a verification or signing operation they call the Signer interface with the accurate per-update state. Signer can construct the commitment/HTLC transactions from data elements and verify/sign. As signer enforces immutability on static channel data, so an implementation can also serve as a commitment tx provider for any ChannelMonitor caller.

That said, if we agree that's where we want to end-up, I think this PR is moving towards the good direction.

// We provide a dummy signature for the remote, since we don't require that sig
// to be passed in to this call. It would have been better if HolderCommitmentTransaction
// didn't require the remote sig.
let dummy_sig = Secp256k1::new().sign(
Copy link

Choose a reason for hiding this comment

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

I think we would like to get ride of HolderCommitmentTransaction. It's API can be enforced either by ChannelMonitor or an external signer implementation like InMemoryChannelKeys.

All dynamic state (balances, HTLCs, ...) would be stored in Channel and the rest assumed to be in signer.

pub fn funding_outpoint(&self) -> &OutPoint { self.funding_outpoint.as_ref().unwrap() }

/// Prepare build information for a commitment tx that the holder can broadcast
pub fn build_holder_commitment_tx<T: secp256k1::Signing + secp256k1::Verification>(
Copy link
Collaborator

Choose a reason for hiding this comment

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

Would this need to be in the public interface, or are you imaging this is only a utility function in the InMemory version?

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.

Conceptually looks good, one question but its the right direction.

@devrandom
Copy link
Member Author

devrandom commented Oct 5, 2020

So, sign_holder_commitment doesn't take TxCreationKeys in this version. It did before (indirectly, via the holder_commitment_tx). I assume that we still want them based on the dev meeting today? Should I just add it as one of the params for now, until we refactor HolderCommitmentTransaction?

Followup: I did the latter

@devrandom
Copy link
Member Author

Superseded by #742

@devrandom devrandom closed this Dec 27, 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.

3 participants