diff --git a/go.mod b/go.mod index 8303d50e8..883db642c 100644 --- a/go.mod +++ b/go.mod @@ -30,7 +30,7 @@ require ( github.com/lightninglabs/lightning-node-connect/hashmailrpc v1.0.2 github.com/lightninglabs/lndclient v1.0.1-0.20240607082608-4ce52a1a3f27 github.com/lightninglabs/neutrino/cache v1.1.2 - github.com/lightningnetwork/lnd v0.18.0-beta.rc4.0.20240627024114-9eec9b504509 + github.com/lightningnetwork/lnd v0.18.0-beta.rc4.0.20240702183719-8d838801616a github.com/lightningnetwork/lnd/cert v1.2.2 github.com/lightningnetwork/lnd/clock v1.1.1 github.com/lightningnetwork/lnd/fn v1.1.0 diff --git a/go.sum b/go.sum index cfaeae104..ccd3733cd 100644 --- a/go.sum +++ b/go.sum @@ -490,8 +490,8 @@ github.com/lightninglabs/protobuf-go-hex-display v1.30.0-hex-display h1:pRdza2wl github.com/lightninglabs/protobuf-go-hex-display v1.30.0-hex-display/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= github.com/lightningnetwork/lightning-onion v1.2.1-0.20230823005744-06182b1d7d2f h1:Pua7+5TcFEJXIIZ1I2YAUapmbcttmLj4TTi786bIi3s= github.com/lightningnetwork/lightning-onion v1.2.1-0.20230823005744-06182b1d7d2f/go.mod h1:c0kvRShutpj3l6B9WtTsNTBUtjSmjZXbJd9ZBRQOSKI= -github.com/lightningnetwork/lnd v0.18.0-beta.rc4.0.20240627024114-9eec9b504509 h1:3Mf45BhHztEjofy0eYtaYM6hs+I/03/Z5AZ0W+zNdIU= -github.com/lightningnetwork/lnd v0.18.0-beta.rc4.0.20240627024114-9eec9b504509/go.mod h1:L3IArArdRrWtuw+wNsUlibuGmf/08Odsm/zo3+bPXuM= +github.com/lightningnetwork/lnd v0.18.0-beta.rc4.0.20240702183719-8d838801616a h1:nb03C8JKvMAeFqGRLncnLJx0Og8CWSdNd5Cw3P/vVRo= +github.com/lightningnetwork/lnd v0.18.0-beta.rc4.0.20240702183719-8d838801616a/go.mod h1:L3IArArdRrWtuw+wNsUlibuGmf/08Odsm/zo3+bPXuM= github.com/lightningnetwork/lnd/cert v1.2.2 h1:71YK6hogeJtxSxw2teq3eGeuy4rHGKcFf0d0Uy4qBjI= github.com/lightningnetwork/lnd/cert v1.2.2/go.mod h1:jQmFn/Ez4zhDgq2hnYSw8r35bqGVxViXhX6Cd7HXM6U= github.com/lightningnetwork/lnd/clock v1.1.1 h1:OfR3/zcJd2RhH0RU+zX/77c0ZiOnIMsDIBjgjWdZgA0= diff --git a/tapcfg/server.go b/tapcfg/server.go index 0b617a050..cf1b21af3 100644 --- a/tapcfg/server.go +++ b/tapcfg/server.go @@ -447,6 +447,13 @@ func genServerConfig(cfg *Config, cfgLogger btclog.Logger, AddrBook: addrBook, TxSender: chainPorter, DefaultCourierAddr: proofCourierAddr, + ProofArchive: proofArchive, + ProofFetcher: proofCourierDispatcher, + HeaderVerifier: headerVerifier, + GroupVerifier: tapgarden.GenGroupVerifier( + context.Background(), assetMintingStore, + ), + ChainBridge: chainBridge, }, ) auxSweeper := tapchannel.NewAuxSweeper( diff --git a/tapchannel/aux_closer.go b/tapchannel/aux_closer.go index 6caea2915..55312ded2 100644 --- a/tapchannel/aux_closer.go +++ b/tapchannel/aux_closer.go @@ -17,6 +17,7 @@ import ( "github.com/lightninglabs/taproot-assets/proof" "github.com/lightninglabs/taproot-assets/tapchannelmsg" "github.com/lightninglabs/taproot-assets/tapfreighter" + "github.com/lightninglabs/taproot-assets/tapgarden" "github.com/lightninglabs/taproot-assets/tappsbt" "github.com/lightninglabs/taproot-assets/tapsend" lfn "github.com/lightningnetwork/lnd/fn" @@ -45,6 +46,22 @@ type AuxChanCloserCfg struct { // DefaultCourierAddr is the default address we'll use to send/receive // proofs for the co-op close process DefaultCourierAddr *url.URL + + // ProofFetcher is used to fetch proofs needed to properly import the + // funding output into the database as our own. + ProofFetcher proof.CourierDispatch + + // ProofArchive is used to store import funding output proofs. + ProofArchive proof.Archiver + + // HeaderVerifier is used to verify headers in a proof. + HeaderVerifier proof.HeaderVerifier + + // GroupVerifier is used to verify group keys in a proof. + GroupVerifier proof.GroupVerifier + + // ChainBridge is used to fetch blocks from the main chain. + ChainBridge tapgarden.ChainBridge } // assetCloseInfo houses the information we need to finalize the close of an @@ -624,6 +641,37 @@ func (a *AuxChanCloser) FinalizeClose(desc chancloser.AuxCloseDesc, desc.ChanPoint) } + // Before we finalize the close process, we'll make sure to also import + // a transfer for the funding outputs. This way we'll ensure that we're + // able to insert the transfer that spends these outputs. We only need + // to do this for the responder though, as the creator of the channel + // already has these proofs inserted. + if !desc.Initiator { + fundingInfo, err := tapchannelmsg.DecodeOpenChannel( + desc.FundingBlob.UnwrapOr(nil), + ) + if err != nil { + return err + } + + fundingInputProofs := fn.Map( + fundingInfo.FundedAssets.Val.Outputs, + func(a *tapchannelmsg.AssetOutput) *proof.Proof { + return &a.Proof.Val + }, + ) + err = importOutputProofs( + desc.ShortChanID, fundingInputProofs, + a.cfg.DefaultCourierAddr, a.cfg.ProofFetcher, + a.cfg.ChainBridge, a.cfg.HeaderVerifier, + a.cfg.GroupVerifier, a.cfg.ProofArchive, + ) + if err != nil { + return fmt.Errorf("unable to import output "+ + "proofs: %w", err) + } + } + log.Infof("Finalizing close for ChannelPoint(%v): ", desc.ChanPoint) defer delete(a.closeInfo, desc.ChanPoint) diff --git a/tapchannel/aux_sweeper.go b/tapchannel/aux_sweeper.go index 7ac01f081..68dabba0c 100644 --- a/tapchannel/aux_sweeper.go +++ b/tapchannel/aux_sweeper.go @@ -757,15 +757,18 @@ func (a *AuxSweeper) importCommitScriptKeys(req lnwallet.ResolutionReq) error { // importOutputProofs imports the output proofs into the pending asset funding // into our local database. This preps us to be able to detect force closes. -func (a *AuxSweeper) importOutputProofs(scid lnwire.ShortChannelID, - outputProofs []*proof.Proof) error { +func importOutputProofs(scid lnwire.ShortChannelID, + outputProofs []*proof.Proof, courierAddr *url.URL, + proofDispatch proof.CourierDispatch, chainBridge tapgarden.ChainBridge, + headerVerifier proof.HeaderVerifier, groupVerifier proof.GroupVerifier, + proofArchive proof.Archiver) error { // TODO(roasbeef): should be part of post confirmation funding validate // (chanvalidate) // First, we'll make a courier to use in fetching the proofs we need. - proofFetcher, err := a.cfg.ProofFetcher.NewCourier( - a.cfg.DefaultCourierAddr, proof.Recipient{}, + proofFetcher, err := proofDispatch.NewCourier( + courierAddr, proof.Recipient{}, ) if err != nil { return fmt.Errorf("unable to create proof courier: %w", err) @@ -790,11 +793,16 @@ func (a *AuxSweeper) importOutputProofs(scid lnwire.ShortChannelID, return fmt.Errorf("unable to convert script key to "+ "pubkey: %w", err) } + inputProofLocator := proof.Locator{ AssetID: &proofPrevID.ID, ScriptKey: *scriptKey, OutPoint: &proofPrevID.OutPoint, } + if proofToImport.Asset.GroupKey != nil { + groupKey := proofToImport.Asset.GroupKey.GroupPubKey + inputProofLocator.GroupKey = &groupKey + } log.Infof("Fetching funding input proof, locator=%v", spew.Sdump(inputProofLocator)) @@ -814,13 +822,13 @@ func (a *AuxSweeper) importOutputProofs(scid lnwire.ShortChannelID, // Before we combine the proofs below, we'll be sure to update // the transition proof to include the proper block+merkle // proof information. - blockHash, err := a.cfg.ChainBridge.GetBlockHash( + blockHash, err := chainBridge.GetBlockHash( ctxb, int64(scid.BlockHeight), ) if err != nil { return fmt.Errorf("unable to get block hash: %w", err) } - block, err := a.cfg.ChainBridge.GetBlock(ctxb, blockHash) + block, err := chainBridge.GetBlock(ctxb, blockHash) if err != nil { return fmt.Errorf("unable to get block: %w", err) } @@ -858,9 +866,9 @@ func (a *AuxSweeper) importOutputProofs(scid lnwire.ShortChannelID, } fundingUTXO := proofToImport.Asset - err = a.cfg.ProofArchive.ImportProofs( - ctxb, a.cfg.HeaderVerifier, proof.DefaultMerkleVerifier, - a.cfg.GroupVerifier, a.cfg.ChainBridge, false, + err = proofArchive.ImportProofs( + ctxb, headerVerifier, proof.DefaultMerkleVerifier, + groupVerifier, chainBridge, false, &proof.AnnotatedProof{ //nolint:lll Locator: proof.Locator{ @@ -932,8 +940,11 @@ func (a *AuxSweeper) importCommitTx(req lnwallet.ResolutionReq, // for the funding transaction here so we can properly recognize the // spent input below. if !req.Initiator { - err := a.importOutputProofs( + err := importOutputProofs( req.ShortChanID, maps.Values(fundingInputProofs), + a.cfg.DefaultCourierAddr, a.cfg.ProofFetcher, + a.cfg.ChainBridge, a.cfg.HeaderVerifier, + a.cfg.GroupVerifier, a.cfg.ProofArchive, ) if err != nil { return fmt.Errorf("unable to import output "+