mirror of
https://github.com/monero-project/monero.git
synced 2024-12-26 19:19:26 -05:00
blockchain_blackball: also blackball N N-sized duplicate rings
These are unlikely to happen at random, but Wijaya et al made a paper about it, so people might try it on purpose now (and it turns out it's easy to add anyway)
This commit is contained in:
parent
66f4700f57
commit
e09710f76e
@ -77,6 +77,15 @@ namespace std
|
|||||||
return reinterpret_cast<const std::size_t &>(h);
|
return reinterpret_cast<const std::size_t &>(h);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
template<> struct hash<std::vector<uint64_t>>
|
||||||
|
{
|
||||||
|
size_t operator()(const std::vector<uint64_t> &v) const
|
||||||
|
{
|
||||||
|
crypto::hash h;
|
||||||
|
crypto::cn_fast_hash(v.data(), v.size() * sizeof(uint64_t), h);
|
||||||
|
return reinterpret_cast<const std::size_t &>(h);
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
struct blackball_state_t
|
struct blackball_state_t
|
||||||
@ -85,6 +94,7 @@ struct blackball_state_t
|
|||||||
std::unordered_map<output_data, std::unordered_set<crypto::key_image>> outputs;
|
std::unordered_map<output_data, std::unordered_set<crypto::key_image>> outputs;
|
||||||
std::unordered_map<std::string, uint64_t> processed_heights;
|
std::unordered_map<std::string, uint64_t> processed_heights;
|
||||||
std::unordered_set<output_data> spent;
|
std::unordered_set<output_data> spent;
|
||||||
|
std::unordered_map<std::vector<uint64_t>, size_t> ring_instances;
|
||||||
|
|
||||||
template <typename t_archive> void serialize(t_archive &a, const unsigned int ver)
|
template <typename t_archive> void serialize(t_archive &a, const unsigned int ver)
|
||||||
{
|
{
|
||||||
@ -92,9 +102,12 @@ struct blackball_state_t
|
|||||||
a & outputs;
|
a & outputs;
|
||||||
a & processed_heights;
|
a & processed_heights;
|
||||||
a & spent;
|
a & spent;
|
||||||
|
if (ver < 1)
|
||||||
|
return;
|
||||||
|
a & ring_instances;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
BOOST_CLASS_VERSION(blackball_state_t, 0)
|
BOOST_CLASS_VERSION(blackball_state_t, 1)
|
||||||
|
|
||||||
static std::string get_default_db_path()
|
static std::string get_default_db_path()
|
||||||
{
|
{
|
||||||
@ -181,6 +194,24 @@ static bool for_all_transactions(const std::string &filename, uint64_t &start_id
|
|||||||
return fret;
|
return fret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static std::vector<uint64_t> canonicalize(const std::vector<uint64_t> &v)
|
||||||
|
{
|
||||||
|
std::vector<uint64_t> c;
|
||||||
|
c.reserve(v.size());
|
||||||
|
c.push_back(v[0]);
|
||||||
|
for (size_t n = 1; n < v.size(); ++n)
|
||||||
|
{
|
||||||
|
if (v[n] != 0)
|
||||||
|
c.push_back(v[n]);
|
||||||
|
}
|
||||||
|
if (c.size() < v.size())
|
||||||
|
{
|
||||||
|
MINFO("Ring has duplicate member(s): " <<
|
||||||
|
boost::join(v | boost::adaptors::transformed([](uint64_t out){return std::to_string(out);}), " "));
|
||||||
|
}
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
int main(int argc, char* argv[])
|
int main(int argc, char* argv[])
|
||||||
{
|
{
|
||||||
TRY_ENTRY();
|
TRY_ENTRY();
|
||||||
@ -396,15 +427,27 @@ int main(int argc, char* argv[])
|
|||||||
for (uint64_t out: absolute)
|
for (uint64_t out: absolute)
|
||||||
state.outputs[output_data(txin.amount, out)].insert(txin.k_image);
|
state.outputs[output_data(txin.amount, out)].insert(txin.k_image);
|
||||||
|
|
||||||
std::vector<uint64_t> new_ring = txin.key_offsets;
|
std::vector<uint64_t> new_ring = canonicalize(txin.key_offsets);
|
||||||
const uint32_t ring_size = txin.key_offsets.size();
|
const uint32_t ring_size = txin.key_offsets.size();
|
||||||
|
state.ring_instances[new_ring] += 1;
|
||||||
if (ring_size == 1)
|
if (ring_size == 1)
|
||||||
{
|
{
|
||||||
const crypto::public_key pkey = core_storage[n]->get_output_key(txin.amount, txin.key_offsets[0]);
|
const crypto::public_key pkey = core_storage[n]->get_output_key(txin.amount, absolute[0]);
|
||||||
MINFO("Blackballing output " << pkey << ", due to being used in a 1-ring");
|
MINFO("Blackballing output " << pkey << ", due to being used in a 1-ring");
|
||||||
ringdb.blackball(pkey);
|
ringdb.blackball(pkey);
|
||||||
newly_spent.insert(output_data(txin.amount, txin.key_offsets[0]));
|
newly_spent.insert(output_data(txin.amount, absolute[0]));
|
||||||
state.spent.insert(output_data(txin.amount, txin.key_offsets[0]));
|
state.spent.insert(output_data(txin.amount, absolute[0]));
|
||||||
|
}
|
||||||
|
else if (state.ring_instances[new_ring] == new_ring.size())
|
||||||
|
{
|
||||||
|
for (size_t o = 0; o < new_ring.size(); ++o)
|
||||||
|
{
|
||||||
|
const crypto::public_key pkey = core_storage[n]->get_output_key(txin.amount, absolute[o]);
|
||||||
|
MINFO("Blackballing output " << pkey << ", due to being used in " << new_ring.size() << " identical " << new_ring.size() << "-rings");
|
||||||
|
ringdb.blackball(pkey);
|
||||||
|
newly_spent.insert(output_data(txin.amount, absolute[o]));
|
||||||
|
state.spent.insert(output_data(txin.amount, absolute[o]));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if (state.relative_rings.find(txin.k_image) != state.relative_rings.end())
|
else if (state.relative_rings.find(txin.k_image) != state.relative_rings.end())
|
||||||
{
|
{
|
||||||
|
Loading…
Reference in New Issue
Block a user