Bitcoin Core  27.99.0
P2P Digital Currency
txreconciliation.cpp
Go to the documentation of this file.
1 // Copyright (c) 2022 The Bitcoin Core developers
2 // Distributed under the MIT software license, see the accompanying
3 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
4 
6 
7 #include <common/system.h>
8 #include <logging.h>
9 #include <util/check.h>
10 
11 #include <unordered_map>
12 #include <variant>
13 
14 
15 namespace {
16 
18 const std::string RECON_STATIC_SALT = "Tx Relay Salting";
19 const HashWriter RECON_SALT_HASHER = TaggedHash(RECON_STATIC_SALT);
20 
26 uint256 ComputeSalt(uint64_t salt1, uint64_t salt2)
27 {
28  // According to BIP-330, salts should be combined in ascending order.
29  return (HashWriter(RECON_SALT_HASHER) << std::min(salt1, salt2) << std::max(salt1, salt2)).GetSHA256();
30 }
31 
35 class TxReconciliationState
36 {
37 public:
47  bool m_we_initiate;
48 
55  uint64_t m_k0, m_k1;
56 
57  TxReconciliationState(bool we_initiate, uint64_t k0, uint64_t k1) : m_we_initiate(we_initiate), m_k0(k0), m_k1(k1) {}
58 };
59 
60 } // namespace
61 
64 {
65 private:
67 
68  // Local protocol version
69  uint32_t m_recon_version;
70 
77  std::unordered_map<NodeId, std::variant<uint64_t, TxReconciliationState>> m_states GUARDED_BY(m_txreconciliation_mutex);
78 
79 public:
80  explicit Impl(uint32_t recon_version) : m_recon_version(recon_version) {}
81 
83  {
86 
87  LogPrintLevel(BCLog::TXRECONCILIATION, BCLog::Level::Debug, "Pre-register peer=%d\n", peer_id);
88  const uint64_t local_salt{GetRand(UINT64_MAX)};
89 
90  // We do this exactly once per peer (which are unique by NodeId, see GetNewNodeId) so it's
91  // safe to assume we don't have this record yet.
92  Assume(m_states.emplace(peer_id, local_salt).second);
93  return local_salt;
94  }
95 
96  ReconciliationRegisterResult RegisterPeer(NodeId peer_id, bool is_peer_inbound, uint32_t peer_recon_version,
98  {
101  auto recon_state = m_states.find(peer_id);
102 
103  if (recon_state == m_states.end()) return ReconciliationRegisterResult::NOT_FOUND;
104 
105  if (std::holds_alternative<TxReconciliationState>(recon_state->second)) {
107  }
108 
109  uint64_t local_salt = *std::get_if<uint64_t>(&recon_state->second);
110 
111  // If the peer supports the version which is lower than ours, we downgrade to the version
112  // it supports. For now, this only guarantees that nodes with future reconciliation
113  // versions have the choice of reconciling with this current version. However, they also
114  // have the choice to refuse supporting reconciliations if the common version is not
115  // satisfactory (e.g. too low).
116  const uint32_t recon_version{std::min(peer_recon_version, m_recon_version)};
117  // v1 is the lowest version, so suggesting something below must be a protocol violation.
118  if (recon_version < 1) return ReconciliationRegisterResult::PROTOCOL_VIOLATION;
119 
120  LogPrintLevel(BCLog::TXRECONCILIATION, BCLog::Level::Debug, "Register peer=%d (inbound=%i)\n",
121  peer_id, is_peer_inbound);
122 
123  const uint256 full_salt{ComputeSalt(local_salt, remote_salt)};
124  recon_state->second = TxReconciliationState(!is_peer_inbound, full_salt.GetUint64(0), full_salt.GetUint64(1));
126  }
127 
129  {
132  if (m_states.erase(peer_id)) {
133  LogPrintLevel(BCLog::TXRECONCILIATION, BCLog::Level::Debug, "Forget txreconciliation state of peer=%d\n", peer_id);
134  }
135  }
136 
138  {
141  auto recon_state = m_states.find(peer_id);
142  return (recon_state != m_states.end() &&
143  std::holds_alternative<TxReconciliationState>(recon_state->second));
144  }
145 };
146 
147 TxReconciliationTracker::TxReconciliationTracker(uint32_t recon_version) : m_impl{std::make_unique<TxReconciliationTracker::Impl>(recon_version)} {}
148 
150 
152 {
153  return m_impl->PreRegisterPeer(peer_id);
154 }
155 
157  uint32_t peer_recon_version, uint64_t remote_salt)
158 {
159  return m_impl->RegisterPeer(peer_id, is_peer_inbound, peer_recon_version, remote_salt);
160 }
161 
163 {
164  m_impl->ForgetPeer(peer_id);
165 }
166 
168 {
169  return m_impl->IsPeerRegistered(peer_id);
170 }
#define Assume(val)
Assume is the identity function.
Definition: check.h:89
A writer stream (for serialization) that computes a 256-bit hash.
Definition: hash.h:101
Actual implementation for TxReconciliationTracker's data structure.
uint64_t PreRegisterPeer(NodeId peer_id) EXCLUSIVE_LOCKS_REQUIRED(!m_txreconciliation_mutex)
void ForgetPeer(NodeId peer_id) EXCLUSIVE_LOCKS_REQUIRED(!m_txreconciliation_mutex)
bool IsPeerRegistered(NodeId peer_id) const EXCLUSIVE_LOCKS_REQUIRED(!m_txreconciliation_mutex)
std::unordered_map< NodeId, std::variant< uint64_t, TxReconciliationState > > m_states GUARDED_BY(m_txreconciliation_mutex)
Keeps track of txreconciliation states of eligible peers.
Impl(uint32_t recon_version)
ReconciliationRegisterResult RegisterPeer(NodeId peer_id, bool is_peer_inbound, uint32_t peer_recon_version, uint64_t remote_salt) EXCLUSIVE_LOCKS_REQUIRED(!m_txreconciliation_mutex)
Transaction reconciliation is a way for nodes to efficiently announce transactions.
bool IsPeerRegistered(NodeId peer_id) const
Check if a peer is registered to reconcile transactions with us.
ReconciliationRegisterResult RegisterPeer(NodeId peer_id, bool is_peer_inbound, uint32_t peer_recon_version, uint64_t remote_salt)
Step 0.
const std::unique_ptr< Impl > m_impl
TxReconciliationTracker(uint32_t recon_version)
uint64_t PreRegisterPeer(NodeId peer_id)
Step 0.
void ForgetPeer(NodeId peer_id)
Attempts to forget txreconciliation-related state of the peer (if we previously stored any).
256-bit opaque blob.
Definition: uint256.h:106
HashWriter TaggedHash(const std::string &tag)
Return a HashWriter primed for tagged hashes (as specified in BIP 340).
Definition: hash.cpp:85
#define LogPrintLevel(category, level,...)
Definition: logging.h:251
@ TXRECONCILIATION
Definition: logging.h:69
int64_t NodeId
Definition: net.h:97
T GetRand(T nMax=std::numeric_limits< T >::max()) noexcept
Generate a uniform random integer of type T in the range [0..nMax) nMax defaults to std::numeric_limi...
Definition: random.h:81
#define AssertLockNotHeld(cs)
Definition: sync.h:147
#define LOCK(cs)
Definition: sync.h:257
#define EXCLUSIVE_LOCKS_REQUIRED(...)
Definition: threadsafety.h:49
ReconciliationRegisterResult