input+lnwallet+contractcourt: define SignDetails for HTLC resolutions
This commit is contained in:
parent
eb8d22e194
commit
1e68cdc8cf
@ -6,7 +6,9 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
|
||||||
|
"github.com/btcsuite/btcd/btcec"
|
||||||
"github.com/btcsuite/btcd/chaincfg/chainhash"
|
"github.com/btcsuite/btcd/chaincfg/chainhash"
|
||||||
|
"github.com/btcsuite/btcd/txscript"
|
||||||
"github.com/btcsuite/btcd/wire"
|
"github.com/btcsuite/btcd/wire"
|
||||||
"github.com/lightningnetwork/lnd/channeldb"
|
"github.com/lightningnetwork/lnd/channeldb"
|
||||||
"github.com/lightningnetwork/lnd/channeldb/kvdb"
|
"github.com/lightningnetwork/lnd/channeldb/kvdb"
|
||||||
@ -275,6 +277,13 @@ var (
|
|||||||
// the full set of resolutions for a channel.
|
// the full set of resolutions for a channel.
|
||||||
resolutionsKey = []byte("resolutions")
|
resolutionsKey = []byte("resolutions")
|
||||||
|
|
||||||
|
// resolutionsSignDetailsKey is the key under the logScope where we
|
||||||
|
// will store input.SignDetails for each HTLC resolution. If this is
|
||||||
|
// not found under the logScope, it means it was written before
|
||||||
|
// SignDetails was introduced, and should be set nil for each HTLC
|
||||||
|
// resolution.
|
||||||
|
resolutionsSignDetailsKey = []byte("resolutions-sign-details")
|
||||||
|
|
||||||
// anchorResolutionKey is the key under the logScope that we'll use to
|
// anchorResolutionKey is the key under the logScope that we'll use to
|
||||||
// store the anchor resolution, if any.
|
// store the anchor resolution, if any.
|
||||||
anchorResolutionKey = []byte("anchor-resolution")
|
anchorResolutionKey = []byte("anchor-resolution")
|
||||||
@ -656,6 +665,10 @@ func (b *boltArbitratorLog) LogContractResolutions(c *ContractResolutions) error
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// As we write the HTLC resolutions, we'll serialize the sign
|
||||||
|
// details for each, to store under a new key.
|
||||||
|
var signDetailsBuf bytes.Buffer
|
||||||
|
|
||||||
// With the output for the commitment transaction written, we
|
// With the output for the commitment transaction written, we
|
||||||
// can now write out the resolutions for the incoming and
|
// can now write out the resolutions for the incoming and
|
||||||
// outgoing HTLC's.
|
// outgoing HTLC's.
|
||||||
@ -668,6 +681,11 @@ func (b *boltArbitratorLog) LogContractResolutions(c *ContractResolutions) error
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
err = encodeSignDetails(&signDetailsBuf, htlc.SignDetails)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
numOutgoing := uint32(len(c.HtlcResolutions.OutgoingHTLCs))
|
numOutgoing := uint32(len(c.HtlcResolutions.OutgoingHTLCs))
|
||||||
if err := binary.Write(&b, endian, numOutgoing); err != nil {
|
if err := binary.Write(&b, endian, numOutgoing); err != nil {
|
||||||
@ -678,13 +696,28 @@ func (b *boltArbitratorLog) LogContractResolutions(c *ContractResolutions) error
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
err = encodeSignDetails(&signDetailsBuf, htlc.SignDetails)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Put the resolutions under the resolutionsKey.
|
||||||
err = scopeBucket.Put(resolutionsKey, b.Bytes())
|
err = scopeBucket.Put(resolutionsKey, b.Bytes())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// We'll put the serialized sign details under its own key to
|
||||||
|
// stay backwards compatible.
|
||||||
|
err = scopeBucket.Put(
|
||||||
|
resolutionsSignDetailsKey, signDetailsBuf.Bytes(),
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
// Write out the anchor resolution if present.
|
// Write out the anchor resolution if present.
|
||||||
if c.AnchorResolution != nil {
|
if c.AnchorResolution != nil {
|
||||||
var b bytes.Buffer
|
var b bytes.Buffer
|
||||||
@ -779,6 +812,33 @@ func (b *boltArbitratorLog) FetchContractResolutions() (*ContractResolutions, er
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Now we attempt to get the sign details for our HTLC
|
||||||
|
// resolutions. If not present the channel is of a type that
|
||||||
|
// doesn't need them. If present there will be SignDetails
|
||||||
|
// encoded for each HTLC resolution.
|
||||||
|
signDetailsBytes := scopeBucket.Get(resolutionsSignDetailsKey)
|
||||||
|
if signDetailsBytes != nil {
|
||||||
|
r := bytes.NewReader(signDetailsBytes)
|
||||||
|
|
||||||
|
// They will be encoded in the same order as the
|
||||||
|
// resolutions: firs incoming HTLCs, then outgoing.
|
||||||
|
for i := uint32(0); i < numIncoming; i++ {
|
||||||
|
htlc := &c.HtlcResolutions.IncomingHTLCs[i]
|
||||||
|
htlc.SignDetails, err = decodeSignDetails(r)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := uint32(0); i < numOutgoing; i++ {
|
||||||
|
htlc := &c.HtlcResolutions.OutgoingHTLCs[i]
|
||||||
|
htlc.SignDetails, err = decodeSignDetails(r)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
anchorResBytes := scopeBucket.Get(anchorResolutionKey)
|
anchorResBytes := scopeBucket.Get(anchorResolutionKey)
|
||||||
if anchorResBytes != nil {
|
if anchorResBytes != nil {
|
||||||
c.AnchorResolution = &lnwallet.AnchorResolution{}
|
c.AnchorResolution = &lnwallet.AnchorResolution{}
|
||||||
@ -941,6 +1001,11 @@ func (b *boltArbitratorLog) WipeHistory() error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
err = scopeBucket.Delete(resolutionsSignDetailsKey)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
// We'll delete any chain actions that are still stored by
|
// We'll delete any chain actions that are still stored by
|
||||||
// removing the enclosing bucket.
|
// removing the enclosing bucket.
|
||||||
err = scopeBucket.DeleteNestedBucket(actionsBucketKey)
|
err = scopeBucket.DeleteNestedBucket(actionsBucketKey)
|
||||||
@ -980,6 +1045,79 @@ func (b *boltArbitratorLog) checkpointContract(c ContractResolver,
|
|||||||
}, func() {})
|
}, func() {})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// encodeSignDetails encodes the gived SignDetails struct to the writer.
|
||||||
|
// SignDetails is allowed to be nil, in which we will encode that it is not
|
||||||
|
// present.
|
||||||
|
func encodeSignDetails(w io.Writer, s *input.SignDetails) error {
|
||||||
|
// If we don't have sign details, write false and return.
|
||||||
|
if s == nil {
|
||||||
|
return binary.Write(w, endian, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Otherwise write true, and the contents of the SignDetails.
|
||||||
|
if err := binary.Write(w, endian, true); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
err := input.WriteSignDescriptor(w, &s.SignDesc)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
err = binary.Write(w, endian, uint32(s.SigHashType))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write the DER-encoded signature.
|
||||||
|
b := s.PeerSig.Serialize()
|
||||||
|
if err := wire.WriteVarBytes(w, 0, b); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// decodeSignDetails extracts a single SignDetails from the reader. It is
|
||||||
|
// allowed to return nil in case the SignDetails were empty.
|
||||||
|
func decodeSignDetails(r io.Reader) (*input.SignDetails, error) {
|
||||||
|
var present bool
|
||||||
|
if err := binary.Read(r, endian, &present); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Simply return nil if the next SignDetails was not present.
|
||||||
|
if !present {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Otherwise decode the elements of the SignDetails.
|
||||||
|
s := input.SignDetails{}
|
||||||
|
err := input.ReadSignDescriptor(r, &s.SignDesc)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var sigHash uint32
|
||||||
|
err = binary.Read(r, endian, &sigHash)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
s.SigHashType = txscript.SigHashType(sigHash)
|
||||||
|
|
||||||
|
// Read DER-encoded signature.
|
||||||
|
rawSig, err := wire.ReadVarBytes(r, 0, 200, "signature")
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
sig, err := btcec.ParseDERSignature(rawSig, btcec.S256())
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
s.PeerSig = sig
|
||||||
|
|
||||||
|
return &s, nil
|
||||||
|
}
|
||||||
|
|
||||||
func encodeIncomingResolution(w io.Writer, i *lnwallet.IncomingHtlcResolution) error {
|
func encodeIncomingResolution(w io.Writer, i *lnwallet.IncomingHtlcResolution) error {
|
||||||
if _, err := w.Write(i.Preimage[:]); err != nil {
|
if _, err := w.Write(i.Preimage[:]); err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -102,6 +102,58 @@ var (
|
|||||||
},
|
},
|
||||||
HashType: txscript.SigHashAll,
|
HashType: txscript.SigHashAll,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
testTx = &wire.MsgTx{
|
||||||
|
Version: 2,
|
||||||
|
TxIn: []*wire.TxIn{
|
||||||
|
{
|
||||||
|
PreviousOutPoint: testChanPoint2,
|
||||||
|
SignatureScript: []byte{0x12, 0x34},
|
||||||
|
Witness: [][]byte{
|
||||||
|
{
|
||||||
|
0x00, 0x14, 0xee, 0x91, 0x41,
|
||||||
|
0x7e, 0x85, 0x6c, 0xde, 0x10,
|
||||||
|
0xa2, 0x91, 0x1e, 0xdc, 0xbd,
|
||||||
|
0xbd, 0x69, 0xe2, 0xef, 0xb5,
|
||||||
|
0x71, 0x48,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Sequence: 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
TxOut: []*wire.TxOut{
|
||||||
|
{
|
||||||
|
Value: 5000000000,
|
||||||
|
PkScript: []byte{
|
||||||
|
0xc6, 0xa5, 0x9d, 0xc2, 0x26, 0xc2,
|
||||||
|
0x86, 0x24, 0xe1, 0x81, 0x75, 0xe8,
|
||||||
|
0x51, 0xc9, 0x6b, 0x97, 0x3d, 0x81,
|
||||||
|
0xb0, 0x1c, 0xc3, 0x1f, 0x04, 0x78,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
LockTime: 123,
|
||||||
|
}
|
||||||
|
|
||||||
|
// A valid, DER-encoded signature (taken from btcec unit tests).
|
||||||
|
testSigBytes = []byte{
|
||||||
|
0x30, 0x44, 0x02, 0x20, 0x4e, 0x45, 0xe1, 0x69,
|
||||||
|
0x32, 0xb8, 0xaf, 0x51, 0x49, 0x61, 0xa1, 0xd3,
|
||||||
|
0xa1, 0xa2, 0x5f, 0xdf, 0x3f, 0x4f, 0x77, 0x32,
|
||||||
|
0xe9, 0xd6, 0x24, 0xc6, 0xc6, 0x15, 0x48, 0xab,
|
||||||
|
0x5f, 0xb8, 0xcd, 0x41, 0x02, 0x20, 0x18, 0x15,
|
||||||
|
0x22, 0xec, 0x8e, 0xca, 0x07, 0xde, 0x48, 0x60,
|
||||||
|
0xa4, 0xac, 0xdd, 0x12, 0x90, 0x9d, 0x83, 0x1c,
|
||||||
|
0xc5, 0x6c, 0xbb, 0xac, 0x46, 0x22, 0x08, 0x22,
|
||||||
|
0x21, 0xa8, 0x76, 0x8d, 0x1d, 0x09,
|
||||||
|
}
|
||||||
|
testSig, _ = btcec.ParseDERSignature(testSigBytes, btcec.S256())
|
||||||
|
|
||||||
|
testSignDetails = &input.SignDetails{
|
||||||
|
SignDesc: testSignDesc,
|
||||||
|
SigHashType: txscript.SigHashSingle,
|
||||||
|
PeerSig: testSig,
|
||||||
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
func makeTestDB() (kvdb.Backend, func(), error) {
|
func makeTestDB() (kvdb.Backend, func(), error) {
|
||||||
@ -550,8 +602,38 @@ func TestContractResolutionsStorage(t *testing.T) {
|
|||||||
ClaimOutpoint: randOutPoint(),
|
ClaimOutpoint: randOutPoint(),
|
||||||
SweepSignDesc: testSignDesc,
|
SweepSignDesc: testSignDesc,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// We add a resolution with SignDetails.
|
||||||
|
{
|
||||||
|
Preimage: testPreimage,
|
||||||
|
SignedSuccessTx: testTx,
|
||||||
|
SignDetails: testSignDetails,
|
||||||
|
CsvDelay: 900,
|
||||||
|
ClaimOutpoint: randOutPoint(),
|
||||||
|
SweepSignDesc: testSignDesc,
|
||||||
|
},
|
||||||
|
|
||||||
|
// We add a resolution with a signed tx, but no
|
||||||
|
// SignDetails.
|
||||||
|
{
|
||||||
|
Preimage: testPreimage,
|
||||||
|
SignedSuccessTx: testTx,
|
||||||
|
CsvDelay: 900,
|
||||||
|
ClaimOutpoint: randOutPoint(),
|
||||||
|
SweepSignDesc: testSignDesc,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
OutgoingHTLCs: []lnwallet.OutgoingHtlcResolution{
|
OutgoingHTLCs: []lnwallet.OutgoingHtlcResolution{
|
||||||
|
// We add a resolution with a signed tx, but no
|
||||||
|
// SignDetails.
|
||||||
|
{
|
||||||
|
Expiry: 103,
|
||||||
|
SignedTimeoutTx: testTx,
|
||||||
|
CsvDelay: 923923,
|
||||||
|
ClaimOutpoint: randOutPoint(),
|
||||||
|
SweepSignDesc: testSignDesc,
|
||||||
|
},
|
||||||
|
// Resolution without signed tx.
|
||||||
{
|
{
|
||||||
Expiry: 103,
|
Expiry: 103,
|
||||||
SignedTimeoutTx: nil,
|
SignedTimeoutTx: nil,
|
||||||
@ -559,6 +641,15 @@ func TestContractResolutionsStorage(t *testing.T) {
|
|||||||
ClaimOutpoint: randOutPoint(),
|
ClaimOutpoint: randOutPoint(),
|
||||||
SweepSignDesc: testSignDesc,
|
SweepSignDesc: testSignDesc,
|
||||||
},
|
},
|
||||||
|
// Resolution with SignDetails.
|
||||||
|
{
|
||||||
|
Expiry: 103,
|
||||||
|
SignedTimeoutTx: testTx,
|
||||||
|
SignDetails: testSignDetails,
|
||||||
|
CsvDelay: 923923,
|
||||||
|
ClaimOutpoint: randOutPoint(),
|
||||||
|
SweepSignDesc: testSignDesc,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
AnchorResolution: &lnwallet.AnchorResolution{
|
AnchorResolution: &lnwallet.AnchorResolution{
|
||||||
@ -585,8 +676,15 @@ func TestContractResolutionsStorage(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if !reflect.DeepEqual(&res, diskRes) {
|
if !reflect.DeepEqual(&res, diskRes) {
|
||||||
t.Fatalf("resolution mismatch: expected %#v\n, got %#v",
|
for _, h := range res.HtlcResolutions.IncomingHTLCs {
|
||||||
&res, diskRes)
|
h.SweepSignDesc.KeyDesc.PubKey.Curve = nil
|
||||||
|
}
|
||||||
|
for _, h := range diskRes.HtlcResolutions.IncomingHTLCs {
|
||||||
|
h.SweepSignDesc.KeyDesc.PubKey.Curve = nil
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Fatalf("resolution mismatch: expected %v\n, got %v",
|
||||||
|
spew.Sdump(&res), spew.Sdump(diskRes))
|
||||||
}
|
}
|
||||||
|
|
||||||
// We'll now delete the state, then attempt to retrieve the set of
|
// We'll now delete the state, then attempt to retrieve the set of
|
||||||
|
@ -355,6 +355,12 @@ func (h *htlcSuccessResolver) Encode(w io.Writer) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// We encode the sign details last for backwards compatibility.
|
||||||
|
err := encodeSignDetails(w, h.htlcResolution.SignDetails)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -388,6 +394,16 @@ func newSuccessResolverFromReader(r io.Reader, resCfg ResolverConfig) (
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Sign details is a new field that was added to the htlc resolution,
|
||||||
|
// so it is serialized last for backwards compatibility. We try to read
|
||||||
|
// it, but don't error out if there are not bytes left.
|
||||||
|
signDetails, err := decodeSignDetails(r)
|
||||||
|
if err == nil {
|
||||||
|
h.htlcResolution.SignDetails = signDetails
|
||||||
|
} else if err != io.EOF && err != io.ErrUnexpectedEOF {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
return h, nil
|
return h, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -455,6 +455,12 @@ func (h *htlcTimeoutResolver) Encode(w io.Writer) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// We encode the sign details last for backwards compatibility.
|
||||||
|
err := encodeSignDetails(w, h.htlcResolution.SignDetails)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -490,6 +496,16 @@ func newTimeoutResolverFromReader(r io.Reader, resCfg ResolverConfig) (
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Sign details is a new field that was added to the htlc resolution,
|
||||||
|
// so it is serialized last for backwards compatibility. We try to read
|
||||||
|
// it, but don't error out if there are not bytes left.
|
||||||
|
signDetails, err := decodeSignDetails(r)
|
||||||
|
if err == nil {
|
||||||
|
h.htlcResolution.SignDetails = signDetails
|
||||||
|
} else if err != io.EOF && err != io.ErrUnexpectedEOF {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
return h, nil
|
return h, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -67,6 +67,22 @@ type TxInfo struct {
|
|||||||
Weight int64
|
Weight int64
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SignDetails is a struct containing information needed to resign certain
|
||||||
|
// inputs. It is used to re-sign 2nd level HTLC transactions that uses the
|
||||||
|
// SINGLE|ANYONECANPAY sighash type, as we have a signature provided by our
|
||||||
|
// peer, but we can aggregate multiple of these 2nd level transactions into a
|
||||||
|
// new transaction, that needs to be signed by us.
|
||||||
|
type SignDetails struct {
|
||||||
|
// SignDesc is the sign descriptor needed for us to sign the input.
|
||||||
|
SignDesc SignDescriptor
|
||||||
|
|
||||||
|
// PeerSig is the peer's signature for this input.
|
||||||
|
PeerSig Signature
|
||||||
|
|
||||||
|
// SigHashType is the sighash signed by the peer.
|
||||||
|
SigHashType txscript.SigHashType
|
||||||
|
}
|
||||||
|
|
||||||
type inputKit struct {
|
type inputKit struct {
|
||||||
outpoint wire.OutPoint
|
outpoint wire.OutPoint
|
||||||
witnessType WitnessType
|
witnessType WitnessType
|
||||||
|
@ -5517,6 +5517,14 @@ type IncomingHtlcResolution struct {
|
|||||||
// claimed directly from the outpoint listed below.
|
// claimed directly from the outpoint listed below.
|
||||||
SignedSuccessTx *wire.MsgTx
|
SignedSuccessTx *wire.MsgTx
|
||||||
|
|
||||||
|
// SignDetails is non-nil if SignedSuccessTx is non-nil, and the
|
||||||
|
// channel is of the anchor type. As the above HTLC transaction will be
|
||||||
|
// signed by the channel peer using SINGLE|ANYONECANPAY for such
|
||||||
|
// channels, we can use the sign details to add the input-output pair
|
||||||
|
// of the HTLC transaction to another transaction, thereby aggregating
|
||||||
|
// multiple HTLC transactions together, and adding fees as needed.
|
||||||
|
SignDetails *input.SignDetails
|
||||||
|
|
||||||
// CsvDelay is the relative time lock (expressed in blocks) that must
|
// CsvDelay is the relative time lock (expressed in blocks) that must
|
||||||
// pass after the SignedSuccessTx is confirmed in the chain before the
|
// pass after the SignedSuccessTx is confirmed in the chain before the
|
||||||
// output can be swept.
|
// output can be swept.
|
||||||
@ -5558,6 +5566,14 @@ type OutgoingHtlcResolution struct {
|
|||||||
// claimed directly from the outpoint listed below.
|
// claimed directly from the outpoint listed below.
|
||||||
SignedTimeoutTx *wire.MsgTx
|
SignedTimeoutTx *wire.MsgTx
|
||||||
|
|
||||||
|
// SignDetails is non-nil if SignedTimeoutTx is non-nil, and the
|
||||||
|
// channel is of the anchor type. As the above HTLC transaction will be
|
||||||
|
// signed by the channel peer using SINGLE|ANYONECANPAY for such
|
||||||
|
// channels, we can use the sign details to add the input-output pair
|
||||||
|
// of the HTLC transaction to another transaction, thereby aggregating
|
||||||
|
// multiple HTLC transactions together, and adding fees as needed.
|
||||||
|
SignDetails *input.SignDetails
|
||||||
|
|
||||||
// CsvDelay is the relative time lock (expressed in blocks) that must
|
// CsvDelay is the relative time lock (expressed in blocks) that must
|
||||||
// pass after the SignedTimeoutTx is confirmed in the chain before the
|
// pass after the SignedTimeoutTx is confirmed in the chain before the
|
||||||
// output can be swept.
|
// output can be swept.
|
||||||
@ -5689,6 +5705,12 @@ func newOutgoingHtlcResolution(signer input.Signer,
|
|||||||
}
|
}
|
||||||
timeoutTx.TxIn[0].Witness = timeoutWitness
|
timeoutTx.TxIn[0].Witness = timeoutWitness
|
||||||
|
|
||||||
|
// If this is an anchor type channel, the sign details will let us
|
||||||
|
// re-sign an aggregated tx later.
|
||||||
|
txSignDetails := HtlcSignDetails(
|
||||||
|
chanType, timeoutSignDesc, sigHashType, htlcSig,
|
||||||
|
)
|
||||||
|
|
||||||
// Finally, we'll generate the script output that the timeout
|
// Finally, we'll generate the script output that the timeout
|
||||||
// transaction creates so we can generate the signDesc required to
|
// transaction creates so we can generate the signDesc required to
|
||||||
// complete the claim process after a delay period.
|
// complete the claim process after a delay period.
|
||||||
@ -5709,6 +5731,7 @@ func newOutgoingHtlcResolution(signer input.Signer,
|
|||||||
return &OutgoingHtlcResolution{
|
return &OutgoingHtlcResolution{
|
||||||
Expiry: htlc.RefundTimeout,
|
Expiry: htlc.RefundTimeout,
|
||||||
SignedTimeoutTx: timeoutTx,
|
SignedTimeoutTx: timeoutTx,
|
||||||
|
SignDetails: txSignDetails,
|
||||||
CsvDelay: csvDelay,
|
CsvDelay: csvDelay,
|
||||||
ClaimOutpoint: wire.OutPoint{
|
ClaimOutpoint: wire.OutPoint{
|
||||||
Hash: timeoutTx.TxHash(),
|
Hash: timeoutTx.TxHash(),
|
||||||
@ -5821,6 +5844,12 @@ func newIncomingHtlcResolution(signer input.Signer,
|
|||||||
}
|
}
|
||||||
successTx.TxIn[0].Witness = successWitness
|
successTx.TxIn[0].Witness = successWitness
|
||||||
|
|
||||||
|
// If this is an anchor type channel, the sign details will let us
|
||||||
|
// re-sign an aggregated tx later.
|
||||||
|
txSignDetails := HtlcSignDetails(
|
||||||
|
chanType, successSignDesc, sigHashType, htlcSig,
|
||||||
|
)
|
||||||
|
|
||||||
// Finally, we'll generate the script that the second-level transaction
|
// Finally, we'll generate the script that the second-level transaction
|
||||||
// creates so we can generate the proper signDesc to sweep it after the
|
// creates so we can generate the proper signDesc to sweep it after the
|
||||||
// CSV delay has passed.
|
// CSV delay has passed.
|
||||||
@ -5840,6 +5869,7 @@ func newIncomingHtlcResolution(signer input.Signer,
|
|||||||
)
|
)
|
||||||
return &IncomingHtlcResolution{
|
return &IncomingHtlcResolution{
|
||||||
SignedSuccessTx: successTx,
|
SignedSuccessTx: successTx,
|
||||||
|
SignDetails: txSignDetails,
|
||||||
CsvDelay: csvDelay,
|
CsvDelay: csvDelay,
|
||||||
ClaimOutpoint: wire.OutPoint{
|
ClaimOutpoint: wire.OutPoint{
|
||||||
Hash: successTx.TxHash(),
|
Hash: successTx.TxHash(),
|
||||||
|
@ -235,6 +235,24 @@ func HtlcSigHashType(chanType channeldb.ChannelType) txscript.SigHashType {
|
|||||||
return txscript.SigHashAll
|
return txscript.SigHashAll
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// HtlcSignDetails converts the passed parameters to a SignDetails valid for
|
||||||
|
// this channel type. For non-anchor channels this will return nil.
|
||||||
|
func HtlcSignDetails(chanType channeldb.ChannelType, signDesc input.SignDescriptor,
|
||||||
|
sigHash txscript.SigHashType, peerSig input.Signature) *input.SignDetails {
|
||||||
|
|
||||||
|
// Non-anchor channels don't need sign details, as the HTLC second
|
||||||
|
// level cannot be altered.
|
||||||
|
if !chanType.HasAnchors() {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return &input.SignDetails{
|
||||||
|
SignDesc: signDesc,
|
||||||
|
SigHashType: sigHash,
|
||||||
|
PeerSig: peerSig,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// HtlcSecondLevelInputSequence dictates the sequence number we must use on the
|
// HtlcSecondLevelInputSequence dictates the sequence number we must use on the
|
||||||
// input to a second level HTLC transaction.
|
// input to a second level HTLC transaction.
|
||||||
func HtlcSecondLevelInputSequence(chanType channeldb.ChannelType) uint32 {
|
func HtlcSecondLevelInputSequence(chanType channeldb.ChannelType) uint32 {
|
||||||
|
Loading…
Reference in New Issue
Block a user