Skip to content

Commit

Permalink
client/{btc,dcr,zec}: Use binary search for maxOrder loop (#2634)
Browse files Browse the repository at this point in the history
* use binary search for maxOrder loop

Signed-off-by: Philemon Ukane <[email protected]>
  • Loading branch information
ukane-philemon authored Jan 11, 2024
1 parent df94dbe commit d74aa68
Show file tree
Hide file tree
Showing 3 changed files with 52 additions and 32 deletions.
29 changes: 18 additions & 11 deletions client/asset/btc/btc.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import (
"net/http"
"os"
"path/filepath"
"sort"
"strconv"
"strings"
"sync"
Expand Down Expand Up @@ -1782,21 +1783,27 @@ func (btc *baseWallet) maxOrder(lotSize, feeSuggestion, maxFeeRate uint64) (utxo
if err != nil {
return nil, nil, fmt.Errorf("error parsing unspent outputs: %w", err)
}

// Start by attempting max lots with a basic fee.
basicFee := btc.initTxSize * maxFeeRate
lots := avail / (lotSize + basicFee)
for lots > 0 {
est, _, _, err := btc.estimateSwap(lots, lotSize, feeSuggestion, maxFeeRate,
utxos, true, 1.0)
maxLotsInt := int(avail / (lotSize + basicFee))
oneLotTooMany := sort.Search(maxLotsInt+1, func(lots int) bool {
_, _, _, err = btc.estimateSwap(uint64(lots), lotSize, feeSuggestion, maxFeeRate, utxos, true, 1.0)
// The only failure mode of estimateSwap -> btc.fund is when there is
// not enough funds, so if an error is encountered, count down the lots
// and repeat until we have enough.
if err != nil {
lots--
continue
}
return utxos, est, nil
// not enough funds.
return err != nil
})

maxLots := uint64(oneLotTooMany - 1)
if oneLotTooMany == 0 {
maxLots = 0
}

if maxLots > 0 {
est, _, _, err = btc.estimateSwap(maxLots, lotSize, feeSuggestion, maxFeeRate, utxos, true, 1.0)
return utxos, est, err
}

return utxos, &asset.SwapEstimate{}, nil
}

Expand Down
27 changes: 17 additions & 10 deletions client/asset/dcr/dcr.go
Original file line number Diff line number Diff line change
Expand Up @@ -1281,21 +1281,28 @@ func (dcr *ExchangeWallet) maxOrder(lotSize, feeSuggestion, maxFeeRate uint64) (

// Start by attempting max lots with a basic fee.
basicFee := dexdcr.InitTxSize * maxFeeRate
lots := avail / (lotSize + basicFee)
// NOTE: Split tx is an order-time option. The max order is generally
// attainable when split is used, regardless of whether they choose it on
// the order form. Allow the split for max order purposes.
trySplitTx := true
for lots > 0 {
est, _, _, err := dcr.estimateSwap(lots, lotSize, feeSuggestion, maxFeeRate, utxos, trySplitTx, 1.0)

// Find the max lots we can fund.
maxLotsInt := int(avail / (lotSize + basicFee))
oneLotTooMany := sort.Search(maxLotsInt+1, func(lots int) bool {
_, _, _, err = dcr.estimateSwap(uint64(lots), lotSize, feeSuggestion, maxFeeRate, utxos, trySplitTx, 1.0)
// The only failure mode of estimateSwap -> dcr.fund is when there is
// not enough funds, so if an error is encountered, count down the lots
// and repeat until we have enough.
if err != nil {
lots--
continue
}
return utxos, est, nil
// not enough funds.
return err != nil
})

maxLots := uint64(oneLotTooMany - 1)
if oneLotTooMany == 0 {
maxLots = 0
}

if maxLots > 0 {
est, _, _, err = dcr.estimateSwap(maxLots, lotSize, feeSuggestion, maxFeeRate, utxos, trySplitTx, 1.0)
return utxos, est, err
}

return nil, &asset.SwapEstimate{}, nil
Expand Down
28 changes: 17 additions & 11 deletions client/asset/zec/zec.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (
"fmt"
"math"
"path/filepath"
"sort"
"strings"
"sync"
"sync/atomic"
Expand Down Expand Up @@ -943,18 +944,23 @@ func (w *zecWallet) maxOrder(lotSize, feeSuggestion, maxFeeRate uint64) (utxos [

avail += bals.orchard.avail

// Start by attempting max lots with a basic fee.
lots := avail / lotSize
for lots > 0 {
est, _, _, err := w.estimateSwap(lots, lotSize, feeSuggestion, maxFeeRate, utxos, bals.orchard, true)
// Find the max lots we can fund.
maxLotsInt := int(avail / lotSize)
oneLotTooMany := sort.Search(maxLotsInt+1, func(lots int) bool {
_, _, _, err = w.estimateSwap(uint64(lots), lotSize, feeSuggestion, maxFeeRate, utxos, bals.orchard, true)
// The only failure mode of estimateSwap -> zec.fund is when there is
// not enough funds, so if an error is encountered, count down the lots
// and repeat until we have enough.
if err != nil {
lots--
continue
}
return utxos, bals, est, nil
// not enough funds.
return err != nil
})

maxLots := uint64(oneLotTooMany - 1)
if oneLotTooMany == 0 {
maxLots = 0
}

if maxLots > 0 {
est, _, _, err = w.estimateSwap(maxLots, lotSize, feeSuggestion, maxFeeRate, utxos, bals.orchard, true)
return utxos, bals, est, err
}

return utxos, bals, &asset.SwapEstimate{}, nil
Expand Down

0 comments on commit d74aa68

Please sign in to comment.