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  }