Skip to content

Commit ab47bcf

Browse files
committed
Merge branch 'coincontrol_utxo_sort'
2 parents 76e49b4 + 6e60ac7 commit ab47bcf

File tree

1 file changed

+46
-12
lines changed

1 file changed

+46
-12
lines changed

backend/coins/btc/account.go

Lines changed: 46 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,6 @@ import (
4444
"github.com/btcsuite/btcd/btcutil"
4545
"github.com/btcsuite/btcd/btcutil/hdkeychain"
4646
"github.com/btcsuite/btcd/chaincfg"
47-
"github.com/btcsuite/btcd/chaincfg/chainhash"
4847
"github.com/btcsuite/btcd/wire"
4948
"github.com/sirupsen/logrus"
5049
)
@@ -772,19 +771,55 @@ func (account *Account) CanVerifyAddresses() (bool, bool, error) {
772771
return keystore.CanVerifyAddress(account.Coin())
773772
}
774773

775-
type byValue struct {
776-
outputs []*SpendableOutput
774+
// addressOutputsSum holds the address and sum of outputs for that address.
775+
type addressOutputsSum struct {
776+
address string
777+
sum int64
777778
}
778779

779-
func (p *byValue) Len() int { return len(p.outputs) }
780-
func (p *byValue) Less(i, j int) bool {
781-
if p.outputs[i].TxOut.Value == p.outputs[j].TxOut.Value {
782-
// Secondary sort to make coin selection deterministic.
783-
return chainhash.HashH(p.outputs[i].TxOut.PkScript).String() < chainhash.HashH(p.outputs[j].TxOut.PkScript).String()
780+
// sortByAddresses sorts the outputs by grouping them based on their addresses and then sorting each group
781+
// from outputs with the biggest amounts to those with the lowest amounts.
782+
func sortByAddresses(result []*SpendableOutput) []*SpendableOutput {
783+
// Create a map to store outputs grouped by address
784+
grouped := make(map[string][]*SpendableOutput)
785+
786+
// Group outputs by address
787+
for _, output := range result {
788+
grouped[output.Address.String()] = append(grouped[output.Address.String()], output)
784789
}
785-
return p.outputs[i].TxOut.Value < p.outputs[j].TxOut.Value
790+
791+
// Create a slice to store the sums of outputs and addresses
792+
sums := make([]addressOutputsSum, 0, len(grouped))
793+
794+
// Calculate sums of values for each group and store in the sums slice
795+
for address, outputs := range grouped {
796+
var sum int64
797+
for _, output := range outputs {
798+
sum += output.TxOut.Value
799+
}
800+
sums = append(sums, addressOutputsSum{
801+
address: address,
802+
sum: sum,
803+
})
804+
}
805+
806+
// Sort the sums slice by the sum of values in descending order
807+
sort.Slice(sums, func(i, j int) bool {
808+
return sums[i].sum > sums[j].sum
809+
})
810+
811+
// Create a new result grouped by addresses, sort them by value
812+
newResult := make([]*SpendableOutput, 0, len(result))
813+
for _, s := range sums {
814+
outputs := grouped[s.address]
815+
sort.Slice(outputs, func(i, j int) bool {
816+
return outputs[i].Value > outputs[j].Value
817+
})
818+
newResult = append(newResult, outputs...)
819+
}
820+
821+
return newResult
786822
}
787-
func (p *byValue) Swap(i, j int) { p.outputs[i], p.outputs[j] = p.outputs[j], p.outputs[i] }
788823

789824
// SpendableOutput is an unspent coin.
790825
type SpendableOutput struct {
@@ -811,8 +846,7 @@ func (account *Account) SpendableOutputs() []*SpendableOutput {
811846
Address: account.getAddress(blockchain.NewScriptHashHex(txOut.TxOut.PkScript)),
812847
})
813848
}
814-
sort.Sort(sort.Reverse(&byValue{result}))
815-
return result
849+
return sortByAddresses(result)
816850
}
817851

818852
// VerifyExtendedPublicKey verifies an account's public key. Returns false, nil if no secure output

0 commit comments

Comments
 (0)