git.gammaspectra.live/P2Pool/consensus@v0.0.0-20240403173234-a039820b20c9/p2pool/sidechain/share.go (about) 1 package sidechain 2 3 import ( 4 "git.gammaspectra.live/P2Pool/consensus/monero/address" 5 "git.gammaspectra.live/P2Pool/consensus/monero/crypto" 6 "git.gammaspectra.live/P2Pool/consensus/types" 7 "slices" 8 "sync" 9 ) 10 11 type Shares []*Share 12 13 func (s Shares) Index(addr address.PackedAddress) int { 14 return slices.IndexFunc(s, func(share *Share) bool { 15 return share.Address == addr 16 }) 17 } 18 19 // Sort Consensus way of sorting Shares 20 func (s Shares) Sort() { 21 slices.SortFunc(s, func(a *Share, b *Share) int { 22 // Fast tests first. Skips further checks 23 if diff := int(a.Address[address.PackedAddressSpend][crypto.PublicKeySize-1]) - int(b.Address[address.PackedAddressSpend][crypto.PublicKeySize-1]); diff != 0 { 24 return diff 25 } 26 if a.Address == b.Address { 27 return 0 28 } 29 30 return a.Address.ComparePacked(&b.Address) 31 }) 32 } 33 34 func (s Shares) Clone() (o Shares) { 35 o = make(Shares, len(s)) 36 preAllocatedStructs := make([]Share, len(s)) 37 for i := range s { 38 o[i] = &preAllocatedStructs[i] 39 o[i].Address = s[i].Address 40 o[i].Weight = s[i].Weight 41 } 42 return o 43 } 44 45 // Compact Merges duplicate Share entries based on Address 46 // len(s) must be greater than 0 47 func (s Shares) Compact() Shares { 48 if len(s) == 0 { 49 return s 50 } 51 52 // Sort shares based on address 53 s.Sort() 54 55 index := 0 56 57 for _, share := range s[1:] { 58 if s[index].Address == share.Address { 59 s[index].Weight = s[index].Weight.Add(share.Weight) 60 } else { 61 index++ 62 s[index].Address = share.Address 63 s[index].Weight = share.Weight 64 } 65 } 66 67 return s[:index+1] 68 } 69 70 type PreAllocatedSharesPool struct { 71 pool sync.Pool 72 } 73 74 func NewPreAllocatedSharesPool[T uint64 | int](n T) *PreAllocatedSharesPool { 75 p := &PreAllocatedSharesPool{} 76 p.pool.New = func() any { 77 return PreAllocateShares(n) 78 } 79 return p 80 } 81 82 func (p *PreAllocatedSharesPool) Get() Shares { 83 return p.pool.Get().(Shares) 84 } 85 86 func (p *PreAllocatedSharesPool) Put(s Shares) { 87 p.pool.Put(s) 88 } 89 90 func PreAllocateShares[T uint64 | int](n T) Shares { 91 preAllocatedShares := make(Shares, n) 92 // Preserve locality 93 preAllocatedStructs := make([]Share, n) 94 for i := range preAllocatedShares { 95 preAllocatedShares[i] = &preAllocatedStructs[i] 96 } 97 return preAllocatedShares 98 } 99 100 type Share struct { 101 Address address.PackedAddress 102 Weight types.Difficulty 103 }