lnwallet: Refactor commitment key generation code.
Create struct holding all commitment keys to clean up code and avoid deriving keys multiple times.
This commit is contained in:
parent
0994852396
commit
3151a3a596
@ -292,6 +292,41 @@ type commitment struct {
|
||||
incomingHTLCIndex map[int32]*PaymentDescriptor
|
||||
}
|
||||
|
||||
// commitmentKeyRing holds all derived keys needed to construct commitment and
|
||||
// HTLC transactions. The keys are derived differently depending whether the
|
||||
// commitment transaction is ours or the remote peer's. Private keys associated
|
||||
// with each key may belong to the commitment owner or the "other party" which
|
||||
// is referred to in the field comments, regardless of which is local and which
|
||||
// is remote.
|
||||
type commitmentKeyRing struct {
|
||||
// commitPoint is the "per commitment point" used to derive the tweak for
|
||||
// each base point.
|
||||
commitPoint *btcec.PublicKey
|
||||
|
||||
// localKeyTweak is the tweak used to derive the local public key from the
|
||||
// local payment base point or the local private key from the base point
|
||||
// secret. This may be included in a SignDescriptor to generate signatures
|
||||
// for the local payment key.
|
||||
localKeyTweak []byte
|
||||
|
||||
// delayKey is the commitment transaction owner's key which is included in
|
||||
// HTLC success and timeout transaction scripts.
|
||||
delayKey *btcec.PublicKey
|
||||
|
||||
// paymentKey is the other party's payment key in the commitment tx.
|
||||
paymentKey *btcec.PublicKey
|
||||
|
||||
// revocationKey is the key that can be used by the other party to redeem
|
||||
// outputs from a revoked commitment transaction if it were to be published.
|
||||
revocationKey *btcec.PublicKey
|
||||
|
||||
// localKey is this node's payment key in the commitment tx.
|
||||
localKey *btcec.PublicKey
|
||||
|
||||
// remoteKey is the remote node's payment key in the commitment tx.
|
||||
remoteKey *btcec.PublicKey
|
||||
}
|
||||
|
||||
// locateOutputIndex is a small helper function to locate the output index of a
|
||||
// particular HTLC within the current commitment transaction. The duplicate map
|
||||
// massed in is to be retained for each output within the commitment
|
||||
@ -1115,27 +1150,15 @@ func newBreachRetribution(chanState *channeldb.OpenChannel, stateNum uint64,
|
||||
|
||||
// With the commitment point generated, we can now generate the four
|
||||
// keys we'll need to reconstruct the commitment state,
|
||||
localKey := TweakPubKey(chanState.LocalChanCfg.PaymentBasePoint,
|
||||
commitmentPoint)
|
||||
remoteKey := TweakPubKey(chanState.RemoteChanCfg.PaymentBasePoint,
|
||||
commitmentPoint)
|
||||
remoteDelayKey := TweakPubKey(chanState.RemoteChanCfg.DelayBasePoint,
|
||||
commitmentPoint)
|
||||
|
||||
// Once we derive the revocation leaf, we can then re-create the
|
||||
// revocation public key used within this state. This is needed in
|
||||
// order to create the proper script below.
|
||||
revocationKey := DeriveRevocationPubkey(
|
||||
chanState.LocalChanCfg.RevocationBasePoint,
|
||||
commitmentPoint,
|
||||
)
|
||||
keyRing := deriveCommitmentKeys(commitmentPoint, false,
|
||||
&chanState.LocalChanCfg, &chanState.RemoteChanCfg)
|
||||
|
||||
// Next, reconstruct the scripts as they were present at this state
|
||||
// number so we can have the proper witness script to sign and include
|
||||
// within the final witness.
|
||||
remoteDelay := uint32(chanState.RemoteChanCfg.CsvDelay)
|
||||
remotePkScript, err := commitScriptToSelf(remoteDelay, remoteDelayKey,
|
||||
revocationKey)
|
||||
remotePkScript, err := commitScriptToSelf(remoteDelay, keyRing.delayKey,
|
||||
keyRing.revocationKey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -1143,7 +1166,7 @@ func newBreachRetribution(chanState *channeldb.OpenChannel, stateNum uint64,
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
localPkScript, err := commitScriptUnencumbered(localKey)
|
||||
localPkScript, err := commitScriptUnencumbered(keyRing.localKey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -1180,13 +1203,8 @@ func newBreachRetribution(chanState *channeldb.OpenChannel, stateNum uint64,
|
||||
// If the local balance exceeds the remote party's dust limit,
|
||||
// instantiate the local sign descriptor.
|
||||
if localAmt >= chanState.RemoteChanCfg.DustLimit {
|
||||
// We'll need to reconstruct the single tweak so we can sweep
|
||||
// our non-delayed pay-to-self output self.
|
||||
singleTweak := SingleTweakBytes(commitmentPoint,
|
||||
chanState.LocalChanCfg.PaymentBasePoint)
|
||||
|
||||
localSignDesc = &SignDescriptor{
|
||||
SingleTweak: singleTweak,
|
||||
SingleTweak: keyRing.localKeyTweak,
|
||||
PubKey: chanState.LocalChanCfg.PaymentBasePoint,
|
||||
WitnessScript: localPkScript,
|
||||
Output: &wire.TxOut{
|
||||
@ -1226,8 +1244,8 @@ func newBreachRetribution(chanState *channeldb.OpenChannel, stateNum uint64,
|
||||
// the sender of the HTLC (relative to us). So we'll
|
||||
// re-generate the sender HTLC script.
|
||||
if htlc.Incoming {
|
||||
htlcScript, err = senderHTLCScript(localKey, remoteKey,
|
||||
revocationKey, htlc.RHash[:])
|
||||
htlcScript, err = senderHTLCScript(keyRing.localKey,
|
||||
keyRing.remoteKey, keyRing.revocationKey, htlc.RHash[:])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -1237,8 +1255,8 @@ func newBreachRetribution(chanState *channeldb.OpenChannel, stateNum uint64,
|
||||
// receiver of this HTLC.
|
||||
} else {
|
||||
htlcScript, err = receiverHTLCScript(
|
||||
htlc.RefundTimeout, localKey, remoteKey,
|
||||
revocationKey, htlc.RHash[:],
|
||||
htlc.RefundTimeout, keyRing.localKey, keyRing.remoteKey,
|
||||
keyRing.revocationKey, htlc.RHash[:],
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@ -1362,7 +1380,7 @@ func (lc *LightningChannel) closeObserver(channelCloseNtfn *chainntnfs.SpendEven
|
||||
// necessary.
|
||||
//
|
||||
// We'll also handle the case of the remote party broadcasting their
|
||||
// commitment transaction which is one height above ours. This case an
|
||||
// commitment transaction which is one height above ours. This case can
|
||||
// arise when we initiate a state transition, but the remote party has
|
||||
// a fail crash _after_ accepting the new state, but _before_ sending
|
||||
// their signature to us.
|
||||
@ -1394,17 +1412,15 @@ func (lc *LightningChannel) closeObserver(channelCloseNtfn *chainntnfs.SpendEven
|
||||
// revocation point so we can re-construct the HTLC state and
|
||||
// also our payment key.
|
||||
commitPoint := lc.channelState.RemoteCurrentRevocation
|
||||
revokeKey := DeriveRevocationPubkey(
|
||||
lc.localChanCfg.RevocationBasePoint,
|
||||
commitPoint,
|
||||
)
|
||||
keyRing := deriveCommitmentKeys(commitPoint, false,
|
||||
lc.localChanCfg, lc.remoteChanCfg)
|
||||
|
||||
// Next, we'll obtain HTLC resolutions for all the outgoing
|
||||
// HTLC's we had on their commitment transaction.
|
||||
htlcResolutions, localKey, err := extractHtlcResolutions(
|
||||
htlcResolutions, err := extractHtlcResolutions(
|
||||
lc.channelState.FeePerKw, false, lc.signer,
|
||||
lc.channelState.Htlcs, commitPoint,
|
||||
revokeKey, lc.localChanCfg, lc.remoteChanCfg,
|
||||
lc.channelState.Htlcs, keyRing,
|
||||
lc.localChanCfg, lc.remoteChanCfg,
|
||||
*commitSpend.SpenderTxHash)
|
||||
if err != nil {
|
||||
walletLog.Errorf("unable to create htlc "+
|
||||
@ -1415,7 +1431,7 @@ func (lc *LightningChannel) closeObserver(channelCloseNtfn *chainntnfs.SpendEven
|
||||
// Before we can generate the proper sign descriptor, we'll
|
||||
// need to locate the output index of our non-delayed output on
|
||||
// the commitment transaction.
|
||||
selfP2WKH, err := commitScriptUnencumbered(localKey)
|
||||
selfP2WKH, err := commitScriptUnencumbered(keyRing.localKey)
|
||||
if err != nil {
|
||||
walletLog.Errorf("unable to create self commit "+
|
||||
"script: %v", err)
|
||||
@ -1440,7 +1456,7 @@ func (lc *LightningChannel) closeObserver(channelCloseNtfn *chainntnfs.SpendEven
|
||||
localPayBase := lc.localChanCfg.PaymentBasePoint
|
||||
selfSignDesc = &SignDescriptor{
|
||||
PubKey: localPayBase,
|
||||
SingleTweak: SingleTweakBytes(commitPoint, localPayBase),
|
||||
SingleTweak: keyRing.localKeyTweak,
|
||||
WitnessScript: selfP2WKH,
|
||||
Output: &wire.TxOut{
|
||||
Value: int64(lc.channelState.LocalBalance.ToSatoshis()),
|
||||
@ -1583,27 +1599,12 @@ func (lc *LightningChannel) restoreStateLogs() error {
|
||||
// the point derived from the commitment secret at the remote party's
|
||||
// revocation based.
|
||||
localCommitPoint := ComputeCommitmentPoint(ourRevPreImage[:])
|
||||
localRevocation := DeriveRevocationPubkey(
|
||||
remoteChanCfg.RevocationBasePoint,
|
||||
localCommitPoint,
|
||||
)
|
||||
localCommitKeys := deriveCommitmentKeys(localCommitPoint, true,
|
||||
localChanCfg, remoteChanCfg)
|
||||
|
||||
remoteCommitPoint := lc.channelState.RemoteCurrentRevocation
|
||||
remoteRevocation := DeriveRevocationPubkey(
|
||||
localChanCfg.RevocationBasePoint,
|
||||
remoteCommitPoint,
|
||||
)
|
||||
|
||||
// Additionally, we'll fetch the current payment base points which are
|
||||
// required to fully generate the scripts.
|
||||
localCommitLocalKey := TweakPubKey(localChanCfg.PaymentBasePoint,
|
||||
localCommitPoint)
|
||||
localCommitRemoteKey := TweakPubKey(remoteChanCfg.PaymentBasePoint,
|
||||
localCommitPoint)
|
||||
|
||||
remoteCommitLocalKey := TweakPubKey(localChanCfg.PaymentBasePoint,
|
||||
remoteCommitPoint)
|
||||
remoteCommitRemoteKey := TweakPubKey(remoteChanCfg.PaymentBasePoint,
|
||||
remoteCommitPoint)
|
||||
remoteCommitKeys := deriveCommitmentKeys(remoteCommitPoint, false,
|
||||
localChanCfg, remoteChanCfg)
|
||||
|
||||
var ourCounter, theirCounter uint64
|
||||
|
||||
@ -1637,8 +1638,8 @@ func (lc *LightningChannel) restoreStateLogs() error {
|
||||
if !isDustLocal {
|
||||
ourP2WSH, ourWitnessScript, err = lc.genHtlcScript(
|
||||
htlc.Incoming, true, htlc.RefundTimeout, htlc.RHash,
|
||||
localCommitLocalKey, localCommitRemoteKey,
|
||||
localRevocation)
|
||||
localCommitKeys.localKey, localCommitKeys.remoteKey,
|
||||
localCommitKeys.revocationKey)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -1646,8 +1647,8 @@ func (lc *LightningChannel) restoreStateLogs() error {
|
||||
if !isDustRemote {
|
||||
theirP2WSH, theirWitnessScript, err = lc.genHtlcScript(
|
||||
htlc.Incoming, false, htlc.RefundTimeout, htlc.RHash,
|
||||
remoteCommitLocalKey, remoteCommitRemoteKey,
|
||||
remoteRevocation)
|
||||
remoteCommitKeys.localKey, remoteCommitKeys.remoteKey,
|
||||
remoteCommitKeys.revocationKey)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -1735,11 +1736,9 @@ func (lc *LightningChannel) fetchHTLCView(theirLogIndex, ourLogIndex uint64) *ht
|
||||
// both local and remote commitment transactions in order to sign or verify new
|
||||
// commitment updates. A fully populated commitment is returned which reflects
|
||||
// the proper balances for both sides at this point in the commitment chain.
|
||||
//
|
||||
// TODO(roasbeef): update commit to to have all keys?
|
||||
func (lc *LightningChannel) fetchCommitmentView(remoteChain bool,
|
||||
ourLogIndex, theirLogIndex uint64,
|
||||
commitPoint *btcec.PublicKey) (*commitment, error) {
|
||||
keyRing *commitmentKeyRing) (*commitment, error) {
|
||||
|
||||
commitChain := lc.localCommitChain
|
||||
if remoteChain {
|
||||
@ -1853,9 +1852,8 @@ func (lc *LightningChannel) fetchCommitmentView(remoteChain bool,
|
||||
}
|
||||
|
||||
var (
|
||||
delayKey, paymentKey, revocationKey *btcec.PublicKey
|
||||
delay uint32
|
||||
delayBalance, p2wkhBalance btcutil.Amount
|
||||
delay uint32
|
||||
delayBalance, p2wkhBalance btcutil.Amount
|
||||
)
|
||||
|
||||
// We'll now compute the delay, payment and revocation key based on the
|
||||
@ -1864,40 +1862,20 @@ func (lc *LightningChannel) fetchCommitmentView(remoteChain bool,
|
||||
// revocation key, we take the opposite party's revocation base point
|
||||
// and combine that with the current commitment point.
|
||||
if remoteChain {
|
||||
delayKey = TweakPubKey(lc.remoteChanCfg.DelayBasePoint,
|
||||
commitPoint)
|
||||
paymentKey = TweakPubKey(lc.localChanCfg.PaymentBasePoint,
|
||||
commitPoint)
|
||||
revocationKey = DeriveRevocationPubkey(
|
||||
lc.localChanCfg.RevocationBasePoint,
|
||||
commitPoint,
|
||||
)
|
||||
|
||||
delay = uint32(lc.remoteChanCfg.CsvDelay)
|
||||
delayBalance = theirBalance.ToSatoshis()
|
||||
p2wkhBalance = ourBalance.ToSatoshis()
|
||||
} else {
|
||||
delayKey = TweakPubKey(lc.localChanCfg.DelayBasePoint,
|
||||
commitPoint)
|
||||
paymentKey = TweakPubKey(lc.remoteChanCfg.PaymentBasePoint,
|
||||
commitPoint)
|
||||
revocationKey = DeriveRevocationPubkey(
|
||||
lc.remoteChanCfg.RevocationBasePoint,
|
||||
commitPoint,
|
||||
)
|
||||
|
||||
delay = uint32(lc.localChanCfg.CsvDelay)
|
||||
delayBalance = ourBalance.ToSatoshis()
|
||||
p2wkhBalance = theirBalance.ToSatoshis()
|
||||
}
|
||||
|
||||
// TODO(roasbeef); create all keys unconditionally within commitment
|
||||
// store in commitment, will need all when doing HTLC's
|
||||
|
||||
// Generate a new commitment transaction with all the latest
|
||||
// unsettled/un-timed out HTLCs.
|
||||
commitTx, err := CreateCommitTx(lc.fundingTxIn, delayKey, paymentKey,
|
||||
revocationKey, delay, delayBalance, p2wkhBalance, dustLimit)
|
||||
commitTx, err := CreateCommitTx(lc.fundingTxIn, keyRing.delayKey,
|
||||
keyRing.paymentKey, keyRing.revocationKey, delay, delayBalance,
|
||||
p2wkhBalance, dustLimit)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -1906,17 +1884,14 @@ func (lc *LightningChannel) fetchCommitmentView(remoteChain bool,
|
||||
// Each output includes an off-chain 2-of-2 covenant clause, so we'll
|
||||
// need the objective local/remote keys for this particular commitment
|
||||
// as well.
|
||||
// TODO(roasbeef): could avoid computing them both here
|
||||
localKey := TweakPubKey(lc.localChanCfg.PaymentBasePoint, commitPoint)
|
||||
remoteKey := TweakPubKey(lc.remoteChanCfg.PaymentBasePoint, commitPoint)
|
||||
for _, htlc := range filteredHTLCView.ourUpdates {
|
||||
if htlcIsDust(false, !remoteChain, feePerKw,
|
||||
htlc.Amount.ToSatoshis(), dustLimit) {
|
||||
continue
|
||||
}
|
||||
|
||||
err := lc.addHTLC(commitTx, ourCommitTx, false, htlc, localKey,
|
||||
remoteKey, revocationKey)
|
||||
err := lc.addHTLC(commitTx, ourCommitTx, false, htlc, keyRing.localKey,
|
||||
keyRing.remoteKey, keyRing.revocationKey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -1927,8 +1902,8 @@ func (lc *LightningChannel) fetchCommitmentView(remoteChain bool,
|
||||
continue
|
||||
}
|
||||
|
||||
err := lc.addHTLC(commitTx, ourCommitTx, true, htlc, localKey,
|
||||
remoteKey, revocationKey)
|
||||
err := lc.addHTLC(commitTx, ourCommitTx, true, htlc, keyRing.localKey,
|
||||
keyRing.remoteKey, keyRing.revocationKey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -2156,26 +2131,10 @@ func processRemoveEntry(htlc *PaymentDescriptor, ourBalance,
|
||||
// generating a new commitment for the remote party. The jobs generated by the
|
||||
// signature can be submitted to the sigPool to generate all the signatures
|
||||
// asynchronously and in parallel.
|
||||
//
|
||||
// TODO(roasbeef): all keys will eventually be generated within the commitment
|
||||
// itself
|
||||
func genRemoteHtlcSigJobs(commitPoint *btcec.PublicKey,
|
||||
func genRemoteHtlcSigJobs(keyRing *commitmentKeyRing,
|
||||
localChanCfg, remoteChanCfg *channeldb.ChannelConfig,
|
||||
remoteCommitView *commitment) ([]signJob, chan struct{}, error) {
|
||||
|
||||
// First, we'll generate all the keys required to generate the scripts
|
||||
// for each HTLC output and transaction.
|
||||
//
|
||||
// TODO(roabseef): avoid re-calculating, put in commitment struct?
|
||||
commitTweak := SingleTweakBytes(commitPoint,
|
||||
localChanCfg.PaymentBasePoint)
|
||||
revocationKey := DeriveRevocationPubkey(
|
||||
localChanCfg.RevocationBasePoint,
|
||||
commitPoint,
|
||||
)
|
||||
remoteDelayKey := TweakPubKey(remoteChanCfg.DelayBasePoint,
|
||||
commitPoint)
|
||||
|
||||
txHash := remoteCommitView.txn.TxHash()
|
||||
dustLimit := localChanCfg.DustLimit
|
||||
feePerKw := remoteCommitView.feePerKw
|
||||
@ -2221,7 +2180,7 @@ func genRemoteHtlcSigJobs(commitPoint *btcec.PublicKey,
|
||||
}
|
||||
sigJob.tx, err = createHtlcTimeoutTx(op, outputAmt,
|
||||
htlc.Timeout, uint32(remoteChanCfg.CsvDelay),
|
||||
revocationKey, remoteDelayKey)
|
||||
keyRing.revocationKey, keyRing.delayKey)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
@ -2231,7 +2190,7 @@ func genRemoteHtlcSigJobs(commitPoint *btcec.PublicKey,
|
||||
// transaction. Note we use the raw HTLC amount.
|
||||
sigJob.signDesc = SignDescriptor{
|
||||
PubKey: localChanCfg.PaymentBasePoint,
|
||||
SingleTweak: commitTweak,
|
||||
SingleTweak: keyRing.localKeyTweak,
|
||||
WitnessScript: htlc.theirWitnessScript,
|
||||
Output: &wire.TxOut{
|
||||
Value: int64(htlc.Amount.ToSatoshis()),
|
||||
@ -2270,8 +2229,8 @@ func genRemoteHtlcSigJobs(commitPoint *btcec.PublicKey,
|
||||
Index: uint32(htlc.remoteOutputIndex),
|
||||
}
|
||||
sigJob.tx, err = createHtlcSuccessTx(op, outputAmt,
|
||||
uint32(remoteChanCfg.CsvDelay), revocationKey,
|
||||
remoteDelayKey)
|
||||
uint32(remoteChanCfg.CsvDelay), keyRing.revocationKey,
|
||||
keyRing.delayKey)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
@ -2281,7 +2240,7 @@ func genRemoteHtlcSigJobs(commitPoint *btcec.PublicKey,
|
||||
// transaction. Note we use the raw HTLC amount.
|
||||
sigJob.signDesc = SignDescriptor{
|
||||
PubKey: localChanCfg.PaymentBasePoint,
|
||||
SingleTweak: commitTweak,
|
||||
SingleTweak: keyRing.localKeyTweak,
|
||||
WitnessScript: htlc.theirWitnessScript,
|
||||
Output: &wire.TxOut{
|
||||
Value: int64(htlc.Amount.ToSatoshis()),
|
||||
@ -2333,6 +2292,8 @@ func (lc *LightningChannel) SignNextCommitment() (*btcec.Signature, []*btcec.Sig
|
||||
// used within fetchCommitmentView to derive all the keys necessary to
|
||||
// construct the commitment state.
|
||||
commitPoint := lc.channelState.RemoteNextRevocation
|
||||
keyRing := deriveCommitmentKeys(commitPoint, false, lc.localChanCfg,
|
||||
lc.remoteChanCfg)
|
||||
|
||||
// Create a new commitment view which will calculate the evaluated
|
||||
// state of the remote node's new commitment including our latest added
|
||||
@ -2342,8 +2303,7 @@ func (lc *LightningChannel) SignNextCommitment() (*btcec.Signature, []*btcec.Sig
|
||||
// _all_ of our changes (pending or committed) but only the remote
|
||||
// node's changes up to the last change we've ACK'd.
|
||||
newCommitView, err := lc.fetchCommitmentView(true,
|
||||
lc.localUpdateLog.logIndex, lc.remoteUpdateLog.ackedIndex,
|
||||
commitPoint)
|
||||
lc.localUpdateLog.logIndex, lc.remoteUpdateLog.ackedIndex, keyRing)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
@ -2364,7 +2324,7 @@ func (lc *LightningChannel) SignNextCommitment() (*btcec.Signature, []*btcec.Sig
|
||||
// need to generate signatures of each of them for the remote party's
|
||||
// commitment state. We do so in two phases: first we generate and
|
||||
// submit the set of signature jobs to the worker pool.
|
||||
sigBatch, cancelChan, err := genRemoteHtlcSigJobs(commitPoint,
|
||||
sigBatch, cancelChan, err := genRemoteHtlcSigJobs(keyRing,
|
||||
lc.localChanCfg, lc.remoteChanCfg, newCommitView,
|
||||
)
|
||||
if err != nil {
|
||||
@ -2507,7 +2467,7 @@ func (lc *LightningChannel) validateCommitmentSanity(theirLogCounter,
|
||||
// commitment state. The jobs generated are fully populated, and can be sent
|
||||
// directly into the pool of workers.
|
||||
func genHtlcSigValidationJobs(localCommitmentView *commitment,
|
||||
commitPoint *btcec.PublicKey, htlcSigs []*btcec.Signature,
|
||||
keyRing *commitmentKeyRing, htlcSigs []*btcec.Signature,
|
||||
localChanCfg, remoteChanCfg *channeldb.ChannelConfig) []verifyJob {
|
||||
|
||||
// If this new commitment state doesn't have any HTLC's that are to be
|
||||
@ -2516,16 +2476,6 @@ func genHtlcSigValidationJobs(localCommitmentView *commitment,
|
||||
return nil
|
||||
}
|
||||
|
||||
// First, we'll re-derive the keys necessary to reconstruct the HTLC
|
||||
// output and transaction state.
|
||||
remoteKey := TweakPubKey(remoteChanCfg.PaymentBasePoint, commitPoint)
|
||||
revocationKey := DeriveRevocationPubkey(
|
||||
remoteChanCfg.RevocationBasePoint,
|
||||
commitPoint,
|
||||
)
|
||||
localDelayKey := TweakPubKey(localChanCfg.DelayBasePoint,
|
||||
commitPoint)
|
||||
|
||||
txHash := localCommitmentView.txn.TxHash()
|
||||
feePerKw := localCommitmentView.feePerKw
|
||||
|
||||
@ -2565,7 +2515,7 @@ func genHtlcSigValidationJobs(localCommitmentView *commitment,
|
||||
|
||||
successTx, err := createHtlcSuccessTx(op,
|
||||
outputAmt, uint32(localChanCfg.CsvDelay),
|
||||
revocationKey, localDelayKey)
|
||||
keyRing.revocationKey, keyRing.delayKey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -2606,7 +2556,7 @@ func genHtlcSigValidationJobs(localCommitmentView *commitment,
|
||||
timeoutTx, err := createHtlcTimeoutTx(op,
|
||||
outputAmt, htlc.Timeout,
|
||||
uint32(localChanCfg.CsvDelay),
|
||||
revocationKey, localDelayKey,
|
||||
keyRing.revocationKey, keyRing.delayKey,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@ -2635,7 +2585,7 @@ func genHtlcSigValidationJobs(localCommitmentView *commitment,
|
||||
}
|
||||
|
||||
verifyJobs = append(verifyJobs, verifyJob{
|
||||
pubKey: remoteKey,
|
||||
pubKey: keyRing.remoteKey,
|
||||
sig: htlcSigs[i],
|
||||
sigHash: sigHash,
|
||||
})
|
||||
@ -2679,13 +2629,14 @@ func (lc *LightningChannel) ReceiveNewCommitment(commitSig *btcec.Signature,
|
||||
return err
|
||||
}
|
||||
commitPoint := ComputeCommitmentPoint(commitSecret[:])
|
||||
keyRing := deriveCommitmentKeys(commitPoint, true, lc.localChanCfg,
|
||||
lc.remoteChanCfg)
|
||||
|
||||
// With the current commitment point re-calculated, construct the new
|
||||
// commitment view which includes all the entries we know of in their
|
||||
// HTLC log, and up to ourLogIndex in our HTLC log.
|
||||
localCommitmentView, err := lc.fetchCommitmentView(false,
|
||||
lc.localUpdateLog.ackedIndex, lc.remoteUpdateLog.logIndex,
|
||||
commitPoint)
|
||||
lc.localUpdateLog.ackedIndex, lc.remoteUpdateLog.logIndex, keyRing)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -2719,8 +2670,7 @@ func (lc *LightningChannel) ReceiveNewCommitment(commitSig *btcec.Signature,
|
||||
// pool to verify each of the HTLc signatures presented. Once
|
||||
// generated, we'll submit these jobs to the worker pool.
|
||||
verifyJobs := genHtlcSigValidationJobs(localCommitmentView,
|
||||
commitPoint,
|
||||
htlcSigs, lc.localChanCfg, lc.remoteChanCfg)
|
||||
keyRing, htlcSigs, lc.localChanCfg, lc.remoteChanCfg)
|
||||
cancelChan := make(chan struct{})
|
||||
verifyResps := lc.sigPool.SubmitVerifyBatch(verifyJobs, cancelChan)
|
||||
|
||||
@ -3413,9 +3363,9 @@ type OutgoingHtlcResolution struct {
|
||||
// caller to sweep an outgoing HTLC present on either their, or the remote
|
||||
// party's commitment transaction.
|
||||
func newHtlcResolution(signer Signer, localChanCfg *channeldb.ChannelConfig,
|
||||
commitHash chainhash.Hash, htlc *channeldb.HTLC, commitPoint,
|
||||
delayKey, localKey, remoteKey *btcec.PublicKey, revokeKey *btcec.PublicKey,
|
||||
feePewKw, dustLimit btcutil.Amount, csvDelay uint32) (*OutgoingHtlcResolution, error) {
|
||||
commitHash chainhash.Hash, htlc *channeldb.HTLC, keyRing *commitmentKeyRing,
|
||||
feePewKw, dustLimit btcutil.Amount, csvDelay uint32,
|
||||
) (*OutgoingHtlcResolution, error) {
|
||||
|
||||
op := wire.OutPoint{
|
||||
Hash: commitHash,
|
||||
@ -3432,7 +3382,7 @@ func newHtlcResolution(signer Signer, localChanCfg *channeldb.ChannelConfig,
|
||||
// transaction.
|
||||
timeoutTx, err := createHtlcTimeoutTx(
|
||||
op, secondLevelOutputAmt, htlc.RefundTimeout, csvDelay,
|
||||
revokeKey, delayKey,
|
||||
keyRing.revocationKey, keyRing.delayKey,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@ -3441,16 +3391,14 @@ func newHtlcResolution(signer Signer, localChanCfg *channeldb.ChannelConfig,
|
||||
// With the transaction created, we can generate a sign descriptor
|
||||
// that's capable of generating the signature required to spend the
|
||||
// HTLC output using the timeout transaction.
|
||||
htlcCreationScript, err := senderHTLCScript(localKey, remoteKey,
|
||||
revokeKey, htlc.RHash[:])
|
||||
htlcCreationScript, err := senderHTLCScript(keyRing.localKey,
|
||||
keyRing.remoteKey, keyRing.revocationKey, htlc.RHash[:])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
timeoutTweak := SingleTweakBytes(commitPoint,
|
||||
localChanCfg.PaymentBasePoint)
|
||||
timeoutSignDesc := SignDescriptor{
|
||||
PubKey: localChanCfg.PaymentBasePoint,
|
||||
SingleTweak: timeoutTweak,
|
||||
SingleTweak: keyRing.localKeyTweak,
|
||||
WitnessScript: htlcCreationScript,
|
||||
Output: &wire.TxOut{
|
||||
Value: int64(htlc.Amt.ToSatoshis()),
|
||||
@ -3473,7 +3421,7 @@ func newHtlcResolution(signer Signer, localChanCfg *channeldb.ChannelConfig,
|
||||
// transaction creates so we can generate the signDesc required to
|
||||
// complete the claim process after a delay period.
|
||||
htlcSweepScript, err := secondLevelHtlcScript(
|
||||
revokeKey, delayKey, csvDelay,
|
||||
keyRing.revocationKey, keyRing.delayKey, csvDelay,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@ -3483,14 +3431,15 @@ func newHtlcResolution(signer Signer, localChanCfg *channeldb.ChannelConfig,
|
||||
return nil, err
|
||||
}
|
||||
|
||||
delayTweak := SingleTweakBytes(commitPoint,
|
||||
// TODO: Signing with the delay key is wrong for remote commitments
|
||||
localDelayTweak := SingleTweakBytes(keyRing.commitPoint,
|
||||
localChanCfg.DelayBasePoint)
|
||||
return &OutgoingHtlcResolution{
|
||||
Expiry: htlc.RefundTimeout,
|
||||
SignedTimeoutTx: timeoutTx,
|
||||
SweepSignDesc: SignDescriptor{
|
||||
PubKey: localChanCfg.DelayBasePoint,
|
||||
SingleTweak: delayTweak,
|
||||
SingleTweak: localDelayTweak,
|
||||
WitnessScript: htlcSweepScript,
|
||||
Output: &wire.TxOut{
|
||||
PkScript: htlcScriptHash,
|
||||
@ -3505,17 +3454,9 @@ func newHtlcResolution(signer Signer, localChanCfg *channeldb.ChannelConfig,
|
||||
// the local key used when generating the HTLC scrips. This function is to be
|
||||
// used in two cases: force close, or a unilateral close.
|
||||
func extractHtlcResolutions(feePerKw btcutil.Amount, ourCommit bool,
|
||||
signer Signer, htlcs []*channeldb.HTLC,
|
||||
commitPoint, revokeKey *btcec.PublicKey,
|
||||
signer Signer, htlcs []*channeldb.HTLC, keyRing *commitmentKeyRing,
|
||||
localChanCfg, remoteChanCfg *channeldb.ChannelConfig,
|
||||
commitHash chainhash.Hash) ([]OutgoingHtlcResolution, *btcec.PublicKey, error) {
|
||||
|
||||
// As uusal, we start by re-generating the key-ring required to
|
||||
// reconstruct the pkScripts used, and sign any transactions or inputs
|
||||
// required to sweep all funds.
|
||||
localKey := TweakPubKey(localChanCfg.PaymentBasePoint, commitPoint)
|
||||
delayKey := TweakPubKey(localChanCfg.DelayBasePoint, commitPoint)
|
||||
remoteKey := TweakPubKey(remoteChanCfg.PaymentBasePoint, commitPoint)
|
||||
commitHash chainhash.Hash) ([]OutgoingHtlcResolution, error) {
|
||||
|
||||
dustLimit := remoteChanCfg.DustLimit
|
||||
csvDelay := remoteChanCfg.CsvDelay
|
||||
@ -3542,19 +3483,18 @@ func extractHtlcResolutions(feePerKw btcutil.Amount, ourCommit bool,
|
||||
}
|
||||
|
||||
ohr, err := newHtlcResolution(
|
||||
signer, localChanCfg, commitHash, htlc, commitPoint,
|
||||
delayKey, localKey, remoteKey, revokeKey, feePerKw,
|
||||
dustLimit, uint32(csvDelay),
|
||||
signer, localChanCfg, commitHash, htlc, keyRing,
|
||||
feePerKw, dustLimit, uint32(csvDelay),
|
||||
)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// TODO(roasbeef): needs to point to proper amount including
|
||||
htlcResolutions = append(htlcResolutions, *ohr)
|
||||
}
|
||||
|
||||
return htlcResolutions, localKey, nil
|
||||
return htlcResolutions, nil
|
||||
}
|
||||
|
||||
// ForceCloseSummary describes the final commitment state before the channel is
|
||||
@ -3628,12 +3568,10 @@ func (lc *LightningChannel) ForceClose() (*ForceCloseSummary, error) {
|
||||
return nil, err
|
||||
}
|
||||
commitPoint := ComputeCommitmentPoint(unusedRevocation[:])
|
||||
revokeKey := DeriveRevocationPubkey(
|
||||
lc.remoteChanCfg.RevocationBasePoint,
|
||||
commitPoint,
|
||||
)
|
||||
delayKey := TweakPubKey(lc.localChanCfg.DelayBasePoint, commitPoint)
|
||||
selfScript, err := commitScriptToSelf(csvTimeout, delayKey, revokeKey)
|
||||
keyRing := deriveCommitmentKeys(commitPoint, true, lc.localChanCfg,
|
||||
lc.remoteChanCfg)
|
||||
selfScript, err := commitScriptToSelf(csvTimeout, keyRing.delayKey,
|
||||
keyRing.revocationKey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -3685,9 +3623,9 @@ func (lc *LightningChannel) ForceClose() (*ForceCloseSummary, error) {
|
||||
// need to create a series of sign descriptors for any lingering
|
||||
// outgoing HTLC's that we'll need to claim as well.
|
||||
txHash := commitTx.TxHash()
|
||||
htlcResolutions, _, err := extractHtlcResolutions(
|
||||
htlcResolutions, err := extractHtlcResolutions(
|
||||
lc.channelState.FeePerKw, true, lc.signer, lc.channelState.Htlcs,
|
||||
commitPoint, revokeKey, lc.localChanCfg, lc.remoteChanCfg, txHash)
|
||||
keyRing, lc.localChanCfg, lc.remoteChanCfg, txHash)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -4009,3 +3947,38 @@ func (lc *LightningChannel) RemoteNextRevocation() *btcec.PublicKey {
|
||||
|
||||
return lc.channelState.RemoteNextRevocation
|
||||
}
|
||||
|
||||
// deriveCommitmentKey generates a new commitment key set using the base points
|
||||
// and commitment point. The keys are derived differently depending whether the
|
||||
// commitment transaction is ours or the remote peer's.
|
||||
func deriveCommitmentKeys(commitPoint *btcec.PublicKey, isOurCommit bool,
|
||||
localChanCfg, remoteChanCfg *channeldb.ChannelConfig) *commitmentKeyRing {
|
||||
keyRing := new(commitmentKeyRing)
|
||||
|
||||
keyRing.commitPoint = commitPoint
|
||||
keyRing.localKeyTweak = SingleTweakBytes(commitPoint,
|
||||
localChanCfg.PaymentBasePoint)
|
||||
keyRing.localKey = TweakPubKeyWithTweak(localChanCfg.PaymentBasePoint,
|
||||
keyRing.localKeyTweak)
|
||||
keyRing.remoteKey = TweakPubKey(remoteChanCfg.PaymentBasePoint, commitPoint)
|
||||
|
||||
// We'll now compute the delay, payment and revocation key based on the
|
||||
// current commitment point. All keys are tweaked each state in order
|
||||
// to ensure the keys from each state are unlinkable. TO create the
|
||||
// revocation key, we take the opposite party's revocation base point
|
||||
// and combine that with the current commitment point.
|
||||
var delayBasePoint, revocationBasePoint *btcec.PublicKey
|
||||
if isOurCommit {
|
||||
keyRing.paymentKey = keyRing.remoteKey
|
||||
delayBasePoint = localChanCfg.DelayBasePoint
|
||||
revocationBasePoint = remoteChanCfg.RevocationBasePoint
|
||||
} else {
|
||||
keyRing.paymentKey = keyRing.localKey
|
||||
delayBasePoint = remoteChanCfg.DelayBasePoint
|
||||
revocationBasePoint = localChanCfg.RevocationBasePoint
|
||||
}
|
||||
keyRing.delayKey = TweakPubKey(delayBasePoint, commitPoint)
|
||||
keyRing.revocationKey = DeriveRevocationPubkey(revocationBasePoint, commitPoint)
|
||||
|
||||
return keyRing
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user