pubkey_bins.rs 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202
  1. use solana_pubkey::Pubkey;
  2. #[derive(Debug)]
  3. pub struct PubkeyBinCalculator24 {
  4. // how many bits from the first 3 bytes to shift away to ignore when calculating bin
  5. shift_bits: u32,
  6. }
  7. impl PubkeyBinCalculator24 {
  8. const fn num_bits<T>() -> usize {
  9. std::mem::size_of::<T>() * 8
  10. }
  11. pub(crate) fn log_2(x: u32) -> u32 {
  12. assert!(x > 0);
  13. Self::num_bits::<u32>() as u32 - x.leading_zeros() - 1
  14. }
  15. pub fn new(bins: usize) -> Self {
  16. const MAX_BITS: u32 = 24;
  17. assert!(bins > 0);
  18. let max_plus_1 = 1 << MAX_BITS;
  19. assert!(bins <= max_plus_1);
  20. assert!(bins.is_power_of_two());
  21. let bits = Self::log_2(bins as u32);
  22. Self {
  23. shift_bits: MAX_BITS - bits,
  24. }
  25. }
  26. #[inline]
  27. pub fn bin_from_pubkey(&self, pubkey: &Pubkey) -> usize {
  28. let as_ref = pubkey.as_ref();
  29. ((as_ref[0] as usize) << 16 | (as_ref[1] as usize) << 8 | (as_ref[2] as usize))
  30. >> self.shift_bits
  31. }
  32. #[cfg(test)]
  33. pub(crate) fn lowest_pubkey_from_bin(&self, mut bin: usize, bins: usize) -> Pubkey {
  34. assert!(bin < bins);
  35. bin <<= self.shift_bits;
  36. let mut pubkey = Pubkey::from([0; 32]);
  37. pubkey.as_mut()[0] = ((bin / 256 / 256) & 0xff) as u8;
  38. pubkey.as_mut()[1] = ((bin / 256) & 0xff) as u8;
  39. pubkey.as_mut()[2] = (bin & 0xff) as u8;
  40. pubkey
  41. }
  42. }
  43. #[cfg(test)]
  44. pub mod tests {
  45. use super::*;
  46. #[test]
  47. fn test_pubkey_bins_log2() {
  48. assert_eq!(PubkeyBinCalculator24::num_bits::<u8>(), 8);
  49. assert_eq!(PubkeyBinCalculator24::num_bits::<u32>(), 32);
  50. for i in 0..32 {
  51. assert_eq!(PubkeyBinCalculator24::log_2(2u32.pow(i)), i);
  52. }
  53. }
  54. #[test]
  55. fn test_pubkey_bins() {
  56. for i in 0..=24 {
  57. let bins = 2u32.pow(i);
  58. let calc = PubkeyBinCalculator24::new(bins as usize);
  59. assert_eq!(calc.shift_bits, 24 - i, "i: {i}");
  60. for bin in 0..bins {
  61. assert_eq!(
  62. bin as usize,
  63. calc.bin_from_pubkey(&calc.lowest_pubkey_from_bin(bin as usize, bins as usize))
  64. );
  65. }
  66. }
  67. }
  68. #[test]
  69. fn test_pubkey_bins_pubkeys() {
  70. let mut pk = Pubkey::from([0; 32]);
  71. for i in 0..=8 {
  72. let bins = 2usize.pow(i);
  73. let calc = PubkeyBinCalculator24::new(bins);
  74. let shift_bits = calc.shift_bits - 16; // we are only dealing with first byte
  75. pk.as_mut()[0] = 0;
  76. assert_eq!(0, calc.bin_from_pubkey(&pk));
  77. pk.as_mut()[0] = 0xff;
  78. assert_eq!(bins - 1, calc.bin_from_pubkey(&pk));
  79. for bin in 0..bins {
  80. pk.as_mut()[0] = (bin << shift_bits) as u8;
  81. assert_eq!(
  82. bin,
  83. calc.bin_from_pubkey(&pk),
  84. "bin: {}/{}, shift_bits: {}, val: {}",
  85. bin,
  86. bins,
  87. shift_bits,
  88. pk.as_ref()[0]
  89. );
  90. if bin > 0 {
  91. pk.as_mut()[0] = ((bin << shift_bits) - 1) as u8;
  92. assert_eq!(bin - 1, calc.bin_from_pubkey(&pk));
  93. }
  94. }
  95. }
  96. for i in 9..=16 {
  97. let mut pk = Pubkey::from([0; 32]);
  98. let bins = 2usize.pow(i);
  99. let calc = PubkeyBinCalculator24::new(bins);
  100. let shift_bits = calc.shift_bits - 8;
  101. pk.as_mut()[1] = 0;
  102. assert_eq!(0, calc.bin_from_pubkey(&pk));
  103. pk.as_mut()[0] = 0xff;
  104. pk.as_mut()[1] = 0xff;
  105. assert_eq!(bins - 1, calc.bin_from_pubkey(&pk));
  106. let mut pk = Pubkey::from([0; 32]);
  107. for bin in 0..bins {
  108. let mut target = (bin << shift_bits) as u16;
  109. pk.as_mut()[0] = (target / 256) as u8;
  110. pk.as_mut()[1] = (target % 256) as u8;
  111. assert_eq!(
  112. bin,
  113. calc.bin_from_pubkey(&pk),
  114. "bin: {}/{}, shift_bits: {}, val: {}",
  115. bin,
  116. bins,
  117. shift_bits,
  118. pk.as_ref()[0]
  119. );
  120. if bin > 0 {
  121. target -= 1;
  122. pk.as_mut()[0] = (target / 256) as u8;
  123. pk.as_mut()[1] = (target % 256) as u8;
  124. assert_eq!(bin - 1, calc.bin_from_pubkey(&pk));
  125. }
  126. }
  127. }
  128. for i in 17..=24 {
  129. let mut pk = Pubkey::from([0; 32]);
  130. let bins = 2usize.pow(i);
  131. let calc = PubkeyBinCalculator24::new(bins);
  132. let shift_bits = calc.shift_bits;
  133. pk.as_mut()[1] = 0;
  134. assert_eq!(0, calc.bin_from_pubkey(&pk));
  135. pk.as_mut()[0] = 0xff;
  136. pk.as_mut()[1] = 0xff;
  137. pk.as_mut()[2] = 0xff;
  138. assert_eq!(bins - 1, calc.bin_from_pubkey(&pk));
  139. let mut pk = Pubkey::from([0; 32]);
  140. for bin in 0..bins {
  141. let mut target = (bin << shift_bits) as u32;
  142. pk.as_mut()[0] = (target / 256 / 256) as u8;
  143. pk.as_mut()[1] = ((target / 256) % 256) as u8;
  144. pk.as_mut()[2] = (target % 256) as u8;
  145. assert_eq!(
  146. bin,
  147. calc.bin_from_pubkey(&pk),
  148. "bin: {}/{}, shift_bits: {}, val: {:?}",
  149. bin,
  150. bins,
  151. shift_bits,
  152. &pk.as_ref()[0..3],
  153. );
  154. if bin > 0 {
  155. target -= 1;
  156. pk.as_mut()[0] = (target / 256 / 256) as u8;
  157. pk.as_mut()[1] = ((target / 256) % 256) as u8;
  158. pk.as_mut()[2] = (target % 256) as u8;
  159. assert_eq!(bin - 1, calc.bin_from_pubkey(&pk));
  160. }
  161. }
  162. }
  163. }
  164. #[test]
  165. #[should_panic(expected = "bins.is_power_of_two()")]
  166. fn test_pubkey_bins_illegal_bins3() {
  167. PubkeyBinCalculator24::new(3);
  168. }
  169. #[test]
  170. #[should_panic(expected = "bins <= max_plus_1")]
  171. fn test_pubkey_bins_illegal_bins2() {
  172. PubkeyBinCalculator24::new(65536 * 256 + 1);
  173. }
  174. #[test]
  175. #[should_panic(expected = "bins > 0")]
  176. fn test_pubkey_bins_illegal_bins() {
  177. PubkeyBinCalculator24::new(0);
  178. }
  179. }