Skip to content

Commit db907aa

Browse files
authored
Merge pull request #1022 from starius/parallel-presign
sweepbatcher: presign transactions in parallel
2 parents 03de0a8 + b458c5e commit db907aa

File tree

4 files changed

+61
-18
lines changed

4 files changed

+61
-18
lines changed

go.mod

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,8 @@ require (
2323
github.com/lightninglabs/lndclient v0.20.0-1
2424
github.com/lightninglabs/loop/looprpc v1.0.7
2525
github.com/lightninglabs/loop/swapserverrpc v1.0.14
26-
github.com/lightninglabs/taproot-assets v0.7.0-rc1.0.20250925100956-c44e078c33e0
27-
github.com/lightninglabs/taproot-assets/taprpc v1.0.10-0.20250925100956-c44e078c33e0
26+
github.com/lightninglabs/taproot-assets v0.7.0-rc1.0.20251014172227-e6ae082c0b4b
27+
github.com/lightninglabs/taproot-assets/taprpc v1.0.10-0.20251014172227-e6ae082c0b4b
2828
github.com/lightningnetwork/lnd v0.20.0-beta.rc1
2929
github.com/lightningnetwork/lnd/cert v1.2.2
3030
github.com/lightningnetwork/lnd/clock v1.1.1

go.sum

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1120,10 +1120,10 @@ github.com/lightninglabs/neutrino/cache v1.1.2 h1:C9DY/DAPaPxbFC+xNNEI/z1SJY9GS3
11201120
github.com/lightninglabs/neutrino/cache v1.1.2/go.mod h1:XJNcgdOw1LQnanGjw8Vj44CvguYA25IMKjWFZczwZuo=
11211121
github.com/lightninglabs/protobuf-go-hex-display v1.34.2-hex-display h1:w7FM5LH9Z6CpKxl13mS48idsu6F+cEZf0lkyiV+Dq9g=
11221122
github.com/lightninglabs/protobuf-go-hex-display v1.34.2-hex-display/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw=
1123-
github.com/lightninglabs/taproot-assets v0.7.0-rc1.0.20250925100956-c44e078c33e0 h1:NkPYeGOwPNITNQ9nLFJgLzD2Ig56S3NhD+NuHLV98nA=
1124-
github.com/lightninglabs/taproot-assets v0.7.0-rc1.0.20250925100956-c44e078c33e0/go.mod h1:qC9TBmn7gV+6LrDhacCe2DD0MnMbD1FgUzJ14LLb7E8=
1125-
github.com/lightninglabs/taproot-assets/taprpc v1.0.10-0.20250925100956-c44e078c33e0 h1:l4EQ6+oBbbPubipKhX1vLLwNWkTRgPOPqGjtKnPO9qM=
1126-
github.com/lightninglabs/taproot-assets/taprpc v1.0.10-0.20250925100956-c44e078c33e0/go.mod h1:ufuKxkMNdfRnv4IcnLw7ken69DcCUxO79WSpC8mIvdM=
1123+
github.com/lightninglabs/taproot-assets v0.7.0-rc1.0.20251014172227-e6ae082c0b4b h1:wXE4vhZlZGXLHzei+rj6lnWsCaxjJCfCAHJlcs3dZH4=
1124+
github.com/lightninglabs/taproot-assets v0.7.0-rc1.0.20251014172227-e6ae082c0b4b/go.mod h1:qC9TBmn7gV+6LrDhacCe2DD0MnMbD1FgUzJ14LLb7E8=
1125+
github.com/lightninglabs/taproot-assets/taprpc v1.0.10-0.20251014172227-e6ae082c0b4b h1:qT27GPShJpH3A/aK7VVi8Onn11GIjEnL/xbqbHMDz/U=
1126+
github.com/lightninglabs/taproot-assets/taprpc v1.0.10-0.20251014172227-e6ae082c0b4b/go.mod h1:ufuKxkMNdfRnv4IcnLw7ken69DcCUxO79WSpC8mIvdM=
11271127
github.com/lightningnetwork/lightning-onion v1.2.1-0.20240815225420-8b40adf04ab9 h1:6D3LrdagJweLLdFm1JNodZsBk6iU4TTsBBFLQ4yiXfI=
11281128
github.com/lightningnetwork/lightning-onion v1.2.1-0.20240815225420-8b40adf04ab9/go.mod h1:EDqJ3MuZIbMq0QI1czTIKDJ/GS8S14RXPwapHw8cw6w=
11291129
github.com/lightningnetwork/lnd v0.20.0-beta.rc1 h1:8Rm3/pcSLQI+tpCjKfYADfMjmEVFkrtoEom470siKRA=

sweepbatcher/presigned.go

Lines changed: 21 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import (
1212
"github.com/btcsuite/btcd/wire"
1313
"github.com/lightningnetwork/lnd/lntypes"
1414
"github.com/lightningnetwork/lnd/lnwallet/chainfee"
15+
"golang.org/x/sync/errgroup"
1516
)
1617

1718
// ensurePresigned checks that there is a presigned transaction spending the
@@ -371,6 +372,8 @@ func presign(ctx context.Context, presigner presigner, destAddr btcutil.Address,
371372
// Set LockTime to 0. It is not critical.
372373
const currentHeight = 0
373374

375+
eg, grCtx := errgroup.WithContext(ctx)
376+
374377
for fr := start; fr <= stop; fr = (fr * factorPPM) / 1_000_000 {
375378
// Construct an unsigned transaction for this fee rate.
376379
tx, _, feeForWeight, fee, err := constructUnsignedTx(
@@ -389,21 +392,31 @@ func presign(ctx context.Context, presigner presigner, destAddr btcutil.Address,
389392

390393
// Try to presign this transaction.
391394
const loadOnly = false
392-
_, err = presigner.SignTx(
393-
ctx, primarySweepID, tx, batchAmt, minRelayFeeRate, fr,
394-
loadOnly,
395-
)
396-
if err != nil {
397-
return fmt.Errorf("failed to presign unsigned tx %v "+
398-
"for feeRate %v: %w", tx.TxHash(), fr, err)
399-
}
395+
eg.Go(func() error {
396+
_, err := presigner.SignTx(
397+
grCtx, primarySweepID, tx, batchAmt,
398+
minRelayFeeRate, fr, loadOnly,
399+
)
400+
if err != nil {
401+
return fmt.Errorf("failed to presign unsigned "+
402+
"tx %v for feeRate %v: %w", tx.TxHash(),
403+
fr, err)
404+
}
405+
406+
return nil
407+
})
400408

401409
// If fee was clamped, stop here, because fee rate won't grow.
402410
if fee < feeForWeight {
403411
break
404412
}
405413
}
406414

415+
if err := eg.Wait(); err != nil {
416+
return fmt.Errorf("presigning of batch of primarySweepID %v "+
417+
"failed: %w", primarySweepID, err)
418+
}
419+
407420
return nil
408421
}
409422

sweepbatcher/presigned_test.go

Lines changed: 34 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package sweepbatcher
33
import (
44
"context"
55
"fmt"
6+
"sync"
67
"testing"
78

89
"github.com/btcsuite/btcd/btcutil"
@@ -630,6 +631,9 @@ type mockPresigner struct {
630631

631632
// failAt is optional index of a call at which it fails, 1 based.
632633
failAt int
634+
635+
// mu protects the state.
636+
mu sync.Mutex
633637
}
634638

635639
// SignTx memorizes the value of the output and fails if the number of
@@ -639,6 +643,9 @@ func (p *mockPresigner) SignTx(ctx context.Context,
639643
minRelayFee, feeRate chainfee.SatPerKWeight,
640644
loadOnly bool) (*wire.MsgTx, error) {
641645

646+
p.mu.Lock()
647+
defer p.mu.Unlock()
648+
642649
if ctx.Err() != nil {
643650
return nil, ctx.Err()
644651
}
@@ -1037,7 +1044,8 @@ func TestPresign(t *testing.T) {
10371044
},
10381045

10391046
{
1040-
name: "small amount => fewer steps until clamped",
1047+
name: "small amount => fewer steps until " +
1048+
"clamped",
10411049
presigner: &mockPresigner{},
10421050
primarySweepID: op1,
10431051
sweeps: []sweep{
@@ -1085,10 +1093,29 @@ func TestPresign(t *testing.T) {
10851093
destAddr: destAddr,
10861094
nextBlockFeeRate: chainfee.FeePerKwFloor,
10871095
minRelayFeeRate: chainfee.FeePerKwFloor,
1088-
wantErr: "for feeRate 363 sat/kw",
1096+
wantErr: "test error in SignTx",
10891097
},
10901098
}
10911099

1100+
type pair struct {
1101+
output btcutil.Amount
1102+
lockTime uint32
1103+
}
1104+
1105+
zip := func(outputs []btcutil.Amount, lockTimes []uint32) []pair {
1106+
require.Equal(t, len(outputs), len(lockTimes))
1107+
1108+
pairs := make([]pair, len(outputs))
1109+
for i, output := range outputs {
1110+
pairs[i] = pair{
1111+
output: output,
1112+
lockTime: lockTimes[i],
1113+
}
1114+
}
1115+
1116+
return pairs
1117+
}
1118+
10921119
for _, tc := range cases {
10931120
t.Run(tc.name, func(t *testing.T) {
10941121
err := presign(
@@ -1102,8 +1129,11 @@ func TestPresign(t *testing.T) {
11021129
} else {
11031130
require.NoError(t, err)
11041131
p := tc.presigner.(*mockPresigner)
1105-
require.Equal(t, tc.wantOutputs, p.outputs)
1106-
require.Equal(t, tc.wantLockTimes, p.lockTimes)
1132+
require.ElementsMatch(
1133+
t,
1134+
zip(tc.wantOutputs, tc.wantLockTimes),
1135+
zip(p.outputs, p.lockTimes),
1136+
)
11071137
}
11081138
})
11091139
}

0 commit comments

Comments
 (0)