mirror of
https://github.com/lightningnetwork/lnd.git
synced 2026-08-19 13:17:32 +02:00
lnwallet: add new aux resolver interface
This will be used by external callers to modify the way we resolve contracts on chain. For a given contract, we'll store an extra "blob", that will later be presented during the sweeping phase.
This commit is contained in:
parent
0f2c16de99
commit
4619cefc8f
8 changed files with 303 additions and 23 deletions
|
|
@ -187,6 +187,10 @@ type AuxComponents struct {
|
|||
// AuxChanCloser is an optional channel closer that can be used to
|
||||
// modify the way a coop-close transaction is constructed.
|
||||
AuxChanCloser fn.Option[chancloser.AuxChanCloser]
|
||||
|
||||
// AuxContractResolver is an optional interface that can be used to
|
||||
// modify the way contracts are resolved.
|
||||
AuxContractResolver fn.Option[lnwallet.AuxContractResolver]
|
||||
}
|
||||
|
||||
// DefaultWalletImpl is the default implementation of our normal, btcwallet
|
||||
|
|
|
|||
|
|
@ -1592,6 +1592,9 @@ func testBreachSpends(t *testing.T, test breachTest) {
|
|||
retribution, err := lnwallet.NewBreachRetribution(
|
||||
alice.State(), height, 1, forceCloseTx,
|
||||
fn.Some[lnwallet.AuxLeafStore](&lnwallet.MockAuxLeafStore{}),
|
||||
fn.Some[lnwallet.AuxContractResolver](
|
||||
&lnwallet.MockAuxContractResolver{},
|
||||
),
|
||||
)
|
||||
require.NoError(t, err, "unable to create breach retribution")
|
||||
|
||||
|
|
@ -1802,6 +1805,9 @@ func TestBreachDelayedJusticeConfirmation(t *testing.T) {
|
|||
retribution, err := lnwallet.NewBreachRetribution(
|
||||
alice.State(), height, uint32(blockHeight), forceCloseTx,
|
||||
fn.Some[lnwallet.AuxLeafStore](&lnwallet.MockAuxLeafStore{}),
|
||||
fn.Some[lnwallet.AuxContractResolver](
|
||||
&lnwallet.MockAuxContractResolver{},
|
||||
),
|
||||
)
|
||||
require.NoError(t, err, "unable to create breach retribution")
|
||||
|
||||
|
|
|
|||
|
|
@ -196,6 +196,9 @@ type chainWatcherConfig struct {
|
|||
|
||||
// auxLeafStore can be used to fetch information for custom channels.
|
||||
auxLeafStore fn.Option[lnwallet.AuxLeafStore]
|
||||
|
||||
// auxResolver is used to supplement contract resolution.
|
||||
auxResolver fn.Option[lnwallet.AuxContractResolver]
|
||||
}
|
||||
|
||||
// chainWatcher is a system that's assigned to every active channel. The duty
|
||||
|
|
@ -896,7 +899,7 @@ func (c *chainWatcher) handlePossibleBreach(commitSpend *chainntnfs.SpendDetail,
|
|||
spendHeight := uint32(commitSpend.SpendingHeight)
|
||||
retribution, err := lnwallet.NewBreachRetribution(
|
||||
c.cfg.chanState, broadcastStateNum, spendHeight,
|
||||
commitSpend.SpendingTx, c.cfg.auxLeafStore,
|
||||
commitSpend.SpendingTx, c.cfg.auxLeafStore, c.cfg.auxResolver,
|
||||
)
|
||||
|
||||
switch {
|
||||
|
|
@ -1147,7 +1150,7 @@ func (c *chainWatcher) dispatchLocalForceClose(
|
|||
|
||||
forceClose, err := lnwallet.NewLocalForceCloseSummary(
|
||||
c.cfg.chanState, c.cfg.signer, commitSpend.SpendingTx, stateNum,
|
||||
c.cfg.auxLeafStore,
|
||||
c.cfg.auxLeafStore, c.cfg.auxResolver,
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
|
|
@ -1239,8 +1242,8 @@ func (c *chainWatcher) dispatchRemoteForceClose(
|
|||
// materials required to let each subscriber sweep the funds in the
|
||||
// channel on-chain.
|
||||
uniClose, err := lnwallet.NewUnilateralCloseSummary(
|
||||
c.cfg.chanState, c.cfg.signer, commitSpend,
|
||||
remoteCommit, commitPoint, c.cfg.auxLeafStore,
|
||||
c.cfg.chanState, c.cfg.signer, commitSpend, remoteCommit,
|
||||
commitPoint, c.cfg.auxLeafStore, c.cfg.auxResolver,
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
|
|
|
|||
89
lnwallet/aux_resolutions.go
Normal file
89
lnwallet/aux_resolutions.go
Normal file
|
|
@ -0,0 +1,89 @@
|
|||
package lnwallet
|
||||
|
||||
import (
|
||||
"github.com/btcsuite/btcd/btcutil"
|
||||
"github.com/btcsuite/btcd/wire"
|
||||
"github.com/lightningnetwork/lnd/fn"
|
||||
"github.com/lightningnetwork/lnd/input"
|
||||
"github.com/lightningnetwork/lnd/lnwire"
|
||||
"github.com/lightningnetwork/lnd/tlv"
|
||||
)
|
||||
|
||||
// CloseType is an enum that represents the type of close that we are trying to
|
||||
// resolve.
|
||||
type CloseType uint8
|
||||
|
||||
const (
|
||||
// LocalForceClose represents a local force close.
|
||||
LocalForceClose CloseType = iota
|
||||
|
||||
// RemoteForceClose represents a remote force close.
|
||||
RemoteForceClose
|
||||
|
||||
// Breach represents a breach by the remote party.
|
||||
Breach
|
||||
)
|
||||
|
||||
// ResolutionReq is used to ask an outside sub-system for additional
|
||||
// information needed to resolve a contract.
|
||||
type ResolutionReq struct {
|
||||
// ChanPoint is the channel point of the channel that we are trying to
|
||||
// resolve.
|
||||
ChanPoint wire.OutPoint
|
||||
|
||||
// ShortChanID is the short channel ID of the channel that we are
|
||||
// trying to resolve.
|
||||
ShortChanID lnwire.ShortChannelID
|
||||
|
||||
// Initiator is a bool if we're the initiator of the channel.
|
||||
Initiator bool
|
||||
|
||||
// CommitBlob is an optional commit blob for the channel.
|
||||
CommitBlob fn.Option[tlv.Blob]
|
||||
|
||||
// FundingBlob is an optional funding blob for the channel.
|
||||
FundingBlob fn.Option[tlv.Blob]
|
||||
|
||||
// Type is the type of the witness that we are trying to resolve.
|
||||
Type input.WitnessType
|
||||
|
||||
// CloseType is the type of close that we are trying to resolve.
|
||||
CloseType CloseType
|
||||
|
||||
// CommitTx is the force close commitment transaction.
|
||||
CommitTx *wire.MsgTx
|
||||
|
||||
// CommitFee is the fee that was paid for the commitment transaction.
|
||||
CommitFee btcutil.Amount
|
||||
|
||||
// ContractPoint is the outpoint of the contract we're trying to
|
||||
// resolve.
|
||||
ContractPoint wire.OutPoint
|
||||
|
||||
// SignDesc is the sign descriptor for the contract.
|
||||
SignDesc input.SignDescriptor
|
||||
|
||||
// KeyRing is the key ring for the channel.
|
||||
KeyRing *CommitmentKeyRing
|
||||
|
||||
// CsvDelay is the CSV delay for the local output for this commitment.
|
||||
CsvDelay uint32
|
||||
|
||||
// BreachCsvDelay is the CSV delay for the remote output. This is only
|
||||
// set when the CloseType is Breach. This indicates the CSV delay to
|
||||
// use for the remote party's to_local delayed output, that is now
|
||||
// rightfully ours in a breach situation.
|
||||
BreachCsvDelay fn.Option[uint32]
|
||||
|
||||
// CltvDelay is the CLTV delay for the outpoint.
|
||||
CltvDelay fn.Option[uint32]
|
||||
}
|
||||
|
||||
// AuxContractResolver is an interface that is used to resolve contracts that
|
||||
// may need additional outside information to resolve correctly.
|
||||
type AuxContractResolver interface {
|
||||
// ResolveContract is called to resolve a contract that needs
|
||||
// additional information to resolve properly. If no extra information
|
||||
// is required, a nil Result error is returned.
|
||||
ResolveContract(ResolutionReq) fn.Result[tlv.Blob]
|
||||
}
|
||||
|
|
@ -764,6 +764,10 @@ type LightningChannel struct {
|
|||
// custom channel variants.
|
||||
auxSigner fn.Option[AuxSigner]
|
||||
|
||||
// auxResolver is an optional component that can be used to modify the
|
||||
// way contracts are resolved.
|
||||
auxResolver fn.Option[AuxContractResolver]
|
||||
|
||||
// Capacity is the total capacity of this channel.
|
||||
Capacity btcutil.Amount
|
||||
|
||||
|
|
@ -824,8 +828,9 @@ type channelOpts struct {
|
|||
localNonce *musig2.Nonces
|
||||
remoteNonce *musig2.Nonces
|
||||
|
||||
leafStore fn.Option[AuxLeafStore]
|
||||
auxSigner fn.Option[AuxSigner]
|
||||
leafStore fn.Option[AuxLeafStore]
|
||||
auxSigner fn.Option[AuxSigner]
|
||||
auxResolver fn.Option[AuxContractResolver]
|
||||
|
||||
skipNonceInit bool
|
||||
}
|
||||
|
|
@ -871,6 +876,14 @@ func WithAuxSigner(signer AuxSigner) ChannelOpt {
|
|||
}
|
||||
}
|
||||
|
||||
// WithAuxResolver is used to specify a custom aux contract resolver for the
|
||||
// channel.
|
||||
func WithAuxResolver(resolver AuxContractResolver) ChannelOpt {
|
||||
return func(o *channelOpts) {
|
||||
o.auxResolver = fn.Some[AuxContractResolver](resolver)
|
||||
}
|
||||
}
|
||||
|
||||
// defaultChannelOpts returns the set of default options for a new channel.
|
||||
func defaultChannelOpts() *channelOpts {
|
||||
return &channelOpts{}
|
||||
|
|
@ -924,6 +937,7 @@ func NewLightningChannel(signer input.Signer,
|
|||
Signer: signer,
|
||||
leafStore: opts.leafStore,
|
||||
auxSigner: opts.auxSigner,
|
||||
auxResolver: opts.auxResolver,
|
||||
sigPool: sigPool,
|
||||
currentHeight: localCommit.CommitHeight,
|
||||
commitChains: commitChains,
|
||||
|
|
@ -1884,6 +1898,10 @@ type HtlcRetribution struct {
|
|||
// this HTLC was offered by us. This flag is used determine the exact
|
||||
// witness type should be used to sweep the output.
|
||||
IsIncoming bool
|
||||
|
||||
// ResolutionBlob is a blob used for aux channels that permits a
|
||||
// spender of this output to claim all funds.
|
||||
ResolutionBlob fn.Option[tlv.Blob]
|
||||
}
|
||||
|
||||
// BreachRetribution contains all the data necessary to bring a channel
|
||||
|
|
@ -1953,6 +1971,14 @@ type BreachRetribution struct {
|
|||
// breaching commitment transaction. This allows downstream clients to
|
||||
// have access to the public keys used in the scripts.
|
||||
KeyRing *CommitmentKeyRing
|
||||
|
||||
// LocalResolutionBlob is a blob used for aux channels that permits an
|
||||
// honest party to sweep the local commitment output.
|
||||
LocalResolutionBlob fn.Option[tlv.Blob]
|
||||
|
||||
// RemoteResolutionBlob is a blob used for aux channels that permits an
|
||||
// honest party to sweep the remote commitment output.
|
||||
RemoteResolutionBlob fn.Option[tlv.Blob]
|
||||
}
|
||||
|
||||
// NewBreachRetribution creates a new fully populated BreachRetribution for the
|
||||
|
|
@ -1964,7 +1990,9 @@ type BreachRetribution struct {
|
|||
// the required fields then ErrRevLogDataMissing will be returned.
|
||||
func NewBreachRetribution(chanState *channeldb.OpenChannel, stateNum uint64,
|
||||
breachHeight uint32, spendTx *wire.MsgTx,
|
||||
leafStore fn.Option[AuxLeafStore]) (*BreachRetribution, error) {
|
||||
leafStore fn.Option[AuxLeafStore],
|
||||
auxResolver fn.Option[AuxContractResolver]) (*BreachRetribution,
|
||||
error) {
|
||||
|
||||
// Query the on-disk revocation log for the snapshot which was recorded
|
||||
// at this particular state num. Based on whether a legacy revocation
|
||||
|
|
@ -2127,6 +2155,38 @@ func NewBreachRetribution(chanState *channeldb.OpenChannel, stateNum uint64,
|
|||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
// At this point, we'll check to see if we need any extra
|
||||
// resolution data for this output.
|
||||
resolveReq := ResolutionReq{
|
||||
ChanPoint: chanState.FundingOutpoint,
|
||||
ShortChanID: chanState.ShortChanID(),
|
||||
Initiator: chanState.IsInitiator,
|
||||
FundingBlob: chanState.CustomBlob,
|
||||
Type: input.TaprootRemoteCommitSpend,
|
||||
CloseType: Breach,
|
||||
CommitTx: spendTx,
|
||||
SignDesc: *br.LocalOutputSignDesc,
|
||||
KeyRing: keyRing,
|
||||
CsvDelay: ourDelay,
|
||||
BreachCsvDelay: fn.Some(theirDelay),
|
||||
CommitFee: chanState.RemoteCommitment.CommitFee,
|
||||
}
|
||||
if revokedLog != nil {
|
||||
resolveReq.CommitBlob = revokedLog.CustomBlob.ValOpt()
|
||||
}
|
||||
|
||||
resolveBlob := fn.MapOptionZ(
|
||||
auxResolver,
|
||||
func(a AuxContractResolver) fn.Result[tlv.Blob] {
|
||||
return a.ResolveContract(resolveReq)
|
||||
},
|
||||
)
|
||||
if err := resolveBlob.Err(); err != nil {
|
||||
return nil, fmt.Errorf("unable to aux resolve: %w", err)
|
||||
}
|
||||
|
||||
br.LocalResolutionBlob = resolveBlob.Option()
|
||||
}
|
||||
|
||||
// Similarly, if their balance exceeds the remote party's dust limit,
|
||||
|
|
@ -2174,6 +2234,37 @@ func NewBreachRetribution(chanState *channeldb.OpenChannel, stateNum uint64,
|
|||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
// At this point, we'll check to see if we need any extra
|
||||
// resolution data for this output.
|
||||
resolveReq := ResolutionReq{
|
||||
ChanPoint: chanState.FundingOutpoint,
|
||||
ShortChanID: chanState.ShortChanID(),
|
||||
Initiator: chanState.IsInitiator,
|
||||
FundingBlob: chanState.CustomBlob,
|
||||
Type: input.TaprootCommitmentRevoke,
|
||||
CloseType: Breach,
|
||||
CommitTx: spendTx,
|
||||
SignDesc: *br.RemoteOutputSignDesc,
|
||||
KeyRing: keyRing,
|
||||
CsvDelay: theirDelay,
|
||||
BreachCsvDelay: fn.Some(theirDelay),
|
||||
CommitFee: chanState.RemoteCommitment.CommitFee,
|
||||
}
|
||||
if revokedLog != nil {
|
||||
resolveReq.CommitBlob = revokedLog.CustomBlob.ValOpt()
|
||||
}
|
||||
resolveBlob := fn.MapOptionZ(
|
||||
auxResolver,
|
||||
func(a AuxContractResolver) fn.Result[tlv.Blob] {
|
||||
return a.ResolveContract(resolveReq)
|
||||
},
|
||||
)
|
||||
if err := resolveBlob.Err(); err != nil {
|
||||
return nil, fmt.Errorf("unable to aux resolve: %w", err)
|
||||
}
|
||||
|
||||
br.RemoteResolutionBlob = resolveBlob.Option()
|
||||
}
|
||||
|
||||
// Finally, with all the necessary data constructed, we can pad the
|
||||
|
|
@ -6473,6 +6564,11 @@ type CommitOutputResolution struct {
|
|||
// that pay to the local party within the broadcast commitment
|
||||
// transaction.
|
||||
MaturityDelay uint32
|
||||
|
||||
// ResolutionBlob is a blob used for aux channels that permits a
|
||||
// spender of the output to properly resolve it in the case of a force
|
||||
// close.
|
||||
ResolutionBlob fn.Option[tlv.Blob]
|
||||
}
|
||||
|
||||
// UnilateralCloseSummary describes the details of a detected unilateral
|
||||
|
|
@ -6530,7 +6626,9 @@ type UnilateralCloseSummary struct {
|
|||
func NewUnilateralCloseSummary(chanState *channeldb.OpenChannel,
|
||||
signer input.Signer, commitSpend *chainntnfs.SpendDetail,
|
||||
remoteCommit channeldb.ChannelCommitment, commitPoint *btcec.PublicKey,
|
||||
leafStore fn.Option[AuxLeafStore]) (*UnilateralCloseSummary, error) {
|
||||
leafStore fn.Option[AuxLeafStore],
|
||||
auxResolver fn.Option[AuxContractResolver]) (*UnilateralCloseSummary,
|
||||
error) {
|
||||
|
||||
// First, we'll generate the commitment point and the revocation point
|
||||
// so we can re-construct the HTLC state and also our payment key.
|
||||
|
|
@ -6554,11 +6652,17 @@ func NewUnilateralCloseSummary(chanState *channeldb.OpenChannel,
|
|||
|
||||
// Next, we'll obtain HTLC resolutions for all the outgoing HTLC's we
|
||||
// had on their commitment transaction.
|
||||
var leaseExpiry uint32
|
||||
var (
|
||||
leaseExpiry uint32
|
||||
selfPoint *wire.OutPoint
|
||||
localBalance int64
|
||||
isRemoteInitiator = !chanState.IsInitiator
|
||||
commitTxBroadcast = commitSpend.SpendingTx
|
||||
)
|
||||
|
||||
if chanState.ChanType.HasLeaseExpiration() {
|
||||
leaseExpiry = chanState.ThawHeight
|
||||
}
|
||||
isRemoteInitiator := !chanState.IsInitiator
|
||||
htlcResolutions, err := extractHtlcResolutions(
|
||||
chainfee.SatPerKWeight(remoteCommit.FeePerKw), commitType,
|
||||
signer, remoteCommit.Htlcs, keyRing, &chanState.LocalChanCfg,
|
||||
|
|
@ -6567,12 +6671,10 @@ func NewUnilateralCloseSummary(chanState *channeldb.OpenChannel,
|
|||
auxResult.AuxLeaves,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to create htlc "+
|
||||
"resolutions: %v", err)
|
||||
return nil, fmt.Errorf("unable to create htlc resolutions: %w",
|
||||
err)
|
||||
}
|
||||
|
||||
commitTxBroadcast := commitSpend.SpendingTx
|
||||
|
||||
// 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.
|
||||
|
|
@ -6587,14 +6689,8 @@ func NewUnilateralCloseSummary(chanState *channeldb.OpenChannel,
|
|||
)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to create self commit "+
|
||||
"script: %v", err)
|
||||
"script: %w", err)
|
||||
}
|
||||
|
||||
var (
|
||||
selfPoint *wire.OutPoint
|
||||
localBalance int64
|
||||
)
|
||||
|
||||
for outputIndex, txOut := range commitTxBroadcast.TxOut {
|
||||
if bytes.Equal(txOut.PkScript, selfScript.PkScript()) {
|
||||
selfPoint = &wire.OutPoint{
|
||||
|
|
@ -6657,6 +6753,35 @@ func NewUnilateralCloseSummary(chanState *channeldb.OpenChannel,
|
|||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
// At this point, we'll check to see if we need any extra
|
||||
// resolution data for this output.
|
||||
resolveReq := ResolutionReq{
|
||||
ChanPoint: chanState.FundingOutpoint,
|
||||
ShortChanID: chanState.ShortChanID(),
|
||||
Initiator: chanState.IsInitiator,
|
||||
CommitBlob: chanState.RemoteCommitment.CustomBlob,
|
||||
FundingBlob: chanState.CustomBlob,
|
||||
Type: input.TaprootRemoteCommitSpend,
|
||||
CloseType: RemoteForceClose,
|
||||
CommitTx: commitTxBroadcast,
|
||||
ContractPoint: *selfPoint,
|
||||
SignDesc: commitResolution.SelfOutputSignDesc,
|
||||
KeyRing: keyRing,
|
||||
CsvDelay: maturityDelay,
|
||||
CommitFee: chanState.RemoteCommitment.CommitFee,
|
||||
}
|
||||
resolveBlob := fn.MapOptionZ(
|
||||
auxResolver,
|
||||
func(a AuxContractResolver) fn.Result[tlv.Blob] {
|
||||
return a.ResolveContract(resolveReq)
|
||||
},
|
||||
)
|
||||
if err := resolveBlob.Err(); err != nil {
|
||||
return nil, fmt.Errorf("unable to aux resolve: %w", err)
|
||||
}
|
||||
|
||||
commitResolution.ResolutionBlob = resolveBlob.Option()
|
||||
}
|
||||
|
||||
closeSummary := channeldb.ChannelCloseSummary{
|
||||
|
|
@ -7513,7 +7638,7 @@ func (lc *LightningChannel) ForceClose() (*LocalForceCloseSummary, error) {
|
|||
localCommitment := lc.channelState.LocalCommitment
|
||||
summary, err := NewLocalForceCloseSummary(
|
||||
lc.channelState, lc.Signer, commitTx,
|
||||
localCommitment.CommitHeight, lc.leafStore,
|
||||
localCommitment.CommitHeight, lc.leafStore, lc.auxResolver,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to gen force close "+
|
||||
|
|
@ -7531,7 +7656,9 @@ func (lc *LightningChannel) ForceClose() (*LocalForceCloseSummary, error) {
|
|||
// transaction corresponding to localCommit.
|
||||
func NewLocalForceCloseSummary(chanState *channeldb.OpenChannel,
|
||||
signer input.Signer, commitTx *wire.MsgTx, stateNum uint64,
|
||||
leafStore fn.Option[AuxLeafStore]) (*LocalForceCloseSummary, error) {
|
||||
leafStore fn.Option[AuxLeafStore],
|
||||
auxResolver fn.Option[AuxContractResolver]) (*LocalForceCloseSummary,
|
||||
error) {
|
||||
|
||||
// Re-derive the original pkScript for to-self output within the
|
||||
// commitment transaction. We'll need this to find the corresponding
|
||||
|
|
@ -7655,6 +7782,35 @@ func NewLocalForceCloseSummary(chanState *channeldb.OpenChannel,
|
|||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
// At this point, we'll check to see if we need any extra
|
||||
// resolution data for this output.
|
||||
resolveBlob := fn.MapOptionZ(
|
||||
auxResolver,
|
||||
func(a AuxContractResolver) fn.Result[tlv.Blob] {
|
||||
//nolint:lll
|
||||
return a.ResolveContract(ResolutionReq{
|
||||
ChanPoint: chanState.FundingOutpoint,
|
||||
ShortChanID: chanState.ShortChanID(),
|
||||
Initiator: chanState.IsInitiator,
|
||||
CommitBlob: chanState.LocalCommitment.CustomBlob,
|
||||
FundingBlob: chanState.CustomBlob,
|
||||
Type: input.TaprootLocalCommitSpend,
|
||||
CloseType: LocalForceClose,
|
||||
CommitTx: commitTx,
|
||||
ContractPoint: commitResolution.SelfOutPoint,
|
||||
SignDesc: commitResolution.SelfOutputSignDesc,
|
||||
KeyRing: keyRing,
|
||||
CsvDelay: csvTimeout,
|
||||
CommitFee: chanState.LocalCommitment.CommitFee,
|
||||
})
|
||||
},
|
||||
)
|
||||
if err := resolveBlob.Err(); err != nil {
|
||||
return nil, fmt.Errorf("unable to aux resolve: %w", err)
|
||||
}
|
||||
|
||||
commitResolution.ResolutionBlob = resolveBlob.Option()
|
||||
}
|
||||
|
||||
// Once the delay output has been found (if it exists), then we'll also
|
||||
|
|
|
|||
|
|
@ -6043,6 +6043,7 @@ func TestChannelUnilateralCloseHtlcResolution(t *testing.T) {
|
|||
aliceChannel.channelState.RemoteCommitment,
|
||||
aliceChannel.channelState.RemoteCurrentRevocation,
|
||||
fn.Some[AuxLeafStore](&MockAuxLeafStore{}),
|
||||
fn.Some[AuxContractResolver](&MockAuxContractResolver{}),
|
||||
)
|
||||
require.NoError(t, err, "unable to create alice close summary")
|
||||
|
||||
|
|
@ -6193,6 +6194,7 @@ func TestChannelUnilateralClosePendingCommit(t *testing.T) {
|
|||
aliceChannel.channelState.RemoteCommitment,
|
||||
aliceChannel.channelState.RemoteCurrentRevocation,
|
||||
fn.Some[AuxLeafStore](&MockAuxLeafStore{}),
|
||||
fn.Some[AuxContractResolver](&MockAuxContractResolver{}),
|
||||
)
|
||||
require.NoError(t, err, "unable to create alice close summary")
|
||||
|
||||
|
|
@ -6211,6 +6213,7 @@ func TestChannelUnilateralClosePendingCommit(t *testing.T) {
|
|||
aliceRemoteChainTip.Commitment,
|
||||
aliceChannel.channelState.RemoteNextRevocation,
|
||||
fn.Some[AuxLeafStore](&MockAuxLeafStore{}),
|
||||
fn.Some[AuxContractResolver](&MockAuxContractResolver{}),
|
||||
)
|
||||
require.NoError(t, err, "unable to create alice close summary")
|
||||
|
||||
|
|
@ -7092,6 +7095,7 @@ func TestNewBreachRetributionSkipsDustHtlcs(t *testing.T) {
|
|||
breachRet, err := NewBreachRetribution(
|
||||
aliceChannel.channelState, revokedStateNum, 100, breachTx,
|
||||
fn.Some[AuxLeafStore](&MockAuxLeafStore{}),
|
||||
fn.Some[AuxContractResolver](&MockAuxContractResolver{}),
|
||||
)
|
||||
require.NoError(t, err, "unable to create breach retribution")
|
||||
|
||||
|
|
@ -10653,6 +10657,7 @@ func testNewBreachRetribution(t *testing.T, chanType channeldb.ChannelType) {
|
|||
_, err = NewBreachRetribution(
|
||||
aliceChannel.channelState, stateNum, breachHeight, breachTx,
|
||||
fn.Some[AuxLeafStore](&MockAuxLeafStore{}),
|
||||
fn.Some[AuxContractResolver](&MockAuxContractResolver{}),
|
||||
)
|
||||
require.ErrorIs(t, err, channeldb.ErrNoPastDeltas)
|
||||
|
||||
|
|
@ -10661,6 +10666,7 @@ func testNewBreachRetribution(t *testing.T, chanType channeldb.ChannelType) {
|
|||
_, err = NewBreachRetribution(
|
||||
aliceChannel.channelState, stateNum, breachHeight, nil,
|
||||
fn.Some[AuxLeafStore](&MockAuxLeafStore{}),
|
||||
fn.Some[AuxContractResolver](&MockAuxContractResolver{}),
|
||||
)
|
||||
require.ErrorIs(t, err, channeldb.ErrNoPastDeltas)
|
||||
|
||||
|
|
@ -10707,6 +10713,7 @@ func testNewBreachRetribution(t *testing.T, chanType channeldb.ChannelType) {
|
|||
br, err := NewBreachRetribution(
|
||||
aliceChannel.channelState, stateNum, breachHeight, breachTx,
|
||||
fn.Some[AuxLeafStore](&MockAuxLeafStore{}),
|
||||
fn.Some[AuxContractResolver](&MockAuxContractResolver{}),
|
||||
)
|
||||
require.NoError(t, err)
|
||||
|
||||
|
|
@ -10719,6 +10726,7 @@ func testNewBreachRetribution(t *testing.T, chanType channeldb.ChannelType) {
|
|||
br, err = NewBreachRetribution(
|
||||
aliceChannel.channelState, stateNum, breachHeight, nil,
|
||||
fn.Some[AuxLeafStore](&MockAuxLeafStore{}),
|
||||
fn.Some[AuxContractResolver](&MockAuxContractResolver{}),
|
||||
)
|
||||
require.NoError(t, err)
|
||||
assertRetribution(br, 1, 0)
|
||||
|
|
@ -10728,6 +10736,7 @@ func testNewBreachRetribution(t *testing.T, chanType channeldb.ChannelType) {
|
|||
_, err = NewBreachRetribution(
|
||||
aliceChannel.channelState, stateNum+1, breachHeight, breachTx,
|
||||
fn.Some[AuxLeafStore](&MockAuxLeafStore{}),
|
||||
fn.Some[AuxContractResolver](&MockAuxContractResolver{}),
|
||||
)
|
||||
require.ErrorIs(t, err, channeldb.ErrLogEntryNotFound)
|
||||
|
||||
|
|
@ -10736,6 +10745,7 @@ func testNewBreachRetribution(t *testing.T, chanType channeldb.ChannelType) {
|
|||
_, err = NewBreachRetribution(
|
||||
aliceChannel.channelState, stateNum+1, breachHeight, nil,
|
||||
fn.Some[AuxLeafStore](&MockAuxLeafStore{}),
|
||||
fn.Some[AuxContractResolver](&MockAuxContractResolver{}),
|
||||
)
|
||||
require.ErrorIs(t, err, channeldb.ErrLogEntryNotFound)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -493,3 +493,14 @@ func (a *MockAuxSigner) VerifySecondLevelSigs(chanState AuxChanState,
|
|||
|
||||
return args.Error(0)
|
||||
}
|
||||
|
||||
type MockAuxContractResolver struct{}
|
||||
|
||||
// ResolveContract is called to resolve a contract that needs
|
||||
// additional information to resolve properly. If no extra information
|
||||
// is required, a nil Result error is returned.
|
||||
func (*MockAuxContractResolver) ResolveContract(
|
||||
ResolutionReq) fn.Result[tlv.Blob] {
|
||||
|
||||
return fn.Ok[tlv.Blob](nil)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1631,6 +1631,7 @@ func newServer(cfg *Config, listenAddrs []net.Addr,
|
|||
br, err := lnwallet.NewBreachRetribution(
|
||||
channel, commitHeight, 0, nil,
|
||||
implCfg.AuxLeafStore,
|
||||
implCfg.AuxContractResolver,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue