Files
thehub/libs/p2p/PrivacySegment.cpp
T

262 lines
7.3 KiB
C++
Raw Permalink Normal View History

2020-04-17 19:33:06 +02:00
/*
* This file is part of the Flowee project
2024-01-04 17:02:37 +01:00
* Copyright (C) 2020-2024 Tom Zander <tom@flowee.org>
2020-04-17 19:33:06 +02:00
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "PrivacySegment.h"
#include "Peer.h"
2020-04-17 19:33:06 +02:00
#include "DataListenerInterface.h"
2021-01-05 22:05:25 +01:00
#include <crypto/common.h>
2020-04-17 19:33:06 +02:00
#include <streaming/P2PBuilder.h>
#include <streaming/P2PParser.h>
#include <primitives/Tx.h>
2023-11-24 18:01:36 +01:00
#include <primitives/PublicKey.h>
2020-04-17 19:33:06 +02:00
#include <cashaddr.h>
#include <base58.h>
2020-05-18 19:49:24 +02:00
#include <random.h>
2020-04-17 19:33:06 +02:00
PrivacySegment::PrivacySegment(uint16_t id, DataListenerInterface *parent)
: m_segmentId(id),
2020-05-18 19:49:24 +02:00
m_bloom(10000, 0.001, GetRandInt(INT_MAX), BLOOM_UPDATE_ALL),
2020-04-17 19:33:06 +02:00
m_parent(parent)
{
assert(m_segmentId > 0); // zero is not allowed, that is the 'unset' value elsewhere
}
uint16_t PrivacySegment::segmentId() const
{
return m_segmentId;
}
2020-05-18 09:35:51 +02:00
PrivacySegment::FilterLock PrivacySegment::clearFilter()
{
2023-04-01 22:59:34 +02:00
std::unique_lock<std::recursive_mutex> mutexLock(m_lock);
m_filterChangedHeight = m_merkleBlockHeight;
2020-05-18 09:35:51 +02:00
FilterLock lock(this);
m_bloom.clear();
if (m_filterShouldFollowWithMemoolCall)
lock.addMempoolRequest();
2020-05-18 09:35:51 +02:00
return lock;
}
2020-06-07 13:56:55 +02:00
void PrivacySegment::addToFilter(const uint256 &prevHash, int outIndex)
2020-04-17 19:33:06 +02:00
{
2020-06-07 13:56:55 +02:00
assert(outIndex >= 0);
2020-05-18 09:35:51 +02:00
std::unique_lock<std::recursive_mutex> lock(m_lock);
2020-04-17 19:33:06 +02:00
std::vector<unsigned char> data;
data.resize(36);
memcpy(data.data(), prevHash.begin(), 32);
WriteLE32(data.data() + 32, outIndex);
m_bloom.insert(data);
}
void PrivacySegment::addToFilter(const std::string &address, int blockHeight)
{
2020-05-18 09:35:51 +02:00
std::unique_lock<std::recursive_mutex> lock(m_lock);
2020-04-17 19:33:06 +02:00
CashAddress::Content c = CashAddress::decodeCashAddrContent(address, "bitcoincash");
if (c.hash.empty()) {
CBase58Data old; // legacy address encoding
if (old.SetString(address)) {
c.hash = old.data();
if (!old.isMainnetPkh() && !old.isMainnetSh()) {
logCritical() << "PrivacySegment::addToFilter: Address could not be parsed";
return;
}
}
}
m_bloom.insert(c.hash);
if (blockHeight > 0) {
if (m_firstBlock == -1)
m_firstBlock = blockHeight;
else
m_firstBlock = std::min(m_firstBlock, blockHeight);
}
m_filterChangedHeight = m_merkleBlockHeight;
2020-04-17 19:33:06 +02:00
}
2022-07-06 21:52:47 +02:00
void PrivacySegment::addKeyToFilter(const KeyId &address, int blockHeight)
{
2020-05-18 09:35:51 +02:00
std::unique_lock<std::recursive_mutex> lock(m_lock);
m_bloom.insert(std::vector<uint8_t>(address.begin(), address.end()));
if (blockHeight > 0) {
if (m_firstBlock == -1)
m_firstBlock = blockHeight;
else
m_firstBlock = std::min(m_firstBlock, blockHeight);
}
m_filterChangedHeight = m_merkleBlockHeight;
}
2023-12-21 15:13:56 +01:00
Streaming::ConstBuffer PrivacySegment::writeFilter(const std::shared_ptr<Streaming::BufferPool> &pool) const
2020-04-17 19:33:06 +02:00
{
2020-05-18 09:35:51 +02:00
std::unique_lock<std::recursive_mutex> lock(m_lock);
2023-12-21 15:13:56 +01:00
pool->reserve(m_bloom.GetSerializeSize(0, 0));
2020-04-17 19:33:06 +02:00
Streaming::P2PBuilder builder(pool);
m_bloom.store(builder);
return builder.buffer();
}
int PrivacySegment::firstBlock() const
{
2020-05-18 09:35:51 +02:00
std::unique_lock<std::recursive_mutex> lock(m_lock);
2020-04-17 19:33:06 +02:00
return m_firstBlock;
}
void PrivacySegment::blockSynched(int height)
{
bool forward = false;
{
std::unique_lock<std::recursive_mutex> lock(m_lock);
if (height <= m_merkleBlockHeight) {
m_softMerkleBlockHeight = height;
} else {
m_merkleBlockHeight = height;
forward = true;
}
}
// avoid deadlocks in wallet / privacysegment interaction and do this outside of our locks.
if (forward) {
2020-10-17 17:25:05 +02:00
assert(m_parent);
m_parent->setLastSynchedBlockHeight(height);
}
2020-04-17 19:33:06 +02:00
}
int PrivacySegment::lastBlockSynched() const
{
2020-05-18 09:35:51 +02:00
std::unique_lock<std::recursive_mutex> lock(m_lock);
2020-04-17 19:33:06 +02:00
if (m_merkleBlockHeight == -1)
return m_firstBlock - 1;
return m_merkleBlockHeight;
}
int PrivacySegment::backupSyncHeight() const
{
2020-05-18 09:35:51 +02:00
std::unique_lock<std::recursive_mutex> lock(m_lock);
2020-04-17 19:33:06 +02:00
if (m_softMerkleBlockHeight == -1)
return m_firstBlock - 1;
return m_softMerkleBlockHeight;
}
void PrivacySegment::newTransactions(const BlockHeader &header, int blockHeight, const std::deque<Tx> &blockTransactions)
2020-04-17 19:33:06 +02:00
{
/*
* Notice that the transactions match hit our filter, that doesn't mean it actually matched the
2020-04-17 19:33:06 +02:00
* address or output that the wallet owns.
* The wallet should thus test this and make sure that our filter is updated continuesly
* with new outputs and replaced with a new filter when many outputs are already spent (which
* we then want to push to peers to avoid them sending us some false-positives).
*/
2023-04-04 13:38:51 +02:00
m_parent->newTransactions(header.createHash(), blockHeight, blockTransactions);
2020-04-17 19:33:06 +02:00
}
void PrivacySegment::newTransaction(const Tx &tx)
{
m_parent->newTransaction(tx);
}
int PrivacySegment::filterChangedHeight() const
{
2020-05-18 09:35:51 +02:00
std::unique_lock<std::recursive_mutex> lock(m_lock);
2020-04-17 19:33:06 +02:00
return m_filterChangedHeight;
}
const CBloomFilter &PrivacySegment::bloomFilter() const
2020-04-17 19:33:06 +02:00
{
2020-05-18 09:35:51 +02:00
std::unique_lock<std::recursive_mutex> lock(m_lock);
2020-04-17 19:33:06 +02:00
return m_bloom;
}
2020-05-18 09:35:51 +02:00
2024-01-04 17:02:37 +01:00
void PrivacySegment::addPeer(const std::shared_ptr<Peer> &peer)
2020-05-18 09:35:51 +02:00
{
2024-01-04 17:02:37 +01:00
assert(peer.get());
2020-05-18 09:35:51 +02:00
std::unique_lock<std::recursive_mutex> lock(m_lock);
2024-01-04 17:02:37 +01:00
for (auto iter = m_peers.begin(); iter != m_peers.end(); ++iter) {
if (iter->lock() == peer)
return;
}
m_peers.push_back(peer);
2020-05-18 09:35:51 +02:00
}
void PrivacySegment::removePeer(Peer *peer)
2020-05-18 09:35:51 +02:00
{
2024-01-04 17:02:37 +01:00
assert(peer);
2020-05-18 09:35:51 +02:00
std::unique_lock<std::recursive_mutex> lock(m_lock);
2024-01-04 17:02:37 +01:00
for (auto iter = m_peers.begin(); iter != m_peers.end(); ++iter) {
if (iter->lock().get() == peer) {
m_peers.erase(iter);
return;
}
2020-05-18 09:35:51 +02:00
}
}
2020-10-19 14:04:57 +02:00
PrivacySegment::Priority PrivacySegment::priority() const
{
return m_priority;
}
2022-04-05 21:10:24 +02:00
void PrivacySegment::setPriority(Priority priority)
2020-10-19 14:04:57 +02:00
{
m_priority = priority;
}
2022-06-23 23:17:05 +02:00
bool PrivacySegment::enabled() const
{
return m_enabled;
}
void PrivacySegment::setEnabled(bool newEnabled)
{
m_enabled = newEnabled;
}
void PrivacySegment::rebuildFilter(IsAtTip tip)
{
m_filterShouldFollowWithMemoolCall = tip == FilterAtTIp;
m_parent->rebuildFilter();
m_filterShouldFollowWithMemoolCall = false;
}
2020-05-18 09:35:51 +02:00
// ///////////////////////////////////////////////////////////////////
PrivacySegment::FilterLock::FilterLock(PrivacySegment *parent)
: parent(parent)
{
parent->m_lock.lock();
}
PrivacySegment::FilterLock::FilterLock(PrivacySegment::FilterLock && other)
: parent(other.parent)
{
}
PrivacySegment::FilterLock::~FilterLock()
{
parent->m_lock.unlock();
2024-01-04 17:02:37 +01:00
for (const auto &wp : parent->m_peers) {
auto peer = wp.lock();
if (peer.get())
peer->filterUpdated(shouldAddMempoolRequest);
2020-05-18 09:35:51 +02:00
}
}
void PrivacySegment::FilterLock::addMempoolRequest()
{
shouldAddMempoolRequest = true;
}