Page Menu
Home
Phabricator
Search
Configure Global Search
Log In
Files
F13711242
D10454.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
7 KB
Subscribers
None
D10454.diff
View Options
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -541,6 +541,7 @@
add_library(server
addrdb.cpp
addrman.cpp
+ # TODO Create an avalanche library
avalanche/avalanche.cpp
avalanche/delegation.cpp
avalanche/delegationbuilder.cpp
@@ -550,6 +551,7 @@
avalanche/proof.cpp
avalanche/proofid.cpp
avalanche/proofbuilder.cpp
+ avalanche/utxostore.cpp
avalanche/voterecord.cpp
banman.cpp
blockencodings.cpp
diff --git a/src/avalanche/peermanager.h b/src/avalanche/peermanager.h
--- a/src/avalanche/peermanager.h
+++ b/src/avalanche/peermanager.h
@@ -8,6 +8,7 @@
#include <avalanche/node.h>
#include <avalanche/orphanproofpool.h>
#include <avalanche/proof.h>
+#include <avalanche/utxostore.h>
#include <coins.h>
#include <pubkey.h>
#include <salteduint256hasher.h>
@@ -130,7 +131,7 @@
PeerId nextPeerId = 0;
PeerSet peers;
- std::unordered_map<COutPoint, ProofRef, SaltedOutpointHasher> utxos;
+ UtxoStore utxos;
using NodeSet = boost::multi_index_container<
Node,
diff --git a/src/avalanche/peermanager.cpp b/src/avalanche/peermanager.cpp
--- a/src/avalanche/peermanager.cpp
+++ b/src/avalanche/peermanager.cpp
@@ -170,6 +170,13 @@
return false;
}
+ if (!utxos.attachProof(proof)) {
+ // Orphan the proof so it can be pulled back if the conflicting ones are
+ // invalidated.
+ orphanProofs.addProof(proof);
+ return false;
+ }
+
return createPeer(proof);
}
@@ -261,35 +268,6 @@
// New peer means new peerid!
const PeerId peerid = nextPeerId++;
- // Attach UTXOs to this proof.
- std::unordered_set<ProofRef> conflicting_proofs;
- for (const auto &s : proof->getStakes()) {
- auto p = utxos.emplace(s.getStake().getUTXO(), proof);
- if (!p.second) {
- // We have a collision with an existing proof.
- conflicting_proofs.insert(p.first->second);
- }
- }
-
- // For now, if there is a conflict, just cleanup the mess.
- if (conflicting_proofs.size() > 0) {
- for (const auto &s : proof->getStakes()) {
- auto it = utxos.find(s.getStake().getUTXO());
- assert(it != utxos.end());
-
- // We need to delete that one.
- if (it->second->getId() == proofid) {
- utxos.erase(it);
- }
- }
-
- // Orphan the proof so it can be pulled back if the conflicting ones are
- // invalidated.
- orphanProofs.addProof(proof);
-
- return false;
- }
-
// We have no peer for this proof, time to create it.
auto inserted = peers.emplace(peerid, proof);
assert(inserted.second);
@@ -338,10 +316,7 @@
peerid, std::chrono::steady_clock::now())));
// Release UTXOs attached to this proof.
- for (const auto &s : it->proof->getStakes()) {
- bool deleted = utxos.erase(s.getStake().getUTXO()) > 0;
- assert(deleted);
- }
+ utxos.detachProof(it->proof);
m_unbroadcast_proofids.erase(it->proof->getId());
@@ -428,18 +403,17 @@
return false;
}
- // Check utxos consistency
- for (const auto &ss : p.proof->getStakes()) {
- auto it = utxos.find(ss.getStake().getUTXO());
-
- if (it == utxos.end()) {
- return false;
- }
- if (it->second->getId() != p.getProofId()) {
+ // Make sure all the proof utxos are in the map
+ for (const SignedStake &ss : p.proof->getStakes()) {
+ const COutPoint &outpoint = ss.getStake().getUTXO();
+ if (!utxos.forUtxo(outpoint, [&](const auto &proof) {
+ return proof->getId() == p.proof->getId();
+ })) {
return false;
}
- if (!peersUtxos.emplace(it->first).second) {
+ // Duplicated utxo
+ if (!peersUtxos.emplace(outpoint).second) {
return false;
}
}
@@ -481,13 +455,13 @@
}
// Check there is no dangling utxo
- for (const auto &[outpoint, proof] : utxos) {
- if (!peersUtxos.count(outpoint)) {
- return false;
- }
- }
+ bool danglingUtxo = false;
+ utxos.forEachUtxo([&](const COutPoint &outpoint, const auto &proof) {
+ danglingUtxo =
+ danglingUtxo || peersUtxos.find(outpoint) == peersUtxos.end();
+ });
- return true;
+ return !danglingUtxo;
}
PeerId selectPeerImpl(const std::vector<Slot> &slots, const uint64_t slot,
diff --git a/src/avalanche/utxostore.h b/src/avalanche/utxostore.h
new file mode 100644
--- /dev/null
+++ b/src/avalanche/utxostore.h
@@ -0,0 +1,46 @@
+// Copyright (c) 2021 The Bitcoin developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#ifndef BITCOIN_AVALANCHE_UTXOSTORE_H
+#define BITCOIN_AVALANCHE_UTXOSTORE_H
+
+#include <avalanche/proof.h>
+#include <coins.h> // For SaltedOutpointHasher
+#include <primitives/transaction.h> // For COutPoint
+
+#include <unordered_map>
+
+namespace avalanche {
+
+/**
+ * Remembers which utxo is associated with which avalanche proof.
+ *
+ * TODO Implement the CCoinsView interface and use it to determine if a coin is
+ * locked due to staking.
+ */
+class UtxoStore {
+ using UtxoMap =
+ std::unordered_map<COutPoint, ProofRef, SaltedOutpointHasher>;
+ UtxoMap utxos;
+
+public:
+ bool attachProof(const ProofRef &proof);
+ bool detachProof(const ProofRef &proof);
+
+ template <typename Callable>
+ bool forUtxo(const COutPoint &outpoint, Callable fun) const {
+ auto it = utxos.find(outpoint);
+ return it != utxos.end() && fun(it->second);
+ }
+
+ template <typename Callable> void forEachUtxo(Callable fun) const {
+ for (const auto &p : utxos) {
+ fun(p.first, p.second);
+ }
+ }
+};
+
+} // namespace avalanche
+
+#endif // BITCOIN_AVALANCHE_UTXOSTORE_H
\ No newline at end of file
diff --git a/src/avalanche/utxostore.cpp b/src/avalanche/utxostore.cpp
new file mode 100644
--- /dev/null
+++ b/src/avalanche/utxostore.cpp
@@ -0,0 +1,47 @@
+// Copyright (c) 2021 The Bitcoin developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#include <avalanche/utxostore.h>
+
+#include <unordered_set>
+
+namespace avalanche {
+
+bool UtxoStore::attachProof(const ProofRef &proof) {
+ // Attach UTXOs to this proof.
+ std::unordered_set<ProofRef> conflicting_proofs;
+ for (const auto &s : proof->getStakes()) {
+ auto p = utxos.emplace(s.getStake().getUTXO(), proof);
+ if (!p.second) {
+ // We have a collision with an existing proof.
+ conflicting_proofs.insert(p.first->second);
+ }
+ }
+
+ // For now, if there is a conflict, just cleanup the mess.
+ if (conflicting_proofs.size() > 0) {
+ for (const auto &s : proof->getStakes()) {
+ auto it = utxos.find(s.getStake().getUTXO());
+ assert(it != utxos.end());
+
+ // We need to delete that one.
+ if (it->second->getId() == proof->getId()) {
+ utxos.erase(it);
+ }
+ }
+ }
+
+ return conflicting_proofs.size() == 0;
+}
+
+bool UtxoStore::detachProof(const ProofRef &proof) {
+ for (const SignedStake &ss : proof->getStakes()) {
+ bool deleted = utxos.erase(ss.getStake().getUTXO());
+ assert(deleted);
+ }
+
+ return true;
+}
+
+} // namespace avalanche
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Sat, Apr 26, 11:07 (10 h, 29 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
5573363
Default Alt Text
D10454.diff (7 KB)
Attached To
D10454: [avalanche] Introduce the UtxoStore class
Event Timeline
Log In to Comment