Skip to content
Merged
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ require (
github.com/lightninglabs/lndclient v0.20.0-5
github.com/lightninglabs/neutrino/cache v1.1.2
github.com/lightninglabs/taproot-assets/taprpc v1.0.9
github.com/lightningnetwork/lnd v0.20.0-beta
github.com/lightningnetwork/lnd v0.20.0-beta.rc4.0.20251127014118-f8b5cb0e8918
github.com/lightningnetwork/lnd/cert v1.2.2
github.com/lightningnetwork/lnd/clock v1.1.1
github.com/lightningnetwork/lnd/fn/v2 v2.0.9
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -1152,8 +1152,8 @@ github.com/lightninglabs/protobuf-go-hex-display v1.34.2-hex-display h1:w7FM5LH9
github.com/lightninglabs/protobuf-go-hex-display v1.34.2-hex-display/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw=
github.com/lightningnetwork/lightning-onion v1.2.1-0.20240815225420-8b40adf04ab9 h1:6D3LrdagJweLLdFm1JNodZsBk6iU4TTsBBFLQ4yiXfI=
github.com/lightningnetwork/lightning-onion v1.2.1-0.20240815225420-8b40adf04ab9/go.mod h1:EDqJ3MuZIbMq0QI1czTIKDJ/GS8S14RXPwapHw8cw6w=
github.com/lightningnetwork/lnd v0.20.0-beta h1:ML+jgJ3UKDGJdUf0m73ZeR/szJKWVtHxpQP+yFC79b8=
github.com/lightningnetwork/lnd v0.20.0-beta/go.mod h1:8hc55AnE3mMSJ/UAEJZgmhgNCcH0yWaPg0olpxhhp4M=
github.com/lightningnetwork/lnd v0.20.0-beta.rc4.0.20251127014118-f8b5cb0e8918 h1:FoCUqt9QVJW7LOQHocOBF6kbiybaNyQrbbsx5/FsmWY=
github.com/lightningnetwork/lnd v0.20.0-beta.rc4.0.20251127014118-f8b5cb0e8918/go.mod h1:8hc55AnE3mMSJ/UAEJZgmhgNCcH0yWaPg0olpxhhp4M=
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=
Expand Down
2 changes: 1 addition & 1 deletion itest/psbt_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3663,7 +3663,7 @@ func testPsbtRelativeLockTimeSendProofFail(t *harnessTest) {

AssertSendEvents(
t.t, aliceScriptKeyBytes, sendEvents,
tapfreighter.SendStateStorePreBroadcast,
tapfreighter.SendStateVerifyPreBroadcast,
tapfreighter.SendStateWaitTxConf,
)

Expand Down
33 changes: 32 additions & 1 deletion lndservices/chain_bridge.go
Original file line number Diff line number Diff line change
Expand Up @@ -125,14 +125,45 @@ func (l *LndRpcChainBridge) GetBlock(ctx context.Context,
block, err := l.lnd.ChainKit.GetBlock(ctx, hash)
if err != nil {
return nil, fmt.Errorf(
"unable to retrieve block: %w", err,
"unable to retrieve block (hash=%s): "+
"%w", hash.String(), err,
)
}
return block, nil
},
)
}

// GetBlockByHeight returns a chain block given the block height.
func (l *LndRpcChainBridge) GetBlockByHeight(ctx context.Context,
blockHeight int64) (*wire.MsgBlock, error) {

// First, we need to resolve the block hash at the given height.
blockHash, err := fn.RetryFuncN(
ctx, l.retryConfig, func() (chainhash.Hash, error) {
var zero chainhash.Hash

blockHash, err := l.lnd.ChainKit.GetBlockHash(
ctx, blockHeight,
)
if err != nil {
return zero, fmt.Errorf(
"unable to retrieve block hash: %w",
err,
)
}

return blockHash, nil
},
)
if err != nil {
return nil, fmt.Errorf("unable to retrieve block hash: %w", err)
}

// Now that we have the block hash, we can fetch the block.
return l.GetBlock(ctx, blockHash)
}

// GetBlockHeader returns a block header given its hash.
func (l *LndRpcChainBridge) GetBlockHeader(ctx context.Context,
hash chainhash.Hash) (*wire.BlockHeader, error) {
Expand Down
42 changes: 42 additions & 0 deletions proof/proof.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,12 @@ import (
"io"

"github.com/btcsuite/btcd/blockchain"
"github.com/btcsuite/btcd/btcec/v2"
"github.com/btcsuite/btcd/txscript"
"github.com/btcsuite/btcd/wire"
"github.com/lightninglabs/taproot-assets/asset"
"github.com/lightninglabs/taproot-assets/commitment"
"github.com/lightninglabs/taproot-assets/fn"
"github.com/lightningnetwork/lnd/input"
"github.com/lightningnetwork/lnd/tlv"
)
Expand Down Expand Up @@ -553,6 +556,45 @@ func (p *Proof) ToChainAsset() (asset.ChainAsset, error) {
}, nil
}

// TaprootOutputScript derives the taproot output script and taproot key
// anchoring this proof using its inclusion path.
func (p *Proof) TaprootOutputScript() ([]byte, *btcec.PublicKey, error) {
commitmentKeys, err := p.InclusionProof.DeriveByAssetInclusion(
&p.Asset, fn.Ptr(false),
)
if err != nil {
return nil, nil, fmt.Errorf("derive inclusion commitment: %w",
err)
}

tapCommitment, err := commitmentKeys.GetCommitment()
if err != nil {
return nil, nil, fmt.Errorf("get taproot commitment: %w", err)
}

siblingPreimage := p.InclusionProof.CommitmentProof.TapSiblingPreimage
_, sibling, err := commitment.MaybeEncodeTapscriptPreimage(
siblingPreimage,
)
if err != nil {
return nil, nil, fmt.Errorf("encode tapscript sibling: %w", err)
}

tapKey, err := deriveTaprootKeyFromTapCommitment(
tapCommitment, sibling, p.InclusionProof.InternalKey,
)
if err != nil {
return nil, nil, fmt.Errorf("derive taproot key: %w", err)
}

pkScript, err := txscript.PayToTaprootScript(tapKey)
if err != nil {
return nil, nil, fmt.Errorf("derive taproot script: %w", err)
}

return pkScript, tapKey, nil
}

// Ensure Proof implements the tlv.RecordProducer interface.
var _ tlv.RecordProducer = (*Proof)(nil)

Expand Down
46 changes: 46 additions & 0 deletions proof/proof_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,52 @@ func assertEqualGroupKeyReveal(t *testing.T, expected,
require.FailNow(t, "unexpected group key reveal type")
}

// TestProofTaprootOutputScript ensures the taproot key and script derived from
// a proof match the tapscript root encoded in the inclusion proof.
func TestProofTaprootOutputScript(t *testing.T) {
t.Parallel()

genesis := asset.RandGenesis(t, asset.Normal)
scriptKey := test.RandPubKey(t)

// Build a minimal block with a single transaction so RandProof can
// anchor the proof.
tx := wire.NewMsgTx(2)
tx.AddTxOut(&wire.TxOut{Value: 1})
block := wire.MsgBlock{
Transactions: []*wire.MsgTx{tx},
}

// RandProof gives us a full inclusion proof (with a non-nil sibling)
// that we can use to exercise the derivation logic.
p := RandProof(t, genesis, scriptKey, block, 0, 0)

pkScript, tapKey, err := p.TaprootOutputScript()
require.NoError(t, err)

commitmentProof := p.InclusionProof.CommitmentProof
tapCommitment, err := commitmentProof.Proof.DeriveByAssetInclusion(
&p.Asset,
)
require.NoError(t, err)

_, siblingHash, err := commitment.MaybeEncodeTapscriptPreimage(
commitmentProof.TapSiblingPreimage,
)
require.NoError(t, err)

expectedTapKey, err := deriveTaprootKeyFromTapCommitment(
tapCommitment, siblingHash, p.InclusionProof.InternalKey,
)
require.NoError(t, err)

expectedPkScript, err := txscript.PayToTaprootScript(expectedTapKey)
require.NoError(t, err)

require.Equal(t, expectedTapKey, tapKey)
require.Equal(t, expectedPkScript, pkScript)
}

func assertEqualProof(t *testing.T, expected, actual *Proof) {
t.Helper()

Expand Down
16 changes: 14 additions & 2 deletions rpcserver.go
Original file line number Diff line number Diff line change
Expand Up @@ -3120,6 +3120,13 @@ func (r *rpcServer) PublishAndLogTransfer(ctx context.Context,
anchorTx.FundedPsbt.LockedUTXOs[idx] = op
}

parcelLabel := fmt.Sprintf(
"pubandlog-%s", anchorTx.FinalTx.TxHash().String(),
)
if req.Label != "" {
parcelLabel = req.Label
}

// We now have everything to ship the pre-anchored parcel using the
// freighter. This will publish the TX, create the transfer database
// entries and ship the proofs to the counterparties. It'll also wait
Expand All @@ -3128,7 +3135,7 @@ func (r *rpcServer) PublishAndLogTransfer(ctx context.Context,
resp, err := r.cfg.ChainPorter.RequestShipment(
tapfreighter.NewPreAnchoredParcel(
activePackets, passivePackets, anchorTx,
req.SkipAnchorTxBroadcast, req.Label,
req.SkipAnchorTxBroadcast, parcelLabel,
),
)
if err != nil {
Expand Down Expand Up @@ -3554,9 +3561,14 @@ func (r *rpcServer) SendAsset(ctx context.Context,
return nil, err
}

label := req.Label
if req.Label == "" {
label = fmt.Sprintf("rpcsendasset-%s", tapAddrs[0].String())
}

resp, err := r.cfg.ChainPorter.RequestShipment(
tapfreighter.NewAddressParcel(
feeRate, req.Label, req.SkipProofCourierPingCheck,
feeRate, label, req.SkipProofCourierPingCheck,
tapAddrs...,
),
)
Expand Down
14 changes: 12 additions & 2 deletions tapchannel/aux_closer.go
Original file line number Diff line number Diff line change
Expand Up @@ -259,6 +259,8 @@ func (a *AuxChanCloser) AuxCloseOutputs(
"state: %w", err)
}

ctxb := context.Background()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we should avoid an indefinite ctx here: this method is called by lnd

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

realized that was the same before, so non-blocking atm


// Each of the co-op close outputs needs to ref a funding input, so
// we'll map a map of asset ID to the funding output now.
inputProofs := make(
Expand All @@ -268,6 +270,14 @@ func (a *AuxChanCloser) AuxCloseOutputs(
inputProofs = append(inputProofs, &fundingInput.Proof.Val)
}

err = updateProofsFromShortChanID(
ctxb, a.cfg.ChainBridge, desc.ShortChanID, inputProofs,
)
if err != nil {
return none, fmt.Errorf("unable to update funding proofs: %w",
err)
}

// We'll also decode the shutdown blobs, so we can extract the shutdown
// information (delivery script keys, etc.).
var localShutdown, remoteShutdown tapchannelmsg.AuxShutdownMsg
Expand Down Expand Up @@ -454,7 +464,6 @@ func (a *AuxChanCloser) AuxCloseOutputs(

// We can now add the witness for the OP_TRUE spend of the commitment
// output to the vPackets.
ctxb := context.Background()
if err := signCommitVirtualPackets(ctxb, vPackets); err != nil {
return none, fmt.Errorf("error signing commit virtual "+
"packets: %w", err)
Expand Down Expand Up @@ -666,8 +675,9 @@ func shipChannelTxn(txSender tapfreighter.Porter, chanTx *wire.MsgTx,
ChainFees: closeFee,
FinalTx: chanTx,
}
parcelLabel := fmt.Sprintf("channel-tx-%s", chanTx.TxHash().String())
preSignedParcel := tapfreighter.NewPreAnchoredParcel(
vPkts, nil, closeAnchor, false, "",
vPkts, nil, closeAnchor, false, parcelLabel,
)
_, err = txSender.RequestShipment(preSignedParcel)
if err != nil {
Expand Down
5 changes: 4 additions & 1 deletion tapchannel/aux_funding_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -1456,8 +1456,11 @@ func (f *FundingController) completeChannelFunding(ctx context.Context,
ChainFees: int64(chainFees),
FinalTx: signedFundingTx,
}
parcelLabel := fmt.Sprintf(
"channel-funding-tx-%s", signedFundingTx.TxHash().String(),
)
preSignedParcel := tapfreighter.NewPreAnchoredParcel(
activePkts, passivePkts, anchorTx, false, "",
activePkts, passivePkts, anchorTx, false, parcelLabel,
)
_, err = f.cfg.TxSender.RequestShipment(preSignedParcel)
if err != nil {
Expand Down
Loading
Loading