Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

More custom channel bugfixes #939

Merged
merged 10 commits into from
Jun 9, 2024
2 changes: 1 addition & 1 deletion cmd/tapd/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ func main() {
defer errQueue.Stop()

server, err := tapcfg.CreateServerFromConfig(
cfg, cfgLogger, shutdownInterceptor, errQueue.ChanIn(),
cfg, cfgLogger, shutdownInterceptor, false, errQueue.ChanIn(),
)
if err != nil {
err := fmt.Errorf("error creating server: %w", err)
Expand Down
5 changes: 5 additions & 0 deletions config.go
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,11 @@ type Config struct {
// connecting to itself as a federation member.
RuntimeID int64

// EnableChannelFeatures indicates that tapd is running inside the
// Lightning Terminal daemon (litd) and can provide Taproot Asset
// channel functionality.
EnableChannelFeatures bool
guggero marked this conversation as resolved.
Show resolved Hide resolved

ChainParams address.ChainParams

Lnd *lndclient.LndServices
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ require (
github.com/lib/pq v1.10.9
github.com/lightninglabs/aperture v0.1.21-beta.0.20230705004936-87bb996a4030
github.com/lightninglabs/lightning-node-connect/hashmailrpc v1.0.2
github.com/lightninglabs/lndclient v1.0.1-0.20240604150101-6b56ac87a4fa
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.rc3.0.20240604145823-53dbd1ee66d0
github.com/lightningnetwork/lnd/cert v1.2.2
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -480,8 +480,8 @@ github.com/lightninglabs/lightning-node-connect v0.2.5-alpha h1:ZRVChwczFXK0CEbx
github.com/lightninglabs/lightning-node-connect v0.2.5-alpha/go.mod h1:A9Pof9fETkH+F67BnOmrBDThPKstqp73wlImWOZvTXQ=
github.com/lightninglabs/lightning-node-connect/hashmailrpc v1.0.2 h1:Er1miPZD2XZwcfE4xoS5AILqP1mj7kqnhbBSxW9BDxY=
github.com/lightninglabs/lightning-node-connect/hashmailrpc v1.0.2/go.mod h1:antQGRDRJiuyQF6l+k6NECCSImgCpwaZapATth2Chv4=
github.com/lightninglabs/lndclient v1.0.1-0.20240604150101-6b56ac87a4fa h1:O4ruYmvqRNm/1/8Crl4Y2fnGWSLmy43nxU12iuOnGBE=
github.com/lightninglabs/lndclient v1.0.1-0.20240604150101-6b56ac87a4fa/go.mod h1:bxd2a15cIaW8KKcmOf9nNDI/GTxxj0upEYs1EIkttqw=
github.com/lightninglabs/lndclient v1.0.1-0.20240607082608-4ce52a1a3f27 h1:vm8a13EzH2Qe6j4eZx+tHPeEVoNhJ7coihFPX6K2kco=
github.com/lightninglabs/lndclient v1.0.1-0.20240607082608-4ce52a1a3f27/go.mod h1:bxd2a15cIaW8KKcmOf9nNDI/GTxxj0upEYs1EIkttqw=
github.com/lightninglabs/neutrino v0.16.1-0.20240425105051-602843d34ffd h1:D8aRocHpoCv43hL8egXEMYyPmyOiefFHZ66338KQB2s=
github.com/lightninglabs/neutrino v0.16.1-0.20240425105051-602843d34ffd/go.mod h1:x3OmY2wsA18+Kc3TSV2QpSUewOCiscw2mKpXgZv2kZk=
github.com/lightninglabs/neutrino/cache v1.1.2 h1:C9DY/DAPaPxbFC+xNNEI/z1SJY9GS3shmlu5hIQ798g=
Expand Down
2 changes: 1 addition & 1 deletion itest/tapd_harness.go
Original file line number Diff line number Diff line change
Expand Up @@ -309,7 +309,7 @@ func (hs *tapdHarness) start(expectErrExit bool) error {
)

hs.server, err = tapcfg.CreateServerFromConfig(
hs.clientCfg, cfgLogger, hs.ht.interceptor, mainErrChan,
hs.clientCfg, cfgLogger, hs.ht.interceptor, false, mainErrChan,
)
if err != nil {
return fmt.Errorf("could not create tapd server: %w", err)
Expand Down
11 changes: 9 additions & 2 deletions psbt_channel_funder.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,12 @@ import (
"github.com/lightningnetwork/lnd/routing/route"
)

const (
// CustomChannelRemoteReserve is the custom channel minimum remote
// reserve that we'll use for our channels.
CustomChannelRemoteReserve = 1062
Copy link
Member

Choose a reason for hiding this comment

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

Oddly precise number?

Copy link
Member Author

Choose a reason for hiding this comment

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

Yeah, not sure where exactly this is coming from. Took over the commit from #934, @GeorgeTsagk did some calculations to arrive at it.
Probably the 1% of our 100k default channel size plus some dust margin?

)

// LndPbstChannelFunder is an implementation of the tapchannel.ChannelFunder
// interface that uses lnd to carry out the PSBT funding process.
type LndPbstChannelFunder struct {
Expand Down Expand Up @@ -92,8 +98,8 @@ func (l *LndPbstChannelFunder) OpenChannel(ctx context.Context,
// taproot channel, that uses the PSBT funding flow.
taprootCommitType := lnrpc.CommitmentType_SIMPLE_TAPROOT
openChanStream, errChan, err := l.lnd.Client.OpenChannelStream(
ctx, route.NewVertex(&req.PeerPub), req.ChanAmt, 0, true,
lndclient.WithCommitmentType(&taprootCommitType),
ctx, route.NewVertex(&req.PeerPub), req.ChanAmt, req.PushAmt,
true, lndclient.WithCommitmentType(&taprootCommitType),
lndclient.WithFundingShim(&lnrpc.FundingShim{
Shim: &lnrpc.FundingShim_PsbtShim{
PsbtShim: &lnrpc.PsbtShim{
Expand All @@ -103,6 +109,7 @@ func (l *LndPbstChannelFunder) OpenChannel(ctx context.Context,
},
},
}),
lndclient.WithRemoteReserve(CustomChannelRemoteReserve),
)
if err != nil {
return nil, fmt.Errorf("unable to open channel with "+
Expand Down
10 changes: 10 additions & 0 deletions rpcserver.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import (

"github.com/btcsuite/btcd/btcec/v2"
"github.com/btcsuite/btcd/btcec/v2/schnorr"
"github.com/btcsuite/btcd/btcutil"
"github.com/btcsuite/btcd/btcutil/psbt"
"github.com/btcsuite/btcd/chaincfg/chainhash"
"github.com/btcsuite/btcd/wire"
Expand Down Expand Up @@ -6394,6 +6395,14 @@ func (r *rpcServer) FundChannel(ctx context.Context,
req *tchrpc.FundChannelRequest) (*tchrpc.FundChannelResponse,
error) {

// If we're not running inside litd, we cannot offer this functionality.
if !r.cfg.EnableChannelFeatures {
return nil, fmt.Errorf("the Taproot Asset channel " +
"functionality is only available when running inside " +
"Lightning Terminal daemon (litd), with lnd and tapd " +
"both running in 'integrated' mode")
}

peerPub, err := btcec.ParsePubKey(req.PeerPubkey)
if err != nil {
return nil, fmt.Errorf("error parsing peer pubkey: %w", err)
Expand All @@ -6414,6 +6423,7 @@ func (r *rpcServer) FundChannel(ctx context.Context,
PeerPub: *peerPub,
AssetAmount: req.AssetAmount,
FeeRate: chainfee.SatPerVByte(req.FeeRateSatPerVbyte),
PushAmount: btcutil.Amount(req.PushSat),
}
copy(fundReq.AssetID[:], req.AssetId)

Expand Down
22 changes: 13 additions & 9 deletions tapcfg/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ type databaseBackend interface {
// NOTE: The RPCConfig and SignalInterceptor fields must be set by the caller
// after generating the server config.
func genServerConfig(cfg *Config, cfgLogger btclog.Logger,
lndServices *lndclient.LndServices,
lndServices *lndclient.LndServices, enableChannelFeatures bool,
mainErrChan chan<- error) (*tap.Config, error) {

var err error
Expand Down Expand Up @@ -452,10 +452,13 @@ func genServerConfig(cfg *Config, cfgLogger btclog.Logger,
}

return &tap.Config{
DebugLevel: cfg.DebugLevel,
RuntimeID: runtimeID,
Lnd: lndServices,
ChainParams: address.ParamsForChain(cfg.ActiveNetParams.Name),
DebugLevel: cfg.DebugLevel,
RuntimeID: runtimeID,
EnableChannelFeatures: enableChannelFeatures,
Lnd: lndServices,
ChainParams: address.ParamsForChain(
cfg.ActiveNetParams.Name,
),
ReOrgWatcher: reOrgWatcher,
AssetMinter: tapgarden.NewChainPlanter(tapgarden.PlanterConfig{
GardenKit: tapgarden.GardenKit{
Expand Down Expand Up @@ -530,7 +533,7 @@ func genServerConfig(cfg *Config, cfgLogger btclog.Logger,
// CreateServerFromConfig creates a new Taproot Asset server from the given CLI
// config.
func CreateServerFromConfig(cfg *Config, cfgLogger btclog.Logger,
shutdownInterceptor signal.Interceptor,
shutdownInterceptor signal.Interceptor, enableChannelFeatures bool,
mainErrChan chan<- error) (*tap.Server, error) {

// Given the config above, grab the TLS config which includes the set
Expand All @@ -556,7 +559,8 @@ func CreateServerFromConfig(cfg *Config, cfgLogger btclog.Logger,
cfgLogger.Infof("lnd connection initialized")

serverCfg, err := genServerConfig(
cfg, cfgLogger, &lndConn.LndServices, mainErrChan,
cfg, cfgLogger, &lndConn.LndServices, enableChannelFeatures,
mainErrChan,
)
if err != nil {
return nil, fmt.Errorf("unable to generate server config: %w",
Expand Down Expand Up @@ -590,11 +594,11 @@ func CreateServerFromConfig(cfg *Config, cfgLogger btclog.Logger,

// ConfigureSubServer updates a Taproot Asset server with the given CLI config.
func ConfigureSubServer(srv *tap.Server, cfg *Config, cfgLogger btclog.Logger,
lndServices *lndclient.LndServices,
lndServices *lndclient.LndServices, litdIntegrated bool,
mainErrChan chan<- error) error {

serverCfg, err := genServerConfig(
cfg, cfgLogger, lndServices, mainErrChan,
cfg, cfgLogger, lndServices, litdIntegrated, mainErrChan,
)
if err != nil {
return fmt.Errorf("unable to generate server config: %w", err)
Expand Down
7 changes: 7 additions & 0 deletions tapchannel/allocation.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package tapchannel
import (
"bytes"
"fmt"
"net/url"
"sort"

"github.com/btcsuite/btcd/btcec/v2"
Expand Down Expand Up @@ -144,6 +145,10 @@ type Allocation struct {
// OutputCommitment is the taproot output commitment that is set after
// fully distributing the coins and creating the asset and TAP trees.
OutputCommitment *commitment.TapCommitment

// ProofDeliveryAddress is the address the proof courier should use to
// upload the proof for this allocation.
ProofDeliveryAddress *url.URL
}

// tapscriptSibling returns the tapscript sibling preimage from the non-asset
Expand Down Expand Up @@ -438,6 +443,7 @@ func DistributeCoins(inputs []*proof.Proof, allocations []*Allocation,
return nil, err
}

deliveryAddr := a.ProofDeliveryAddress
vOut := &tappsbt.VOutput{
Amount: allocating,
AssetVersion: a.AssetVersion,
Expand All @@ -447,6 +453,7 @@ func DistributeCoins(inputs []*proof.Proof, allocations []*Allocation,
AnchorOutputInternalKey: a.InternalKey,
AnchorOutputTapscriptSibling: sibling,
ScriptKey: a.ScriptKey,
ProofDeliveryAddress: deliveryAddr,
Copy link
Member

Choose a reason for hiding this comment

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

In order for us to send the proofs to the correct proof courier address,
we need to be able to specify different delivery addresses for each
allocation.

In the future, or today?

Copy link
Member Author

Choose a reason for hiding this comment

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

Today. Otherwise if the initiator of the shutdown process uses the non-default proof courier address, the respondent wouldn't ever learn that and wouldn't know where to download the proof from.

}
p.packet.Outputs = append(p.packet.Outputs, vOut)

Expand Down
64 changes: 42 additions & 22 deletions tapchannel/aux_closer.go
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,19 @@ func createCloseAlloc(isLocal, isInitiator bool, closeAsset *asset.Asset,
return nil, fmt.Errorf("no script key for asset %v", assetID)
}

var proofDeliveryUrl *url.URL
err := lfn.MapOptionZ(
shutdownMsg.ProofDeliveryAddr.ValOpt(), func(u []byte) error {
var err error
proofDeliveryUrl, err = url.Parse(string(u))
return err
},
)
if err != nil {
return nil, fmt.Errorf("unable to decode proof delivery "+
"address: %w", err)
}

return &Allocation{
Type: func() AllocationType {
if isLocal {
Expand All @@ -110,13 +123,14 @@ func createCloseAlloc(isLocal, isInitiator bool, closeAsset *asset.Asset,

return CommitAllocationToRemote
}(),
SplitRoot: isInitiator,
InternalKey: shutdownMsg.AssetInternalKey.Val,
ScriptKey: asset.NewScriptKey(&scriptKey),
Amount: closeAsset.Amount,
AssetVersion: asset.V0,
BtcAmount: tapsend.DummyAmtSats,
SortTaprootKeyBytes: sortKeyBytes,
SplitRoot: isInitiator,
InternalKey: shutdownMsg.AssetInternalKey.Val,
ScriptKey: asset.NewScriptKey(&scriptKey),
Amount: closeAsset.Amount,
AssetVersion: asset.V0,
BtcAmount: tapsend.DummyAmtSats,
SortTaprootKeyBytes: sortKeyBytes,
ProofDeliveryAddress: proofDeliveryUrl,
Copy link
Member

Choose a reason for hiding this comment

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

Ah existing tests assumed that they were all using the same courier.

Copy link
Member Author

Choose a reason for hiding this comment

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

Before this commit the respondent to the shutdown process didn't actually know what proof courier the final proof would be uploaded to. Now the desired delivery address is sent along with the internal and script key, so the non-shutdown-initiator will know where to look for the proof.

}, nil
}

Expand Down Expand Up @@ -325,14 +339,6 @@ func (a *AuxChanCloser) AuxCloseOutputs(
return none, fmt.Errorf("unable to distribute coins: %w", err)
}

// For each vPkt, we'll also go ahead and add the default proof courier
// addr to them.
for _, vPacket := range vPackets {
for _, vOut := range vPacket.Outputs {
vOut.ProofDeliveryAddress = a.cfg.DefaultCourierAddr
}
}

// With the vPackets created we'll now prepare all the split
// information encoded in the vPackets.
fundingScriptTree := NewFundingScriptTree()
Expand Down Expand Up @@ -493,32 +499,46 @@ func (a *AuxChanCloser) ShutdownBlob(
return none, err
}

// Next, we'll collect all the asset IDs that we own in this channel.
assetIDs := lfn.Map(func(o *tapchannelmsg.AssetOutput) asset.ID {
return o.AssetID.Val
}, commitState.LocalAssets.Val.Outputs)
// Next, we'll collect all the assets that we own in this channel.
assets := commitState.LocalAssets.Val.Outputs

// Now that we have all the asset IDs, we'll query for a new key for
// each of them which we'll use as both the internal key and the script
// key.
scriptKeys := make(tapchannelmsg.ScriptKeyMap)
for _, assetID := range assetIDs {
for idx := range assets {
channelAsset := assets[idx]

newKey, err := a.cfg.AddrBook.NextScriptKey(
ctx, asset.TaprootAssetsKeyFamily,
)
if err != nil {
return none, err
}

scriptKeys[assetID] = *newKey.PubKey
// We now add the a
// TODO(guggero): This only works if there's only a single asset
// in the channel. We need to extend this to support multiple
// assets.
_, err = a.cfg.AddrBook.NewAddressWithKeys(
ctx, channelAsset.AssetID.Val, channelAsset.Amount.Val,
newKey, newInternalKey, nil, *a.cfg.DefaultCourierAddr,
)
if err != nil {
return none, fmt.Errorf("error adding new address: %w",
err)
}

scriptKeys[channelAsset.AssetID.Val] = *newKey.PubKey
}

// Finally, we'll map the extra shutdown info to a TLV record map we
// can send to lnd to have included.
shutdownRecord := tapchannelmsg.NewAuxShutdownMsg(
&btcInternalKey, newInternalKey.PubKey, scriptKeys,
a.cfg.DefaultCourierAddr,
)
records, err := tlv.RecordsToMap(shutdownRecord.Records())
records, err := tlv.RecordsToMap(shutdownRecord.EncodeRecords())
if err != nil {
return none, err
}
Expand Down
11 changes: 11 additions & 0 deletions tapchannel/aux_funding_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,9 @@ type OpenChanReq struct {
// CPFP with the channel anchor outputs.
ChanAmt btcutil.Amount

// PushAmt is the amount of BTC to push to the remote peer.
PushAmt btcutil.Amount

// PeerPub is the identity public key of the remote peer we wish to
// open the channel with.
PeerPub btcec.PublicKey
Expand Down Expand Up @@ -290,6 +293,8 @@ type pendingAssetFunding struct {

amt uint64

pushAmt btcutil.Amount

inputProofs []*proof.Proof

feeRate chainfee.SatPerVByte
Expand Down Expand Up @@ -946,6 +951,7 @@ func (f *FundingController) completeChannelFunding(ctx context.Context,
// flow with lnd.
fundingReq := OpenChanReq{
ChanAmt: 100_000,
PushAmt: fundingState.pushAmt,
PeerPub: fundingState.peerPub,
TempPID: fundingState.pid,
}
Expand Down Expand Up @@ -1173,6 +1179,7 @@ func (f *FundingController) chanFunder() {
pid: tempPID,
initiator: true,
amt: fundReq.AssetAmount,
pushAmt: fundReq.PushAmount,
feeRate: fundReq.FeeRate,
fundingAckChan: make(chan bool, 1),
fundingFinalizedSignal: make(chan struct{}),
Expand Down Expand Up @@ -1602,6 +1609,10 @@ type FundReq struct {
// FeeRate is the fee rate that we'll use to fund the channel.
FeeRate chainfee.SatPerVByte

// PushAmount is the amount of satoshis that we'll push to the remote
// party.
PushAmount btcutil.Amount

ctx context.Context
respChan chan *wire.OutPoint
errChan chan error
Expand Down
Loading
Loading