Page MenuHomePhabricator

D2042.diff
No OneTemporary

D2042.diff

diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -181,6 +181,7 @@
add_library(server
addrman.cpp
addrdb.cpp
+ avalanche.cpp
bloom.cpp
blockencodings.cpp
chain.cpp
diff --git a/src/Makefile.am b/src/Makefile.am
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -102,7 +102,7 @@
BITCOIN_CORE_H = \
addrdb.h \
addrman.h \
- avalanche_impl.h \
+ avalanche.h \
base58.h \
bloom.h \
blockencodings.h \
@@ -227,6 +227,7 @@
libbitcoin_server_a_SOURCES = \
addrman.cpp \
addrdb.cpp \
+ avalanche.cpp \
bloom.cpp \
blockencodings.cpp \
chain.cpp \
diff --git a/src/avalanche_impl.h b/src/avalanche.h
rename from src/avalanche_impl.h
rename to src/avalanche.h
--- a/src/avalanche_impl.h
+++ b/src/avalanche.h
@@ -2,16 +2,28 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#ifndef BITCOIN_AVALANCHE_IMPL_H
-#define BITCOIN_AVALANCHE_IMPL_H
+#ifndef BITCOIN_AVALANCHE_H
+#define BITCOIN_AVALANCHE_H
+
+#include "net.h" // for NodeId
+#include "protocol.h" // for CInv
+#include "rwcollection.h"
+#include "serialize.h"
+#include "uint256.h"
#include <cstdint>
+#include <vector>
+
+class Config;
+class CBlockIndex;
+class CScheduler;
namespace {
/**
* Finalization score.
*/
static int AVALANCHE_FINALIZATION_SCORE = 128;
+}
/**
* Vote history.
@@ -77,6 +89,64 @@
return true;
}
};
-}
-#endif // BITCOIN_AVALANCHE_IMPL_H
+class AvalancheVote {
+ uint32_t error;
+ uint256 hash;
+
+public:
+ AvalancheVote() : error(-1), hash() {}
+ AvalancheVote(uint32_t errorIn, uint256 hashIn)
+ : error(errorIn), hash(hashIn) {}
+
+ const uint256 &GetHash() const { return hash; }
+ bool IsValid() const { return error == 0; }
+
+ // serialization support
+ ADD_SERIALIZE_METHODS;
+
+ template <typename Stream, typename Operation>
+ inline void SerializationOp(Stream &s, Operation ser_action) {
+ READWRITE(error);
+ READWRITE(hash);
+ }
+};
+
+class AvalancheResponse {
+ uint32_t cooldown;
+ std::vector<AvalancheVote> votes;
+
+public:
+ AvalancheResponse(uint32_t cooldownIn, std::vector<AvalancheVote> votesIn)
+ : cooldown(cooldownIn), votes(votesIn) {}
+
+ const std::vector<AvalancheVote> &GetVotes() const { return votes; }
+
+ // serialization support
+ ADD_SERIALIZE_METHODS;
+
+ template <typename Stream, typename Operation>
+ inline void SerializationOp(Stream &s, Operation ser_action) {
+ READWRITE(cooldown);
+ READWRITE(votes);
+ }
+};
+
+class AvalancheProcessor {
+private:
+ /**
+ * Blocks to run avalanche on.
+ */
+ RWCollection<std::map<const CBlockIndex *, VoteRecord>> vote_records;
+
+public:
+ AvalancheProcessor() {}
+
+ bool addBlockToReconcile(const CBlockIndex *pindex);
+ bool isAccepted(const CBlockIndex *pindex) const;
+ bool hasFinalized(const CBlockIndex *pindex) const;
+
+ bool registerVotes(const AvalancheResponse &response);
+};
+
+#endif // BITCOIN_AVALANCHE_H
diff --git a/src/avalanche.cpp b/src/avalanche.cpp
new file mode 100644
--- /dev/null
+++ b/src/avalanche.cpp
@@ -0,0 +1,76 @@
+// Copyright (c) 2018 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.h"
+
+#include "chain.h"
+#include "netmessagemaker.h"
+#include "scheduler.h"
+#include "validation.h"
+
+bool AvalancheProcessor::addBlockToReconcile(const CBlockIndex *pindex) {
+ return vote_records.getWriteView()
+ ->insert(std::make_pair(pindex, VoteRecord()))
+ .second;
+}
+
+static const VoteRecord *GetRecord(
+ const RWCollection<std::map<const CBlockIndex *, VoteRecord>> &vote_records,
+ const CBlockIndex *pindex) {
+ auto r = vote_records.getReadView();
+ auto it = r->find(pindex);
+ if (it == r.end()) {
+ return nullptr;
+ }
+
+ return &it->second;
+}
+
+bool AvalancheProcessor::isAccepted(const CBlockIndex *pindex) const {
+ if (auto vr = GetRecord(vote_records, pindex)) {
+ return vr->isValid();
+ }
+
+ return false;
+}
+
+bool AvalancheProcessor::hasFinalized(const CBlockIndex *pindex) const {
+ if (auto vr = GetRecord(vote_records, pindex)) {
+ return vr->hasFinalized();
+ }
+
+ return false;
+}
+
+bool AvalancheProcessor::registerVotes(const AvalancheResponse &response) {
+ const std::vector<AvalancheVote> &votes = response.GetVotes();
+
+ std::map<const CBlockIndex *, AvalancheVote> responseIndex;
+
+ {
+ LOCK(cs_main);
+ for (auto &v : votes) {
+ BlockMap::iterator mi = mapBlockIndex.find(v.GetHash());
+ if (mi == mapBlockIndex.end()) {
+ // This should not happen, but just in case...
+ continue;
+ }
+
+ responseIndex.insert(std::make_pair(mi->second, v));
+ }
+ }
+
+ {
+ // Register votes.
+ auto w = vote_records.getWriteView();
+ for (auto &p : responseIndex) {
+ const CBlockIndex *pindex = p.first;
+ const AvalancheVote &v = p.second;
+
+ w[pindex].registerVote(v.IsValid());
+ }
+ }
+
+ return true;
+}
diff --git a/src/test/avalanche_tests.cpp b/src/test/avalanche_tests.cpp
--- a/src/test/avalanche_tests.cpp
+++ b/src/test/avalanche_tests.cpp
@@ -2,13 +2,13 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "avalanche_impl.h"
+#include "avalanche.h"
#include "test/test_bitcoin.h"
#include <boost/test/unit_test.hpp>
-BOOST_FIXTURE_TEST_SUITE(avalanche_tests, BasicTestingSetup)
+BOOST_FIXTURE_TEST_SUITE(avalanche_tests, TestChain100Setup)
#define REGISTER_VOTE_AND_CHECK(vr, vote, state, finalized, confidence) \
vr.registerVote(vote); \
@@ -66,4 +66,66 @@
AVALANCHE_FINALIZATION_SCORE);
}
+BOOST_AUTO_TEST_CASE(block_register) {
+ AvalancheProcessor p;
+
+ CBlock block = CreateAndProcessBlock({}, CScript());
+ const uint256 hash = block.GetHash();
+ const CBlockIndex *pindex = mapBlockIndex[hash];
+
+ // Querying for random block returns false.
+ BOOST_CHECK(!p.isAccepted(pindex));
+ BOOST_CHECK(!p.hasFinalized(pindex));
+
+ // Newly added blocks are also considered rejected.
+ BOOST_CHECK(p.addBlockToReconcile(pindex));
+ BOOST_CHECK(!p.isAccepted(pindex));
+ BOOST_CHECK(!p.hasFinalized(pindex));
+
+ // Let's vote for this block a few times.
+ AvalancheResponse resp{0, {AvalancheVote(0, hash)}};
+ for (int i = 0; i < 5; i++) {
+ p.registerVotes(resp);
+ BOOST_CHECK(!p.isAccepted(pindex));
+ BOOST_CHECK(!p.hasFinalized(pindex));
+ }
+
+ // Now it is accepted, but we can vote for it numerous times.
+ for (int i = 0; i < AVALANCHE_FINALIZATION_SCORE; i++) {
+ p.registerVotes(resp);
+ BOOST_CHECK(p.isAccepted(pindex));
+ BOOST_CHECK(!p.hasFinalized(pindex));
+ }
+
+ // Now finalize the decision.
+ resp = {0, {AvalancheVote(1, hash)}};
+ p.registerVotes(resp);
+ BOOST_CHECK(p.isAccepted(pindex));
+ BOOST_CHECK(p.hasFinalized(pindex));
+
+ // Now let's undo this and finalize rejection.
+ for (int i = 0; i < 5; i++) {
+ p.registerVotes(resp);
+ BOOST_CHECK(p.isAccepted(pindex));
+ BOOST_CHECK(p.hasFinalized(pindex));
+ }
+
+ // Now it is rejected, but we can vote for it numerous times.
+ for (int i = 0; i < AVALANCHE_FINALIZATION_SCORE; i++) {
+ p.registerVotes(resp);
+ BOOST_CHECK(!p.isAccepted(pindex));
+ BOOST_CHECK(!p.hasFinalized(pindex));
+ }
+
+ // Now finalize the decision.
+ p.registerVotes(resp);
+ BOOST_CHECK(!p.isAccepted(pindex));
+ BOOST_CHECK(p.hasFinalized(pindex));
+
+ // Adding the block twice does nothing.
+ BOOST_CHECK(!p.addBlockToReconcile(pindex));
+ BOOST_CHECK(!p.isAccepted(pindex));
+ BOOST_CHECK(p.hasFinalized(pindex));
+}
+
BOOST_AUTO_TEST_SUITE_END()

File Metadata

Mime Type
text/plain
Expires
Sat, Mar 1, 11:42 (6 h, 37 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
5187669
Default Alt Text
D2042.diff (8 KB)

Event Timeline