Skip to content

Commit f5d39c9

Browse files
authored
Merge pull request #1030 from lightninglabs/channel-bug-fixes
custom channels: more bug fixes
2 parents 395a180 + 0fcb312 commit f5d39c9

14 files changed

+1021
-892
lines changed

cmd/tapcli/assets.go

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ var (
4747
assetGroupedAssetName = "grouped_asset"
4848
assetShowWitnessName = "show_witness"
4949
assetShowSpentName = "show_spent"
50+
assetShowUnconfMintsName = "show_unconfirmed_mints"
5051
assetGroupKeyName = "group_key"
5152
assetGroupAnchorName = "group_anchor"
5253
batchKeyName = "batch_key"
@@ -554,6 +555,11 @@ var listAssetsCommand = cli.Command{
554555
Name: assetShowSpentName,
555556
Usage: "include fully spent assets in the list",
556557
},
558+
cli.BoolFlag{
559+
Name: assetShowUnconfMintsName,
560+
Usage: "include freshly minted and not yet confirmed " +
561+
"assets in the list",
562+
},
557563
},
558564
Action: listAssets,
559565
}
@@ -566,8 +572,9 @@ func listAssets(ctx *cli.Context) error {
566572
// TODO(roasbeef): need to reverse txid
567573

568574
resp, err := client.ListAssets(ctxc, &taprpc.ListAssetRequest{
569-
WithWitness: ctx.Bool(assetShowWitnessName),
570-
IncludeSpent: ctx.Bool(assetShowSpentName),
575+
WithWitness: ctx.Bool(assetShowWitnessName),
576+
IncludeSpent: ctx.Bool(assetShowSpentName),
577+
IncludeUnconfirmedMints: ctx.Bool(assetShowUnconfMintsName),
571578
})
572579
if err != nil {
573580
return fmt.Errorf("unable to list assets: %w", err)

itest/assertions.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1826,6 +1826,11 @@ func AssertAssetsMinted(t *testing.T, tapClient TapdClient,
18261826
firstOutpoint)
18271827
}
18281828

1829+
if anchor.BlockHeight == 0 {
1830+
return fmt.Errorf("missing block " +
1831+
"height")
1832+
}
1833+
18291834
return nil
18301835
},
18311836
AssetScriptKeyCheck(assetRequest.Asset.ScriptKey),

itest/utils.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -358,7 +358,9 @@ func FinalizeBatchUnconfirmed(t *testing.T, minerClient *rpcclient.Client,
358358
// Make sure the assets were all minted within the same anchor but don't
359359
// yet have a block hash associated with them.
360360
listRespUnconfirmed, err := tapClient.ListAssets(
361-
ctxt, &taprpc.ListAssetRequest{},
361+
ctxt, &taprpc.ListAssetRequest{
362+
IncludeUnconfirmedMints: true,
363+
},
362364
)
363365
require.NoError(t, err)
364366

rpcserver.go

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -975,6 +975,37 @@ func (r *rpcServer) ListAssets(ctx context.Context,
975975
return nil, err
976976
}
977977

978+
var (
979+
filteredAssets []*taprpc.Asset
980+
unconfirmedMints uint64
981+
)
982+
983+
// We now count and filter the assets according to the
984+
// IncludeUnconfirmedMints flag.
985+
//
986+
// TODO(guggero): Do this on the SQL level once we add pagination to the
987+
// asset list query, as this will no longer work with pagination.
988+
for idx := range rpcAssets {
989+
switch {
990+
// If the asset isn't confirmed yet, we count it but only
991+
// include it in the output list if the client requested it.
992+
case rpcAssets[idx].ChainAnchor.BlockHeight == 0:
993+
unconfirmedMints++
994+
995+
if req.IncludeUnconfirmedMints {
996+
filteredAssets = append(
997+
filteredAssets, rpcAssets[idx],
998+
)
999+
}
1000+
1001+
// Don't filter out confirmed assets.
1002+
default:
1003+
filteredAssets = append(
1004+
filteredAssets, rpcAssets[idx],
1005+
)
1006+
}
1007+
}
1008+
9781009
// We will also report the number of unconfirmed transfers. This is
9791010
// useful for clients as unconfirmed asset coins are not included in the
9801011
// asset list.
@@ -985,8 +1016,9 @@ func (r *rpcServer) ListAssets(ctx context.Context,
9851016
}
9861017

9871018
return &taprpc.ListAssetResponse{
988-
Assets: rpcAssets,
1019+
Assets: filteredAssets,
9891020
UnconfirmedTransfers: uint64(len(outboundParcels)),
1021+
UnconfirmedMints: unconfirmedMints,
9901022
}, nil
9911023
}
9921024

tapchannel/aux_funding_controller.go

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"bytes"
55
"context"
66
crand "crypto/rand"
7+
"errors"
78
"fmt"
89
"io"
910
"net/url"
@@ -1264,7 +1265,7 @@ func (f *FundingController) processFundingMsg(ctx context.Context,
12641265
)
12651266
if err != nil {
12661267
return tempPID, fmt.Errorf("unable to create "+
1267-
"commitment: %v", err)
1268+
"commitment: %w", err)
12681269
}
12691270

12701271
// Do we expect more proofs to be incoming?
@@ -1431,19 +1432,30 @@ func (f *FundingController) processFundingReq(fundingFlows fundingFlowIndex,
14311432
fundReq.ctx, f.cfg.ChainWallet,
14321433
)
14331434
if uErr != nil {
1434-
log.Errorf("unable to unlock "+
1435-
"inputs: %v", uErr)
1435+
log.Errorf("unable to unlock inputs: %v", uErr)
14361436
}
14371437

14381438
uErr = fundingState.unlockAssetInputs(
14391439
fundReq.ctx, f.cfg.CoinSelector,
14401440
)
14411441
if uErr != nil {
1442-
log.Errorf("Unable to unlock "+
1443-
"asset inputs: %v",
1442+
log.Errorf("Unable to unlock asset inputs: %v",
14441443
uErr)
14451444
}
14461445

1446+
// If anything went wrong during the funding process,
1447+
// the remote side might have an in-memory state and
1448+
// wouldn't allow us to try again within the next 10
1449+
// minutes (due to only one pending channel per peer
1450+
// default value). To avoid running into this issue, we
1451+
// make sure to inform the remote about us aborting the
1452+
// channel. We don't send them the actual error though,
1453+
// that would give away too much information.
1454+
f.cfg.ErrReporter.ReportError(
1455+
fundReq.ctx, fundReq.PeerPub, tempPID,
1456+
errors.New("internal error"),
1457+
)
1458+
14471459
fundReq.errChan <- err
14481460
return
14491461
}

tapchannel/commitment.go

Lines changed: 9 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -667,9 +667,8 @@ func CreateAllocations(chanState *channeldb.OpenChannel, ourBalance,
667667

668668
// Next, we add the HTLC outputs, using this helper function to
669669
// distinguish between incoming and outgoing HTLCs. The haveHtlcSplit
670-
// boolean is used to determine if one of the HTLCs needs to become the
671-
// split root. See below where it's used for a more in-depth
672-
// explanation.
670+
// boolean is used to store if one of the HTLCs has already been chosen
671+
// to be the split root (only the very first HTLC might be chosen).
673672
var haveHtlcSplitRoot bool
674673
addHtlc := func(htlc *DecodedDescriptor, isIncoming bool) error {
675674
htlcScript, err := lnwallet.GenTaprootHtlcScript(
@@ -688,34 +687,14 @@ func CreateAllocations(chanState *channeldb.OpenChannel, ourBalance,
688687
"sibling: %w", err)
689688
}
690689

691-
// The "incoming" vs. "outgoing" naming is always viewed from
692-
// the perspective of the local node and independent of
693-
// isOurCommit. So to find out if an HTLC is for the initiator
694-
// it only depends on the direction and whether we are the
695-
// initiator. The human-readable version of the below switch
696-
// statement is: Either we're the initiator and the HTLC is
697-
// incoming, or we're not the initiator and the HTLC is
698-
// outgoing.
699-
var htlcIsForInitiator bool
700-
switch {
701-
// If the HTLC is incoming and the local node is the channel
702-
// initiator, then the HTLC is for the channel initiator.
703-
case chanState.IsInitiator && isIncoming:
704-
htlcIsForInitiator = true
705-
706-
// If the HTLC is outgoing and the local node is not the
707-
// channel initiator, then the HTLC is for the channel
708-
// initiator.
709-
case !chanState.IsInitiator && !isIncoming:
710-
htlcIsForInitiator = true
711-
}
712-
713-
// We should always just have a single split root on the side
714-
// of the initiator. So if the initiator doesn't have any normal
715-
// asset output to house the split root, then we'll take the
716-
// _first_ HTLC that pays to the initiator.
690+
// We should always just have a single split root, which
691+
// normally is the initiator's balance. However, if the
692+
// initiator has no balance, then we choose the very first HTLC
693+
// in the list to be the split root. If there are no HTLCs, then
694+
// all the balance is on the receiver side and we don't need a
695+
// split root.
717696
shouldHouseSplitRoot := initiatorAssetBalance == 0 &&
718-
htlcIsForInitiator && !haveHtlcSplitRoot
697+
!haveHtlcSplitRoot
719698

720699
// Make sure we only select the very first HTLC that pays to the
721700
// initiator.

tapdb/assets_store.go

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -755,11 +755,14 @@ func (a *AssetStore) dbAssetsToChainAssets(dbAssets []ConfirmedAsset,
755755
}
756756

757757
chainAssets[i] = &asset.ChainAsset{
758-
Asset: assetSprout,
759-
IsSpent: sprout.Spent,
760-
AnchorTx: anchorTx,
761-
AnchorBlockHash: anchorBlockHash,
762-
AnchorOutpoint: anchorOutpoint,
758+
Asset: assetSprout,
759+
IsSpent: sprout.Spent,
760+
AnchorTx: anchorTx,
761+
AnchorBlockHash: anchorBlockHash,
762+
AnchorOutpoint: anchorOutpoint,
763+
AnchorBlockHeight: uint32(
764+
sprout.AnchorBlockHeight.Int32,
765+
),
763766
AnchorInternalKey: anchorInternalKey,
764767
AnchorMerkleRoot: sprout.AnchorMerkleRoot,
765768
AnchorTapscriptSibling: sprout.AnchorTapscriptSibling,
@@ -1820,6 +1823,11 @@ func (a *AssetStore) ListEligibleCoins(ctx context.Context,
18201823
assetFilter.Spent = sqlBool(false)
18211824
assetFilter.Leased = sqlBool(false)
18221825

1826+
// We also only want to select confirmed commitments (freshly minted
1827+
// unconfirmed assets would otherwise be included). Unconfirmed assets
1828+
// have a block height of 0, so we set the minimum block height to 1.
1829+
assetFilter.MinAnchorHeight = sqlInt32(1)
1830+
18231831
return a.queryCommitments(ctx, assetFilter)
18241832
}
18251833

tapdb/assets_store_test.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -301,6 +301,7 @@ func TestImportAssetProof(t *testing.T) {
301301
t, testProof.AssetSnapshot.OutPoint, dbAsset.AnchorOutpoint,
302302
)
303303
require.Equal(t, testProof.AnchorTx.TxHash(), dbAsset.AnchorTx.TxHash())
304+
require.NotZero(t, dbAsset.AnchorBlockHeight)
304305

305306
// We should also be able to fetch the proof we just inserted using the
306307
// script key of the new asset.

tapdb/sqlutils_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ func (d *DbHandler) AddRandomAssetProof(t *testing.T) (*asset.Asset,
105105
Asset: testAsset,
106106
OutPoint: anchorPoint,
107107
AnchorBlockHash: blockHash,
108-
AnchorBlockHeight: test.RandInt[uint32](),
108+
AnchorBlockHeight: uint32(test.RandIntn(1000) + 1),
109109
AnchorTxIndex: test.RandInt[uint32](),
110110
AnchorTx: anchorTx,
111111
OutputIndex: 0,

0 commit comments

Comments
 (0)