From b4bdd55081212557547b2bc5a602381cc7a2ac18 Mon Sep 17 00:00:00 2001 From: Olaoluwa Osuntokun Date: Mon, 8 Jan 2018 18:50:24 -0800 Subject: [PATCH] lnwallet: if we fail to validate a remote commit sig, return detailed error MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In this commit, we add a new detailed error that’s to be returned when/if the remote peer sends us an invalid commit signature. The new error contains the transaction that we attempted to validate the signature over, the sighs, and the state number. Returning this additional information will serve to aide in debugging any cross-implementation issues. --- lnwallet/channel.go | 41 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 40 insertions(+), 1 deletion(-) diff --git a/lnwallet/channel.go b/lnwallet/channel.go index 05d8b847..48cb2c02 100644 --- a/lnwallet/channel.go +++ b/lnwallet/channel.go @@ -3591,6 +3591,33 @@ func genHtlcSigValidationJobs(localCommitmentView *commitment, return verifyJobs } +// InvalidCommitSigError is a struct that implements the error interface to +// report a failure to validation a commitment signature for a remote peer. +// We'll use the items in this struct to generate a rich error message for the +// remote peer when we receive an invalid signature from it. Doing so can +// greatly aide in debugging cross implementation issues. +type InvalidCommitSigError struct { + commitHeight uint64 + + commitSig []byte + + sigHash []byte + + commitTx []byte +} + +// Error returns a detailed error string including the exact transaction that +// caused an invalid commitment signature. +func (i *InvalidCommitSigError) Error() string { + return fmt.Sprintf("rejected commitment: commit_height=%v, "+ + "invalid_sig=%x, commit_tx=%x, sig_hash=%x", i.commitHeight, + i.commitSig[:], i.commitTx, i.sigHash[:]) +} + +// A compile time flag to ensure that InvalidCommitSigError implements the +// error interface. +var _ error = (*InvalidCommitSigError)(nil) + // ReceiveNewCommitment process a signature for a new commitment state sent by // the remote party. This method should be called in response to the // remote party initiating a new change, or when the remote party sends a @@ -3688,7 +3715,19 @@ func (lc *LightningChannel) ReceiveNewCommitment(commitSig *btcec.Signature, } if !commitSig.Verify(sigHash, &verifyKey) { close(cancelChan) - return fmt.Errorf("invalid commitment signature") + + // If we fail to validate their commitment signature, we'll + // generate a special error to send over the protocol. We'll + // include the exact signature and commitment we failed to + // verify against in order to aide debugging. + var txBytes bytes.Buffer + localCommitTx.Serialize(&txBytes) + return &InvalidCommitSigError{ + commitHeight: nextHeight, + commitSig: commitSig.Serialize(), + sigHash: sigHash, + commitTx: txBytes.Bytes(), + } } // With the primary commitment transaction validated, we'll check each