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
|
||||
// present if they have a non-dust balance on the commitment.
|
||||
remotePkScript, err := input.CommitScriptUnencumbered(
|
||||
commitKeyRing.ToRemoteKey,
|
||||
remoteDelay := uint32(remoteChanCfg.CsvDelay)
|
||||
remoteScript, err := lnwallet.CommitScriptToRemote(
|
||||
chanType, remoteDelay, commitKeyRing.ToRemoteKey,
|
||||
)
|
||||
if err != nil {
|
||||
return false, err
|
||||
@ -383,7 +384,7 @@ func isOurCommitment(localChanCfg, remoteChanCfg channeldb.ChannelConfig,
|
||||
case bytes.Equal(localPkScript, pkScript):
|
||||
return true, nil
|
||||
|
||||
case bytes.Equal(remotePkScript, pkScript):
|
||||
case bytes.Equal(remoteScript.PkScript, pkScript):
|
||||
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
|
||||
// number so we can have the proper witness script to sign and include
|
||||
// within the final witness.
|
||||
remoteDelay := uint32(chanState.RemoteChanCfg.CsvDelay)
|
||||
remotePkScript, err := input.CommitScriptToSelf(
|
||||
remoteDelay, keyRing.ToLocalKey, keyRing.RevocationKey,
|
||||
theirDelay := uint32(chanState.RemoteChanCfg.CsvDelay)
|
||||
theirPkScript, err := input.CommitScriptToSelf(
|
||||
theirDelay, keyRing.ToLocalKey, keyRing.RevocationKey,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
remoteWitnessHash, err := input.WitnessScriptHash(remotePkScript)
|
||||
theirWitnessHash, err := input.WitnessScriptHash(theirPkScript)
|
||||
if err != nil {
|
||||
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 {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// In order to fully populate the breach retribution struct, we'll need
|
||||
// to find the exact index of the local+remote commitment outputs.
|
||||
localOutpoint := wire.OutPoint{
|
||||
// to find the exact index of the commitment outputs.
|
||||
ourOutpoint := wire.OutPoint{
|
||||
Hash: commitHash,
|
||||
}
|
||||
remoteOutpoint := wire.OutPoint{
|
||||
theirOutpoint := wire.OutPoint{
|
||||
Hash: commitHash,
|
||||
}
|
||||
for i, txOut := range revokedSnapshot.CommitTx.TxOut {
|
||||
switch {
|
||||
case bytes.Equal(txOut.PkScript, localPkScript):
|
||||
localOutpoint.Index = uint32(i)
|
||||
case bytes.Equal(txOut.PkScript, remoteWitnessHash):
|
||||
remoteOutpoint.Index = uint32(i)
|
||||
case bytes.Equal(txOut.PkScript, ourScript.PkScript):
|
||||
ourOutpoint.Index = uint32(i)
|
||||
case bytes.Equal(txOut.PkScript, theirWitnessHash):
|
||||
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
|
||||
// party's dust limit, the respective sign descriptor will be nil.
|
||||
var (
|
||||
localSignDesc *input.SignDescriptor
|
||||
remoteSignDesc *input.SignDescriptor
|
||||
ourSignDesc *input.SignDescriptor
|
||||
theirSignDesc *input.SignDescriptor
|
||||
)
|
||||
|
||||
// Compute the local and remote balances in satoshis.
|
||||
localAmt := revokedSnapshot.LocalBalance.ToSatoshis()
|
||||
remoteAmt := revokedSnapshot.RemoteBalance.ToSatoshis()
|
||||
// Compute the balances in satoshis.
|
||||
ourAmt := revokedSnapshot.LocalBalance.ToSatoshis()
|
||||
theirAmt := revokedSnapshot.RemoteBalance.ToSatoshis()
|
||||
|
||||
// If the local balance exceeds the remote party's dust limit,
|
||||
// instantiate the local sign descriptor.
|
||||
if localAmt >= chanState.RemoteChanCfg.DustLimit {
|
||||
localSignDesc = &input.SignDescriptor{
|
||||
// If our balance exceeds the remote party's dust limit, instantiate
|
||||
// the sign descriptor for our output.
|
||||
if ourAmt >= chanState.RemoteChanCfg.DustLimit {
|
||||
ourSignDesc = &input.SignDescriptor{
|
||||
SingleTweak: keyRing.LocalCommitKeyTweak,
|
||||
KeyDesc: chanState.LocalChanCfg.PaymentBasePoint,
|
||||
WitnessScript: localPkScript,
|
||||
WitnessScript: ourScript.WitnessScript,
|
||||
Output: &wire.TxOut{
|
||||
PkScript: localPkScript,
|
||||
Value: int64(localAmt),
|
||||
PkScript: ourScript.PkScript,
|
||||
Value: int64(ourAmt),
|
||||
},
|
||||
HashType: txscript.SigHashAll,
|
||||
}
|
||||
}
|
||||
|
||||
// Similarly, if the remote balance exceeds the remote party's dust
|
||||
// limit, assemble the remote sign descriptor.
|
||||
if remoteAmt >= chanState.RemoteChanCfg.DustLimit {
|
||||
remoteSignDesc = &input.SignDescriptor{
|
||||
// Similarly, if their balance exceeds the remote party's dust limit,
|
||||
// assemble the sign descriptor for their output, which we can sweep.
|
||||
if theirAmt >= chanState.RemoteChanCfg.DustLimit {
|
||||
theirSignDesc = &input.SignDescriptor{
|
||||
KeyDesc: chanState.LocalChanCfg.RevocationBasePoint,
|
||||
DoubleTweak: commitmentSecret,
|
||||
WitnessScript: remotePkScript,
|
||||
WitnessScript: theirPkScript,
|
||||
Output: &wire.TxOut{
|
||||
PkScript: remoteWitnessHash,
|
||||
Value: int64(remoteAmt),
|
||||
PkScript: theirWitnessHash,
|
||||
Value: int64(theirAmt),
|
||||
},
|
||||
HashType: txscript.SigHashAll,
|
||||
}
|
||||
@ -1971,7 +1977,7 @@ func NewBreachRetribution(chanState *channeldb.OpenChannel, stateNum uint64,
|
||||
// remote commitment transaction, and *they* go to the second
|
||||
// level.
|
||||
secondLevelWitnessScript, err := input.SecondLevelHtlcScript(
|
||||
keyRing.RevocationKey, keyRing.ToLocalKey, remoteDelay,
|
||||
keyRing.RevocationKey, keyRing.ToLocalKey, theirDelay,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@ -2037,13 +2043,13 @@ func NewBreachRetribution(chanState *channeldb.OpenChannel, stateNum uint64,
|
||||
BreachHeight: breachHeight,
|
||||
RevokedStateNum: stateNum,
|
||||
PendingHTLCs: revokedSnapshot.Htlcs,
|
||||
LocalOutpoint: localOutpoint,
|
||||
LocalOutputSignDesc: localSignDesc,
|
||||
RemoteOutpoint: remoteOutpoint,
|
||||
RemoteOutputSignDesc: remoteSignDesc,
|
||||
LocalOutpoint: ourOutpoint,
|
||||
LocalOutputSignDesc: ourSignDesc,
|
||||
RemoteOutpoint: theirOutpoint,
|
||||
RemoteOutputSignDesc: theirSignDesc,
|
||||
HtlcRetributions: htlcRetributions,
|
||||
KeyRing: keyRing,
|
||||
RemoteDelay: remoteDelay,
|
||||
RemoteDelay: theirDelay,
|
||||
}, 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
|
||||
// locate the output index of our non-delayed output on the commitment
|
||||
// transaction.
|
||||
selfP2WKH, err := input.CommitScriptUnencumbered(keyRing.ToRemoteKey)
|
||||
localDelay := uint32(chanState.LocalChanCfg.CsvDelay)
|
||||
selfScript, err := CommitScriptToRemote(
|
||||
chanState.ChanType, localDelay, keyRing.ToRemoteKey,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to create self commit "+
|
||||
"script: %v", err)
|
||||
@ -4770,7 +4779,7 @@ func NewUnilateralCloseSummary(chanState *channeldb.OpenChannel, signer input.Si
|
||||
)
|
||||
|
||||
for outputIndex, txOut := range commitTxBroadcast.TxOut {
|
||||
if bytes.Equal(txOut.PkScript, selfP2WKH) {
|
||||
if bytes.Equal(txOut.PkScript, selfScript.PkScript) {
|
||||
selfPoint = &wire.OutPoint{
|
||||
Hash: *commitSpend.SpenderTxHash,
|
||||
Index: uint32(outputIndex),
|
||||
@ -4791,10 +4800,10 @@ func NewUnilateralCloseSummary(chanState *channeldb.OpenChannel, signer input.Si
|
||||
SelfOutputSignDesc: input.SignDescriptor{
|
||||
KeyDesc: localPayBase,
|
||||
SingleTweak: keyRing.LocalCommitKeyTweak,
|
||||
WitnessScript: selfP2WKH,
|
||||
WitnessScript: selfScript.WitnessScript,
|
||||
Output: &wire.TxOut{
|
||||
Value: localBalance,
|
||||
PkScript: selfP2WKH,
|
||||
PkScript: selfScript.PkScript,
|
||||
},
|
||||
HashType: txscript.SigHashAll,
|
||||
},
|
||||
|
@ -162,6 +162,37 @@ func DeriveCommitmentKeys(commitPoint *btcec.PublicKey,
|
||||
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
|
||||
// with, and abstracts the various ways of constructing commitment
|
||||
// transactions.
|
||||
@ -292,15 +323,15 @@ func (cb *CommitmentBuilder) createUnsignedCommitmentTx(ourBalance,
|
||||
// out HTLCs.
|
||||
if isOurs {
|
||||
commitTx, err = CreateCommitTx(
|
||||
fundingTxIn(cb.chanState), keyRing, &cb.chanState.LocalChanCfg,
|
||||
&cb.chanState.RemoteChanCfg, ourBalance.ToSatoshis(),
|
||||
theirBalance.ToSatoshis(),
|
||||
cb.chanState.ChanType, fundingTxIn(cb.chanState), keyRing,
|
||||
&cb.chanState.LocalChanCfg, &cb.chanState.RemoteChanCfg,
|
||||
ourBalance.ToSatoshis(), theirBalance.ToSatoshis(),
|
||||
)
|
||||
} else {
|
||||
commitTx, err = CreateCommitTx(
|
||||
fundingTxIn(cb.chanState), keyRing, &cb.chanState.RemoteChanCfg,
|
||||
&cb.chanState.LocalChanCfg, theirBalance.ToSatoshis(),
|
||||
ourBalance.ToSatoshis(),
|
||||
cb.chanState.ChanType, fundingTxIn(cb.chanState), keyRing,
|
||||
&cb.chanState.RemoteChanCfg, &cb.chanState.LocalChanCfg,
|
||||
theirBalance.ToSatoshis(), ourBalance.ToSatoshis(),
|
||||
)
|
||||
}
|
||||
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
|
||||
// paying the counterparty within the channel, which can be spent immediately
|
||||
// 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,
|
||||
amountToLocal, amountToRemote btcutil.Amount) (*wire.MsgTx, error) {
|
||||
|
||||
@ -412,10 +444,9 @@ func CreateCommitTx(fundingOutput wire.TxIn, keyRing *CommitmentKeyRing,
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Next, we create the script paying to the remote. This is just a
|
||||
// regular P2WPKH output, without any added CSV delay.
|
||||
toRemoteWitnessKeyHash, err := input.CommitScriptUnencumbered(
|
||||
keyRing.ToRemoteKey,
|
||||
// Next, we create the script paying to the remote.
|
||||
toRemoteScript, err := CommitScriptToRemote(
|
||||
chanType, uint32(remoteChanCfg.CsvDelay), keyRing.ToRemoteKey,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@ -436,7 +467,7 @@ func CreateCommitTx(fundingOutput wire.TxIn, keyRing *CommitmentKeyRing,
|
||||
}
|
||||
if amountToRemote >= localChanCfg.DustLimit {
|
||||
commitTx.AddTxOut(&wire.TxOut{
|
||||
PkScript: toRemoteWitnessKeyHash,
|
||||
PkScript: toRemoteScript.PkScript,
|
||||
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
|
||||
// pubkey.
|
||||
bobPayKey := input.TweakPubKey(bobKeyPub, commitPoint)
|
||||
channelType := channeldb.SingleFunderBit
|
||||
if tweakless {
|
||||
bobPayKey = bobKeyPub
|
||||
channelType = channeldb.SingleFunderTweaklessBit
|
||||
}
|
||||
|
||||
aliceCommitTweak := input.SingleTweakBytes(commitPoint, aliceKeyPub)
|
||||
@ -1086,8 +1088,8 @@ func testSpendValidation(t *testing.T, tweakless bool) {
|
||||
ToRemoteKey: bobPayKey,
|
||||
}
|
||||
commitmentTx, err := CreateCommitTx(
|
||||
*fakeFundingTxIn, keyRing, aliceChanCfg, bobChanCfg,
|
||||
channelBalance, channelBalance,
|
||||
channelType, *fakeFundingTxIn, keyRing, aliceChanCfg,
|
||||
bobChanCfg, channelBalance, channelBalance,
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatalf("unable to create commitment transaction: %v", nil)
|
||||
|
@ -783,8 +783,8 @@ func CreateCommitmentTxns(localBalance, remoteBalance btcutil.Amount,
|
||||
)
|
||||
|
||||
ourCommitTx, err := CreateCommitTx(
|
||||
fundingTxIn, localCommitmentKeys, ourChanCfg, theirChanCfg,
|
||||
localBalance, remoteBalance,
|
||||
chanType, fundingTxIn, localCommitmentKeys, ourChanCfg,
|
||||
theirChanCfg, localBalance, remoteBalance,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
@ -796,8 +796,8 @@ func CreateCommitmentTxns(localBalance, remoteBalance btcutil.Amount,
|
||||
}
|
||||
|
||||
theirCommitTx, err := CreateCommitTx(
|
||||
fundingTxIn, remoteCommitmentKeys, theirChanCfg, ourChanCfg,
|
||||
remoteBalance, localBalance,
|
||||
chanType, fundingTxIn, remoteCommitmentKeys, theirChanCfg,
|
||||
ourChanCfg, remoteBalance, localBalance,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
|
Loading…
Reference in New Issue
Block a user