Introduce libclaimtrie

Signed-off-by: Anthony Fieroni <bvbfan@abv.bg>
This commit is contained in:
Anthony Fieroni 2019-10-09 18:09:30 +03:00 committed by Brannon King
parent 61625c0eef
commit 53a61258e1
61 changed files with 1461 additions and 905 deletions

View file

@ -29,6 +29,7 @@ LIBBITCOIN_COMMON=libbitcoin_common.a
LIBBITCOIN_CONSENSUS=libbitcoin_consensus.a
LIBBITCOIN_CLI=libbitcoin_cli.a
LIBBITCOIN_UTIL=libbitcoin_util.a
LIBCLAIMTRIE=claimtrie/libclaimtrie.a
LIBBITCOIN_CRYPTO_BASE=crypto/libbitcoin_crypto_base.a
LIBBITCOINQT=qt/libbitcoinqt.a
LIBSECP256K1=secp256k1/libsecp256k1.la
@ -63,6 +64,7 @@ $(LIBSECP256K1): $(wildcard secp256k1/src/*.h) $(wildcard secp256k1/src/*.c) $(w
# Make is not made aware of per-object dependencies to avoid limiting building parallelization
# But to build the less dependent modules first, we manually select their order here:
EXTRA_LIBRARIES += \
$(LIBCLAIMTRIE) \
$(LIBBITCOIN_CRYPTO) \
$(LIBBITCOIN_UTIL) \
$(LIBBITCOIN_COMMON) \
@ -103,7 +105,7 @@ BITCOIN_CORE_H = \
checkpoints.h \
checkqueue.h \
claimscriptop.h \
claimtrie.h \
claimtrie_serial.h \
clientversion.h \
coins.h \
compat.h \
@ -170,8 +172,6 @@ BITCOIN_CORE_H = \
script/standard.h \
shutdown.h \
streams.h \
sqlite/sqlite3.h \
sqlite/hdr/sqlite_modern_cpp.h \
support/allocators/secure.h \
support/allocators/zeroafterfree.h \
support/cleanse.h \
@ -223,7 +223,6 @@ libbitcoin_util_a-clientversion.$(OBJEXT): obj/build.h
# server: shared between lbrycrdd and lbrycrd-qt
libbitcoin_server_a_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) $(MINIUPNPC_CPPFLAGS) $(EVENT_CFLAGS) $(EVENT_PTHREADS_CFLAGS)
libbitcoin_server_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
libbitcoin_server_a_CFLAGS = $(PIE_FLAGS)
libbitcoin_server_a_SOURCES = \
addrdb.cpp \
addrman.cpp \
@ -232,8 +231,6 @@ libbitcoin_server_a_SOURCES = \
chain.cpp \
checkpoints.cpp \
claimscriptop.cpp \
claimtrie.cpp \
claimtrieforks.cpp \
consensus/tx_verify.cpp \
httprpc.cpp \
httpserver.cpp \
@ -263,7 +260,6 @@ libbitcoin_server_a_SOURCES = \
rpc/server.cpp \
rpc/util.cpp \
script/sigcache.cpp \
sqlite/sqlite3.c \
shutdown.cpp \
timedata.cpp \
torcontrol.cpp \
@ -415,6 +411,20 @@ libbitcoin_common_a_SOURCES = \
warnings.cpp \
$(BITCOIN_CORE_H)
# claimtrie: shared between all executables.
claimtrie_libclaimtrie_a_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES)
claimtrie_libclaimtrie_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
claimtrie_libclaimtrie_a_CFLAGS = $(PIE_FLAGS)
claimtrie_libclaimtrie_a_SOURCES = \
claimtrie/sqlite/sqlite3.c \
claimtrie/data.cpp \
claimtrie/forks.cpp \
claimtrie/hash.cpp \
claimtrie/log.cpp \
claimtrie/trie.cpp \
claimtrie/txoutpoint.cpp \
claimtrie/uints.cpp
# util: shared between all executables.
# This library *must* be included to make sure that the glibc
# backward-compatibility objects and their sanity checks are linked.
@ -482,7 +492,7 @@ lbrycrdd_LDADD = \
$(LIBMEMENV) \
$(LIBSECP256K1)
lbrycrdd_LDADD += $(BOOST_LIBS) $(BDB_LIBS) $(CRYPTO_LIBS) $(ICU_LIBS) $(MINIUPNPC_LIBS) $(EVENT_PTHREADS_LIBS) $(EVENT_LIBS) $(ZMQ_LIBS)
lbrycrdd_LDADD += $(BOOST_LIBS) $(LIBCLAIMTRIE) $(BOOST_LOCALE_LIB) $(BDB_LIBS) $(CRYPTO_LIBS) $(ICU_LIBS) $(MINIUPNPC_LIBS) $(EVENT_PTHREADS_LIBS) $(EVENT_LIBS) $(ZMQ_LIBS)
# lbrycrd-cli binary #
lbrycrd_cli_SOURCES = bitcoin-cli.cpp
@ -500,7 +510,7 @@ lbrycrd_cli_LDADD = \
$(LIBBITCOIN_UTIL) \
$(LIBBITCOIN_CRYPTO)
lbrycrd_cli_LDADD += $(BOOST_LIBS) $(CRYPTO_LIBS) $(ICU_LIBS) $(EVENT_LIBS)
lbrycrd_cli_LDADD += $(BOOST_LIBS) $(LIBCLAIMTRIE) $(BOOST_LOCALE_LIB) $(CRYPTO_LIBS) $(ICU_LIBS) $(EVENT_LIBS)
#
# bitcoin-tx binary #
@ -521,7 +531,7 @@ lbrycrd_tx_LDADD = \
$(LIBBITCOIN_CRYPTO) \
$(LIBSECP256K1)
lbrycrd_tx_LDADD += $(BOOST_LIBS) $(ICU_LIBS) $(CRYPTO_LIBS)
lbrycrd_tx_LDADD += $(BOOST_LIBS) $(LIBCLAIMTRIE) $(BOOST_LOCALE_LIB) $(ICU_LIBS) $(CRYPTO_LIBS)
#
# bitcoinconsensus library #

View file

@ -55,7 +55,7 @@ if ENABLE_WALLET
bench_bench_bitcoin_SOURCES += bench/coin_selection.cpp
endif
bench_bench_bitcoin_LDADD += $(BOOST_LIBS) $(BDB_LIBS) $(CRYPTO_LIBS) $(ICU_LIBS) $(MINIUPNPC_LIBS) $(EVENT_PTHREADS_LIBS) $(EVENT_LIBS)
bench_bench_bitcoin_LDADD += $(BOOST_LIBS) $(LIBCLAIMTRIE) $(BOOST_LOCALE_LIB) $(BDB_LIBS) $(CRYPTO_LIBS) $(ICU_LIBS) $(MINIUPNPC_LIBS) $(EVENT_PTHREADS_LIBS) $(EVENT_LIBS)
bench_bench_bitcoin_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
CLEAN_BITCOIN_BENCH = bench/*.gcda bench/*.gcno $(GENERATED_BENCH_FILES)

View file

@ -409,7 +409,7 @@ if ENABLE_ZMQ
qt_lbrycrd_qt_LDADD += $(LIBBITCOIN_ZMQ) $(ZMQ_LIBS)
endif
qt_lbrycrd_qt_LDADD += $(LIBBITCOIN_CLI) $(LIBBITCOIN_COMMON) $(LIBBITCOIN_UTIL) $(LIBBITCOIN_CONSENSUS) $(LIBBITCOIN_CRYPTO) $(LIBUNIVALUE) $(LIBLEVELDB) $(LIBLEVELDB_SSE42) $(LIBMEMENV) \
$(BOOST_LIBS) $(QT_LIBS) $(QT_DBUS_LIBS) $(QR_LIBS) $(PROTOBUF_LIBS) $(ICU_LIBS) $(BDB_LIBS) $(SSL_LIBS) $(CRYPTO_LIBS) $(MINIUPNPC_LIBS) $(LIBSECP256K1) \
$(BOOST_LIBS) $(LIBCLAIMTRIE) $(BOOST_LOCALE_LIB) $(QT_LIBS) $(QT_DBUS_LIBS) $(QR_LIBS) $(PROTOBUF_LIBS) $(ICU_LIBS) $(BDB_LIBS) $(SSL_LIBS) $(CRYPTO_LIBS) $(MINIUPNPC_LIBS) $(LIBSECP256K1) \
$(EVENT_PTHREADS_LIBS) $(EVENT_LIBS)
qt_lbrycrd_qt_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(QT_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
qt_lbrycrd_qt_LIBTOOLFLAGS = $(AM_LIBTOOLFLAGS) --tag CXX

View file

@ -63,7 +63,7 @@ if ENABLE_ZMQ
qt_test_test_lbrycrd_qt_LDADD += $(LIBBITCOIN_ZMQ) $(ZMQ_LIBS)
endif
qt_test_test_lbrycrd_qt_LDADD += $(LIBBITCOIN_CLI) $(LIBBITCOIN_COMMON) $(LIBBITCOIN_UTIL) $(LIBBITCOIN_CONSENSUS) $(LIBBITCOIN_CRYPTO) $(LIBUNIVALUE) $(LIBLEVELDB) \
$(LIBLEVELDB_SSE42) $(LIBMEMENV) $(BOOST_LIBS) $(QT_DBUS_LIBS) $(QT_TEST_LIBS) $(QT_LIBS) \
$(LIBLEVELDB_SSE42) $(LIBMEMENV) $(BOOST_LIBS) $(LIBCLAIMTRIE) $(BOOST_LOCALE_LIB) $(QT_DBUS_LIBS) $(QT_TEST_LIBS) $(QT_LIBS) \
$(QR_LIBS) $(PROTOBUF_LIBS) $(ICU_LIBS) $(BDB_LIBS) $(SSL_LIBS) $(CRYPTO_LIBS) $(MINIUPNPC_LIBS) $(LIBSECP256K1) \
$(EVENT_PTHREADS_LIBS) $(EVENT_LIBS)
qt_test_test_lbrycrd_qt_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(QT_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)

View file

@ -126,7 +126,7 @@ test_test_lbrycrd_LDADD += $(LIBBITCOIN_WALLET)
endif
test_test_lbrycrd_LDADD += $(LIBBITCOIN_SERVER) $(LIBBITCOIN_CLI) $(LIBBITCOIN_COMMON) $(LIBBITCOIN_UTIL) $(LIBBITCOIN_CONSENSUS) $(LIBBITCOIN_CRYPTO) $(LIBUNIVALUE) \
$(LIBLEVELDB) $(LIBLEVELDB_SSE42) $(LIBMEMENV) $(BOOST_LIBS) $(BOOST_UNIT_TEST_FRAMEWORK_LIB) $(LIBSECP256K1) $(EVENT_LIBS) $(EVENT_PTHREADS_LIBS)
$(LIBLEVELDB) $(LIBLEVELDB_SSE42) $(LIBMEMENV) $(BOOST_LIBS) $(LIBCLAIMTRIE) $(BOOST_LOCALE_LIB) $(BOOST_UNIT_TEST_FRAMEWORK_LIB) $(LIBSECP256K1) $(EVENT_LIBS) $(EVENT_PTHREADS_LIBS)
test_test_lbrycrd_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
test_test_lbrycrd_LDADD += $(LIBBITCOIN_CONSENSUS) $(BDB_LIBS) $(CRYPTO_LIBS) $(ICU_LIBS) $(MINIUPNPC_LIBS)
@ -155,7 +155,7 @@ test_test_lbrycrd_fuzzy_LDADD = \
$(LIBBITCOIN_CRYPTO_SHANI) \
$(LIBSECP256K1)
test_test_lbrycrd_fuzzy_LDADD += $(BOOST_LIBS) $(CRYPTO_LIBS) $(ICU_LIBS)
test_test_lbrycrd_fuzzy_LDADD += $(BOOST_LIBS) $(LIBCLAIMTRIE) $(BOOST_LOCALE_LIB) $(CRYPTO_LIBS) $(ICU_LIBS)
nodist_test_test_lbrycrd_SOURCES = $(GENERATED_TEST_FILES)

View file

@ -143,8 +143,6 @@ public:
consensus.nAllowMinDiffMinHeight = -1;
consensus.nAllowMinDiffMaxHeight = -1;
consensus.nNormalizedNameForkHeight = 539940; // targeting 21 March 2019
consensus.nMinTakeoverWorkaroundHeight = 496850;
consensus.nMaxTakeoverWorkaroundHeight = 658300; // targeting 30 Oct 2019
consensus.nWitnessForkHeight = 680770; // targeting 11 Dec 2019
consensus.nAllClaimsInMerkleForkHeight = 658310; // targeting 30 Oct 2019
consensus.fPowAllowMinDifficultyBlocks = false;
@ -261,8 +259,6 @@ public:
consensus.nAllowMinDiffMinHeight = 277299;
consensus.nAllowMinDiffMaxHeight = 1100000;
consensus.nNormalizedNameForkHeight = 993380; // targeting, 21 Feb 2019
consensus.nMinTakeoverWorkaroundHeight = 99;
consensus.nMaxTakeoverWorkaroundHeight = 1198550; // targeting 30 Sep 2019
consensus.nWitnessForkHeight = 1198600;
consensus.nAllClaimsInMerkleForkHeight = 1198560; // targeting 30 Sep 2019
consensus.fPowAllowMinDifficultyBlocks = true;
@ -368,8 +364,6 @@ public:
consensus.nAllowMinDiffMinHeight = -1;
consensus.nAllowMinDiffMaxHeight = -1;
consensus.nNormalizedNameForkHeight = 250; // SDK depends upon this number
consensus.nMinTakeoverWorkaroundHeight = -1;
consensus.nMaxTakeoverWorkaroundHeight = -1;
consensus.nWitnessForkHeight = 150;
consensus.nAllClaimsInMerkleForkHeight = 350;
consensus.fPowAllowMinDifficultyBlocks = false;

View file

@ -39,7 +39,7 @@ bool CClaimScriptAddOp::supportClaim(CClaimTrieCache& trieCache, const std::stri
{
LogPrint(BCLog::CLAIMS, "+++ Support added: %s, c: %.6s, t: %.6s:%d, h: %.6d, a: %d\n",
name, claimId.GetHex(), point.hash.GetHex(), point.n, nHeight, nValue);
return trieCache.addSupport(name, point, nValue, claimId, nHeight, -1, metadata);
return trieCache.addSupport(name, point, claimId, nValue, nHeight, -1, metadata);
}
CClaimScriptUndoAddOp::CClaimScriptUndoAddOp(const COutPoint& point, int nHeight) : point(point), nHeight(nHeight)
@ -164,7 +164,7 @@ bool CClaimScriptUndoSpendOp::supportClaim(CClaimTrieCache& trieCache, const std
{
LogPrint(BCLog::CLAIMS, "+++ Undoing support spend: %s, c: %.6s, t: %.6s:%d, h: %.6d, vh: %d\n",
name, claimId.GetHex(), point.hash.GetHex(), point.n, nHeight, nValidHeight);
return trieCache.addSupport(name, point, nValue, claimId, nHeight, nValidHeight, metadata);
return trieCache.addSupport(name, point, claimId, nValue, nHeight, nValidHeight, metadata);
}
static std::string vchToString(const std::vector<unsigned char>& name)

View file

@ -6,7 +6,7 @@
#define CLAIMSCRIPTOP_H
#include "amount.h"
#include "claimtrie.h"
#include "claimtrie/forks.h"
#include "hash.h"
#include "primitives/transaction.h"
#include "script/script.h"

View file

@ -1,491 +0,0 @@
#ifndef BITCOIN_CLAIMTRIE_H
#define BITCOIN_CLAIMTRIE_H
#include <amount.h>
#include <chain.h>
#include <chainparams.h>
#include <primitives/transaction.h>
#include <serialize.h>
#include <uint256.h>
#include <util.h>
#include <map>
#include <string>
#include <vector>
#include <unordered_map>
#include <unordered_set>
#include <sqlite/sqlite3.h>
namespace sqlite
{
inline int bind_col_in_db(sqlite3_stmt* stmt, int inx, const uint160& val) {
return sqlite3_bind_blob(stmt, inx, val.begin(), int(val.size()), SQLITE_STATIC);
}
inline int bind_col_in_db(sqlite3_stmt* stmt, int inx, const uint256& val) {
return sqlite3_bind_blob(stmt, inx, val.begin(), int(val.size()), SQLITE_STATIC);
}
inline void store_result_in_db(sqlite3_context* db, const uint160& val) {
sqlite3_result_blob(db, val.begin(), int(val.size()), SQLITE_TRANSIENT); // I think we need transient here but I'm not 100% sure
}
inline void store_result_in_db(sqlite3_context* db, const uint256& val) {
sqlite3_result_blob(db, val.begin(), int(val.size()), SQLITE_TRANSIENT);
}
}
#include <sqlite/hdr/sqlite_modern_cpp.h>
namespace sqlite {
template<>
struct has_sqlite_type<uint256, SQLITE_BLOB, void> : std::true_type {};
template<>
struct has_sqlite_type<uint160, SQLITE_BLOB, void> : std::true_type {};
inline uint160 get_col_from_db(sqlite3_stmt* stmt, int inx, result_type<uint160>) {
uint160 ret;
auto ptr = sqlite3_column_blob(stmt, inx);
if (!ptr) return ret;
int bytes = sqlite3_column_bytes(stmt, inx);
assert(bytes == ret.size());
std::memcpy(ret.begin(), ptr, bytes);
return ret;
}
inline uint256 get_col_from_db(sqlite3_stmt* stmt, int inx, result_type<uint256>) {
uint256 ret;
auto ptr = sqlite3_column_blob(stmt, inx);
if (!ptr) return ret;
int bytes = sqlite3_column_bytes(stmt, inx);
assert(bytes == ret.size());
std::memcpy(ret.begin(), ptr, bytes);
return ret;
}
}
uint256 getValueHash(const COutPoint& outPoint, int nHeightOfLastTakeover);
struct CClaimValue
{
COutPoint outPoint;
uint160 claimId;
CAmount nAmount = 0;
CAmount nEffectiveAmount = 0;
int nHeight = 0;
int nValidAtHeight = 0;
CClaimValue() = default;
CClaimValue(const COutPoint& outPoint, const uint160& claimId, CAmount nAmount, int nHeight, int nValidAtHeight)
: outPoint(outPoint), claimId(claimId), nAmount(nAmount), nEffectiveAmount(nAmount), nHeight(nHeight), nValidAtHeight(nValidAtHeight)
{
}
CClaimValue(CClaimValue&&) = default;
CClaimValue(const CClaimValue&) = default;
CClaimValue& operator=(CClaimValue&&) = default;
CClaimValue& operator=(const CClaimValue&) = default;
ADD_SERIALIZE_METHODS;
template <typename Stream, typename Operation>
inline void SerializationOp(Stream& s, Operation ser_action)
{
READWRITE(outPoint);
READWRITE(claimId);
READWRITE(nAmount);
READWRITE(nHeight);
READWRITE(nValidAtHeight);
}
bool operator<(const CClaimValue& other) const
{
if (nEffectiveAmount < other.nEffectiveAmount)
return true;
if (nEffectiveAmount != other.nEffectiveAmount)
return false;
if (nHeight > other.nHeight)
return true;
if (nHeight != other.nHeight)
return false;
return outPoint != other.outPoint && !(outPoint < other.outPoint);
}
bool operator==(const CClaimValue& other) const
{
return outPoint == other.outPoint && claimId == other.claimId && nAmount == other.nAmount && nHeight == other.nHeight && nValidAtHeight == other.nValidAtHeight;
}
bool operator!=(const CClaimValue& other) const
{
return !(*this == other);
}
};
struct CSupportValue
{
COutPoint outPoint;
uint160 supportedClaimId;
CAmount nAmount = 0;
int nHeight = 0;
int nValidAtHeight = 0;
CSupportValue() = default;
CSupportValue(const COutPoint& outPoint, const uint160& supportedClaimId, CAmount nAmount, int nHeight, int nValidAtHeight)
: outPoint(outPoint), supportedClaimId(supportedClaimId), nAmount(nAmount), nHeight(nHeight), nValidAtHeight(nValidAtHeight)
{
}
CSupportValue(CSupportValue&&) = default;
CSupportValue(const CSupportValue&) = default;
CSupportValue& operator=(CSupportValue&&) = default;
CSupportValue& operator=(const CSupportValue&) = default;
ADD_SERIALIZE_METHODS;
template <typename Stream, typename Operation>
inline void SerializationOp(Stream& s, Operation ser_action)
{
READWRITE(outPoint);
READWRITE(supportedClaimId);
READWRITE(nAmount);
READWRITE(nHeight);
READWRITE(nValidAtHeight);
}
bool operator==(const CSupportValue& other) const
{
return outPoint == other.outPoint && supportedClaimId == other.supportedClaimId && nAmount == other.nAmount && nHeight == other.nHeight && nValidAtHeight == other.nValidAtHeight;
}
bool operator!=(const CSupportValue& other) const
{
return !(*this == other);
}
};
typedef std::vector<CClaimValue> claimEntryType;
typedef std::vector<CSupportValue> supportEntryType;
struct CNameOutPointHeightType
{
std::string name;
COutPoint outPoint;
int nValidHeight = 0;
CNameOutPointHeightType() = default;
CNameOutPointHeightType(std::string name, const COutPoint& outPoint, int nValidHeight)
: name(std::move(name)), outPoint(outPoint), nValidHeight(nValidHeight)
{
}
ADD_SERIALIZE_METHODS;
template <typename Stream, typename Operation>
inline void SerializationOp(Stream& s, Operation ser_action)
{
READWRITE(name);
READWRITE(outPoint);
READWRITE(nValidHeight);
}
};
struct CClaimNsupports
{
CClaimNsupports() = default;
CClaimNsupports(CClaimNsupports&&) = default;
CClaimNsupports(const CClaimNsupports&) = default;
CClaimNsupports& operator=(CClaimNsupports&&) = default;
CClaimNsupports& operator=(const CClaimNsupports&) = default;
CClaimNsupports(const CClaimValue& claim, CAmount effectiveAmount, const std::vector<CSupportValue>& supports = {})
: claim(claim), effectiveAmount(effectiveAmount), supports(supports)
{
}
bool IsNull() const
{
return claim.claimId.IsNull();
}
bool operator<(const CClaimNsupports& other) const {
return claim < other.claim;
}
CClaimValue claim;
CAmount effectiveAmount = 0;
std::vector<CSupportValue> supports;
};
static const CClaimNsupports invalid;
struct CClaimSupportToName
{
CClaimSupportToName(const std::string& name, int nLastTakeoverHeight, std::vector<CClaimNsupports> claimsNsupports, std::vector<CSupportValue> unmatchedSupports)
: name(name), nLastTakeoverHeight(nLastTakeoverHeight), claimsNsupports(std::move(claimsNsupports)), unmatchedSupports(std::move(unmatchedSupports))
{
}
const CClaimNsupports& find(const uint160& claimId) const
{
auto it = std::find_if(claimsNsupports.begin(), claimsNsupports.end(), [&claimId](const CClaimNsupports& value) {
return claimId == value.claim.claimId;
});
return it != claimsNsupports.end() ? *it : invalid;
}
const CClaimNsupports& find(const std::string& partialId) const
{
std::string lowered(partialId);
for (auto& c: lowered)
c = std::tolower(c);
auto it = std::find_if(claimsNsupports.begin(), claimsNsupports.end(), [&lowered](const CClaimNsupports& value) {
return value.claim.claimId.GetHex().find(lowered) == 0;
});
return it != claimsNsupports.end() ? *it : invalid;
}
const std::string name;
const int nLastTakeoverHeight;
const std::vector<CClaimNsupports> claimsNsupports;
const std::vector<CSupportValue> unmatchedSupports;
};
class CClaimTrieCacheBase;
class CClaimTrie
{
friend CClaimTrieCacheBase;
std::string dbPath;
int nNextHeight;
sqlite::database db; // keep below dbPath
public:
const int nProportionalDelayFactor;
CClaimTrie() = delete;
CClaimTrie(CClaimTrie&&) = delete;
CClaimTrie(const CClaimTrie&) = delete;
CClaimTrie(bool fWipe, int height, int proportionalDelayFactor = 32);
CClaimTrie& operator=(CClaimTrie&&) = delete;
CClaimTrie& operator=(const CClaimTrie&) = delete;
bool SyncToDisk();
bool empty(); // for tests
};
struct CClaimTrieProofNode
{
CClaimTrieProofNode(std::vector<std::pair<unsigned char, uint256>> children, bool hasValue, const uint256& valHash)
: children(std::move(children)), hasValue(hasValue), valHash(valHash)
{
}
CClaimTrieProofNode(CClaimTrieProofNode&&) = default;
CClaimTrieProofNode(const CClaimTrieProofNode&) = default;
CClaimTrieProofNode& operator=(CClaimTrieProofNode&&) = default;
CClaimTrieProofNode& operator=(const CClaimTrieProofNode&) = default;
std::vector<std::pair<unsigned char, uint256>> children;
bool hasValue;
uint256 valHash;
};
struct CClaimTrieProof
{
CClaimTrieProof() = default;
CClaimTrieProof(CClaimTrieProof&&) = default;
CClaimTrieProof(const CClaimTrieProof&) = default;
CClaimTrieProof& operator=(CClaimTrieProof&&) = default;
CClaimTrieProof& operator=(const CClaimTrieProof&) = default;
std::vector<std::pair<bool, uint256>> pairs;
std::vector<CClaimTrieProofNode> nodes;
int nHeightOfLastTakeover = 0;
bool hasValue = false;
COutPoint outPoint;
};
template <typename T>
using queueEntryType = std::pair<std::string, T>;
typedef std::vector<queueEntryType<CClaimValue>> claimUndoType;
typedef std::vector<queueEntryType<CSupportValue>> supportUndoType;
typedef std::vector<CNameOutPointHeightType> insertUndoType;
typedef std::vector<queueEntryType<std::pair<int, uint160>>> takeoverUndoType;
class CClaimTrieCacheBase
{
public:
explicit CClaimTrieCacheBase(CClaimTrie* base);
virtual ~CClaimTrieCacheBase();
uint256 getMerkleHash();
bool flush();
bool checkConsistency();
bool ValidateTipMatches(const CBlockIndex* tip);
bool haveClaim(const std::string& name, const COutPoint& outPoint) const;
bool haveClaimInQueue(const std::string& name, const COutPoint& outPoint, int& nValidAtHeight) const;
bool haveSupport(const std::string& name, const COutPoint& outPoint) const;
bool haveSupportInQueue(const std::string& name, const COutPoint& outPoint, int& nValidAtHeight) const;
bool addClaim(const std::string& name, const COutPoint& outPoint, const uint160& claimId, CAmount nAmount,
int nHeight, int nValidHeight = -1, const std::vector<unsigned char>& metadata = {});
bool addSupport(const std::string& name, const COutPoint& outPoint, CAmount nAmount,
const uint160& supportedClaimId, int nHeight, int nValidHeight = -1, const std::vector<unsigned char>& metadata = {});
bool removeSupport(const COutPoint& outPoint, std::string& nodeName, int& validHeight);
bool removeClaim(const uint160& claimId, const COutPoint& outPoint, std::string& nodeName, int& validHeight);
virtual bool incrementBlock(insertUndoType& insertUndo,
claimUndoType& expireUndo,
insertUndoType& insertSupportUndo,
supportUndoType& expireSupportUndo,
takeoverUndoType& takeovers);
virtual bool decrementBlock(insertUndoType& insertUndo,
claimUndoType& expireUndo,
insertUndoType& insertSupportUndo,
supportUndoType& expireSupportUndo);
virtual bool getInfoForName(const std::string& name, CClaimValue& claim, int heightOffset = 0) const;
virtual bool getProofForName(const std::string& name, const uint160& finalClaim, CClaimTrieProof& proof);
virtual int expirationTime() const;
virtual bool finalizeDecrement(takeoverUndoType& takeovers);
virtual CClaimSupportToName getClaimsForName(const std::string& name) const;
virtual std::string adjustNameForValidHeight(const std::string& name, int validHeight) const;
std::size_t getTotalNamesInTrie() const;
std::size_t getTotalClaimsInTrie() const;
CAmount getTotalValueOfClaimsInTrie(bool fControllingOnly) const;
bool findNameForClaim(std::vector<unsigned char> claim, CClaimValue& value, std::string& name);
void getNamesInTrie(std::function<void(const std::string&)> callback);
bool getLastTakeoverForName(const std::string& name, uint160& claimId, int& takeoverHeight) const;
protected:
CClaimTrie* base;
mutable sqlite::database db;
int nNextHeight; // Height of the block that is being worked on, which is
bool transacting;
mutable std::unordered_set<std::string> removalWorkaround;
// one greater than the height of the chain's tip
mutable sqlite::database_binder claimHashQuery, childHashQuery;
virtual uint256 recursiveComputeMerkleHash(const std::string& name, int takeoverHeight, bool checkOnly);
supportEntryType getSupportsForName(const std::string& name) const;
virtual int getDelayForName(const std::string& name, const uint160& claimId) const;
bool deleteNodeIfPossible(const std::string& name, std::string& parent, int64_t& claims);
void ensureTreeStructureIsUpToDate();
private:
// for unit test
friend struct ClaimTrieChainFixture;
friend class CClaimTrieCacheTest;
bool activateAllFor(insertUndoType& insertUndo, insertUndoType& insertSupportUndo,
const std::string& takeover);
};
class CClaimTrieCacheExpirationFork : public CClaimTrieCacheBase
{
public:
explicit CClaimTrieCacheExpirationFork(CClaimTrie* base);
void setExpirationTime(int time);
int expirationTime() const override;
virtual void initializeIncrement();
bool finalizeDecrement(takeoverUndoType& takeovers) override;
bool incrementBlock(insertUndoType& insertUndo,
claimUndoType& expireUndo,
insertUndoType& insertSupportUndo,
supportUndoType& expireSupportUndo,
takeoverUndoType& takeovers) override;
bool decrementBlock(insertUndoType& insertUndo,
claimUndoType& expireUndo,
insertUndoType& insertSupportUndo,
supportUndoType& expireSupportUndo) override;
private:
int nExpirationTime;
bool forkForExpirationChange(bool increment);
};
class CClaimTrieCacheNormalizationFork : public CClaimTrieCacheExpirationFork
{
public:
explicit CClaimTrieCacheNormalizationFork(CClaimTrie* base)
: CClaimTrieCacheExpirationFork(base)
{
}
bool shouldNormalize() const;
// lower-case and normalize any input string name
// see: https://unicode.org/reports/tr15/#Norm_Forms
std::string normalizeClaimName(const std::string& name, bool force = false) const; // public only for validating name field on update op
bool incrementBlock(insertUndoType& insertUndo,
claimUndoType& expireUndo,
insertUndoType& insertSupportUndo,
supportUndoType& expireSupportUndo,
takeoverUndoType& takeovers) override;
bool decrementBlock(insertUndoType& insertUndo,
claimUndoType& expireUndo,
insertUndoType& insertSupportUndo,
supportUndoType& expireSupportUndo) override;
bool getProofForName(const std::string& name, const uint160& finalClaim, CClaimTrieProof& proof) override;
bool getInfoForName(const std::string& name, CClaimValue& claim, int heightOffset = 0) const override;
CClaimSupportToName getClaimsForName(const std::string& name) const override;
std::string adjustNameForValidHeight(const std::string& name, int validHeight) const override;
protected:
int getDelayForName(const std::string& name, const uint160& claimId) const override;
private:
bool normalizeAllNamesInTrieIfNecessary(takeoverUndoType& takeovers);
bool unnormalizeAllNamesInTrieIfNecessary();
};
class CClaimTrieCacheHashFork : public CClaimTrieCacheNormalizationFork
{
public:
explicit CClaimTrieCacheHashFork(CClaimTrie* base);
bool getProofForName(const std::string& name, const uint160& finalClaim, CClaimTrieProof& proof) override;
void initializeIncrement() override;
bool finalizeDecrement(takeoverUndoType& takeovers) override;
bool allowSupportMetadata() const;
protected:
uint256 recursiveComputeMerkleHash(const std::string& name, int takeoverHeight, bool checkOnly) override;
};
typedef CClaimTrieCacheHashFork CClaimTrieCache;
#endif // BITCOIN_CLAIMTRIE_H

84
src/claimtrie/data.cpp Normal file
View file

@ -0,0 +1,84 @@
#include <claimtrie/data.h>
#include <claimtrie/log.h>
#include <algorithm>
#include <sstream>
#define logPrint CLogPrint::global()
CClaimValue::CClaimValue(CTxOutPoint outPoint, CUint160 claimId, int64_t nAmount, int nHeight, int nValidAtHeight)
: outPoint(std::move(outPoint)), claimId(std::move(claimId)), nAmount(nAmount), nEffectiveAmount(nAmount), nHeight(nHeight), nValidAtHeight(nValidAtHeight)
{
}
bool CClaimValue::operator<(const CClaimValue& other) const
{
if (nEffectiveAmount < other.nEffectiveAmount)
return true;
if (nEffectiveAmount != other.nEffectiveAmount)
return false;
if (nHeight > other.nHeight)
return true;
if (nHeight != other.nHeight)
return false;
return outPoint != other.outPoint && !(outPoint < other.outPoint);
}
bool CClaimValue::operator==(const CClaimValue& other) const
{
return outPoint == other.outPoint && claimId == other.claimId && nAmount == other.nAmount && nHeight == other.nHeight && nValidAtHeight == other.nValidAtHeight;
}
bool CClaimValue::operator!=(const CClaimValue& other) const
{
return !(*this == other);
}
std::string CClaimValue::ToString() const
{
std::stringstream ss;
ss << "CClaimValue(" << outPoint.ToString()
<< ", " << claimId.ToString()
<< ", " << nAmount
<< ", " << nEffectiveAmount
<< ", " << nHeight
<< ", " << nValidAtHeight << ')';
return ss.str();
}
CSupportValue::CSupportValue(CTxOutPoint outPoint, CUint160 supportedClaimId, int64_t nAmount, int nHeight, int nValidAtHeight)
: outPoint(std::move(outPoint)), supportedClaimId(std::move(supportedClaimId)), nAmount(nAmount), nHeight(nHeight), nValidAtHeight(nValidAtHeight)
{
}
bool CSupportValue::operator==(const CSupportValue& other) const
{
return outPoint == other.outPoint && supportedClaimId == other.supportedClaimId && nAmount == other.nAmount && nHeight == other.nHeight && nValidAtHeight == other.nValidAtHeight;
}
bool CSupportValue::operator!=(const CSupportValue& other) const
{
return !(*this == other);
}
std::string CSupportValue::ToString() const
{
std::stringstream ss;
ss << "CSupportValue(" << outPoint.ToString()
<< ", " << supportedClaimId.ToString()
<< ", " << nAmount
<< ", " << nHeight
<< ", " << nValidAtHeight << ')';
return ss.str();
}
CNameOutPointHeightType::CNameOutPointHeightType(std::string name, CTxOutPoint outPoint, int nValidHeight)
: name(std::move(name)), outPoint(std::move(outPoint)), nValidHeight(nValidHeight)
{
}
CClaimIndexElement::CClaimIndexElement(std::string name, CClaimValue claim)
: name(std::move(name)), claim(std::move(claim))
{
}

131
src/claimtrie/data.h Normal file
View file

@ -0,0 +1,131 @@
#ifndef CLAIMTRIE_DATA_H
#define CLAIMTRIE_DATA_H
#include <claimtrie/sqlite/sqlite3.h>
#include <claimtrie/txoutpoint.h>
#include <claimtrie/uints.h>
#include <cstring>
#include <string>
#include <vector>
namespace sqlite
{
inline int bind_col_in_db(sqlite3_stmt* stmt, int inx, const CUint160& val) {
return sqlite3_bind_blob(stmt, inx, val.begin(), int(val.size()), SQLITE_STATIC);
}
inline int bind_col_in_db(sqlite3_stmt* stmt, int inx, const CUint256& val) {
return sqlite3_bind_blob(stmt, inx, val.begin(), int(val.size()), SQLITE_STATIC);
}
inline void store_result_in_db(sqlite3_context* db, const CUint160& val) {
sqlite3_result_blob(db, val.begin(), int(val.size()), SQLITE_TRANSIENT);
}
inline void store_result_in_db(sqlite3_context* db, const CUint256& val) {
sqlite3_result_blob(db, val.begin(), int(val.size()), SQLITE_TRANSIENT);
}
}
#include <claimtrie/sqlite/hdr/sqlite_modern_cpp.h>
namespace sqlite
{
template<>
struct has_sqlite_type<CUint256, SQLITE_BLOB, void> : std::true_type {};
template<>
struct has_sqlite_type<CUint160, SQLITE_BLOB, void> : std::true_type {};
inline CUint160 get_col_from_db(sqlite3_stmt* stmt, int inx, result_type<CUint160>) {
CUint160 ret;
auto ptr = sqlite3_column_blob(stmt, inx);
if (!ptr) return ret;
int bytes = sqlite3_column_bytes(stmt, inx);
assert(bytes == ret.size());
std::memcpy(ret.begin(), ptr, bytes);
return ret;
}
inline CUint256 get_col_from_db(sqlite3_stmt* stmt, int inx, result_type<CUint256>) {
CUint256 ret;
auto ptr = sqlite3_column_blob(stmt, inx);
if (!ptr) return ret;
int bytes = sqlite3_column_bytes(stmt, inx);
assert(bytes == ret.size());
std::memcpy(ret.begin(), ptr, bytes);
return ret;
}
}
struct CClaimValue
{
CTxOutPoint outPoint;
CUint160 claimId;
int64_t nAmount = 0;
int64_t nEffectiveAmount = 0;
int nHeight = 0;
int nValidAtHeight = 0;
CClaimValue() = default;
CClaimValue(CTxOutPoint outPoint, CUint160 claimId, int64_t nAmount, int nHeight, int nValidAtHeight);
CClaimValue(CClaimValue&&) = default;
CClaimValue(const CClaimValue&) = default;
CClaimValue& operator=(CClaimValue&&) = default;
CClaimValue& operator=(const CClaimValue&) = default;
bool operator<(const CClaimValue& other) const;
bool operator==(const CClaimValue& other) const;
bool operator!=(const CClaimValue& other) const;
std::string ToString() const;
};
struct CSupportValue
{
CTxOutPoint outPoint;
CUint160 supportedClaimId;
int64_t nAmount = 0;
int nHeight = 0;
int nValidAtHeight = 0;
CSupportValue() = default;
CSupportValue(CTxOutPoint outPoint, CUint160 supportedClaimId, int64_t nAmount, int nHeight, int nValidAtHeight);
CSupportValue(CSupportValue&&) = default;
CSupportValue(const CSupportValue&) = default;
CSupportValue& operator=(CSupportValue&&) = default;
CSupportValue& operator=(const CSupportValue&) = default;
bool operator==(const CSupportValue& other) const;
bool operator!=(const CSupportValue& other) const;
std::string ToString() const;
};
typedef std::vector<CClaimValue> claimEntryType;
typedef std::vector<CSupportValue> supportEntryType;
struct CNameOutPointHeightType
{
std::string name;
CTxOutPoint outPoint;
int nValidHeight = 0;
CNameOutPointHeightType() = default;
CNameOutPointHeightType(std::string name, CTxOutPoint outPoint, int nValidHeight);
};
struct CClaimIndexElement
{
std::string name;
CClaimValue claim;
CClaimIndexElement() = default;
CClaimIndexElement(std::string name, CClaimValue claim);
};
#endif // CLAIMTRIE_DATA_H

View file

@ -1,35 +1,33 @@
#include <consensus/merkle.h>
#include <chainparams.h>
#include <claimtrie.h>
#include <hash.h>
#include <claimtrie/forks.h>
#include <claimtrie/hash.h>
#include <claimtrie/log.h>
#include <claimtrie/trie.h>
#include <boost/locale.hpp>
#include <boost/locale/conversion.hpp>
#include <boost/locale/localization_backend.hpp>
#include <boost/scoped_ptr.hpp>
CClaimTrieCacheExpirationFork::CClaimTrieCacheExpirationFork(CClaimTrie* base)
: CClaimTrieCacheBase(base)
{
setExpirationTime(Params().GetConsensus().GetExpirationTime(nNextHeight));
}
#define logPrint CLogPrint::global()
void CClaimTrieCacheExpirationFork::setExpirationTime(int time)
CClaimTrieCacheExpirationFork::CClaimTrieCacheExpirationFork(CClaimTrie* base) : CClaimTrieCacheBase(base)
{
nExpirationTime = time;
expirationHeight = nNextHeight;
}
int CClaimTrieCacheExpirationFork::expirationTime() const
{
return nExpirationTime;
if (expirationHeight < base->nExtendedClaimExpirationForkHeight)
return CClaimTrieCacheBase::expirationTime();
return base->nExtendedClaimExpirationTime;
}
bool CClaimTrieCacheExpirationFork::incrementBlock(insertUndoType& insertUndo, claimUndoType& expireUndo,
insertUndoType& insertSupportUndo, supportUndoType& expireSupportUndo, takeoverUndoType& takeoverUndo)
{
if (CClaimTrieCacheBase::incrementBlock(insertUndo, expireUndo, insertSupportUndo, expireSupportUndo, takeoverUndo)) {
setExpirationTime(Params().GetConsensus().GetExpirationTime(nNextHeight));
expirationHeight = nNextHeight;
return true;
}
return false;
@ -38,7 +36,7 @@ bool CClaimTrieCacheExpirationFork::incrementBlock(insertUndoType& insertUndo, c
bool CClaimTrieCacheExpirationFork::decrementBlock(insertUndoType& insertUndo, claimUndoType& expireUndo, insertUndoType& insertSupportUndo, supportUndoType& expireSupportUndo)
{
if (CClaimTrieCacheBase::decrementBlock(insertUndo, expireUndo, insertSupportUndo, expireSupportUndo)) {
setExpirationTime(Params().GetConsensus().GetExpirationTime(nNextHeight));
expirationHeight = nNextHeight;
return true;
}
return false;
@ -47,7 +45,7 @@ bool CClaimTrieCacheExpirationFork::decrementBlock(insertUndoType& insertUndo, c
void CClaimTrieCacheExpirationFork::initializeIncrement()
{
// we could do this in the constructor, but that would not allow for multiple increments in a row (as done in unit tests)
if (nNextHeight != Params().GetConsensus().nExtendedClaimExpirationForkHeight)
if (nNextHeight != base->nExtendedClaimExpirationForkHeight)
return;
forkForExpirationChange(true);
@ -56,7 +54,7 @@ void CClaimTrieCacheExpirationFork::initializeIncrement()
bool CClaimTrieCacheExpirationFork::finalizeDecrement(takeoverUndoType& takeoverUndo)
{
auto ret = CClaimTrieCacheBase::finalizeDecrement(takeoverUndo);
if (ret && nNextHeight == Params().GetConsensus().nExtendedClaimExpirationForkHeight)
if (ret && nNextHeight == base->nExtendedClaimExpirationForkHeight)
forkForExpirationChange(false);
return ret;
}
@ -73,7 +71,7 @@ bool CClaimTrieCacheExpirationFork::forkForExpirationChange(bool increment)
will have their expiration extension removed.
*/
auto extension = Params().GetConsensus().nExtendedClaimExpirationTime - Params().GetConsensus().nOriginalClaimExpirationTime;
auto extension = base->nExtendedClaimExpirationTime - base->nOriginalClaimExpirationTime;
if (increment) {
db << "UPDATE claims SET expirationHeight = expirationHeight + ? WHERE expirationHeight >= ?"
<< extension << nNextHeight;
@ -89,9 +87,13 @@ bool CClaimTrieCacheExpirationFork::forkForExpirationChange(bool increment)
return true;
}
CClaimTrieCacheNormalizationFork::CClaimTrieCacheNormalizationFork(CClaimTrie* base) : CClaimTrieCacheExpirationFork(base)
{
}
bool CClaimTrieCacheNormalizationFork::shouldNormalize() const
{
return nNextHeight > Params().GetConsensus().nNormalizedNameForkHeight;
return nNextHeight > base->nNormalizedNameForkHeight;
}
std::string CClaimTrieCacheNormalizationFork::normalizeClaimName(const std::string& name, bool force) const
@ -125,10 +127,10 @@ std::string CClaimTrieCacheNormalizationFork::normalizeClaimName(const std::stri
} catch (const boost::locale::conv::conversion_error& e) {
return name;
} catch (const std::bad_cast& e) {
LogPrintf("%s() is invalid or dependencies are missing: %s\n", __func__, e.what());
logPrint << "CClaimTrieCacheNormalizationFork::" << __func__ << "() is invalid or dependencies are missing: " << e.what() << Clog::endl;
throw;
} catch (const std::exception& e) { // TODO: change to use ... with current_exception() in c++11
LogPrintf("%s() had an unexpected exception: %s\n", __func__, e.what());
logPrint << "CClaimTrieCacheNormalizationFork::" << __func__ << "() had an unexpected exception: " << e.what() << Clog::endl;
return name;
}
@ -159,11 +161,11 @@ bool CClaimTrieCacheNormalizationFork::normalizeAllNamesInTrieIfNecessary(takeov
for (auto&& row: query) {
std::string name;
int takeoverHeight;
std::unique_ptr<uint160> takeoverID;
std::unique_ptr<CUint160> takeoverID;
row >> name >> takeoverHeight >> takeoverID;
if (name.empty()) continue; // preserve our root node
if (takeoverHeight > 0)
takeoverUndo.emplace_back(name, std::make_pair(takeoverHeight, takeoverID ? *takeoverID : uint160()));
takeoverUndo.emplace_back(name, std::make_pair(takeoverHeight, takeoverID ? *takeoverID : CUint160()));
// we need to let the tree structure method do the actual node delete:
db << "UPDATE nodes SET hash = NULL WHERE name = ?" << name;
}
@ -202,57 +204,22 @@ bool CClaimTrieCacheNormalizationFork::unnormalizeAllNamesInTrieIfNecessary()
bool CClaimTrieCacheNormalizationFork::incrementBlock(insertUndoType& insertUndo, claimUndoType& expireUndo,
insertUndoType& insertSupportUndo, supportUndoType& expireSupportUndo, takeoverUndoType& takeoverUndo)
{
if (nNextHeight == Params().GetConsensus().nNormalizedNameForkHeight)
if (nNextHeight == base->nNormalizedNameForkHeight)
normalizeAllNamesInTrieIfNecessary(takeoverUndo);
auto ret = CClaimTrieCacheExpirationFork::incrementBlock(insertUndo, expireUndo, insertSupportUndo, expireSupportUndo, takeoverUndo);
// if (nNextHeight == 588319) {
// getMerkleHash();
// auto q2 = db << "SELECT name, nodeName FROM claims WHERE nodeName NOT IN (SELECT name FROM nodes) "
// "AND validHeight < ?1 AND expirationHeight >= ?1" << nNextHeight;
// for (auto&& row: q2) {
// std::string name, nn;
// row >> name >> nn;
// LogPrintf("BAD NAME 2: %s, %s\n", name, nn);
// }
// std::ifstream input("dump588318.txt");
// std::string line;
// std::vector<std::string> lines;
// while (std::getline(input, line)) {
// lines.push_back(line);
// }
// std::sort(lines.begin(), lines.end());
// auto q3 = db << "SELECT n.name, n.hash, IFNULL(n.takeoverHeight, 0), "
// "(SELECT COUNT(*) FROM claims c WHERE c.nodeName = n.name "
// "AND validHeight < ?1 AND expirationHeight >= ?1) as cc FROM nodes n ORDER BY n.name" << nNextHeight;
// for (auto&& row: q3) {
// std::string name; int takeover, childs; uint256 hash;
// row >> name >> hash >> takeover >> childs;
// std::string m = name + ", " + std::to_string(name.size()) + ", " + hash.GetHex() + ", " + std::to_string(takeover) + ", " + std::to_string(childs);
// if (!std::binary_search(lines.begin(), lines.end(), m)) {
// LogPrintf("BAD BAD: %s\n", m);
// }
// }
// auto q4 = db << "SELECT n.name, n.parent FROM nodes n LEFT JOIN claims c ON n.name = c.nodeName LEFT JOIN nodes n2 ON n.name = n2.parent WHERE c.nodeName IS NULL AND n2.parent IS NULL";
// for (auto&& row: q4) {
// std::string name, nn;
// row >> name >> nn;
// LogPrintf("BAD NAME 3: %s, %s\n", name, nn);
// }
// }
return ret;
return CClaimTrieCacheExpirationFork::incrementBlock(insertUndo, expireUndo, insertSupportUndo, expireSupportUndo, takeoverUndo);
}
bool CClaimTrieCacheNormalizationFork::decrementBlock(insertUndoType& insertUndo, claimUndoType& expireUndo, insertUndoType& insertSupportUndo, supportUndoType& expireSupportUndo)
{
auto ret = CClaimTrieCacheExpirationFork::decrementBlock(insertUndo, expireUndo, insertSupportUndo, expireSupportUndo);
if (ret && nNextHeight == Params().GetConsensus().nNormalizedNameForkHeight)
if (ret && nNextHeight == base->nNormalizedNameForkHeight)
unnormalizeAllNamesInTrieIfNecessary();
return ret;
}
bool CClaimTrieCacheNormalizationFork::getProofForName(const std::string& name, const uint160& finalClaim, CClaimTrieProof& proof)
bool CClaimTrieCacheNormalizationFork::getProofForName(const std::string& name, const CUint160& claim, CClaimTrieProof& proof)
{
return CClaimTrieCacheExpirationFork::getProofForName(normalizeClaimName(name), finalClaim, proof);
return CClaimTrieCacheExpirationFork::getProofForName(normalizeClaimName(name), claim, proof);
}
bool CClaimTrieCacheNormalizationFork::getInfoForName(const std::string& name, CClaimValue& claim, int offsetHeight) const
@ -265,30 +232,45 @@ CClaimSupportToName CClaimTrieCacheNormalizationFork::getClaimsForName(const std
return CClaimTrieCacheExpirationFork::getClaimsForName(normalizeClaimName(name));
}
int CClaimTrieCacheNormalizationFork::getDelayForName(const std::string& name, const uint160& claimId) const
int CClaimTrieCacheNormalizationFork::getDelayForName(const std::string& name, const CUint160& claimId) const
{
return CClaimTrieCacheExpirationFork::getDelayForName(normalizeClaimName(name), claimId);
}
std::string CClaimTrieCacheNormalizationFork::adjustNameForValidHeight(const std::string& name, int validHeight) const
{
return normalizeClaimName(name, validHeight > Params().GetConsensus().nNormalizedNameForkHeight);
return normalizeClaimName(name, validHeight > base->nNormalizedNameForkHeight);
}
CClaimTrieCacheHashFork::CClaimTrieCacheHashFork(CClaimTrie* base) : CClaimTrieCacheNormalizationFork(base)
{
}
static const uint256 leafHash = uint256S("0000000000000000000000000000000000000000000000000000000000000002");
static const uint256 emptyHash = uint256S("0000000000000000000000000000000000000000000000000000000000000003");
static const auto leafHash = CUint256S("0000000000000000000000000000000000000000000000000000000000000002");
static const auto emptyHash = CUint256S("0000000000000000000000000000000000000000000000000000000000000003");
uint256 CClaimTrieCacheHashFork::recursiveComputeMerkleHash(const std::string& name, int takeoverHeight, bool checkOnly)
CUint256 ComputeMerkleRoot(std::vector<CUint256> hashes)
{
if (nNextHeight < Params().GetConsensus().nAllClaimsInMerkleForkHeight)
while (hashes.size() > 1) {
if (hashes.size() & 1)
hashes.push_back(hashes.back());
for (std::size_t i = 0, j = 0; i < hashes.size(); i += 2)
hashes[j++] = Hash(hashes[i].begin(), hashes[i].end(),
hashes[i+1].begin(), hashes[i+1].end());
hashes.resize(hashes.size() / 2);
}
return hashes.empty() ? CUint256{} : hashes[0];
}
CUint256 CClaimTrieCacheHashFork::recursiveComputeMerkleHash(const std::string& name, int takeoverHeight, bool checkOnly)
{
if (nNextHeight < base->nAllClaimsInMerkleForkHeight)
return CClaimTrieCacheNormalizationFork::recursiveComputeMerkleHash(name, takeoverHeight, checkOnly);
// it may be that using RAM for this is more expensive than preparing a new query statement in each recursive call
struct Triple { std::string name; std::unique_ptr<uint256> hash; int takeoverHeight; };
struct Triple { std::string name; std::unique_ptr<CUint256> hash; int takeoverHeight; };
std::vector<Triple> children;
for (auto&& row : childHashQuery << name) {
children.emplace_back();
@ -297,19 +279,19 @@ uint256 CClaimTrieCacheHashFork::recursiveComputeMerkleHash(const std::string& n
}
childHashQuery++;
std::vector<uint256> childHashes;
std::vector<CUint256> childHashes;
for (auto& child: children) {
if (child.hash == nullptr) child.hash = std::make_unique<uint256>();
if (child.hash == nullptr) child.hash = std::make_unique<CUint256>();
if (child.hash->IsNull()) {
*child.hash = recursiveComputeMerkleHash(child.name, child.takeoverHeight, checkOnly);
}
childHashes.push_back(*child.hash);
}
std::vector<uint256> claimHashes;
std::vector<CUint256> claimHashes;
//if (takeoverHeight > 0) {
for (auto &&row: claimHashQuery << nNextHeight << name) {
COutPoint p;
CTxOutPoint p;
row >> p.hash >> p.n;
auto claimHash = getValueHash(p, takeoverHeight);
claimHashes.push_back(claimHash);
@ -326,14 +308,14 @@ uint256 CClaimTrieCacheHashFork::recursiveComputeMerkleHash(const std::string& n
return computedHash;
}
std::vector<uint256> ComputeMerklePath(const std::vector<uint256>& hashes, uint32_t idx)
std::vector<CUint256> ComputeMerklePath(const std::vector<CUint256>& hashes, uint32_t idx)
{
uint32_t count = 0;
int matchlevel = -1;
bool matchh = false;
uint256 inner[32], h;
CUint256 inner[32], h;
const uint32_t one = 1;
std::vector<uint256> res;
std::vector<CUint256> res;
const auto iterateInner = [&](int& level) {
for (; !(count & (one << level)); level++) {
@ -381,12 +363,12 @@ std::vector<uint256> ComputeMerklePath(const std::vector<uint256>& hashes, uint3
return res;
}
bool CClaimTrieCacheHashFork::getProofForName(const std::string& name, const uint160& finalClaim, CClaimTrieProof& proof)
bool CClaimTrieCacheHashFork::getProofForName(const std::string& name, const CUint160& claim, CClaimTrieProof& proof)
{
if (nNextHeight < Params().GetConsensus().nAllClaimsInMerkleForkHeight)
return CClaimTrieCacheNormalizationFork::getProofForName(name, finalClaim, proof);
if (nNextHeight < base->nAllClaimsInMerkleForkHeight)
return CClaimTrieCacheNormalizationFork::getProofForName(name, claim, proof);
auto fillPairs = [&proof](const std::vector<uint256>& hashes, uint32_t idx) {
auto fillPairs = [&proof](const std::vector<CUint256>& hashes, uint32_t idx) {
auto partials = ComputeMerklePath(hashes, idx);
for (int i = partials.size() - 1; i >= 0; --i)
proof.pairs.emplace_back((idx >> i) & 1, partials[i]);
@ -400,14 +382,14 @@ bool CClaimTrieCacheHashFork::getProofForName(const std::string& name, const uin
"SELECT POPS(p) FROM prefix WHERE p != '') SELECT p FROM prefix) "
"ORDER BY name" << name;
for (auto&& row: nodeQuery) {
std::string key;;
std::string key;
int takeoverHeight;
row >> key >> takeoverHeight;
std::vector<uint256> childHashes;
uint32_t nextCurrentIdx = 0;
std::vector<CUint256> childHashes;
for (auto&& child : childHashQuery << key) {
std::string childKey;
uint256 childHash;
CUint256 childHash;
child >> childKey >> childHash;
if (name.find(childKey) == 0)
nextCurrentIdx = uint32_t(childHashes.size());
@ -415,14 +397,14 @@ bool CClaimTrieCacheHashFork::getProofForName(const std::string& name, const uin
}
childHashQuery++;
std::vector<uint256> claimHashes;
uint32_t finalClaimIdx = 0;
std::vector<CUint256> claimHashes;
uint32_t claimIdx = 0;
for (auto&& child: claimHashQuery << nNextHeight << key) {
COutPoint childOutPoint;
uint160 childClaimID;
CTxOutPoint childOutPoint;
CUint160 childClaimID;
child >> childOutPoint.hash >> childOutPoint.n >> childClaimID;
if (childClaimID == finalClaim && key == name) {
finalClaimIdx = uint32_t(claimHashes.size());
if (childClaimID == claim && key == name) {
claimIdx = uint32_t(claimHashes.size());
proof.outPoint = childOutPoint;
proof.hasValue = true;
}
@ -438,7 +420,7 @@ bool CClaimTrieCacheHashFork::getProofForName(const std::string& name, const uin
auto hash = childHashes.empty() ? leafHash : ComputeMerkleRoot(childHashes);
proof.pairs.emplace_back(true, hash);
if (!claimHashes.empty())
fillPairs(claimHashes, finalClaimIdx);
fillPairs(claimHashes, claimIdx);
} else {
auto hash = claimHashes.empty() ? emptyHash : ComputeMerkleRoot(claimHashes);
proof.pairs.emplace_back(false, hash);
@ -454,7 +436,7 @@ void CClaimTrieCacheHashFork::initializeIncrement()
{
CClaimTrieCacheNormalizationFork::initializeIncrement();
// we could do this in the constructor, but that would not allow for multiple increments in a row (as done in unit tests)
if (nNextHeight == Params().GetConsensus().nAllClaimsInMerkleForkHeight - 1) {
if (nNextHeight == base->nAllClaimsInMerkleForkHeight - 1) {
if (!transacting) { transacting = true; db << "begin"; }
db << "UPDATE nodes SET hash = NULL";
}
@ -463,7 +445,7 @@ void CClaimTrieCacheHashFork::initializeIncrement()
bool CClaimTrieCacheHashFork::finalizeDecrement(takeoverUndoType& takeoverUndo)
{
auto ret = CClaimTrieCacheNormalizationFork::finalizeDecrement(takeoverUndo);
if (ret && nNextHeight == Params().GetConsensus().nAllClaimsInMerkleForkHeight - 1) {
if (ret && nNextHeight == base->nAllClaimsInMerkleForkHeight - 1) {
if (!transacting) { transacting = true; db << "begin"; }
db << "UPDATE nodes SET hash = NULL";
}
@ -472,5 +454,5 @@ bool CClaimTrieCacheHashFork::finalizeDecrement(takeoverUndoType& takeoverUndo)
bool CClaimTrieCacheHashFork::allowSupportMetadata() const
{
return nNextHeight >= Params().GetConsensus().nAllClaimsInMerkleForkHeight;
return nNextHeight >= base->nAllClaimsInMerkleForkHeight;
}

87
src/claimtrie/forks.h Normal file
View file

@ -0,0 +1,87 @@
#ifndef CLAIMTRIE_FORKS_H
#define CLAIMTRIE_FORKS_H
#include <claimtrie/trie.h>
class CClaimTrieCacheExpirationFork : public CClaimTrieCacheBase
{
public:
explicit CClaimTrieCacheExpirationFork(CClaimTrie* base);
int expirationTime() const override;
virtual void initializeIncrement();
bool finalizeDecrement(takeoverUndoType& takeoverHeightUndo) override;
bool incrementBlock(insertUndoType& insertUndo,
claimUndoType& expireUndo,
insertUndoType& insertSupportUndo,
supportUndoType& expireSupportUndo,
takeoverUndoType& takeoverHeightUndo) override;
bool decrementBlock(insertUndoType& insertUndo,
claimUndoType& expireUndo,
insertUndoType& insertSupportUndo,
supportUndoType& expireSupportUndo) override;
protected:
int expirationHeight;
private:
bool forkForExpirationChange(bool increment);
};
class CClaimTrieCacheNormalizationFork : public CClaimTrieCacheExpirationFork
{
public:
explicit CClaimTrieCacheNormalizationFork(CClaimTrie* base);
bool shouldNormalize() const;
// lower-case and normalize any input string name
// see: https://unicode.org/reports/tr15/#Norm_Forms
std::string normalizeClaimName(const std::string& name, bool force = false) const; // public only for validating name field on update op
bool incrementBlock(insertUndoType& insertUndo,
claimUndoType& expireUndo,
insertUndoType& insertSupportUndo,
supportUndoType& expireSupportUndo,
takeoverUndoType& takeoverHeightUndo) override;
bool decrementBlock(insertUndoType& insertUndo,
claimUndoType& expireUndo,
insertUndoType& insertSupportUndo,
supportUndoType& expireSupportUndo) override;
bool getProofForName(const std::string& name, const CUint160& claim, CClaimTrieProof& proof) override;
bool getInfoForName(const std::string& name, CClaimValue& claim, int heightOffset = 0) const override;
CClaimSupportToName getClaimsForName(const std::string& name) const override;
std::string adjustNameForValidHeight(const std::string& name, int validHeight) const override;
protected:
int getDelayForName(const std::string& name, const CUint160& claimId) const override;
private:
bool normalizeAllNamesInTrieIfNecessary(takeoverUndoType& takeovers);
bool unnormalizeAllNamesInTrieIfNecessary();
};
class CClaimTrieCacheHashFork : public CClaimTrieCacheNormalizationFork
{
public:
explicit CClaimTrieCacheHashFork(CClaimTrie* base);
bool getProofForName(const std::string& name, const CUint160& claim, CClaimTrieProof& proof) override;
void initializeIncrement() override;
bool finalizeDecrement(takeoverUndoType& takeoverHeightUndo) override;
bool allowSupportMetadata() const;
protected:
CUint256 recursiveComputeMerkleHash(const std::string& name, int takeoverHeight, bool checkOnly) override;
};
typedef CClaimTrieCacheHashFork CClaimTrieCache;
#endif // CLAIMTRIE_FORKS_H

12
src/claimtrie/hash.cpp Normal file
View file

@ -0,0 +1,12 @@
#include <claimtrie/hash.h>
CUint256 CalcHash(SHA256_CTX* sha)
{
CUint256 result;
SHA256_Final(result.begin(), sha);
SHA256_Init(sha);
SHA256_Update(sha, result.begin(), result.size());
SHA256_Final(result.begin(), sha);
return result;
}

29
src/claimtrie/hash.h Normal file
View file

@ -0,0 +1,29 @@
#ifndef CLAIMTRIE_HASH_H
#define CLAIMTRIE_HASH_H
#include <openssl/sha.h>
#include <claimtrie/uints.h>
// Bitcoin doubles hashes
CUint256 CalcHash(SHA256_CTX* sha);
template<typename TIterator, typename... Args>
CUint256 CalcHash(SHA256_CTX* sha, TIterator begin, TIterator end, Args... args)
{
static uint8_t blank;
SHA256_Update(sha, begin == end ? &blank : (uint8_t*)&begin[0], std::distance(begin, end) * sizeof(begin[0]));
return CalcHash(sha, args...);
}
template<typename TIterator, typename... Args>
CUint256 Hash(TIterator begin, TIterator end, Args... args)
{
static_assert((sizeof...(args) & 1) != 1, "Parameters should be even number");
SHA256_CTX sha;
SHA256_Init(&sha);
return CalcHash(&sha, begin, end, args...);
}
#endif // CLAIMTRIE_HASH_H

23
src/claimtrie/log.cpp Normal file
View file

@ -0,0 +1,23 @@
#include <claimtrie/log.h>
void CLogPrint::setLogger(ClogBase* log)
{
logger = log;
}
CLogPrint& CLogPrint::global()
{
static CLogPrint logger;
return logger;
}
CLogPrint& CLogPrint::operator<<(const Clog& cl)
{
if (logger && cl == Clog::endl) {
ss << '\n';
logger->LogPrintStr(ss.str());
ss.str({});
}
return *this;
}

41
src/claimtrie/log.h Normal file
View file

@ -0,0 +1,41 @@
#ifndef CLAIMTRIE_LOG_H
#define CLAIMTRIE_LOG_H
#include <string>
#include <sstream>
struct ClogBase
{
ClogBase() = default;
virtual ~ClogBase() = default;
virtual void LogPrintStr(const std::string&) = 0;
};
enum struct Clog
{
endl = 0,
};
struct CLogPrint
{
template <typename T>
CLogPrint& operator<<(const T& a)
{
if (logger)
ss << a;
return *this;
}
CLogPrint& operator<<(const Clog& cl);
void setLogger(ClogBase* log);
static CLogPrint& global();
private:
CLogPrint() = default;
std::stringstream ss;
ClogBase* logger = nullptr;
};
#endif // CLAIMTRIE_LOG_H

View file

@ -9,7 +9,7 @@
#define MODERN_SQLITE_VERSION 3002008
#include <sqlite/sqlite3.h>
#include "../sqlite3.h"
#include "sqlite_modern_cpp/type_wrapper.h"
#include "sqlite_modern_cpp/errors.h"

View file

@ -3,7 +3,7 @@
#include <string>
#include <stdexcept>
#include <sqlite/sqlite3.h>
#include "../../sqlite3.h"
namespace sqlite {

View file

@ -49,7 +49,7 @@ namespace sqlite
typedef const std::u16string& u16str_ref;
}
#endif
#include <sqlite/sqlite3.h>
#include "../../sqlite3.h"
#include "errors.h"
namespace sqlite {

View file

@ -1,21 +1,22 @@
#include <claimtrie.h>
#include <hash.h>
#include <logging.h>
#include <util.h>
#include <utilstrencodings.h>
#include <claimtrie/hash.h>
#include <claimtrie/log.h>
#include <claimtrie/trie.h>
#include <algorithm>
#include <memory>
#include <consensus/merkle.h>
#include <iomanip>
#include <boost/container/flat_map.hpp>
#include <boost/container/flat_set.hpp>
extern const uint256 one = uint256S("0000000000000000000000000000000000000000000000000000000000000001");
#define logPrint CLogPrint::global()
static const auto one = CUint256S("0000000000000000000000000000000000000000000000000000000000000001");
std::vector<unsigned char> heightToVch(int n)
{
std::vector<unsigned char> vchHeight(8, 0);
std::vector<uint8_t> vchHeight(8, 0);
vchHeight[4] = n >> 24;
vchHeight[5] = n >> 16;
vchHeight[6] = n >> 8;
@ -23,23 +24,61 @@ std::vector<unsigned char> heightToVch(int n)
return vchHeight;
}
uint256 getValueHash(const COutPoint& outPoint, int nHeightOfLastTakeover)
CUint256 getValueHash(const CTxOutPoint& outPoint, int nHeightOfLastTakeover)
{
CHash256 hasher;
auto hash = Hash(outPoint.hash.begin(), outPoint.hash.end());
hasher.Write(hash.begin(), hash.size());
auto hash1 = Hash(outPoint.hash.begin(), outPoint.hash.end());
auto snOut = std::to_string(outPoint.n);
hash = Hash(snOut.begin(), snOut.end());
hasher.Write(hash.begin(), hash.size());
auto hash2 = Hash(snOut.begin(), snOut.end());
auto vchHash = heightToVch(nHeightOfLastTakeover);
hash = Hash(vchHash.begin(), vchHash.end());
hasher.Write(hash.begin(), hash.size());
auto hash3 = Hash(vchHash.begin(), vchHash.end());
return Hash(hash1.begin(), hash1.end(), hash2.begin(), hash2.end(), hash3.begin(), hash3.end());
}
uint256 result;
hasher.Finalize(result.begin());
return result;
CClaimNsupports::CClaimNsupports(CClaimValue claim, int64_t effectiveAmount, std::vector<CSupportValue> supports)
: claim(std::move(claim)), effectiveAmount(effectiveAmount), supports(std::move(supports))
{
}
bool CClaimNsupports::IsNull() const
{
return claim.claimId.IsNull();
}
CClaimSupportToName::CClaimSupportToName(std::string name, int nLastTakeoverHeight, std::vector<CClaimNsupports> claimsNsupports, std::vector<CSupportValue> unmatchedSupports)
: name(std::move(name)), nLastTakeoverHeight(nLastTakeoverHeight), claimsNsupports(std::move(claimsNsupports)), unmatchedSupports(std::move(unmatchedSupports))
{
}
static const CClaimNsupports invalid;
const CClaimNsupports& CClaimSupportToName::find(const CUint160& claimId) const
{
auto it = std::find_if(claimsNsupports.begin(), claimsNsupports.end(), [&claimId](const CClaimNsupports& value) {
return claimId == value.claim.claimId;
});
return it != claimsNsupports.end() ? *it : invalid;
}
const CClaimNsupports& CClaimSupportToName::find(const std::string& partialId) const
{
std::string lowered(partialId);
for (auto& c: lowered)
c = std::tolower(c);
auto it = std::find_if(claimsNsupports.begin(), claimsNsupports.end(), [&lowered](const CClaimNsupports& value) {
return value.claim.claimId.GetHex().find(lowered) == 0;
});
return it != claimsNsupports.end() ? *it : invalid;
}
bool CClaimNsupports::operator<(const CClaimNsupports& other) const
{
return claim < other.claim;
}
CClaimTrieProofNode::CClaimTrieProofNode(std::vector<std::pair<unsigned char, CUint256>> children, bool hasValue, CUint256 valHash)
: children(std::move(children)), hasValue(hasValue), valHash(std::move(valHash))
{
}
static const sqlite::sqlite_config sharedConfig {
@ -47,16 +86,22 @@ static const sqlite::sqlite_config sharedConfig{
nullptr, sqlite::Encoding::UTF8
};
CClaimTrie::CClaimTrie(bool fWipe, int height, int proportionalDelayFactor)
: dbPath((GetDataDir() / "claims.sqlite").string()), db(dbPath, sharedConfig),
nNextHeight(height), nProportionalDelayFactor(proportionalDelayFactor)
CClaimTrie::CClaimTrie(bool fWipe, int height,
int nNormalizedNameForkHeight,
int64_t nOriginalClaimExpirationTime,
int64_t nExtendedClaimExpirationTime,
int64_t nExtendedClaimExpirationForkHeight,
int64_t nAllClaimsInMerkleForkHeight,
int proportionalDelayFactor) :
nNextHeight(height),
db("claims.sqlite", sharedConfig),
nProportionalDelayFactor(proportionalDelayFactor),
nNormalizedNameForkHeight(nNormalizedNameForkHeight),
nOriginalClaimExpirationTime(nOriginalClaimExpirationTime),
nExtendedClaimExpirationTime(nExtendedClaimExpirationTime),
nExtendedClaimExpirationForkHeight(nExtendedClaimExpirationForkHeight),
nAllClaimsInMerkleForkHeight(nAllClaimsInMerkleForkHeight)
{
// db.define("MERKLE_ROOT", [](std::vector<uint256>& hashes, const std::vector<unsigned char>& blob) { hashes.emplace_back(uint256(blob)); },
// [](const std::vector<uint256>& hashes) { return ComputeMerkleRoot(hashes); });
//
// db.define("MERKLE_PAIR", [](const std::vector<unsigned char>& blob1, const std::vector<unsigned char>& blob2) { return Hash(blob1.begin(), blob1.end(), blob2.begin(), blob2.end()); });
// db.define("MERKLE", [](const std::vector<unsigned char>& blob1) { return Hash(blob1.begin(), blob1.end()); });
db << "CREATE TABLE IF NOT EXISTS nodes (name TEXT NOT NULL PRIMARY KEY, parent TEXT REFERENCES nodes(name) DEFERRABLE INITIALLY DEFERRED, "
"hash BLOB COLLATE BINARY, takeoverHeight INTEGER, takeoverID BLOB COLLATE BINARY)";
db << "CREATE INDEX IF NOT EXISTS nodes_hash ON nodes (hash)";
@ -95,7 +140,8 @@ CClaimTrie::CClaimTrie(bool fWipe, int height, int proportionalDelayFactor)
db << "INSERT OR IGNORE INTO nodes(name, hash) VALUES('', ?)" << one; // ensure that we always have our root node
}
CClaimTrieCacheBase::~CClaimTrieCacheBase() {
CClaimTrieCacheBase::~CClaimTrieCacheBase()
{
if (transacting) {
db << "rollback";
transacting = false;
@ -111,13 +157,14 @@ bool CClaimTrie::SyncToDisk()
return rc == SQLITE_OK;
}
bool CClaimTrie::empty() {
bool CClaimTrie::empty()
{
int64_t count;
db << "SELECT COUNT(*) FROM claims WHERE validHeight < ?1 AND expirationHeight >= ?1" << nNextHeight >> count;
return count == 0;
}
bool CClaimTrieCacheBase::haveClaim(const std::string& name, const COutPoint& outPoint) const
bool CClaimTrieCacheBase::haveClaim(const std::string& name, const CTxOutPoint& outPoint) const
{
auto query = db << "SELECT 1 FROM claims WHERE nodeName = ?1 AND txID = ?2 AND txN = ?3 "
"AND validHeight < ?4 AND expirationHeight >= ?4 LIMIT 1"
@ -125,7 +172,7 @@ bool CClaimTrieCacheBase::haveClaim(const std::string& name, const COutPoint& ou
return query.begin() != query.end();
}
bool CClaimTrieCacheBase::haveSupport(const std::string& name, const COutPoint& outPoint) const
bool CClaimTrieCacheBase::haveSupport(const std::string& name, const CTxOutPoint& outPoint) const
{
auto query = db << "SELECT 1 FROM supports WHERE nodeName = ?1 AND txID = ?2 AND txN = ?3 "
"AND validHeight < ?4 AND expirationHeight >= ?4 LIMIT 1"
@ -148,7 +195,7 @@ supportEntryType CClaimTrieCacheBase::getSupportsForName(const std::string& name
return ret;
}
bool CClaimTrieCacheBase::haveClaimInQueue(const std::string& name, const COutPoint& outPoint, int& nValidAtHeight) const
bool CClaimTrieCacheBase::haveClaimInQueue(const std::string& name, const CTxOutPoint& outPoint, int& nValidAtHeight) const
{
auto query = db << "SELECT validHeight FROM claims WHERE nodeName = ? AND txID = ? AND txN = ? "
"AND validHeight >= ? AND expirationHeight > validHeight LIMIT 1"
@ -160,7 +207,7 @@ bool CClaimTrieCacheBase::haveClaimInQueue(const std::string& name, const COutPo
return false;
}
bool CClaimTrieCacheBase::haveSupportInQueue(const std::string& name, const COutPoint& outPoint, int& nValidAtHeight) const
bool CClaimTrieCacheBase::haveSupportInQueue(const std::string& name, const CTxOutPoint& outPoint, int& nValidAtHeight) const
{
auto query = db << "SELECT validHeight FROM supports WHERE nodeName = ? AND txID = ? AND txN = ? "
"AND validHeight >= ? AND expirationHeight > validHeight LIMIT 1"
@ -172,7 +219,8 @@ bool CClaimTrieCacheBase::haveSupportInQueue(const std::string& name, const COut
return false;
}
bool CClaimTrieCacheBase::deleteNodeIfPossible(const std::string& name, std::string& parent, int64_t& claims) {
bool CClaimTrieCacheBase::deleteNodeIfPossible(const std::string& name, std::string& parent, int64_t& claims)
{
if (name.empty()) return false;
// to remove a node it must have one or less children and no claims
db << "SELECT COUNT(*) FROM claims WHERE nodeName = ?1 AND validHeight < ?2 AND expirationHeight >= ?2 "
@ -186,7 +234,7 @@ bool CClaimTrieCacheBase::deleteNodeIfPossible(const std::string& name, std::str
// alternately: SELECT COUNT(DISTINCT nodeName) FROM claims WHERE SUBSTR(nodeName, 1, len(?)) == ? AND LENGTH(nodeName) > len(?)
db << "SELECT COUNT(*),MAX(name) FROM nodes WHERE parent = ?" << name >> std::tie(count, childName);
if (count > 1) return false; // still has multiple children
LogPrint(BCLog::CLAIMS, "Removing node %s with %d children\n", name, count);
logPrint << "Removing node " << name << " with " << count << " children" << Clog::endl;
// okay. it's going away
auto query = db << "SELECT parent FROM nodes WHERE name = ?" << name;
auto it = query.begin();
@ -202,7 +250,8 @@ bool CClaimTrieCacheBase::deleteNodeIfPossible(const std::string& name, std::str
return ret;
}
void CClaimTrieCacheBase::ensureTreeStructureIsUpToDate() {
void CClaimTrieCacheBase::ensureTreeStructureIsUpToDate()
{
if (!transacting) return;
// your children are your nodes that match your key but go at least one longer,
@ -272,7 +321,7 @@ void CClaimTrieCacheBase::ensureTreeStructureIsUpToDate() {
break;
}
// insert the split node:
LogPrint(BCLog::CLAIMS, "Inserting split node %s near %s, parent %s\n", newNodeName, sibling, parent);
logPrint << "Inserting split node " << newNodeName << " near " << sibling << ", parent " << parent << Clog::endl;
insertQuery << newNodeName << parent;
insertQuery++;
@ -281,7 +330,7 @@ void CClaimTrieCacheBase::ensureTreeStructureIsUpToDate() {
}
}
LogPrint(BCLog::CLAIMS, "Inserting or updating node %s (%s), parent %s\n", name, HexStr(name), parent);
logPrint << "Inserting or updating node " << name << ", parent " << parent << Clog::endl;
insertQuery << name << parent;
insertQuery++;
}
@ -313,9 +362,9 @@ std::size_t CClaimTrieCacheBase::getTotalClaimsInTrie() const
return ret;
}
CAmount CClaimTrieCacheBase::getTotalValueOfClaimsInTrie(bool fControllingOnly) const
int64_t CClaimTrieCacheBase::getTotalValueOfClaimsInTrie(bool fControllingOnly) const
{
CAmount ret = 0;
int64_t ret = 0;
std::string query("SELECT SUM(SELECT IFNULL(SUM(s.amount),0)+c.amount FROM supports s "
"WHERE s.supportedClaimID = c.claimID AND s.validHeight < ?1 AND s.expirationHeight >= ?1) "
"FROM claims c WHERE c.validHeight < ?1 AND s.expirationHeight >= ?1");
@ -348,9 +397,9 @@ CClaimSupportToName CClaimTrieCacheBase::getClaimsForName(const std::string& nam
if (it != query.end())
*it >> nLastTakeoverHeight;
}
auto supports = getSupportsForName(name);
claimEntryType claims;
auto supports = getSupportsForName(name);
{
auto query = db << "SELECT claimID, txID, txN, blockHeight, validHeight, amount "
"FROM claims WHERE nodeName = ? AND expirationHeight >= ?"
@ -362,6 +411,7 @@ CClaimSupportToName CClaimTrieCacheBase::getClaimsForName(const std::string& nam
claims.push_back(claim);
}
}
auto find = [&supports](decltype(supports)::iterator& it, const CClaimValue& claim) {
it = std::find_if(it, supports.end(), [&claim](const CSupportValue& support) {
return claim.claimId == support.supportedClaimId;
@ -372,7 +422,7 @@ CClaimSupportToName CClaimTrieCacheBase::getClaimsForName(const std::string& nam
// match support to claim
std::vector<CClaimNsupports> claimsNsupports;
for (const auto& claim : claims) {
CAmount nAmount = claim.nValidAtHeight < nNextHeight ? claim.nAmount : 0;
int64_t nAmount = claim.nValidAtHeight < nNextHeight ? claim.nAmount : 0;
auto ic = claimsNsupports.emplace(claimsNsupports.end(), claim, nAmount);
for (auto it = supports.begin(); find(it, claim); it = supports.erase(it)) {
if (it->nValidAtHeight < nNextHeight)
@ -385,22 +435,18 @@ CClaimSupportToName CClaimTrieCacheBase::getClaimsForName(const std::string& nam
return {name, nLastTakeoverHeight, std::move(claimsNsupports), std::move(supports)};
}
void completeHash(uint256& partialHash, const std::string& key, std::size_t to)
void completeHash(CUint256& partialHash, const std::string& key, int to)
{
CHash256 hasher;
for (auto i = key.size(); i > to + 1; --i, hasher.Reset())
hasher
.Write((uint8_t*)&key[i - 1], 1)
.Write(partialHash.begin(), partialHash.size())
.Finalize(partialHash.begin());
for (auto it = key.rbegin(); std::distance(it, key.rend()) > to + 1; ++it)
partialHash = Hash(it, it + 1, partialHash.begin(), partialHash.end());
}
uint256 CClaimTrieCacheBase::recursiveComputeMerkleHash(const std::string& name, int takeoverHeight, bool checkOnly)
CUint256 CClaimTrieCacheBase::recursiveComputeMerkleHash(const std::string& name, int takeoverHeight, bool checkOnly)
{
std::vector<uint8_t> vchToHash;
const auto pos = name.size();
// we have to free up the hash query so it can be reused by a child
struct Triple { std::string name; std::unique_ptr<uint256> hash; int takeoverHeight; };
struct Triple { std::string name; std::unique_ptr<CUint256> hash; int takeoverHeight; };
std::vector<Triple> children;
for (auto&& row : childHashQuery << name) {
children.emplace_back();
@ -410,12 +456,10 @@ uint256 CClaimTrieCacheBase::recursiveComputeMerkleHash(const std::string& name,
childHashQuery++;
for (auto& child: children) {
if (child.hash == nullptr) child.hash = std::make_unique<uint256>();
if (child.hash == nullptr) child.hash = std::make_unique<CUint256>();
if (child.hash->IsNull()) {
*child.hash = recursiveComputeMerkleHash(child.name, child.takeoverHeight, checkOnly);
}
if (!checkOnly)
LogPrint(BCLog::CLAIMS, "Using hash of %s (%s): %s, takeover: %d\n", child.name, HexStr(child.name), (*child.hash).GetHex(), child.takeoverHeight);
completeHash(*child.hash, child.name, pos);
vchToHash.push_back(child.name[pos]);
vchToHash.insert(vchToHash.end(), child.hash->begin(), child.hash->end());
@ -423,7 +467,7 @@ uint256 CClaimTrieCacheBase::recursiveComputeMerkleHash(const std::string& name,
CClaimValue claim;
if (getInfoForName(name, claim)) {
uint256 valueHash = getValueHash(claim.outPoint, takeoverHeight);
CUint256 valueHash = getValueHash(claim.outPoint, takeoverHeight);
vchToHash.insert(vchToHash.end(), valueHash.begin(), valueHash.end());
}
@ -440,7 +484,7 @@ bool CClaimTrieCacheBase::checkConsistency()
auto query = db << "SELECT name, hash, IFNULL(takeoverHeight, 0) FROM nodes";
for (auto&& row: query) {
std::string name;
uint256 hash;
CUint256 hash;
int takeoverHeight;
row >> name >> hash >> takeoverHeight;
auto computedHash = recursiveComputeMerkleHash(name, takeoverHeight, true);
@ -459,7 +503,7 @@ bool CClaimTrieCacheBase::flush()
db << "commit";
}
catch (const sqlite::sqlite_exception& e) {
LogPrintf("ERROR in ClaimTrieCache flush: %s\n", e.what());
logPrint << "ERROR in ClaimTrieCache flush: " << e.what() << Clog::endl;
auto code = e.get_code();
if (code == SQLITE_LOCKED || code == SQLITE_BUSY) {
LogPrintf("Retrying the commit in one second.\n", e.what());
@ -475,36 +519,25 @@ bool CClaimTrieCacheBase::flush()
return true;
}
bool CClaimTrieCacheBase::ValidateTipMatches(const CBlockIndex* tip)
bool CClaimTrieCacheBase::ReadFromDisk(int nHeight, const CUint256& rootHash)
{
base->nNextHeight = nNextHeight = tip ? tip->nHeight + 1 : 0;
base->nNextHeight = nNextHeight = nHeight + 1;
LogPrintf("Checking claim trie consistency... ");
logPrint << "Checking claim trie consistency... " << Clog::endl;
if (checkConsistency()) {
LogPrintf("consistent\n");
if (tip && tip->hashClaimTrie != getMerkleHash()) {
// suppose we leave the old LevelDB data there: any harm done? It's ~10GB
// eh, we better blow it away; it's their job to back up the folder first
// well, only do it if we're empty on the sqlite side -- aka, we haven't trie to sync first
std::size_t count;
db << "SELECT COUNT(*) FROM nodes" >> count;
if (count <= 1) {
auto oldDataPath = GetDataDir() / "claimtrie";
boost::system::error_code ec;
boost::filesystem::remove_all(oldDataPath, ec);
}
return error("%s(): the block's root claim hash doesn't match the persisted claim root hash.", __func__);
logPrint << "consistent" << Clog::endl;
if (rootHash != getMerkleHash()) {
logPrint << "Merkle hash does not match root hash" << Clog::endl;
return false;
}
return true;
}
LogPrintf("inconsistent!\n");
logPrint << "inconsistent!" << Clog::endl;
return false;
}
CClaimTrieCacheBase::CClaimTrieCacheBase(CClaimTrie* base)
: base(base), db(base->dbPath, sharedConfig), transacting(false),
: base(base), db(base->db), transacting(false),
childHashQuery(db << "SELECT name, hash, IFNULL(takeoverHeight, 0) FROM nodes WHERE parent = ? ORDER BY name"),
claimHashQuery(db << "SELECT c.txID, c.txN, c.claimID, c.blockHeight, c.validHeight, c.amount, "
"(SELECT IFNULL(SUM(s.amount),0)+c.amount FROM supports s WHERE s.supportedClaimID = c.claimID "
@ -526,13 +559,13 @@ CClaimTrieCacheBase::CClaimTrieCacheBase(CClaimTrie* base)
int CClaimTrieCacheBase::expirationTime() const
{
return Params().GetConsensus().nOriginalClaimExpirationTime;
return base->nOriginalClaimExpirationTime;
}
uint256 CClaimTrieCacheBase::getMerkleHash()
CUint256 CClaimTrieCacheBase::getMerkleHash()
{
ensureTreeStructureIsUpToDate();
std::unique_ptr<uint256> hash;
std::unique_ptr<CUint256> hash;
int takeoverHeight;
// can't use childHashQuery here because "IS NULL" must be used instead of parent = NULL
db << "SELECT hash, IFNULL(takeoverHeight, 0) FROM nodes WHERE name = ''" >> std::tie(hash, takeoverHeight);
@ -543,7 +576,7 @@ uint256 CClaimTrieCacheBase::getMerkleHash()
return *hash;
}
bool CClaimTrieCacheBase::getLastTakeoverForName(const std::string& name, uint160& claimId, int& takeoverHeight) const
bool CClaimTrieCacheBase::getLastTakeoverForName(const std::string& name, CUint160& claimId, int& takeoverHeight) const
{
auto query = db << "SELECT takeoverHeight, takeoverID FROM nodes WHERE name = ? AND takeoverID IS NOT NULL" << name;
auto it = query.begin();
@ -553,8 +586,8 @@ bool CClaimTrieCacheBase::getLastTakeoverForName(const std::string& name, uint16
return !claimId.IsNull();
}
bool CClaimTrieCacheBase::addClaim(const std::string& name, const COutPoint& outPoint, const uint160& claimId,
CAmount nAmount, int nHeight, int nValidHeight, const std::vector<unsigned char>& metadata)
bool CClaimTrieCacheBase::addClaim(const std::string& name, const CTxOutPoint& outPoint, const CUint160& claimId,
int64_t nAmount, int nHeight, int nValidHeight, const std::vector<unsigned char>& metadata)
{
if (!transacting) { transacting = true; db << "begin"; }
@ -584,8 +617,8 @@ bool CClaimTrieCacheBase::addClaim(const std::string& name, const COutPoint& out
return true;
}
bool CClaimTrieCacheBase::addSupport(const std::string& name, const COutPoint& outPoint, CAmount nAmount,
const uint160& supportedClaimId, int nHeight, int nValidHeight, const std::vector<unsigned char>& metadata)
bool CClaimTrieCacheBase::addSupport(const std::string& name, const CTxOutPoint& outPoint, const CUint160& supportedClaimId,
int64_t nAmount, int nHeight, int nValidHeight, const std::vector<unsigned char>& metadata)
{
if (!transacting) { transacting = true; db << "begin"; }
@ -603,7 +636,7 @@ bool CClaimTrieCacheBase::addSupport(const std::string& name, const COutPoint& o
return true;
}
bool CClaimTrieCacheBase::removeClaim(const uint160& claimId, const COutPoint& outPoint, std::string& nodeName, int& validHeight)
bool CClaimTrieCacheBase::removeClaim(const CUint160& claimId, const CTxOutPoint& outPoint, std::string& nodeName, int& validHeight)
{
if (!transacting) { transacting = true; db << "begin"; }
@ -640,11 +673,10 @@ bool CClaimTrieCacheBase::removeClaim(const uint160& claimId, const COutPoint& o
}
}
}
return true;
}
bool CClaimTrieCacheBase::removeSupport(const COutPoint& outPoint, std::string& nodeName, int& validHeight)
bool CClaimTrieCacheBase::removeSupport(const CTxOutPoint& outPoint, std::string& nodeName, int& validHeight)
{
if (!transacting) { transacting = true; db << "begin"; }
@ -1147,6 +1179,7 @@ bool CClaimTrieCacheBase::incrementBlock(insertUndoType& insertUndo, claimUndoTy
expireSupportUndo.emplace_back(name, value);
}
}
db << "UPDATE nodes SET hash = NULL WHERE name IN (SELECT nodeName FROM supports WHERE expirationHeight = ?)"
<< nNextHeight;
@ -1156,10 +1189,10 @@ bool CClaimTrieCacheBase::incrementBlock(insertUndoType& insertUndo, claimUndoTy
>> [&takeovers](std::string name) {
takeovers.push_back(std::move(name));
};
auto getTakeoverQuery = db << "SELECT IFNULL(takeoverHeight, 0), takeoverID FROM nodes WHERE name = ?";
auto hasCandidateQuery = db << "UPDATE nodes SET takeoverHeight = ?, takeoverID = ? WHERE name = ?";
auto noCandidateQuery = db << "UPDATE nodes SET takeoverHeight = NULL, takeoverID = NULL WHERE name = ?";
auto maxWorkaround = Params().GetConsensus().nMaxTakeoverWorkaroundHeight;
for (const auto& nameWithTakeover : takeovers) {
// if somebody activates on this block and they are the new best, then everybody activates on this block
@ -1167,7 +1200,7 @@ bool CClaimTrieCacheBase::incrementBlock(insertUndoType& insertUndo, claimUndoTy
auto hasCandidate = getInfoForName(nameWithTakeover, candidateValue, 1);
// now that they're all in get the winner:
int existingHeight;
std::unique_ptr<uint160> existingID;
std::unique_ptr<CUint160> existingID;
getTakeoverQuery << nameWithTakeover >> std::tie(existingHeight, existingID);
getTakeoverQuery++; // reset it
@ -1179,15 +1212,15 @@ bool CClaimTrieCacheBase::incrementBlock(insertUndoType& insertUndo, claimUndoTy
// This is a super ugly hack to work around bug in old code.
// The bug: un/support a name then update it. This will cause its takeover height to be reset to current.
// This is because the old code with add to the cache without setting block originals when dealing in supports.
if (nNextHeight < maxWorkaround) {
if (nNextHeight < 658300) {
auto wit = takeoverWorkarounds.find(std::make_pair(nNextHeight, nameWithTakeover));
takeoverHappening |= wit != takeoverWorkarounds.end();
}
LogPrint(BCLog::CLAIMS, "Takeover on %s (%s) at %d, happening: %d, set before: %d\n", nameWithTakeover, HexStr(nameWithTakeover), nNextHeight, takeoverHappening, hasBeenSetBefore);
logPrint << "Takeover on " << nameWithTakeover << " at " << nNextHeight << ", happening: " << takeoverHappening << ", set before: " << hasBeenSetBefore << Clog::endl;
if (takeoverHappening || !hasBeenSetBefore) {
takeoverUndo.emplace_back(nameWithTakeover, std::make_pair(existingHeight, hasBeenSetBefore ? *existingID : uint160()));
takeoverUndo.emplace_back(nameWithTakeover, std::make_pair(existingHeight, hasBeenSetBefore ? *existingID : CUint160()));
if (hasCandidate) {
hasCandidateQuery << nNextHeight << candidateValue.claimId << nameWithTakeover;
hasCandidateQuery++;
@ -1203,25 +1236,24 @@ bool CClaimTrieCacheBase::incrementBlock(insertUndoType& insertUndo, claimUndoTy
getTakeoverQuery.used(true);
hasCandidateQuery.used(true);
noCandidateQuery.used(true);
nNextHeight++;
return true;
}
bool CClaimTrieCacheBase::activateAllFor(insertUndoType& insertUndo, insertUndoType& insertSupportUndo,
const std::string& name) {
bool CClaimTrieCacheBase::activateAllFor(insertUndoType& insertUndo, insertUndoType& insertSupportUndo, const std::string& name)
{
// now that we know a takeover is happening, we bring everybody in:
auto ret = false;
{
auto query = db << "SELECT txID, txN, validHeight FROM claims WHERE nodeName = ?1 AND validHeight > ?2 AND expirationHeight > ?2"
<< name << nNextHeight;
for (auto &&row: query) {
uint256 hash;
CUint256 hash;
uint32_t n;
int oldValidHeight;
row >> hash >> n >> oldValidHeight;
insertUndo.emplace_back(name, COutPoint(hash, n), oldValidHeight);
LogPrint(BCLog::CLAIMS, "Early activation of claim %s, t: %s:%d at %d\n", name, hash.GetHex().substr(0, 6), n, nNextHeight);
insertUndo.emplace_back(name, CTxOutPoint(hash, n), oldValidHeight);
logPrint << "Early activation of claim " << name << ", " << CTxOutPoint(hash, n).ToString() << " at " << nNextHeight << Clog::endl;
}
}
// and then update them all to activate now:
@ -1234,12 +1266,12 @@ bool CClaimTrieCacheBase::activateAllFor(insertUndoType& insertUndo, insertUndoT
auto query = db << "SELECT txID, txN, validHeight FROM supports WHERE nodeName = ?1 AND validHeight > ?2 AND expirationHeight > ?2"
<< name << nNextHeight;
for (auto &&row: query) {
uint256 hash;
CUint256 hash;
uint32_t n;
int oldValidHeight;
row >> hash >> n >> oldValidHeight;
insertSupportUndo.emplace_back(name, COutPoint(hash, n), oldValidHeight);
LogPrint(BCLog::CLAIMS, "Early activation of support %s, t: %s:%d at %d\n", name, hash.GetHex().substr(0, 6), n, nNextHeight);
insertSupportUndo.emplace_back(name, CTxOutPoint(hash, n), oldValidHeight);
logPrint << "Early activation of support " << name << ", " << CTxOutPoint(hash, n).ToString() << " at " << nNextHeight << Clog::endl;
}
}
// and then update them all to activate now:
@ -1267,14 +1299,14 @@ bool CClaimTrieCacheBase::decrementBlock(insertUndoType& insertUndo, claimUndoTy
}
for (auto it = insertSupportUndo.crbegin(); it != insertSupportUndo.crend(); ++it) {
LogPrint(BCLog::CLAIMS, "Resetting support valid height to %d for %s\n", it->nValidHeight, it->name);
logPrint << "Resetting support valid height to " << it->nValidHeight << " for " << it->name << Clog::endl;
db << "UPDATE supports SET validHeight = ? WHERE txID = ? AND txN = ?"
<< it->nValidHeight << it->outPoint.hash << it->outPoint.n;
db << "INSERT INTO nodes(name) VALUES(?) ON CONFLICT(name) DO UPDATE SET hash = NULL" << it->name;
}
for (auto it = insertUndo.crbegin(); it != insertUndo.crend(); ++it) {
LogPrint(BCLog::CLAIMS, "Resetting valid height to %d for %s\n", it->nValidHeight, it->name);
logPrint << "Resetting valid height to " << it->nValidHeight << " for " << it->name << Clog::endl;
db << "UPDATE claims SET validHeight = ? WHERE nodeName = ? AND txID = ? AND txN = ?"
<< it->nValidHeight << it->name << it->outPoint.hash << it->outPoint.n;
db << "INSERT INTO nodes(name) VALUES(?) ON CONFLICT(name) DO UPDATE SET hash = NULL" << it->name;
@ -1300,9 +1332,9 @@ bool CClaimTrieCacheBase::finalizeDecrement(takeoverUndoType& takeoverUndo)
return true;
}
int CClaimTrieCacheBase::getDelayForName(const std::string& name, const uint160& claimId) const
int CClaimTrieCacheBase::getDelayForName(const std::string& name, const CUint160& claimId) const
{
uint160 winningClaimId;
CUint160 winningClaimId;
int winningTakeoverHeight;
auto found = getLastTakeoverForName(name, winningClaimId, winningTakeoverHeight);
if (found && winningClaimId == claimId) {
@ -1326,7 +1358,7 @@ std::string CClaimTrieCacheBase::adjustNameForValidHeight(const std::string& nam
return name;
}
bool CClaimTrieCacheBase::getProofForName(const std::string& name, const uint160& finalClaim, CClaimTrieProof& proof)
bool CClaimTrieCacheBase::getProofForName(const std::string& name, const CUint160& finalClaim, CClaimTrieProof& proof)
{
// cache the parent nodes
getMerkleHash();
@ -1341,25 +1373,25 @@ bool CClaimTrieCacheBase::getProofForName(const std::string& name, const uint160
int takeoverHeight;
row >> key >> takeoverHeight;
bool fNodeHasValue = getInfoForName(key, claim);
uint256 valueHash;
CUint256 valueHash;
if (fNodeHasValue)
valueHash = getValueHash(claim.outPoint, takeoverHeight);
const auto pos = key.size();
std::vector<std::pair<unsigned char, uint256>> children;
std::vector<std::pair<unsigned char, CUint256>> children;
for (auto&& child : childHashQuery << key) {
std::string childKey;
uint256 hash;
CUint256 hash;
child >> childKey >> hash;
if (name.find(childKey) == 0) {
for (auto i = pos; i + 1 < childKey.size(); ++i) {
children.emplace_back(childKey[i], uint256{});
children.emplace_back(childKey[i], CUint256{});
proof.nodes.emplace_back(children, fNodeHasValue, valueHash);
children.clear();
valueHash.SetNull();
fNodeHasValue = false;
}
children.emplace_back(childKey.back(), uint256{});
children.emplace_back(childKey.back(), CUint256{});
continue;
}
completeHash(hash, childKey, pos);
@ -1379,7 +1411,8 @@ bool CClaimTrieCacheBase::getProofForName(const std::string& name, const uint160
return true;
}
bool CClaimTrieCacheBase::findNameForClaim(std::vector<unsigned char> claim, CClaimValue& value, std::string& name) {
bool CClaimTrieCacheBase::findNameForClaim(std::vector<unsigned char> claim, CClaimValue& value, std::string& name)
{
std::reverse(claim.begin(), claim.end());
auto query = db << "SELECT nodeName, claimId, txID, txN, amount, validHeight, blockHeight "
"FROM claims WHERE SUBSTR(claimID, ?) = ? AND validHeight < ? AND expirationHeight >= ?"

207
src/claimtrie/trie.h Normal file
View file

@ -0,0 +1,207 @@
#ifndef CLAIMTRIE_TRIE_H
#define CLAIMTRIE_TRIE_H
#include <claimtrie/data.h>
#include <claimtrie/txoutpoint.h>
#include <claimtrie/uints.h>
#include <functional>
#include <map>
#include <memory>
#include <string>
#include <vector>
#include <unordered_map>
#include <unordered_set>
#include <utility>
CUint256 getValueHash(const CTxOutPoint& outPoint, int nHeightOfLastTakeover);
struct CClaimNsupports
{
CClaimNsupports() = default;
CClaimNsupports(CClaimNsupports&&) = default;
CClaimNsupports(const CClaimNsupports&) = default;
bool operator<(const CClaimNsupports& other) const;
CClaimNsupports& operator=(CClaimNsupports&&) = default;
CClaimNsupports& operator=(const CClaimNsupports&) = default;
CClaimNsupports(CClaimValue claim, int64_t effectiveAmount, std::vector<CSupportValue> supports = {});
bool IsNull() const;
CClaimValue claim;
int64_t effectiveAmount = 0;
std::vector<CSupportValue> supports;
};
struct CClaimSupportToName
{
CClaimSupportToName(std::string name, int nLastTakeoverHeight, std::vector<CClaimNsupports> claimsNsupports, std::vector<CSupportValue> unmatchedSupports);
const CClaimNsupports& find(const CUint160& claimId) const;
const CClaimNsupports& find(const std::string& partialId) const;
const std::string name;
const int nLastTakeoverHeight;
const std::vector<CClaimNsupports> claimsNsupports;
const std::vector<CSupportValue> unmatchedSupports;
};
class CClaimTrie
{
friend class CClaimTrieCacheBase;
friend class ClaimTrieChainFixture;
friend class CClaimTrieCacheHashFork;
friend class CClaimTrieCacheExpirationFork;
friend class CClaimTrieCacheNormalizationFork;
public:
CClaimTrie() = default;
CClaimTrie(CClaimTrie&&) = delete;
CClaimTrie(const CClaimTrie&) = delete;
CClaimTrie(bool fWipe, int height,
int nNormalizedNameForkHeight,
int64_t nOriginalClaimExpirationTime,
int64_t nExtendedClaimExpirationTime,
int64_t nExtendedClaimExpirationForkHeight,
int64_t nAllClaimsInMerkleForkHeight,
int proportionalDelayFactor = 32);
CClaimTrie& operator=(CClaimTrie&&) = delete;
CClaimTrie& operator=(const CClaimTrie&) = delete;
bool empty();
bool SyncToDisk();
protected:
int nNextHeight = 0;
sqlite::database db;
const int nProportionalDelayFactor = 0;
const int nNormalizedNameForkHeight = -1;
const int64_t nOriginalClaimExpirationTime = -1;
const int64_t nExtendedClaimExpirationTime = -1;
const int64_t nExtendedClaimExpirationForkHeight = -1;
const int64_t nAllClaimsInMerkleForkHeight = -1;
};
struct CClaimTrieProofNode
{
CClaimTrieProofNode(std::vector<std::pair<unsigned char, CUint256>> children, bool hasValue, CUint256 valHash);
CClaimTrieProofNode(CClaimTrieProofNode&&) = default;
CClaimTrieProofNode(const CClaimTrieProofNode&) = default;
CClaimTrieProofNode& operator=(CClaimTrieProofNode&&) = default;
CClaimTrieProofNode& operator=(const CClaimTrieProofNode&) = default;
std::vector<std::pair<unsigned char, CUint256>> children;
bool hasValue;
CUint256 valHash;
};
struct CClaimTrieProof
{
CClaimTrieProof() = default;
CClaimTrieProof(CClaimTrieProof&&) = default;
CClaimTrieProof(const CClaimTrieProof&) = default;
CClaimTrieProof& operator=(CClaimTrieProof&&) = default;
CClaimTrieProof& operator=(const CClaimTrieProof&) = default;
std::vector<std::pair<bool, CUint256>> pairs;
std::vector<CClaimTrieProofNode> nodes;
int nHeightOfLastTakeover = 0;
bool hasValue = false;
CTxOutPoint outPoint;
};
template <typename T>
using queueEntryType = std::pair<std::string, T>;
typedef std::vector<queueEntryType<CClaimValue>> claimUndoType;
typedef std::vector<queueEntryType<CSupportValue>> supportUndoType;
typedef std::vector<CNameOutPointHeightType> insertUndoType;
typedef std::vector<queueEntryType<std::pair<int, CUint160>>> takeoverUndoType;
class CClaimTrieCacheBase
{
public:
explicit CClaimTrieCacheBase(CClaimTrie* base);
virtual ~CClaimTrieCacheBase();
CUint256 getMerkleHash();
bool flush();
bool empty() const;
bool checkConsistency();
bool ReadFromDisk(int nHeight, const CUint256& rootHash);
std::size_t getTotalNamesInTrie() const;
std::size_t getTotalClaimsInTrie() const;
int64_t getTotalValueOfClaimsInTrie(bool fControllingOnly) const;
bool haveClaim(const std::string& name, const CTxOutPoint& outPoint) const;
bool haveClaimInQueue(const std::string& name, const CTxOutPoint& outPoint, int& nValidAtHeight) const;
bool haveSupport(const std::string& name, const CTxOutPoint& outPoint) const;
bool haveSupportInQueue(const std::string& name, const CTxOutPoint& outPoint, int& nValidAtHeight) const;
bool addClaim(const std::string& name, const CTxOutPoint& outPoint, const CUint160& claimId, int64_t nAmount,
int nHeight, int nValidHeight = -1, const std::vector<unsigned char>& metadata = {});
bool addSupport(const std::string& name, const CTxOutPoint& outPoint, const CUint160& supportedClaimId, int64_t nAmount,
int nHeight, int nValidHeight = -1, const std::vector<unsigned char>& metadata = {});
bool removeClaim(const CUint160& claimId, const CTxOutPoint& outPoint, std::string& nodeName, int& validHeight);
bool removeSupport(const CTxOutPoint& outPoint, std::string& nodeName, int& validHeight);
virtual bool incrementBlock(insertUndoType& insertUndo,
claimUndoType& expireUndo,
insertUndoType& insertSupportUndo,
supportUndoType& expireSupportUndo,
takeoverUndoType& takeoverHeightUndo);
virtual bool decrementBlock(insertUndoType& insertUndo,
claimUndoType& expireUndo,
insertUndoType& insertSupportUndo,
supportUndoType& expireSupportUndo);
virtual bool getProofForName(const std::string& name, const CUint160& claim, CClaimTrieProof& proof);
virtual bool getInfoForName(const std::string& name, CClaimValue& claim, int heightOffset = 0) const;
virtual int expirationTime() const;
virtual bool finalizeDecrement(takeoverUndoType& takeoverHeightUndo);
virtual CClaimSupportToName getClaimsForName(const std::string& name) const;
virtual std::string adjustNameForValidHeight(const std::string& name, int validHeight) const;
bool findNameForClaim(std::vector<unsigned char> claim, CClaimValue& value, std::string& name);
void getNamesInTrie(std::function<void(const std::string&)> callback);
bool getLastTakeoverForName(const std::string& name, CUint160& claimId, int& takeoverHeight) const;
protected:
CClaimTrie* base;
mutable sqlite::database db;
int nNextHeight; // Height of the block that is being worked on, which is
bool transacting;
mutable std::unordered_set<std::string> removalWorkaround;
mutable sqlite::database_binder claimHashQuery, childHashQuery;
virtual CUint256 recursiveComputeMerkleHash(const std::string& name, int takeoverHeight, bool checkOnly);
supportEntryType getSupportsForName(const std::string& name) const;
virtual int getDelayForName(const std::string& name, const CUint160& claimId) const;
bool deleteNodeIfPossible(const std::string& name, std::string& parent, int64_t& claims);
void ensureTreeStructureIsUpToDate();
private:
// for unit test
friend struct ClaimTrieChainFixture;
friend class CClaimTrieCacheTest;
bool activateAllFor(insertUndoType& insertUndo, insertUndoType& insertSupportUndo, const std::string& takeover);
};
#endif // CLAIMTRIE_TRIE_H

View file

@ -0,0 +1,42 @@
#include <claimtrie/txoutpoint.h>
#include <sstream>
CTxOutPoint::CTxOutPoint(CUint256 hashIn, uint32_t nIn) : hash(std::move(hashIn)), n(nIn)
{
}
void CTxOutPoint::SetNull()
{
hash.SetNull();
n = uint32_t(-1);
}
bool CTxOutPoint::IsNull() const
{
return hash.IsNull() && n == uint32_t(-1);
}
std::string CTxOutPoint::ToString() const
{
std::stringstream ss;
ss << "CTxOutPoint(" << hash.ToString().substr(0, 10) << ", " << n << ')';
return ss.str();
}
bool operator<(const CTxOutPoint& a, const CTxOutPoint& b)
{
int cmp = a.hash.Compare(b.hash);
return cmp < 0 || (cmp == 0 && a.n < b.n);
}
bool operator==(const CTxOutPoint& a, const CTxOutPoint& b)
{
return (a.hash == b.hash && a.n == b.n);
}
bool operator!=(const CTxOutPoint& a, const CTxOutPoint& b)
{
return !(a == b);
}

View file

@ -0,0 +1,37 @@
#ifndef CLAIMTRIE_TXOUTPUT_H
#define CLAIMTRIE_TXOUTPUT_H
#include <claimtrie/uints.h>
#include <algorithm>
#include <type_traits>
#include <vector>
#include <utility>
/** An outpoint - a combination of a transaction hash and an index n into its vout */
class CTxOutPoint
{
public:
CUint256 hash;
uint32_t n = uint32_t(-1);
CTxOutPoint() = default;
CTxOutPoint(CTxOutPoint&&) = default;
CTxOutPoint(const CTxOutPoint&) = default;
CTxOutPoint(CUint256 hashIn, uint32_t nIn);
CTxOutPoint& operator=(CTxOutPoint&&) = default;
CTxOutPoint& operator=(const CTxOutPoint&) = default;
void SetNull();
bool IsNull() const;
friend bool operator<(const CTxOutPoint& a, const CTxOutPoint& b);
friend bool operator==(const CTxOutPoint& a, const CTxOutPoint& b);
friend bool operator!=(const CTxOutPoint& a, const CTxOutPoint& b);
std::string ToString() const;
};
#endif // CLAIMTRIE_TXOUTPUT_H

155
src/claimtrie/uints.cpp Normal file
View file

@ -0,0 +1,155 @@
#include <claimtrie/uints.h>
#include <algorithm>
#include <cassert>
#include <cstring>
#include <iomanip>
#include <sstream>
/** Template base class for fixed-sized opaque blobs. */
template<uint32_t BITS>
CBaseBlob<BITS>::CBaseBlob() : data(std::make_unique<uint8_t[]>(WIDTH))
{
SetNull();
}
template<uint32_t BITS>
CBaseBlob<BITS>::CBaseBlob(const std::vector<uint8_t>& vec) : data(std::make_unique<uint8_t[]>(WIDTH))
{
assert(vec.size() == size());
std::copy(vec.begin(), vec.end(), begin());
}
template<uint32_t BITS>
CBaseBlob<BITS>::CBaseBlob(const CBaseBlob& o) : data(std::make_unique<uint8_t[]>(WIDTH))
{
*this = o;
}
template<uint32_t BITS>
CBaseBlob<BITS>& CBaseBlob<BITS>::operator=(const CBaseBlob& o)
{
if (this != &o)
std::copy(o.begin(), o.end(), begin());
return *this;
}
template<uint32_t BITS>
bool CBaseBlob<BITS>::IsNull() const
{
return std::all_of(begin(), end(), [](uint8_t e) { return e == 0; });
}
template<uint32_t BITS>
void CBaseBlob<BITS>::SetNull()
{
std::memset(begin(), 0, size());
}
template<uint32_t BITS>
int CBaseBlob<BITS>::Compare(const CBaseBlob& other) const
{
return std::memcmp(begin(), other.begin(), size());
}
template<uint32_t BITS>
std::string CBaseBlob<BITS>::GetHex() const
{
std::stringstream ss;
ss << std::hex;
for (int i = WIDTH - 1; i >= 0; --i)
ss << std::setw(2) << std::setfill('0') << uint32_t(data[i]);
return ss.str();
}
template<uint32_t BITS>
void CBaseBlob<BITS>::SetHex(const char* psz)
{
SetNull();
// skip leading spaces
while (isspace(*psz))
psz++;
// skip 0x
if (psz[0] == '0' && tolower(psz[1]) == 'x')
psz += 2;
auto b = psz;
// advance to end
while (isxdigit(*psz))
psz++;
--psz;
char buf[3] = {};
auto it = begin();
while (psz >= b && it != end()) {
buf[1] = *psz--;
buf[0] = psz >= b ? *psz-- : '0';
*it++ = std::strtoul(buf, nullptr, 16);
}
}
template<uint32_t BITS>
void CBaseBlob<BITS>::SetHex(const std::string& str)
{
SetHex(str.c_str());
}
template<uint32_t BITS>
std::string CBaseBlob<BITS>::ToString() const
{
return GetHex();
}
template<uint32_t BITS>
uint8_t* CBaseBlob<BITS>::begin()
{
return data.get();
}
template<uint32_t BITS>
uint8_t* CBaseBlob<BITS>::end()
{
return begin() + WIDTH;
}
template<uint32_t BITS>
const uint8_t* CBaseBlob<BITS>::begin() const
{
return data.get();
}
template<uint32_t BITS>
const uint8_t* CBaseBlob<BITS>::end() const
{
return begin() + WIDTH;
}
CUint160 CUint160S(const char* str)
{
CUint160 s;
s.SetHex(str);
return s;
}
CUint160 CUint160S(const std::string& s)
{
return CUint160S(s.c_str());
}
CUint256 CUint256S(const char* str)
{
CUint256 s;
s.SetHex(str);
return s;
}
CUint256 CUint256S(const std::string& s)
{
return CUint256S(s.c_str());
}
template class CBaseBlob<160>;
template class CBaseBlob<256>;

59
src/claimtrie/uints.h Normal file
View file

@ -0,0 +1,59 @@
#ifndef CLAIMTRIE_UINTS_H
#define CLAIMTRIE_UINTS_H
#include <memory>
#include <vector>
/** Template base class for fixed-sized opaque blobs. */
template<uint32_t BITS>
class CBaseBlob
{
protected:
static constexpr int WIDTH = BITS / 8;
std::unique_ptr<uint8_t[]> data;
public:
CBaseBlob();
explicit CBaseBlob(const std::vector<uint8_t>& vec);
CBaseBlob(CBaseBlob&&) = default;
CBaseBlob& operator=(CBaseBlob&&) = default;
CBaseBlob(const CBaseBlob& o);
CBaseBlob& operator=(const CBaseBlob& o);
bool IsNull() const;
void SetNull();
int Compare(const CBaseBlob& other) const;
friend inline bool operator==(const CBaseBlob& a, const CBaseBlob& b) { return a.Compare(b) == 0; }
friend inline bool operator!=(const CBaseBlob& a, const CBaseBlob& b) { return a.Compare(b) != 0; }
friend inline bool operator<(const CBaseBlob& a, const CBaseBlob& b) { return a.Compare(b) < 0; }
std::string GetHex() const;
void SetHex(const char* psz);
void SetHex(const std::string& str);
std::string ToString() const;
uint8_t* begin();
uint8_t* end();
const uint8_t* begin() const;
const uint8_t* end() const;
constexpr uint32_t size() const { return WIDTH; }
};
typedef CBaseBlob<160> CUint160;
typedef CBaseBlob<256> CUint256;
CUint160 CUint160S(const char* str);
CUint160 CUint160S(const std::string& s);
CUint256 CUint256S(const char* str);
CUint256 CUint256S(const std::string& s);
#endif // CLAIMTRIE_UINTS_H

105
src/claimtrie_serial.h Normal file
View file

@ -0,0 +1,105 @@
#ifndef CLAIMTRIE_SERIAL_H
#define CLAIMTRIE_SERIAL_H
#include <claimtrie/data.h>
#include <claimtrie/txoutpoint.h>
#include <claimtrie/uints.h>
template<typename Stream, uint32_t BITS>
void Serialize(Stream& s, const CBaseBlob<BITS>& u)
{
s.write((const char*)u.begin(), u.size());
}
template<typename Stream, uint32_t BITS>
void Unserialize(Stream& s, CBaseBlob<BITS>& u)
{
s.read((char*)u.begin(), u.size());
}
template<typename Stream>
void Serialize(Stream& s, const CTxOutPoint& u)
{
Serialize(s, u.hash);
Serialize(s, u.n);
}
template<typename Stream>
void Unserialize(Stream& s, CTxOutPoint& u)
{
Unserialize(s, u.hash);
Unserialize(s, u.n);
}
template<typename Stream>
void Serialize(Stream& s, const CClaimValue& u)
{
Serialize(s, u.outPoint);
Serialize(s, u.claimId);
Serialize(s, u.nAmount);
Serialize(s, u.nHeight);
Serialize(s, u.nValidAtHeight);
}
template<typename Stream>
void Unserialize(Stream& s, CClaimValue& u)
{
Unserialize(s, u.outPoint);
Unserialize(s, u.claimId);
Unserialize(s, u.nAmount);
Unserialize(s, u.nHeight);
Unserialize(s, u.nValidAtHeight);
}
template<typename Stream>
void Serialize(Stream& s, const CSupportValue& u)
{
Serialize(s, u.outPoint);
Serialize(s, u.supportedClaimId);
Serialize(s, u.nAmount);
Serialize(s, u.nHeight);
Serialize(s, u.nValidAtHeight);
}
template<typename Stream>
void Unserialize(Stream& s, CSupportValue& u)
{
Unserialize(s, u.outPoint);
Unserialize(s, u.supportedClaimId);
Unserialize(s, u.nAmount);
Unserialize(s, u.nHeight);
Unserialize(s, u.nValidAtHeight);
}
template<typename Stream>
void Serialize(Stream& s, const CNameOutPointHeightType& u)
{
Serialize(s, u.name);
Serialize(s, u.outPoint);
Serialize(s, u.nValidHeight);
}
template<typename Stream>
void Unserialize(Stream& s, CNameOutPointHeightType& u)
{
Unserialize(s, u.name);
Unserialize(s, u.outPoint);
Unserialize(s, u.nValidHeight);
}
template<typename Stream>
void Serialize(Stream& s, const CClaimIndexElement& u)
{
Serialize(s, u.name);
Serialize(s, u.claim);
}
template<typename Stream>
void Unserialize(Stream& s, CClaimIndexElement& u)
{
Unserialize(s, u.name);
Unserialize(s, u.claim);
}
#endif // CLAIMTRIE_SERIAL_H

View file

@ -78,9 +78,6 @@ struct Params {
int nAllowMinDiffMaxHeight;
int nNormalizedNameForkHeight;
int nMinTakeoverWorkaroundHeight;
int nMaxTakeoverWorkaroundHeight;
int nWitnessForkHeight;
int64_t nPowTargetSpacing;

View file

@ -14,7 +14,7 @@
#include <chain.h>
#include <chainparams.h>
#include <checkpoints.h>
#include <claimtrie.h>
#include <claimtrie/forks.h>
#include <compat/sanity.h>
#include <consensus/validation.h>
#include <fs.h>
@ -1455,7 +1455,16 @@ bool AppInitMain()
pblocktree.reset();
pblocktree.reset(new CBlockTreeDB(nBlockTreeDBCache, false, fReset));
delete pclaimTrie;
pclaimTrie = new CClaimTrie(fReindex || fReindexChainState, 0);
auto& consensus = chainparams.GetConsensus();
if (g_logger->Enabled() && LogAcceptCategory(BCLog::CLAIMS))
CLogPrint::global().setLogger(g_logger);
pclaimTrie = new CClaimTrie(fReindex || fReindexChainState, 0,
consensus.nNormalizedNameForkHeight,
consensus.nOriginalClaimExpirationTime,
consensus.nExtendedClaimExpirationTime,
consensus.nExtendedClaimExpirationForkHeight,
consensus.nAllClaimsInMerkleForkHeight,
32);
if (fReset) {
pblocktree->WriteReindexing(true);
@ -1528,13 +1537,13 @@ bool AppInitMain()
}
assert(chainActive.Tip() != nullptr);
}
{
auto tip = chainActive.Tip();
assert(tip);
CClaimTrieCache trieCache(pclaimTrie);
if (!trieCache.ValidateTipMatches(chainActive.Tip())) {
if (!trieCache.ReadFromDisk(tip->nHeight, tip->hashClaimTrie)) {
strLoadError = _("Error loading the claim trie from disk");
break;
}
}
if (!fReset) {
// Note that RewindBlockIndex MUST run even if we're about to -reindex-chainstate.
// It both disconnects blocks based on chainActive, and drops block data in

View file

@ -3,8 +3,6 @@
#include <cstdio>
uint32_t g_memfileSize = 0;
unsigned int CalculateLbryNextWorkRequired(const CBlockIndex* pindexLast, int64_t nFirstBlockTime, const Consensus::Params& params)
{
if (params.fPowNoRetargeting)

View file

@ -4,7 +4,6 @@
#include <chain.h>
#include <chainparams.h>
extern uint32_t g_memfileSize;
unsigned int CalculateLbryNextWorkRequired(const CBlockIndex* pindexLast, int64_t nLastRetargetTime, const Consensus::Params& params);
#endif

View file

@ -6,6 +6,7 @@
#ifndef BITCOIN_LOGGING_H
#define BITCOIN_LOGGING_H
#include <claimtrie/log.h>
#include <fs.h>
#include <tinyformat.h>
@ -57,7 +58,7 @@ namespace BCLog {
ALL = ~(uint32_t)0,
};
class Logger
class Logger : public ClogBase
{
private:
FILE* m_fileout = nullptr;
@ -87,7 +88,7 @@ namespace BCLog {
std::atomic<bool> m_reopen_file{false};
/** Send a string to the log output */
void LogPrintStr(const std::string &str);
void LogPrintStr(const std::string &str) override;
/** Returns whether logs will be written to any output */
bool Enabled() const { return m_print_to_console || m_print_to_file; }

View file

@ -9,6 +9,7 @@
#include <chain.h>
#include <chainparams.h>
#include <claimscriptop.h>
#include <claimtrie/forks.h>
#include <coins.h>
#include <consensus/consensus.h>
#include <consensus/tx_verify.h>
@ -204,7 +205,7 @@ std::unique_ptr<CBlockTemplate> BlockAssembler::CreateNewBlock(const CScript& sc
{
CClaimTrieCache trieCache(pclaimTrie);
blockToCache(pblock, trieCache, nHeight);
pblock->hashClaimTrie = trieCache.getMerkleHash();
pblock->hashClaimTrie = uint256(trieCache.getMerkleHash());
}
CValidationState state;
if (!TestBlockValidity(state, chainparams, *pblock, pindexPrev, false, false)) {

View file

@ -68,14 +68,10 @@ bool DecodeClaimScript(const CScript& scriptIn, int& op, std::vector<std::vector
op = -1;
opcodetype opcode;
if (!scriptIn.GetOp(pc, opcode))
{
return false;
}
if (opcode != OP_CLAIM_NAME && opcode != OP_SUPPORT_CLAIM && opcode != OP_UPDATE_CLAIM)
{
return false;
}
op = opcode;
@ -90,57 +86,40 @@ bool DecodeClaimScript(const CScript& scriptIn, int& op, std::vector<std::vector
// All others are invalid.
if (!scriptIn.GetOp(pc, opcode, vchParam1) || opcode < 0 || opcode > OP_PUSHDATA4)
{
return false;
}
if (!scriptIn.GetOp(pc, opcode, vchParam2) || opcode < 0 || opcode > OP_PUSHDATA4)
{
return false;
}
if (op == OP_UPDATE_CLAIM || op == OP_SUPPORT_CLAIM)
{
static const size_t claimIdHashSize = sizeof(uint160);
if (vchParam2.size() != claimIdHashSize) {
if (vchParam2.size() != sizeof(uint160))
return false;
}
}
if (!scriptIn.GetOp(pc, opcode, vchParam3))
{
return false;
}
auto last_drop = OP_DROP;
if (opcode >= 0 && opcode <= OP_PUSHDATA4 && op != OP_CLAIM_NAME)
{
if (opcode >= 0 && opcode <= OP_PUSHDATA4 && op != OP_CLAIM_NAME) {
if (!scriptIn.GetOp(pc, opcode))
{
return false;
}
last_drop = OP_2DROP;
}
else if (op == OP_UPDATE_CLAIM)
{
} else if (op == OP_UPDATE_CLAIM)
return false;
}
if (opcode != OP_2DROP)
{
return false;
}
if (!scriptIn.GetOp(pc, opcode) || opcode != last_drop)
{
return false;
}
if (op == OP_SUPPORT_CLAIM && last_drop == OP_2DROP && !allowSupportMetadata)
{
return false;
}
vvchParams.push_back(std::move(vchParam1));
vvchParams.push_back(std::move(vchParam2));
if (last_drop == OP_2DROP)
{
vvchParams.push_back(std::move(vchParam3));
}
return true;
}
@ -164,9 +143,7 @@ CScript StripClaimScriptPrefix(const CScript& scriptIn, int& op)
CScript::const_iterator pc = scriptIn.begin();
if (!DecodeClaimScript(scriptIn, op, vvchParams, pc))
{
return scriptIn;
}
return CScript(pc, scriptIn.end());
}
@ -183,31 +160,21 @@ size_t ClaimNameSize(const CScript& scriptIn)
CScript::const_iterator pc = scriptIn.begin();
int op;
if (!DecodeClaimScript(scriptIn, op, vvchParams, pc))
{
return 0;
}
else
{
return vvchParams[0].size();
}
}
CAmount CalcMinClaimTrieFee(const CTransaction& tx, const CAmount &minFeePerNameClaimChar)
{
if (minFeePerNameClaimChar == 0)
{
return 0;
}
CAmount min_fee = 0;
for (const CTxOut& txout: tx.vout)
{
for (const CTxOut& txout: tx.vout) {
int op;
std::vector<std::vector<unsigned char> > vvchParams;
if (DecodeClaimScript(txout.scriptPubKey, op, vvchParams))
{
if (op == OP_CLAIM_NAME)
{
if (DecodeClaimScript(txout.scriptPubKey, op, vvchParams)) {
if (op == OP_CLAIM_NAME) {
int claim_name_size = vvchParams[0].size();
min_fee += claim_name_size*minFeePerNameClaimChar;
}

View file

@ -8,6 +8,7 @@
#include <stdint.h>
#include <amount.h>
#include <claimtrie/txoutpoint.h>
#include <script/script.h>
#include <serialize.h>
#include <uint256.h>
@ -22,6 +23,7 @@ public:
uint32_t n;
COutPoint(): n((uint32_t) -1) { }
explicit COutPoint(const CTxOutPoint& c) : hash(c.hash), n(c.n) { }
COutPoint(const uint256& hashIn, uint32_t nIn): hash(hashIn), n(nIn) { }
ADD_SERIALIZE_METHODS;
@ -52,6 +54,11 @@ public:
}
std::string ToString() const;
operator CTxOutPoint() const
{
return CTxOutPoint{hash, n};
}
};
/** An input of a transaction. It contains the location of the previous

View file

@ -1,4 +1,5 @@
#include <claimtrie.h>
#include <claimtrie/forks.h>
#include <coins.h>
#include <core_io.h>
#include <key_io.h>
@ -20,13 +21,6 @@
static constexpr size_t claimIdHexLength = 40;
uint160 uint160S(const std::string& str)
{
uint160 s;
s.SetHex(str);
return s;
}
void ParseClaimtrieId(const UniValue& v, std::string& claimId, const std::string& strName)
{
// use IsHexNumber which verify odd strings size
@ -137,7 +131,7 @@ std::vector<CClaimNsupports> seqSort(const std::vector<CClaimNsupports>& source)
return claimsNsupports;
}
std::size_t indexOf(const std::vector<CClaimNsupports>& source, const uint160& claimId)
std::size_t indexOf(const std::vector<CClaimNsupports>& source, const CUint160& claimId)
{
auto it = std::find_if(source.begin(), source.end(), [&claimId](const CClaimNsupports& claimNsupports) {
return claimNsupports.claim.claimId == claimId;
@ -150,7 +144,7 @@ UniValue claimToJSON(const CCoinsViewCache& coinsCache, const CClaimValue& claim
{
UniValue result(UniValue::VOBJ);
auto& coin = coinsCache.AccessCoin(claim.outPoint);
auto& coin = coinsCache.AccessCoin(COutPoint(claim.outPoint));
if (!coin.IsSpent()) {
std::string name, value;
if (extractValue(coin.out.scriptPubKey, name, value)) {
@ -177,7 +171,7 @@ UniValue supportToJSON(const CCoinsViewCache& coinsCache, const CSupportValue& s
{
UniValue ret(UniValue::VOBJ);
auto& coin = coinsCache.AccessCoin(support.outPoint);
auto& coin = coinsCache.AccessCoin(COutPoint(support.outPoint));
if (!coin.IsSpent()) {
std::string name, value;
if (extractValue(coin.out.scriptPubKey, name, value)) {
@ -296,7 +290,7 @@ static UniValue getvalueforname(const JSONRPCRequest& request)
return ret;
auto& claimNsupports =
claimId.length() == claimIdHexLength ? csToName.find(uint160S(claimId)) :
claimId.length() == claimIdHexLength ? csToName.find(CUint160S(claimId)) :
!claimId.empty() ? csToName.find(claimId) : csToName.claimsNsupports[0];
if (claimNsupports.IsNull())
@ -546,11 +540,11 @@ UniValue getclaimsfortx(const JSONRPCRequest& request)
std::string sName(vvchParams[0].begin(), vvchParams[0].end());
o.pushKV(T_NAME, escapeNonUtf8(sName));
if (op == OP_CLAIM_NAME) {
uint160 claimId = ClaimIdHash(hash, i);
CUint160 claimId = ClaimIdHash(hash, i);
o.pushKV(T_CLAIMID, claimId.GetHex());
o.pushKV(T_VALUE, HexStr(vvchParams[1].begin(), vvchParams[1].end()));
} else if (op == OP_UPDATE_CLAIM || op == OP_SUPPORT_CLAIM) {
uint160 claimId(vvchParams[1]);
CUint160 claimId(vvchParams[1]);
o.pushKV(T_CLAIMID, claimId.GetHex());
if (vvchParams.size() > 2)
o.pushKV(T_VALUE, HexStr(vvchParams[2].begin(), vvchParams[2].end()));
@ -755,7 +749,7 @@ UniValue removedToJSON(const std::vector<queueEntryType<T>>& undo)
{
UniValue ret(UniValue::VARR);
for (auto& u : undo) {
auto& outPoint = u.second.outPoint;
auto outPoint = COutPoint(u.second.outPoint);
ret.push_back(ClaimIdHash(outPoint.hash, outPoint.n).ToString());
}
return ret;
@ -780,7 +774,7 @@ UniValue getchangesinblock(const JSONRPCRequest& request)
auto addedUpdated = [](const insertUndoType& insertUndo) {
UniValue added(UniValue::VARR);
for (auto& a : insertUndo)
added.push_back(ClaimIdHash(a.outPoint.hash, a.outPoint.n).ToString());
added.push_back(ClaimIdHash(uint256(a.outPoint.hash), a.outPoint.n).ToString());
return added;
};

View file

@ -10,6 +10,7 @@
#include <algorithm>
#include <assert.h>
#include <claimtrie_serial.h>
#include <ios>
#include <limits>
#include <map>

View file

@ -30,7 +30,7 @@ BOOST_AUTO_TEST_CASE(takeover_stability_test) {
CMutableTransaction tx2 = fixture.MakeClaim(fixture.GetCoinbase(), "@bass", "two", 2);
fixture.IncrementBlocks(1);
BOOST_CHECK(fixture.is_best_claim("@bass", tx2));
uint160 id; int takeover;
CUint160 id; int takeover;
BOOST_REQUIRE(fixture.getLastTakeoverForName("@bass", id, takeover));
auto height = chainActive.Tip()->nHeight;
BOOST_CHECK_EQUAL(takeover, height);
@ -426,7 +426,7 @@ BOOST_AUTO_TEST_CASE(claimtrie_update_takeover_test)
CMutableTransaction tx1 = fixture.MakeClaim(fixture.GetCoinbase(), "test", "one", 5);
auto cid = ClaimIdHash(tx1.GetHash(), 0);
fixture.IncrementBlocks(1);
uint160 cid2;
CUint160 cid2;
int takeover;
int height = chainActive.Tip()->nHeight;
fixture.getLastTakeoverForName("test", cid2, takeover);
@ -1148,7 +1148,7 @@ BOOST_AUTO_TEST_CASE(basic_merkle_test)
CMutableTransaction tx1 = fixture.MakeClaim(fixture.GetCoinbase(), sName, sValue, 10);
fixture.IncrementBlocks(20);
uint256 tx1MerkleHash = fixture.getMerkleHash();
auto tx1MerkleHash = fixture.getMerkleHash();
fixture.DecrementBlocks(20);
BOOST_CHECK(tx1MerkleHash != fixture.getMerkleHash());
fixture.CommitTx(tx1);
@ -1230,7 +1230,7 @@ BOOST_AUTO_TEST_CASE(supporting_claims_test)
BOOST_CHECK(fixture.getInfoForName(sName, val));
BOOST_CHECK_EQUAL(val.outPoint.hash, tx1.GetHash());
BOOST_CHECK_EQUAL(val.outPoint.n, 0);
uint256 tx1MerkleHash = fixture.getMerkleHash();
auto tx1MerkleHash = fixture.getMerkleHash();
CMutableTransaction tx4 = BuildTransaction(tx1);
CMutableTransaction tx5 = BuildTransaction(tx2);
@ -1553,7 +1553,7 @@ BOOST_AUTO_TEST_CASE(supporting_claims2_test)
fixture.CommitTx(tx2);
fixture.IncrementBlocks(1); // 7
uint256 rootMerkleHash = fixture.getMerkleHash();
auto rootMerkleHash = fixture.getMerkleHash();
BOOST_CHECK(!pclaimTrie->empty());
BOOST_CHECK(!fixture.queueEmpty());
@ -1920,7 +1920,7 @@ BOOST_AUTO_TEST_CASE(update_on_support2_test)
CMutableTransaction s2 = fixture.MakeSupport(fixture.GetCoinbase(), tx1, name, 1);
fixture.IncrementBlocks(1);
uint160 claimId;
CUint160 claimId;
int lastTakeover;
BOOST_CHECK(fixture.getLastTakeoverForName(name, claimId, lastTakeover));
BOOST_CHECK_EQUAL(lastTakeover, height + 1);

View file

@ -1,4 +1,5 @@
#include <claimtrie.h>
#include <claimtrie/forks.h>
#include <nameclaim.h>
#include <uint256.h>
#include <validation.h>
@ -24,12 +25,12 @@ public:
p.hash = Hash(key.begin(), key.end());
auto c = value.claimId;
if (c.IsNull())
c = ClaimIdHash(p.hash, p.n);
c = ClaimIdHash(uint256(p.hash), p.n);
return addClaim(key, p, c, value.nAmount, value.nHeight);
}
bool removeClaimFromTrie(const std::string& key, const COutPoint& outPoint) {
bool removeClaimFromTrie(const std::string& key, const CTxOutPoint& outPoint) {
int validHeight;
std::string nodeName;
@ -37,7 +38,7 @@ public:
if (p.hash.IsNull())
p.hash = Hash(key.begin(), key.end());
auto ret = removeClaim(ClaimIdHash(p.hash, p.n), p, nodeName, validHeight);
auto ret = removeClaim(ClaimIdHash(uint256(p.hash), p.n), p, nodeName, validHeight);
assert(!ret || nodeName == key);
return ret;
}
@ -47,10 +48,10 @@ public:
if (p.hash.IsNull())
p.hash = Hash(key.begin(), key.end());
return addSupport(key, p, value.nAmount, value.supportedClaimId, value.nHeight);
return addSupport(key, p, value.supportedClaimId, value.nAmount, value.nHeight);
}
bool removeSupportFromMap(const std::string& key, const COutPoint& outPoint) {
bool removeSupportFromMap(const std::string& key, const CTxOutPoint& outPoint) {
int validHeight;
std::string nodeName;
@ -69,7 +70,7 @@ BOOST_FIXTURE_TEST_SUITE(claimtriecache_tests, RegTestingSetup)
BOOST_AUTO_TEST_CASE(merkle_hash_single_test)
{
// check empty trie
uint256 one(uint256S("0000000000000000000000000000000000000000000000000000000000000001"));
auto one = uint256S("0000000000000000000000000000000000000000000000000000000000000001");
CClaimTrieCacheTest cc(pclaimTrie);
BOOST_CHECK_EQUAL(one, cc.getMerkleHash());
@ -80,30 +81,31 @@ BOOST_AUTO_TEST_CASE(merkle_hash_single_test)
BOOST_AUTO_TEST_CASE(merkle_hash_multiple_test)
{
uint256 hash0(uint256S("0000000000000000000000000000000000000000000000000000000000000001"));
auto hash0 = uint256S("0000000000000000000000000000000000000000000000000000000000000001");
CUint160 hash160;
CMutableTransaction tx1 = BuildTransaction(hash0);
COutPoint tx1OutPoint(tx1.GetHash(), 0);
CTxOutPoint tx1OutPoint(tx1.GetHash(), 0);
CMutableTransaction tx2 = BuildTransaction(tx1.GetHash());
COutPoint tx2OutPoint(tx2.GetHash(), 0);
CTxOutPoint tx2OutPoint(tx2.GetHash(), 0);
CMutableTransaction tx3 = BuildTransaction(tx2.GetHash());
COutPoint tx3OutPoint(tx3.GetHash(), 0);
CTxOutPoint tx3OutPoint(tx3.GetHash(), 0);
CMutableTransaction tx4 = BuildTransaction(tx3.GetHash());
COutPoint tx4OutPoint(tx4.GetHash(), 0);
CTxOutPoint tx4OutPoint(tx4.GetHash(), 0);
CMutableTransaction tx5 = BuildTransaction(tx4.GetHash());
COutPoint tx5OutPoint(tx5.GetHash(), 0);
CTxOutPoint tx5OutPoint(tx5.GetHash(), 0);
CMutableTransaction tx6 = BuildTransaction(tx5.GetHash());
COutPoint tx6OutPoint(tx6.GetHash(), 0);
CTxOutPoint tx6OutPoint(tx6.GetHash(), 0);
uint256 hash1;
CUint256 hash1;
hash1.SetHex("71c7b8d35b9a3d7ad9a1272b68972979bbd18589f1efe6f27b0bf260a6ba78fa");
uint256 hash2;
CUint256 hash2;
hash2.SetHex("c4fc0e2ad56562a636a0a237a96a5f250ef53495c2cb5edd531f087a8de83722");
uint256 hash3;
CUint256 hash3;
hash3.SetHex("baf52472bd7da19fe1e35116cfb3bd180d8770ffbe3ae9243df1fb58a14b0975");
uint256 hash4;
CUint256 hash4;
hash4.SetHex("c73232a755bf015f22eaa611b283ff38100f2a23fb6222e86eca363452ba0c51");
CClaimTrie master(false, 2, 1);
@ -212,10 +214,10 @@ BOOST_AUTO_TEST_CASE(basic_insertion_info_test)
CClaimTrieCacheTest ctc(pclaimTrie);
// create and insert claim
uint256 hash0(uint256S("0000000000000000000000000000000000000000000000000000000000000001"));
auto hash0 = uint256S("0000000000000000000000000000000000000000000000000000000000000001");
CMutableTransaction tx1 = BuildTransaction(hash0);
uint160 claimId = ClaimIdHash(tx1.GetHash(), 0);
COutPoint claimOutPoint(tx1.GetHash(), 0);
CUint160 claimId = ClaimIdHash(tx1.GetHash(), 0);
CTxOutPoint claimOutPoint(tx1.GetHash(), 0);
CAmount amount(10);
int height = 0;
int validHeight = 0;
@ -236,9 +238,9 @@ BOOST_AUTO_TEST_CASE(basic_insertion_info_test)
// insert a support
CAmount supportAmount(10);
uint256 hash1(uint256S("0000000000000000000000000000000000000000000000000000000000000002"));
auto hash1 = uint256S("0000000000000000000000000000000000000000000000000000000000000002");
CMutableTransaction tx2 = BuildTransaction(hash1);
COutPoint supportOutPoint(tx2.GetHash(), 0);
CTxOutPoint supportOutPoint(tx2.GetHash(), 0);
CSupportValue support(supportOutPoint, claimId, supportAmount, height, validHeight);
ctc.insertSupportIntoMap("test", support);
@ -256,7 +258,7 @@ BOOST_AUTO_TEST_CASE(basic_insertion_info_test)
// CClaimTrieCacheTest cc(pclaimTrie);
// BOOST_CHECK_EQUAL(0, cc.getTotalClaimsInTrie());
//
// COutPoint outpoint;
// CTxOutPoint outpoint;
// uint160 claimId;
// CAmount amount(20);
// int height = 0;
@ -302,14 +304,13 @@ BOOST_AUTO_TEST_CASE(trie_stays_consistent_test)
"goodness", "goodnight", "goodnatured", "goods", "go", "goody", "goo"
};
CClaimTrie trie(false, 0, 1);
CClaimTrieCacheTest cache(&trie);
CClaimTrieCacheTest cache(pclaimTrie);
CClaimValue value;
for (auto& name: names) {
value.outPoint.hash = Hash(name.begin(), name.end());
value.outPoint.n = 0;
value.claimId = ClaimIdHash(value.outPoint.hash, 0);
value.claimId = ClaimIdHash(uint256(value.outPoint.hash), 0);
BOOST_CHECK(cache.insertClaimIntoTrie(name, value));
}
@ -318,17 +319,17 @@ BOOST_AUTO_TEST_CASE(trie_stays_consistent_test)
for (auto& name: names) {
auto hash = Hash(name.begin(), name.end());
BOOST_CHECK(cache.removeClaimFromTrie(name, COutPoint(hash, 0)));
BOOST_CHECK(cache.removeClaimFromTrie(name, CTxOutPoint(hash, 0)));
cache.flush();
BOOST_CHECK(cache.checkConsistency());
}
BOOST_CHECK(trie.empty());
BOOST_CHECK(pclaimTrie->empty());
}
BOOST_AUTO_TEST_CASE(verify_basic_serialization)
{
CClaimValue cv;
cv.outPoint = COutPoint(uint256S("123"), 2);
cv.outPoint = CTxOutPoint(CUint256S("123"), 2);
cv.nHeight = 3;
cv.claimId.SetHex("4567");
cv.nEffectiveAmount = 4;

View file

@ -276,7 +276,8 @@ BOOST_AUTO_TEST_CASE(hardfork_disk_test)
BOOST_CHECK_EQUAL(fixture.expirationTime(), 3);
fixture.IncrementBlocks(7, true);
BOOST_CHECK_EQUAL(fixture.expirationTime(), 6);
fixture.ValidateTipMatches(chainActive.Tip());
auto tip = chainActive.Tip();
fixture.ReadFromDisk(tip->nHeight, tip->hashClaimTrie);
BOOST_CHECK_EQUAL(fixture.expirationTime(), 6);
// Create a claim and support 1 block before the fork height that will expire after the fork height.
@ -287,7 +288,8 @@ BOOST_AUTO_TEST_CASE(hardfork_disk_test)
CMutableTransaction s1 = fixture.MakeSupport(fixture.GetCoinbase(), tx1, "test", 1);
fixture.IncrementBlocks(1);
fixture.ValidateTipMatches(chainActive.Tip());
tip = chainActive.Tip();
fixture.ReadFromDisk(tip->nHeight, tip->hashClaimTrie);
BOOST_CHECK_EQUAL(fixture.expirationTime(), 3);
fixture.IncrementBlocks(1);
BOOST_CHECK_EQUAL(fixture.expirationTime(), 6);
@ -308,7 +310,8 @@ BOOST_AUTO_TEST_CASE(hardfork_disk_test)
CMutableTransaction tx2 = fixture.MakeClaim(fixture.GetCoinbase(),"test2","one",1);
CMutableTransaction s2 = fixture.MakeSupport(fixture.GetCoinbase(),tx2,"test2",1);
fixture.IncrementBlocks(1);
fixture.ValidateTipMatches(chainActive.Tip());
tip = chainActive.Tip();
fixture.ReadFromDisk(tip->nHeight, tip->hashClaimTrie);
CMutableTransaction u2 = fixture.MakeUpdate(tx2, "test2", "two", ClaimIdHash(tx2.GetHash(), 0), 1);
// increment to fork
fixture.IncrementBlocks(2);
@ -503,7 +506,7 @@ BOOST_AUTO_TEST_CASE(claim_expiration_test)
BOOST_CHECK(!fixture.expirationQueueEmpty());
BOOST_CHECK(fixture.getInfoForName(sName, val));
BOOST_CHECK_EQUAL(val.outPoint, tx1OutPoint);
uint256 tx1MerkleHash = fixture.getMerkleHash();
auto tx1MerkleHash = fixture.getMerkleHash();
// roll back to before tx3 is valid
fixture.DecrementBlocks(1); // 10
@ -601,7 +604,7 @@ BOOST_AUTO_TEST_CASE(expiring_supports_test)
BOOST_CHECK(!fixture.queueEmpty());
BOOST_CHECK(!fixture.supportEmpty());
BOOST_CHECK(fixture.supportQueueEmpty());
uint256 rootMerkleHash = fixture.getMerkleHash();
auto rootMerkleHash = fixture.getMerkleHash();
// Advance until tx2 is valid
fixture.IncrementBlocks(20); // 42

View file

@ -95,16 +95,22 @@ ClaimTrieChainFixture::~ClaimTrieChainFixture()
added_unchecked = false;
DecrementBlocks(chainActive.Height());
auto& consensus = const_cast<Consensus::Params&>(Params().GetConsensus());
if (normalization_original >= 0)
if (normalization_original >= 0) {
consensus.nNormalizedNameForkHeight = normalization_original;
const_cast<int&>(base->nNormalizedNameForkHeight) = normalization_original;
}
if (expirationForkHeight >= 0) {
consensus.nExtendedClaimExpirationForkHeight = expirationForkHeight;
consensus.nExtendedClaimExpirationTime = extendedExpiration;
consensus.nOriginalClaimExpirationTime = originalExpiration;
const_cast<int64_t&>(base->nExtendedClaimExpirationForkHeight) = expirationForkHeight;
const_cast<int64_t&>(base->nOriginalClaimExpirationTime) = originalExpiration;
const_cast<int64_t&>(base->nExtendedClaimExpirationTime) = extendedExpiration;
}
if (forkhash_original >= 0)
if (forkhash_original >= 0) {
consensus.nAllClaimsInMerkleForkHeight = forkhash_original;
const_cast<int64_t&>(base->nAllClaimsInMerkleForkHeight) = forkhash_original;
}
}
void ClaimTrieChainFixture::setExpirationForkHeight(int targetMinusCurrent, int64_t preForkExpirationTime, int64_t postForkExpirationTime)
@ -119,7 +125,9 @@ void ClaimTrieChainFixture::setExpirationForkHeight(int targetMinusCurrent, int6
consensus.nExtendedClaimExpirationForkHeight = target;
consensus.nExtendedClaimExpirationTime = postForkExpirationTime;
consensus.nOriginalClaimExpirationTime = preForkExpirationTime;
setExpirationTime(targetMinusCurrent >= 0 ? preForkExpirationTime : postForkExpirationTime);
const_cast<int64_t&>(base->nExtendedClaimExpirationForkHeight) = target;
const_cast<int64_t&>(base->nOriginalClaimExpirationTime) = preForkExpirationTime;
const_cast<int64_t&>(base->nExtendedClaimExpirationTime) = postForkExpirationTime;
}
void ClaimTrieChainFixture::setNormalizationForkHeight(int targetMinusCurrent)
@ -129,6 +137,7 @@ void ClaimTrieChainFixture::setNormalizationForkHeight(int targetMinusCurrent)
if (normalization_original < 0)
normalization_original = consensus.nNormalizedNameForkHeight;
consensus.nNormalizedNameForkHeight = target;
const_cast<int&>(base->nNormalizedNameForkHeight) = target;
}
void ClaimTrieChainFixture::setHashForkHeight(int targetMinusCurrent)
@ -138,6 +147,7 @@ void ClaimTrieChainFixture::setHashForkHeight(int targetMinusCurrent)
if (forkhash_original < 0)
forkhash_original = consensus.nAllClaimsInMerkleForkHeight;
consensus.nAllClaimsInMerkleForkHeight = target;
const_cast<int64_t&>(base->nAllClaimsInMerkleForkHeight) = target;
}
bool ClaimTrieChainFixture::CreateBlock(const std::unique_ptr<CBlockTemplate>& pblocktemplate)
@ -277,9 +287,9 @@ void ClaimTrieChainFixture::IncrementBlocks(int num_blocks, bool mark)
BOOST_CHECK_EQUAL(pblocktemplate->block.vtx.size(), num_txs_for_next_block + 1);
BOOST_REQUIRE(CreateBlock(pblocktemplate));
num_txs_for_next_block = 0;
expirationHeight = chainActive.Height();
nNextHeight = chainActive.Height() + 1;
}
setExpirationTime(Params().GetConsensus().GetExpirationTime(nNextHeight - 1));
}
// disconnect i blocks from tip
@ -295,8 +305,8 @@ void ClaimTrieChainFixture::DecrementBlocks(int num_blocks)
BOOST_CHECK_EQUAL(ActivateBestChain(state, Params()), true);
mempool.clear();
num_txs_for_next_block = 0;
expirationHeight = chainActive.Height();
nNextHeight = chainActive.Height() + 1;
setExpirationTime(Params().GetConsensus().GetExpirationTime(nNextHeight - 1));
}
// decrement back to last mark

View file

@ -6,7 +6,7 @@
#define _CLAIMTRIEFIXTURE_H_
#include <chainparams.h>
#include <claimtrie.h>
#include <claimtrie/forks.h>
#include <coins.h>
#include <consensus/merkle.h>
#include <consensus/validation.h>

View file

@ -6,7 +6,7 @@
using namespace std;
void ValidatePairs(CClaimTrieCache& cache, const std::vector<std::pair<bool, uint256>>& pairs, uint256 claimHash)
void ValidatePairs(CClaimTrieCache& cache, const std::vector<std::pair<bool, CUint256>>& pairs, CUint256 claimHash)
{
for (auto& pair : pairs)
if (pair.first) // we're on the right because we were an odd index number
@ -27,7 +27,7 @@ BOOST_AUTO_TEST_CASE(hash_includes_all_claims_rollback_test)
CMutableTransaction tx1 = fixture.MakeClaim(fixture.GetCoinbase(), "test", "one", 1);
fixture.IncrementBlocks(1);
uint256 currentRoot = fixture.getMerkleHash();
auto currentRoot = fixture.getMerkleHash();
fixture.IncrementBlocks(1);
BOOST_CHECK_EQUAL(currentRoot, fixture.getMerkleHash());
fixture.IncrementBlocks(3);
@ -81,8 +81,7 @@ BOOST_AUTO_TEST_CASE(hash_includes_all_claims_triple_test)
BOOST_CHECK(fixture.getProofForName(name, claim.claimId, proof));
BOOST_CHECK(proof.hasValue);
BOOST_CHECK_EQUAL(proof.outPoint, claim.outPoint);
BOOST_CHECK_EQUAL(proof.nHeightOfLastTakeover, cfn.nLastTakeoverHeight);
uint256 claimHash = getValueHash(claim.outPoint, proof.nHeightOfLastTakeover);
auto claimHash = getValueHash(claim.outPoint, proof.nHeightOfLastTakeover);
ValidatePairs(fixture, proof.pairs, claimHash);
}
}
@ -111,7 +110,7 @@ BOOST_AUTO_TEST_CASE(hash_includes_all_claims_branched_test)
BOOST_CHECK(fixture.getProofForName(name, claim.claimId, proof));
BOOST_CHECK(proof.hasValue);
BOOST_CHECK_EQUAL(proof.outPoint, claim.outPoint);
uint256 claimHash = getValueHash(claim.outPoint, proof.nHeightOfLastTakeover);
auto claimHash = getValueHash(claim.outPoint, proof.nHeightOfLastTakeover);
ValidatePairs(fixture, proof.pairs, claimHash);
}
}
@ -172,15 +171,15 @@ BOOST_AUTO_TEST_CASE(hash_claims_children_fuzzer_test)
BOOST_CHECK(fixture.getProofForName(name, claim.claimId, proof));
BOOST_CHECK(proof.hasValue);
BOOST_CHECK_EQUAL(proof.outPoint, claim.outPoint);
uint256 claimHash = getValueHash(claim.outPoint, proof.nHeightOfLastTakeover);
auto claimHash = getValueHash(claim.outPoint, proof.nHeightOfLastTakeover);
ValidatePairs(fixture, proof.pairs, claimHash);
}
}
}
bool verify_proof(const CClaimTrieProof proof, uint256 rootHash, const std::string& name)
bool verify_proof(const CClaimTrieProof proof, CUint256 rootHash, const std::string& name)
{
uint256 previousComputedHash;
CUint256 previousComputedHash;
std::string computedReverseName;
bool verifiedValue = false;
@ -189,7 +188,7 @@ bool verify_proof(const CClaimTrieProof proof, uint256 rootHash, const std::stri
std::vector<unsigned char> vchToHash;
for (auto itChildren = itNodes->children.begin(); itChildren != itNodes->children.end(); ++itChildren) {
vchToHash.push_back(itChildren->first);
uint256 childHash;
CUint256 childHash;
if (itChildren->second.IsNull()) {
if (previousComputedHash.IsNull()) {
return false;
@ -209,7 +208,7 @@ bool verify_proof(const CClaimTrieProof proof, uint256 rootHash, const std::stri
return false;
}
if (itNodes->hasValue) {
uint256 valHash;
CUint256 valHash;
if (itNodes->valHash.IsNull()) {
if (itNodes != proof.nodes.rbegin()) {
return false;
@ -232,7 +231,7 @@ bool verify_proof(const CClaimTrieProof proof, uint256 rootHash, const std::stri
std::vector<unsigned char> vchHash(hasher.OUTPUT_SIZE);
hasher.Write(vchToHash.data(), vchToHash.size());
hasher.Finalize(&(vchHash[0]));
uint256 calculatedHash(vchHash);
CUint256 calculatedHash(vchHash);
previousComputedHash = calculatedHash;
}
if (previousComputedHash != rootHash) {
@ -324,7 +323,7 @@ BOOST_AUTO_TEST_CASE(value_proof_test)
BOOST_CHECK(verify_proof(proof, chainActive.Tip()->hashClaimTrie, sName6));
BOOST_CHECK_EQUAL(proof.hasValue, false);
BOOST_CHECK(fixture.getProofForName(sName7, ClaimIdHash(fixture.getMerkleHash(), 0), proof));
BOOST_CHECK(fixture.getProofForName(sName7, ClaimIdHash(uint256(fixture.getMerkleHash()), 0), proof));
BOOST_CHECK(verify_proof(proof, chainActive.Tip()->hashClaimTrie, sName7));
BOOST_CHECK_EQUAL(proof.hasValue, false);

View file

@ -307,8 +307,8 @@ BOOST_AUTO_TEST_CASE(normalization_removal_test)
cache.addClaim("AB", COutPoint(tx1.GetHash(), 0), ClaimIdHash(tx1.GetHash(), 0), 1, height);
cache.addClaim("Ab", COutPoint(tx2.GetHash(), 0), ClaimIdHash(tx2.GetHash(), 0), 2, height);
cache.addClaim("aB", COutPoint(tx3.GetHash(), 0), ClaimIdHash(tx3.GetHash(), 0), 3, height);
cache.addSupport("AB", COutPoint(sx1.GetHash(), 0), 1, ClaimIdHash(tx1.GetHash(), 0), height);
cache.addSupport("Ab", COutPoint(sx2.GetHash(), 0), 1, ClaimIdHash(tx2.GetHash(), 0), height);
cache.addSupport("AB", COutPoint(sx1.GetHash(), 0), ClaimIdHash(tx1.GetHash(), 0), 1, height);
cache.addSupport("Ab", COutPoint(sx2.GetHash(), 0), ClaimIdHash(tx2.GetHash(), 0), 1, height);
insertUndoType insertUndo;
claimUndoType expireUndo;
insertUndoType insertSupportUndo;

View file

@ -6,7 +6,7 @@
using namespace std;
extern void ValidatePairs(CClaimTrieCache& cache, const std::vector<std::pair<bool, uint256>>& pairs, uint256 claimHash);
extern void ValidatePairs(CClaimTrieCache& cache, const std::vector<std::pair<bool, CUint256>>& pairs, CUint256 claimHash);
BOOST_FIXTURE_TEST_SUITE(claimtrierpc_tests, RegTestingSetup)
@ -190,12 +190,12 @@ BOOST_AUTO_TEST_CASE(claim_rpcs_rollback3_test)
BOOST_CHECK_EQUAL(valueResults[T_AMOUNT].get_int(), 3);
}
std::vector<std::pair<bool, uint256>> jsonToPairs(const UniValue& jsonPair)
std::vector<std::pair<bool, CUint256>> jsonToPairs(const UniValue& jsonPair)
{
std::vector<std::pair<bool, uint256>> pairs;
std::vector<std::pair<bool, CUint256>> pairs;
for (std::size_t i = 0; i < jsonPair.size(); ++i) {
auto& jpair = jsonPair[i];
pairs.emplace_back(jpair[T_ODD].get_bool(), uint256S(jpair[T_HASH].get_str()));
pairs.emplace_back(jpair[T_ODD].get_bool(), CUint256S(jpair[T_HASH].get_str()));
}
return pairs;
}

View file

@ -19,7 +19,6 @@
#include <rpc/register.h>
#include <script/sigcache.h>
#include "claimtrie.h"
#include <boost/test/unit_test.hpp>
#include <boost/test/unit_test_parameters.hpp>
@ -61,24 +60,33 @@ std::ostream& operator<<(std::ostream& os, const COutPoint& point)
return os;
}
std::ostream& operator<<(std::ostream& os, const CUint256& num)
{
os << num.ToString();
return os;
}
std::ostream& operator<<(std::ostream& os, const CUint160& num)
{
os << num.ToString();
return os;
}
std::ostream& operator<<(std::ostream& os, const CTxOutPoint& point)
{
os << point.ToString();
return os;
}
std::ostream& operator<<(std::ostream& os, const CClaimValue& claim)
{
os << "claim(" << claim.outPoint.ToString()
<< ", " << claim.claimId.ToString()
<< ", " << claim.nAmount
<< ", " << claim.nEffectiveAmount
<< ", " << claim.nHeight
<< ", " << claim.nValidAtHeight << ')';
os << claim.ToString();
return os;
}
std::ostream& operator<<(std::ostream& os, const CSupportValue& support)
{
os << "support(" << support.outPoint.ToString()
<< ", " << support.supportedClaimId.ToString()
<< ", " << support.nAmount
<< ", " << support.nHeight
<< ", " << support.nValidAtHeight << ')';
os << support.ToString();
return os;
}
@ -91,6 +99,7 @@ BasicTestingSetup::BasicTestingSetup(const std::string& chainName)
g_logger->m_print_to_console = true;
g_logger->m_log_time_micros = true;
g_logger->EnableCategory(BCLog::ALL);
CLogPrint::global().setLogger(g_logger);
}
SHA256AutoDetect();
@ -138,7 +147,14 @@ TestingSetup::TestingSetup(const std::string& chainName) : BasicTestingSetup(cha
pblocktree.reset(new CBlockTreeDB(1 << 20, true));
pcoinsdbview.reset(new CCoinsViewDB(1 << 23, true));
pcoinsTip.reset(new CCoinsViewCache(pcoinsdbview.get()));
pclaimTrie = new CClaimTrie(true, 0, 1);
auto& consensus = chainparams.GetConsensus();
pclaimTrie = new CClaimTrie(true, false,
consensus.nNormalizedNameForkHeight,
consensus.nOriginalClaimExpirationTime,
consensus.nExtendedClaimExpirationTime,
consensus.nExtendedClaimExpirationForkHeight,
consensus.nAllClaimsInMerkleForkHeight, 1);
if (!LoadGenesisBlock(chainparams)) {
throw std::runtime_error("LoadGenesisBlock failed.");
}

View file

@ -6,6 +6,7 @@
#define BITCOIN_TEST_TEST_BITCOIN_H
#include <chainparamsbase.h>
#include <claimtrie/forks.h>
#include <fs.h>
#include <key.h>
#include <pubkey.h>
@ -134,10 +135,9 @@ std::ostream& operator<<(std::ostream& os, const uint256& num);
std::ostream& operator<<(std::ostream& os, const uint160& num);
std::ostream& operator<<(std::ostream& os, const COutPoint& point);
struct CClaimValue;
std::ostream& operator<<(std::ostream& os, const CUint256& num);
std::ostream& operator<<(std::ostream& os, const CUint160& num);
std::ostream& operator<<(std::ostream& os, const CTxOutPoint& point);
std::ostream& operator<<(std::ostream& os, const CClaimValue& claim);
struct CSupportValue;
std::ostream& operator<<(std::ostream& os, const CSupportValue& support);
#endif

View file

@ -14,6 +14,8 @@
#include <vector>
#include <crypto/common.h>
#include <claimtrie/uints.h>
/** Template base class for fixed-sized opaque blobs. */
template<unsigned int BITS>
class base_blob
@ -27,6 +29,11 @@ public:
memset(data, 0, sizeof(data));
}
explicit base_blob(const CBaseBlob<BITS>& b)
{
std::copy(b.begin(), b.end(), begin());
}
explicit base_blob(const std::vector<unsigned char>& vch);
bool IsNull() const
@ -102,6 +109,13 @@ public:
{
s.read((char*)data, sizeof(data));
}
operator CBaseBlob<BITS>() const
{
CBaseBlob<BITS> c;
std::copy(begin(), end(), c.begin());
return c;
}
};
/** 160-bit opaque blob.
@ -110,8 +124,7 @@ public:
*/
class uint160 : public base_blob<160> {
public:
uint160() {}
explicit uint160(const std::vector<unsigned char>& vch) : base_blob<160>(vch) {}
using base_blob<160>::base_blob;
};
/** 256-bit opaque blob.
@ -121,8 +134,7 @@ public:
*/
class uint256 : public base_blob<256> {
public:
uint256() {}
explicit uint256(const std::vector<unsigned char>& vch) : base_blob<256>(vch) {}
using base_blob<256>::base_blob;
/** A cheap hash function that just returns 64 bits from the result, it can be
* used when the contents are considered uniformly random. It is not appropriate

View file

@ -7,7 +7,7 @@
#define BITCOIN_UNDO_H
#include <compressor.h>
#include <claimtrie.h>
#include <claimtrie/forks.h>
#include <primitives/transaction.h>
#include <serialize.h>

View file

@ -11,7 +11,7 @@
#endif
#include <amount.h>
#include <claimtrie.h>
#include <claimtrie/forks.h>
#include <coins.h>
#include <fs.h>
#include <index/txindex.h>

View file

@ -7,6 +7,7 @@
#include <chain.h>
#include <consensus/validation.h>
#include <core_io.h>
#include <claimtrie/forks.h>
#include <httpserver.h>
#include <validation.h>
#include <key_io.h>
@ -952,7 +953,7 @@ UniValue supportclaim(const JSONRPCRequest& request)
if (isTip) {
CTransactionRef ref;
uint256 block;
if (!GetTransaction(claimNsupports.claim.outPoint.hash, ref, Params().GetConsensus(), block, true))
if (!GetTransaction(uint256(claimNsupports.claim.outPoint.hash), ref, Params().GetConsensus(), block, true))
throw JSONRPCError(RPC_INVALID_PARAMETER, "Unable to locate the TX with the claim's output.");
if (!ExtractDestination(ref->vout[claimNsupports.claim.outPoint.n].scriptPubKey, dest))
throw JSONRPCError(RPC_INVALID_PARAMETER, "Unable to extract the destination from the chosen claim.");