forked from citp/BlockSci
-
Notifications
You must be signed in to change notification settings - Fork 4
Expand file tree
/
Copy pathaddress_state.hpp
More file actions
193 lines (160 loc) · 6.6 KB
/
Copy pathaddress_state.hpp
File metadata and controls
193 lines (160 loc) · 6.6 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
//
// address_state.hpp
// blocksci
//
// Created by Harry Kalodner on 9/10/17.
//
//
#ifndef address_state_hpp
#define address_state_hpp
#include "bloom_filter.hpp"
#include "hash_index_creator.hpp"
#include "parser_fwd.hpp"
#include "serializable_map.hpp"
#include <internal/bitcoin_uint256_hex.hpp>
#include <internal/dedup_address_info.hpp>
#include <cstdint>
#include <memory>
#include <tuple>
#include <type_traits>
#include <utility>
#include <vector>
enum class AddressLocation { MultiUseMap, LevelDb, NotFound };
template <blocksci::AddressType::Enum type> struct RawAddressInfo {
blocksci::uint160 hash;
AddressLocation location;
uint32_t addressNum;
};
template <blocksci::AddressType::Enum type> struct NonDudupAddressInfo {
uint32_t addressNum;
};
template <blocksci::DedupAddressType::Enum> inline constexpr int startingCount = 0;
template <> inline constexpr int startingCount<blocksci::DedupAddressType::PUBKEY> = 600'000'000;
template <> inline constexpr int startingCount<blocksci::DedupAddressType::SCRIPTHASH> = 100'000'000;
template <> inline constexpr int startingCount<blocksci::DedupAddressType::MULTISIG> = 100'000'000;
class AddressState {
static constexpr auto AddressFalsePositiveRate = .05;
template <blocksci::DedupAddressType::Enum scriptType>
class AddressMap : public SerializableMap<blocksci::uint160, uint32_t> {
public:
static constexpr auto type = scriptType;
AddressMap()
: SerializableMap(blocksci::uint160S("FFFFFFFFFFFFFFFFFFFF"), blocksci::uint160S("AAAAAAAAAAAAAAAAAA")) {
}
};
template <blocksci::DedupAddressType::Enum scriptType> class AddressBloomFilter : public BloomFilter {
public:
static constexpr auto type = scriptType;
AddressBloomFilter(const filesystem::path &path)
: BloomFilter(filesystem::path(path.str() + dedupAddressName(type)).str(), startingCount<scriptType>,
AddressFalsePositiveRate) {
}
};
template <blocksci::DedupAddressType::Enum scriptType>
using AddressBloomFilterPointer = std::unique_ptr<AddressBloomFilter<scriptType>>;
filesystem::path path;
HashIndexCreator &db;
using AddressMapTuple = blocksci::to_dedup_address_tuple_t<AddressMap>;
using AddressBloomFilterTuple = blocksci::to_dedup_address_tuple_t<AddressBloomFilterPointer>;
AddressMapTuple multiAddressMaps;
AddressBloomFilterTuple addressBloomFilters;
mutable long bloomNegativeCount = 0;
mutable long multiCount = 0;
mutable long dbCount = 0;
mutable long bloomFPCount = 0;
std::vector<uint32_t> scriptIndexes;
template <blocksci::AddressType::Enum type> void reloadBloomFilter(int sizeIncreaseRatio) {
auto &addressBloomFilter = std::get<AddressBloomFilterPointer<dedupType(type)>>(addressBloomFilters);
addressBloomFilter->reset(addressBloomFilter->getMaxItems() * sizeIncreaseRatio, addressBloomFilter->getFPRate());
db.clearAddressCache<blocksci::DedupAddressInfo<dedupType(type)>::reprType>();
RANGES_FOR(auto item, db.db.getAddressRange<blocksci::DedupAddressInfo<dedupType(type)>::reprType>()) {
addressBloomFilter->add(item.second);
}
}
void reloadBloomFilters() {
reloadBloomFilter<blocksci::AddressType::PUBKEYHASH>(1);
reloadBloomFilter<blocksci::AddressType::SCRIPTHASH>(1);
reloadBloomFilter<blocksci::AddressType::MULTISIG>(1);
}
public:
AddressState(filesystem::path path, HashIndexCreator &hashDb);
AddressState(const AddressState &) = delete;
AddressState &operator=(const AddressState &) = delete;
AddressState(AddressState &&) = delete;
AddressState &operator=(AddressState &&) = delete;
~AddressState();
template <blocksci::AddressType::Enum type,
std::enable_if_t<!blocksci::DedupAddressInfo<dedupType(type)>::equived, int> = 0>
NonDudupAddressInfo<type> findAddress(const ScriptOutputData<type> &) {
uint32_t scriptNum = getNewAddressIndex(dedupType(type));
return NonDudupAddressInfo<type>{scriptNum};
}
template <blocksci::AddressType::Enum type>
std::pair<uint32_t, bool> resolveAddress(const NonDudupAddressInfo<type> &addressInfo) {
return std::make_pair(addressInfo.addressNum, true);
}
template <blocksci::AddressType::Enum type,
std::enable_if_t<blocksci::DedupAddressInfo<dedupType(type)>::equived, int> = 0>
RawAddressInfo<type> findAddress(const ScriptOutputData<type> &data) {
auto hash = data.getHash();
auto &addressBloomFilter = std::get<AddressBloomFilterPointer<dedupType(type)>>(addressBloomFilters);
if (!addressBloomFilter->possiblyContains(hash)) {
// Address has definitely never been seen
bloomNegativeCount++;
return {hash, AddressLocation::NotFound, 0};
}
{
auto &multiAddressMap = std::get<AddressMap<dedupType(type)>>(multiAddressMaps);
auto it = multiAddressMap.find(hash);
if (it != multiAddressMap.end()) {
multiCount++;
return {hash, AddressLocation::MultiUseMap, it->second};
}
}
ranges::optional<uint32_t> destNum = db.lookupAddress<blocksci::DedupAddressInfo<dedupType(type)>::reprType>(hash);
if (destNum) {
dbCount++;
return {hash, AddressLocation::LevelDb, *destNum};
} else {
bloomFPCount++;
// We must have had a false positive
return {hash, AddressLocation::NotFound, 0};
}
}
// Bool is true if address is new
template <blocksci::AddressType::Enum type>
std::pair<uint32_t, bool> resolveAddress(const RawAddressInfo<type> &addressInfo) {
bool existingAddress = false;
switch (addressInfo.location) {
case AddressLocation::LevelDb: {
auto &multiAddressMap = std::get<AddressMap<dedupType(type)>>(multiAddressMaps);
multiAddressMap.add(addressInfo.hash, addressInfo.addressNum);
existingAddress = true;
break;
}
case AddressLocation::MultiUseMap: {
existingAddress = true;
break;
}
case AddressLocation::NotFound: {
existingAddress = false;
break;
}
}
uint32_t addressNum = addressInfo.addressNum;
if (!existingAddress) {
addressNum = getNewAddressIndex(dedupType(type));
auto &addressBloomFilter = std::get<AddressBloomFilterPointer<dedupType(type)>>(addressBloomFilters);
addressBloomFilter->add(addressInfo.hash);
db.addAddress<blocksci::DedupAddressInfo<dedupType(type)>::reprType>(addressInfo.hash, addressNum);
if (addressBloomFilter->isFull()) {
reloadBloomFilter<type>(2);
}
}
return std::make_pair(addressNum, !existingAddress);
}
uint32_t getNewAddressIndex(blocksci::DedupAddressType::Enum type);
// Called after resetting index
void reset(const blocksci::State &state);
};
#endif /* address_state_hpp */