Bitcoin ABC 0.33.5
P2P Digital Currency
shortidprocessor.h
Go to the documentation of this file.
1// Copyright (c) 2022 The Bitcoin developers
2// Distributed under the MIT software license, see the accompanying
3// file COPYING or http://www.opensource.org/licenses/mit-license.php.
4
5#ifndef BITCOIN_SHORTIDPROCESSOR_H
6#define BITCOIN_SHORTIDPROCESSOR_H
7
8#include <cassert>
9#include <cstddef>
10#include <cstdint>
11#include <unordered_map>
12#include <utility>
13#include <vector>
14
15template <typename PrefilledItemType, typename Adapter, typename ItemCompare>
16class ShortIdProcessor : Adapter, ItemCompare {
17 using ItemType = typename std::remove_reference<
18 decltype(std::declval<Adapter &>().getItem(
19 std::declval<PrefilledItemType &>()))>::type;
20
21 bool evenlyDistributed = true;
22 bool shortIdCollision = false;
23 bool outOfBoundIndex = false;
24
25 std::vector<ItemType> itemsAvailable;
26 std::vector<bool> haveItem;
27 std::unordered_map<uint64_t, uint32_t> shortIdIndexMap;
28
29 int addItem(uint32_t index, const ItemType &item) {
30 if (index >= itemsAvailable.size()) {
31 outOfBoundIndex = true;
32 return 0;
33 }
34
35 if (!haveItem[index]) {
36 haveItem[index] = true;
37 itemsAvailable[index] = item;
38 return 1;
39 }
40
41 // If we find two items that collides for the same index, just request
42 // this index. This should be rare enough that the extra bandwidth
43 // doesn't matter. Due to the way the compact messages are encoded, this
44 // can only occur in the event of a shortid collision.
45 if (itemsAvailable[index] && !(*this)(itemsAvailable[index], item)) {
46 itemsAvailable[index] = ItemType();
47 return -1;
48 }
49
50 return 0;
51 }
52
53public:
54 ShortIdProcessor(const std::vector<PrefilledItemType> &prefilledItems,
55 const std::vector<uint64_t> &shortids,
56 size_t maxShortIdPerBucket)
57 : itemsAvailable(prefilledItems.size() + shortids.size()),
58 haveItem(prefilledItems.size() + shortids.size()),
59 shortIdIndexMap(shortids.size()) {
60 for (const auto &prefilledItem : prefilledItems) {
61 addItem(Adapter::getIndex(prefilledItem),
62 Adapter::getItem(prefilledItem));
63 }
64
65 uint32_t index_offset = 0;
66 for (size_t i = 0; i < shortids.size(); i++) {
67 while (itemsAvailable[i + index_offset]) {
68 index_offset++;
69 }
70
71 shortIdIndexMap[shortids[i]] = i + index_offset;
72
73 // Because well-formed compact messages will have a (relatively)
74 // uniform distribution of short IDs, any highly-uneven distribution
75 // of elements can be safely treated as an error.
76 if (shortIdIndexMap.bucket_size(shortIdIndexMap.bucket(
77 shortids[i])) > maxShortIdPerBucket) {
78 evenlyDistributed = false;
79 }
80 }
81
82 shortIdCollision = shortIdIndexMap.size() != shortids.size();
83 }
84
86 bool isEvenlyDistributed() const { return evenlyDistributed; }
87 bool hasShortIdCollision() const { return shortIdCollision; }
88 bool hasOutOfBoundIndex() const { return outOfBoundIndex; }
89
91 size_t getItemCount() const { return itemsAvailable.size(); }
93 size_t getShortIdCount() const { return shortIdIndexMap.size(); }
94
108 int matchKnownItem(uint64_t shortid, const ItemType &item) {
109 auto idit = shortIdIndexMap.find(shortid);
110 if (idit == shortIdIndexMap.end()) {
111 return 0;
112 }
113
114 return addItem(idit->second, item);
115 }
116
117 const ItemType &getItem(size_t index) const {
118 assert(index < itemsAvailable.size());
119
120 return itemsAvailable[index];
121 }
122};
123
124#endif // BITCOIN_SHORTIDPROCESSOR_H
int addItem(uint32_t index, const ItemType &item)
const ItemType & getItem(size_t index) const
bool isEvenlyDistributed() const
Status accessors.
typename std::remove_reference< decltype(std::declval< Adapter & >().getItem(std::declval< PrefilledItemType & >()))>::type ItemType
size_t getItemCount() const
Total item count.
int matchKnownItem(uint64_t shortid, const ItemType &item)
Attempts to add a known item by matching its shortid with the supplied ones.
std::unordered_map< uint64_t, uint32_t > shortIdIndexMap
ShortIdProcessor(const std::vector< PrefilledItemType > &prefilledItems, const std::vector< uint64_t > &shortids, size_t maxShortIdPerBucket)
size_t getShortIdCount() const
Unique shortid count.
std::vector< ItemType > itemsAvailable
bool hasShortIdCollision() const
std::vector< bool > haveItem
bool hasOutOfBoundIndex() const
assert(!tx.IsCoinBase())