github.com/mit-dci/lit@v0.0.0-20221102210550-8c3d3b49f2ce/portxo/sort.go (about) 1 package portxo 2 3 import ( 4 "bytes" 5 6 "github.com/mit-dci/lit/btcutil/chaincfg/chainhash" 7 ) 8 9 // txoSliceByBip69 is a sortable txo slice - same algo as txsort / BIP69 10 type TxoSliceByBip69 []*PorTxo 11 12 // Sort utxos just like txins -- Len, Less, Swap 13 func (s TxoSliceByBip69) Len() int { return len(s) } 14 func (s TxoSliceByBip69) Swap(i, j int) { s[i], s[j] = s[j], s[i] } 15 16 // outpoint sort; First input hash (reversed / rpc-style), then index. 17 func (s TxoSliceByBip69) Less(i, j int) bool { 18 // Input hashes are the same, so compare the index. 19 ihash := s[i].Op.Hash 20 jhash := s[j].Op.Hash 21 if ihash == jhash { 22 return s[i].Op.Index < s[j].Op.Index 23 } 24 // At this point, the hashes are not equal, so reverse them to 25 // big-endian and return the result of the comparison. 26 const hashSize = chainhash.HashSize 27 for b := 0; b < hashSize/2; b++ { 28 ihash[b], ihash[hashSize-1-b] = ihash[hashSize-1-b], ihash[b] 29 jhash[b], jhash[hashSize-1-b] = jhash[hashSize-1-b], jhash[b] 30 } 31 return bytes.Compare(ihash[:], jhash[:]) == -1 32 } 33 34 // txoSliceByAmt is a sortable txo slice. Sorts by value, and puts unconfirmed last. 35 // Also has sum functions for calculating balances 36 type TxoSliceByAmt []*PorTxo 37 38 func (s TxoSliceByAmt) Len() int { return len(s) } 39 func (s TxoSliceByAmt) Swap(i, j int) { s[i], s[j] = s[j], s[i] } 40 41 // height 0 means you are lesser 42 func (s TxoSliceByAmt) Less(i, j int) bool { 43 if s[i].Height == 0 && s[j].Height > 0 { 44 return true 45 } 46 if s[j].Height == 0 && s[i].Height > 0 { 47 return false 48 } 49 return s[i].Value < s[j].Value 50 } 51 52 func (s TxoSliceByAmt) Sum() int64 { 53 var total int64 54 for _, txo := range s { 55 total += txo.Value 56 } 57 return total 58 } 59 60 func (s TxoSliceByAmt) SumWitness(currentHeight int32) int64 { 61 var total int64 62 for _, txo := range s { 63 // check that it's witness, 64 // then make sure it's confirmed, and any timeouts have passed 65 if txo.Mode&FlagTxoWitness != 0 && 66 txo.Height > 0 && txo.Height+int32(txo.Seq) <= currentHeight { 67 total += txo.Value 68 } 69 } 70 return total 71 } 72 73 // KeyGenSortableSlice is a sortable slice of keygens. Shorter and lower numbers first. 74 type KeyGenSortableSlice []*KeyGen 75 76 func (s KeyGenSortableSlice) Len() int { return len(s) } 77 func (s KeyGenSortableSlice) Swap(i, j int) { s[i], s[j] = s[j], s[i] } 78 79 func (s KeyGenSortableSlice) Less(i, j int) bool { 80 // first - shorter path is less 81 if s[i].Depth < s[j].Depth { 82 return true 83 } 84 if s[i].Depth > s[j].Depth { 85 return false 86 } 87 88 // paths are the same, iterate and compare 89 for x := uint8(0); x < s[i].Depth; x++ { 90 if s[i].Step[x] < s[j].Step[x] { 91 return true 92 } 93 } 94 95 // if we got here, they're exactly the same 96 return false 97 }