Skip to content

Commit b1e73ad

Browse files
committed
tapgarden: start courier only after confirmation
This commit makes sure we only start the proof courier once the on-chain transaction has confirmed. Otherwise we'll run into backoffs for sure until we get the first confirmation.
1 parent dac604a commit b1e73ad

File tree

2 files changed

+102
-7
lines changed

2 files changed

+102
-7
lines changed

tapgarden/custodian.go

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -396,13 +396,21 @@ func (c *Custodian) inspectWalletTx(walletTx *lndclient.Transaction) error {
396396
}
397397

398398
c.events[op] = event
399+
400+
// Now that we've seen this output confirm on
401+
// chain, we'll launch a goroutine to use the
402+
// ProofCourier to import the proof into our
403+
// local DB.
404+
c.Wg.Add(1)
405+
go c.receiveProof(event.Addr.Tap, op)
399406
}
400407

401408
continue
402409
}
403410

404411
// This is a new output, let's find out if it's for an address
405-
// of ours.
412+
// of ours. This step also creates a new event for the address
413+
// if it doesn't exist yet.
406414
addr, err := c.mapToTapAddr(walletTx, uint32(idx), op)
407415
if err != nil {
408416
return err
@@ -414,9 +422,17 @@ func (c *Custodian) inspectWalletTx(walletTx *lndclient.Transaction) error {
414422
continue
415423
}
416424

417-
// Now that we've seen this output on chain, we'll launch a
418-
// goroutine to use the ProofCourier to import the proof into
419-
// our local DB.
425+
// We now need to wait for a confirmation, since proofs will
426+
// be delivered once the anchor transaction is confirmed. If
427+
// we skip it now, we'll receive another notification once the
428+
// transaction is confirmed.
429+
if walletTx.Confirmations == 0 {
430+
continue
431+
}
432+
433+
// Now that we've seen this output confirm on chain, we'll
434+
// launch a goroutine to use the ProofCourier to import the
435+
// proof into our local DB.
420436
c.Wg.Add(1)
421437
go c.receiveProof(addr, op)
422438
}
@@ -450,7 +466,7 @@ func (c *Custodian) receiveProof(addr *address.Tap, op wire.OutPoint) {
450466
&addr.ProofCourierAddr, recipient,
451467
)
452468
if err != nil {
453-
log.Errorf("unable to initiate proof courier service handle: "+
469+
log.Errorf("Unable to initiate proof courier service handle: "+
454470
"%v", err)
455471
return
456472
}
@@ -589,8 +605,7 @@ func (c *Custodian) importAddrToWallet(addr *address.AddrWithKeyInfo) error {
589605

590606
log.Infof("Imported Taproot Asset address %v into wallet", addrStr)
591607
if p2trAddr != nil {
592-
log.Infof("watching p2tr address %v on chain",
593-
p2trAddr.String())
608+
log.Infof("Watching p2tr address %v on chain", p2trAddr)
594609
}
595610

596611
return c.cfg.AddrBook.SetAddrManaged(ctxt, addr, time.Now())

tapgarden/custodian_test.go

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -539,6 +539,86 @@ func TestTransactionHandling(t *testing.T) {
539539
require.EqualValues(t, mockProof.Blob, dbProof)
540540
}
541541

542+
// TestTransactionConfirmedOnly tests that the custodian only starts the proof
543+
// courier once a transaction has been confirmed. We also test that it correctly
544+
// re-tries fetching proofs using a proof courier after it has been restarted.
545+
func TestTransactionConfirmedOnly(t *testing.T) {
546+
t.Parallel()
547+
548+
runTransactionConfirmedOnlyTest(t, false)
549+
runTransactionConfirmedOnlyTest(t, true)
550+
}
551+
552+
// runTransactionConfirmedOnlyTest runs the transaction confirmed only test,
553+
// optionally restarting the custodian in the middle.
554+
func runTransactionConfirmedOnlyTest(t *testing.T, withRestart bool) {
555+
h := newHarness(t, nil)
556+
557+
// Before we start the custodian, we create a few random addresses.
558+
ctx := context.Background()
559+
560+
const numAddrs = 5
561+
addrs := make([]*address.AddrWithKeyInfo, numAddrs)
562+
genesis := make([]*asset.Genesis, numAddrs)
563+
for i := 0; i < numAddrs; i++ {
564+
addrs[i], genesis[i] = randAddr(h)
565+
err := h.tapdbBook.InsertAddrs(ctx, *addrs[i])
566+
require.NoError(t, err)
567+
}
568+
569+
// We start the custodian and make sure it's started up correctly. This
570+
// should add pending events for each of the addresses.
571+
require.NoError(t, h.c.Start())
572+
t.Cleanup(func() {
573+
require.NoError(t, h.c.Stop())
574+
})
575+
h.assertStartup()
576+
577+
// We expect all addresses to be watched by the wallet now.
578+
h.assertAddrsRegistered(addrs...)
579+
580+
// To make sure the custodian adds address events for each address, we
581+
// need to signal an unconfirmed transaction for each of them now.
582+
outputIndexes := make([]int, numAddrs)
583+
transactions := make([]*lndclient.Transaction, numAddrs)
584+
for idx := range addrs {
585+
outputIndex, tx := randWalletTx(addrs[idx])
586+
outputIndexes[idx] = outputIndex
587+
transactions[idx] = tx
588+
h.walletAnchor.SubscribeTx <- *tx
589+
590+
// We also simulate that the proof courier has all the proofs
591+
// it needs.
592+
mockProof := randProof(
593+
t, outputIndexes[idx], tx.Tx, genesis[idx], addrs[idx],
594+
)
595+
_ = h.courier.DeliverProof(nil, mockProof)
596+
}
597+
598+
// We want events to be created for each address, they should be in the
599+
// state where they detected a transaction.
600+
h.assertEventsPresent(numAddrs, address.StatusTransactionDetected)
601+
602+
// In case we're testing with a restart, we now restart the custodian.
603+
if withRestart {
604+
require.NoError(t, h.c.Stop())
605+
606+
h.c = tapgarden.NewCustodian(h.cfg)
607+
require.NoError(t, h.c.Start())
608+
h.assertStartup()
609+
}
610+
611+
// Now we confirm the transactions. This should trigger the custodian to
612+
// fetch the proof for each of the addresses.
613+
for idx := range transactions {
614+
tx := transactions[idx]
615+
tx.Confirmations = 1
616+
h.walletAnchor.SubscribeTx <- *tx
617+
}
618+
619+
h.assertEventsPresent(numAddrs, address.StatusCompleted)
620+
}
621+
542622
func mustMakeAddr(t *testing.T,
543623
gen asset.Genesis, groupKey *btcec.PublicKey,
544624
groupWitness wire.TxWitness, scriptKey btcec.PublicKey) *address.Tap {

0 commit comments

Comments
 (0)