lnwallet: use channel type to derive remote script
Based on the current channel type, we derive the script used for the to_remote output. Currently only the unencumbered p2wkh type is used, but that will change with upcoming channel types.
This commit is contained in:
parent
9b5809a884
commit
a56ed72bd7
@ -351,8 +351,9 @@ func isOurCommitment(localChanCfg, remoteChanCfg channeldb.ChannelConfig,
|
|||||||
|
|
||||||
// With the keys derived, we'll construct the remote script that'll be
|
// With the keys derived, we'll construct the remote script that'll be
|
||||||
// present if they have a non-dust balance on the commitment.
|
// present if they have a non-dust balance on the commitment.
|
||||||
remotePkScript, err := input.CommitScriptUnencumbered(
|
remoteDelay := uint32(remoteChanCfg.CsvDelay)
|
||||||
commitKeyRing.ToRemoteKey,
|
remoteScript, err := lnwallet.CommitScriptToRemote(
|
||||||
|
chanType, remoteDelay, commitKeyRing.ToRemoteKey,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, err
|
return false, err
|
||||||
@ -383,7 +384,7 @@ func isOurCommitment(localChanCfg, remoteChanCfg channeldb.ChannelConfig,
|
|||||||
case bytes.Equal(localPkScript, pkScript):
|
case bytes.Equal(localPkScript, pkScript):
|
||||||
return true, nil
|
return true, nil
|
||||||
|
|
||||||
case bytes.Equal(remotePkScript, pkScript):
|
case bytes.Equal(remoteScript.PkScript, pkScript):
|
||||||
return true, nil
|
return true, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1871,36 +1871,42 @@ func NewBreachRetribution(chanState *channeldb.OpenChannel, stateNum uint64,
|
|||||||
// Next, reconstruct the scripts as they were present at this state
|
// Next, reconstruct the scripts as they were present at this state
|
||||||
// number so we can have the proper witness script to sign and include
|
// number so we can have the proper witness script to sign and include
|
||||||
// within the final witness.
|
// within the final witness.
|
||||||
remoteDelay := uint32(chanState.RemoteChanCfg.CsvDelay)
|
theirDelay := uint32(chanState.RemoteChanCfg.CsvDelay)
|
||||||
remotePkScript, err := input.CommitScriptToSelf(
|
theirPkScript, err := input.CommitScriptToSelf(
|
||||||
remoteDelay, keyRing.ToLocalKey, keyRing.RevocationKey,
|
theirDelay, keyRing.ToLocalKey, keyRing.RevocationKey,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
remoteWitnessHash, err := input.WitnessScriptHash(remotePkScript)
|
theirWitnessHash, err := input.WitnessScriptHash(theirPkScript)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
localPkScript, err := input.CommitScriptUnencumbered(keyRing.ToRemoteKey)
|
|
||||||
|
// Since it is the remote breach we are reconstructing, the output going
|
||||||
|
// to us will be a to-remote script with our local params.
|
||||||
|
ourDelay := uint32(chanState.LocalChanCfg.CsvDelay)
|
||||||
|
ourScript, err := CommitScriptToRemote(
|
||||||
|
chanState.ChanType, ourDelay, keyRing.ToRemoteKey,
|
||||||
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// In order to fully populate the breach retribution struct, we'll need
|
// In order to fully populate the breach retribution struct, we'll need
|
||||||
// to find the exact index of the local+remote commitment outputs.
|
// to find the exact index of the commitment outputs.
|
||||||
localOutpoint := wire.OutPoint{
|
ourOutpoint := wire.OutPoint{
|
||||||
Hash: commitHash,
|
Hash: commitHash,
|
||||||
}
|
}
|
||||||
remoteOutpoint := wire.OutPoint{
|
theirOutpoint := wire.OutPoint{
|
||||||
Hash: commitHash,
|
Hash: commitHash,
|
||||||
}
|
}
|
||||||
for i, txOut := range revokedSnapshot.CommitTx.TxOut {
|
for i, txOut := range revokedSnapshot.CommitTx.TxOut {
|
||||||
switch {
|
switch {
|
||||||
case bytes.Equal(txOut.PkScript, localPkScript):
|
case bytes.Equal(txOut.PkScript, ourScript.PkScript):
|
||||||
localOutpoint.Index = uint32(i)
|
ourOutpoint.Index = uint32(i)
|
||||||
case bytes.Equal(txOut.PkScript, remoteWitnessHash):
|
case bytes.Equal(txOut.PkScript, theirWitnessHash):
|
||||||
remoteOutpoint.Index = uint32(i)
|
theirOutpoint.Index = uint32(i)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1908,39 +1914,39 @@ func NewBreachRetribution(chanState *channeldb.OpenChannel, stateNum uint64,
|
|||||||
// commitment outputs. If either is considered dust using the remote
|
// commitment outputs. If either is considered dust using the remote
|
||||||
// party's dust limit, the respective sign descriptor will be nil.
|
// party's dust limit, the respective sign descriptor will be nil.
|
||||||
var (
|
var (
|
||||||
localSignDesc *input.SignDescriptor
|
ourSignDesc *input.SignDescriptor
|
||||||
remoteSignDesc *input.SignDescriptor
|
theirSignDesc *input.SignDescriptor
|
||||||
)
|
)
|
||||||
|
|
||||||
// Compute the local and remote balances in satoshis.
|
// Compute the balances in satoshis.
|
||||||
localAmt := revokedSnapshot.LocalBalance.ToSatoshis()
|
ourAmt := revokedSnapshot.LocalBalance.ToSatoshis()
|
||||||
remoteAmt := revokedSnapshot.RemoteBalance.ToSatoshis()
|
theirAmt := revokedSnapshot.RemoteBalance.ToSatoshis()
|
||||||
|
|
||||||
// If the local balance exceeds the remote party's dust limit,
|
// If our balance exceeds the remote party's dust limit, instantiate
|
||||||
// instantiate the local sign descriptor.
|
// the sign descriptor for our output.
|
||||||
if localAmt >= chanState.RemoteChanCfg.DustLimit {
|
if ourAmt >= chanState.RemoteChanCfg.DustLimit {
|
||||||
localSignDesc = &input.SignDescriptor{
|
ourSignDesc = &input.SignDescriptor{
|
||||||
SingleTweak: keyRing.LocalCommitKeyTweak,
|
SingleTweak: keyRing.LocalCommitKeyTweak,
|
||||||
KeyDesc: chanState.LocalChanCfg.PaymentBasePoint,
|
KeyDesc: chanState.LocalChanCfg.PaymentBasePoint,
|
||||||
WitnessScript: localPkScript,
|
WitnessScript: ourScript.WitnessScript,
|
||||||
Output: &wire.TxOut{
|
Output: &wire.TxOut{
|
||||||
PkScript: localPkScript,
|
PkScript: ourScript.PkScript,
|
||||||
Value: int64(localAmt),
|
Value: int64(ourAmt),
|
||||||
},
|
},
|
||||||
HashType: txscript.SigHashAll,
|
HashType: txscript.SigHashAll,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Similarly, if the remote balance exceeds the remote party's dust
|
// Similarly, if their balance exceeds the remote party's dust limit,
|
||||||
// limit, assemble the remote sign descriptor.
|
// assemble the sign descriptor for their output, which we can sweep.
|
||||||
if remoteAmt >= chanState.RemoteChanCfg.DustLimit {
|
if theirAmt >= chanState.RemoteChanCfg.DustLimit {
|
||||||
remoteSignDesc = &input.SignDescriptor{
|
theirSignDesc = &input.SignDescriptor{
|
||||||
KeyDesc: chanState.LocalChanCfg.RevocationBasePoint,
|
KeyDesc: chanState.LocalChanCfg.RevocationBasePoint,
|
||||||
DoubleTweak: commitmentSecret,
|
DoubleTweak: commitmentSecret,
|
||||||
WitnessScript: remotePkScript,
|
WitnessScript: theirPkScript,
|
||||||
Output: &wire.TxOut{
|
Output: &wire.TxOut{
|
||||||
PkScript: remoteWitnessHash,
|
PkScript: theirWitnessHash,
|
||||||
Value: int64(remoteAmt),
|
Value: int64(theirAmt),
|
||||||
},
|
},
|
||||||
HashType: txscript.SigHashAll,
|
HashType: txscript.SigHashAll,
|
||||||
}
|
}
|
||||||
@ -1971,7 +1977,7 @@ func NewBreachRetribution(chanState *channeldb.OpenChannel, stateNum uint64,
|
|||||||
// remote commitment transaction, and *they* go to the second
|
// remote commitment transaction, and *they* go to the second
|
||||||
// level.
|
// level.
|
||||||
secondLevelWitnessScript, err := input.SecondLevelHtlcScript(
|
secondLevelWitnessScript, err := input.SecondLevelHtlcScript(
|
||||||
keyRing.RevocationKey, keyRing.ToLocalKey, remoteDelay,
|
keyRing.RevocationKey, keyRing.ToLocalKey, theirDelay,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -2037,13 +2043,13 @@ func NewBreachRetribution(chanState *channeldb.OpenChannel, stateNum uint64,
|
|||||||
BreachHeight: breachHeight,
|
BreachHeight: breachHeight,
|
||||||
RevokedStateNum: stateNum,
|
RevokedStateNum: stateNum,
|
||||||
PendingHTLCs: revokedSnapshot.Htlcs,
|
PendingHTLCs: revokedSnapshot.Htlcs,
|
||||||
LocalOutpoint: localOutpoint,
|
LocalOutpoint: ourOutpoint,
|
||||||
LocalOutputSignDesc: localSignDesc,
|
LocalOutputSignDesc: ourSignDesc,
|
||||||
RemoteOutpoint: remoteOutpoint,
|
RemoteOutpoint: theirOutpoint,
|
||||||
RemoteOutputSignDesc: remoteSignDesc,
|
RemoteOutputSignDesc: theirSignDesc,
|
||||||
HtlcRetributions: htlcRetributions,
|
HtlcRetributions: htlcRetributions,
|
||||||
KeyRing: keyRing,
|
KeyRing: keyRing,
|
||||||
RemoteDelay: remoteDelay,
|
RemoteDelay: theirDelay,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -4758,7 +4764,10 @@ func NewUnilateralCloseSummary(chanState *channeldb.OpenChannel, signer input.Si
|
|||||||
// Before we can generate the proper sign descriptor, we'll need to
|
// Before we can generate the proper sign descriptor, we'll need to
|
||||||
// locate the output index of our non-delayed output on the commitment
|
// locate the output index of our non-delayed output on the commitment
|
||||||
// transaction.
|
// transaction.
|
||||||
selfP2WKH, err := input.CommitScriptUnencumbered(keyRing.ToRemoteKey)
|
localDelay := uint32(chanState.LocalChanCfg.CsvDelay)
|
||||||
|
selfScript, err := CommitScriptToRemote(
|
||||||
|
chanState.ChanType, localDelay, keyRing.ToRemoteKey,
|
||||||
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("unable to create self commit "+
|
return nil, fmt.Errorf("unable to create self commit "+
|
||||||
"script: %v", err)
|
"script: %v", err)
|
||||||
@ -4770,7 +4779,7 @@ func NewUnilateralCloseSummary(chanState *channeldb.OpenChannel, signer input.Si
|
|||||||
)
|
)
|
||||||
|
|
||||||
for outputIndex, txOut := range commitTxBroadcast.TxOut {
|
for outputIndex, txOut := range commitTxBroadcast.TxOut {
|
||||||
if bytes.Equal(txOut.PkScript, selfP2WKH) {
|
if bytes.Equal(txOut.PkScript, selfScript.PkScript) {
|
||||||
selfPoint = &wire.OutPoint{
|
selfPoint = &wire.OutPoint{
|
||||||
Hash: *commitSpend.SpenderTxHash,
|
Hash: *commitSpend.SpenderTxHash,
|
||||||
Index: uint32(outputIndex),
|
Index: uint32(outputIndex),
|
||||||
@ -4791,10 +4800,10 @@ func NewUnilateralCloseSummary(chanState *channeldb.OpenChannel, signer input.Si
|
|||||||
SelfOutputSignDesc: input.SignDescriptor{
|
SelfOutputSignDesc: input.SignDescriptor{
|
||||||
KeyDesc: localPayBase,
|
KeyDesc: localPayBase,
|
||||||
SingleTweak: keyRing.LocalCommitKeyTweak,
|
SingleTweak: keyRing.LocalCommitKeyTweak,
|
||||||
WitnessScript: selfP2WKH,
|
WitnessScript: selfScript.WitnessScript,
|
||||||
Output: &wire.TxOut{
|
Output: &wire.TxOut{
|
||||||
Value: localBalance,
|
Value: localBalance,
|
||||||
PkScript: selfP2WKH,
|
PkScript: selfScript.PkScript,
|
||||||
},
|
},
|
||||||
HashType: txscript.SigHashAll,
|
HashType: txscript.SigHashAll,
|
||||||
},
|
},
|
||||||
|
@ -162,6 +162,37 @@ func DeriveCommitmentKeys(commitPoint *btcec.PublicKey,
|
|||||||
return keyRing
|
return keyRing
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ScriptInfo holds a redeem script and hash.
|
||||||
|
type ScriptInfo struct {
|
||||||
|
// PkScript is the output's PkScript.
|
||||||
|
PkScript []byte
|
||||||
|
|
||||||
|
// WitnessScript is the full script required to properly redeem the
|
||||||
|
// output. This field should be set to the full script if a p2wsh
|
||||||
|
// output is being signed. For p2wkh it should be set equal to the
|
||||||
|
// PkScript.
|
||||||
|
WitnessScript []byte
|
||||||
|
}
|
||||||
|
|
||||||
|
// CommitScriptToRemote creates the script that will pay to the non-owner of
|
||||||
|
// the commitment transaction, adding a delay to the script based on the
|
||||||
|
// channel type.
|
||||||
|
func CommitScriptToRemote(_ channeldb.ChannelType, csvTimeout uint32,
|
||||||
|
key *btcec.PublicKey) (*ScriptInfo, error) {
|
||||||
|
|
||||||
|
p2wkh, err := input.CommitScriptUnencumbered(key)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Since this is a regular P2WKH, the WitnessScipt and PkScript should
|
||||||
|
// both be set to the script hash.
|
||||||
|
return &ScriptInfo{
|
||||||
|
WitnessScript: p2wkh,
|
||||||
|
PkScript: p2wkh,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
// CommitmentBuilder is a type that wraps the type of channel we are dealing
|
// CommitmentBuilder is a type that wraps the type of channel we are dealing
|
||||||
// with, and abstracts the various ways of constructing commitment
|
// with, and abstracts the various ways of constructing commitment
|
||||||
// transactions.
|
// transactions.
|
||||||
@ -292,15 +323,15 @@ func (cb *CommitmentBuilder) createUnsignedCommitmentTx(ourBalance,
|
|||||||
// out HTLCs.
|
// out HTLCs.
|
||||||
if isOurs {
|
if isOurs {
|
||||||
commitTx, err = CreateCommitTx(
|
commitTx, err = CreateCommitTx(
|
||||||
fundingTxIn(cb.chanState), keyRing, &cb.chanState.LocalChanCfg,
|
cb.chanState.ChanType, fundingTxIn(cb.chanState), keyRing,
|
||||||
&cb.chanState.RemoteChanCfg, ourBalance.ToSatoshis(),
|
&cb.chanState.LocalChanCfg, &cb.chanState.RemoteChanCfg,
|
||||||
theirBalance.ToSatoshis(),
|
ourBalance.ToSatoshis(), theirBalance.ToSatoshis(),
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
commitTx, err = CreateCommitTx(
|
commitTx, err = CreateCommitTx(
|
||||||
fundingTxIn(cb.chanState), keyRing, &cb.chanState.RemoteChanCfg,
|
cb.chanState.ChanType, fundingTxIn(cb.chanState), keyRing,
|
||||||
&cb.chanState.LocalChanCfg, theirBalance.ToSatoshis(),
|
&cb.chanState.RemoteChanCfg, &cb.chanState.LocalChanCfg,
|
||||||
ourBalance.ToSatoshis(),
|
theirBalance.ToSatoshis(), ourBalance.ToSatoshis(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -389,7 +420,8 @@ func (cb *CommitmentBuilder) createUnsignedCommitmentTx(ourBalance,
|
|||||||
// spent after a relative block delay or revocation event, and a remote output
|
// spent after a relative block delay or revocation event, and a remote output
|
||||||
// paying the counterparty within the channel, which can be spent immediately
|
// paying the counterparty within the channel, which can be spent immediately
|
||||||
// or after a delay depending on the commitment type..
|
// or after a delay depending on the commitment type..
|
||||||
func CreateCommitTx(fundingOutput wire.TxIn, keyRing *CommitmentKeyRing,
|
func CreateCommitTx(chanType channeldb.ChannelType,
|
||||||
|
fundingOutput wire.TxIn, keyRing *CommitmentKeyRing,
|
||||||
localChanCfg, remoteChanCfg *channeldb.ChannelConfig,
|
localChanCfg, remoteChanCfg *channeldb.ChannelConfig,
|
||||||
amountToLocal, amountToRemote btcutil.Amount) (*wire.MsgTx, error) {
|
amountToLocal, amountToRemote btcutil.Amount) (*wire.MsgTx, error) {
|
||||||
|
|
||||||
@ -412,10 +444,9 @@ func CreateCommitTx(fundingOutput wire.TxIn, keyRing *CommitmentKeyRing,
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Next, we create the script paying to the remote. This is just a
|
// Next, we create the script paying to the remote.
|
||||||
// regular P2WPKH output, without any added CSV delay.
|
toRemoteScript, err := CommitScriptToRemote(
|
||||||
toRemoteWitnessKeyHash, err := input.CommitScriptUnencumbered(
|
chanType, uint32(remoteChanCfg.CsvDelay), keyRing.ToRemoteKey,
|
||||||
keyRing.ToRemoteKey,
|
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -436,7 +467,7 @@ func CreateCommitTx(fundingOutput wire.TxIn, keyRing *CommitmentKeyRing,
|
|||||||
}
|
}
|
||||||
if amountToRemote >= localChanCfg.DustLimit {
|
if amountToRemote >= localChanCfg.DustLimit {
|
||||||
commitTx.AddTxOut(&wire.TxOut{
|
commitTx.AddTxOut(&wire.TxOut{
|
||||||
PkScript: toRemoteWitnessKeyHash,
|
PkScript: toRemoteScript.PkScript,
|
||||||
Value: int64(amountToRemote),
|
Value: int64(amountToRemote),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -1048,8 +1048,10 @@ func testSpendValidation(t *testing.T, tweakless bool) {
|
|||||||
// our commitments, if it's tweakless, his key will just be his regular
|
// our commitments, if it's tweakless, his key will just be his regular
|
||||||
// pubkey.
|
// pubkey.
|
||||||
bobPayKey := input.TweakPubKey(bobKeyPub, commitPoint)
|
bobPayKey := input.TweakPubKey(bobKeyPub, commitPoint)
|
||||||
|
channelType := channeldb.SingleFunderBit
|
||||||
if tweakless {
|
if tweakless {
|
||||||
bobPayKey = bobKeyPub
|
bobPayKey = bobKeyPub
|
||||||
|
channelType = channeldb.SingleFunderTweaklessBit
|
||||||
}
|
}
|
||||||
|
|
||||||
aliceCommitTweak := input.SingleTweakBytes(commitPoint, aliceKeyPub)
|
aliceCommitTweak := input.SingleTweakBytes(commitPoint, aliceKeyPub)
|
||||||
@ -1086,8 +1088,8 @@ func testSpendValidation(t *testing.T, tweakless bool) {
|
|||||||
ToRemoteKey: bobPayKey,
|
ToRemoteKey: bobPayKey,
|
||||||
}
|
}
|
||||||
commitmentTx, err := CreateCommitTx(
|
commitmentTx, err := CreateCommitTx(
|
||||||
*fakeFundingTxIn, keyRing, aliceChanCfg, bobChanCfg,
|
channelType, *fakeFundingTxIn, keyRing, aliceChanCfg,
|
||||||
channelBalance, channelBalance,
|
bobChanCfg, channelBalance, channelBalance,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("unable to create commitment transaction: %v", nil)
|
t.Fatalf("unable to create commitment transaction: %v", nil)
|
||||||
|
@ -783,8 +783,8 @@ func CreateCommitmentTxns(localBalance, remoteBalance btcutil.Amount,
|
|||||||
)
|
)
|
||||||
|
|
||||||
ourCommitTx, err := CreateCommitTx(
|
ourCommitTx, err := CreateCommitTx(
|
||||||
fundingTxIn, localCommitmentKeys, ourChanCfg, theirChanCfg,
|
chanType, fundingTxIn, localCommitmentKeys, ourChanCfg,
|
||||||
localBalance, remoteBalance,
|
theirChanCfg, localBalance, remoteBalance,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
@ -796,8 +796,8 @@ func CreateCommitmentTxns(localBalance, remoteBalance btcutil.Amount,
|
|||||||
}
|
}
|
||||||
|
|
||||||
theirCommitTx, err := CreateCommitTx(
|
theirCommitTx, err := CreateCommitTx(
|
||||||
fundingTxIn, remoteCommitmentKeys, theirChanCfg, ourChanCfg,
|
chanType, fundingTxIn, remoteCommitmentKeys, theirChanCfg,
|
||||||
remoteBalance, localBalance,
|
ourChanCfg, remoteBalance, localBalance,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
|
Loading…
Reference in New Issue
Block a user