Use fully static linkage #364
38 changed files with 258293 additions and 3343 deletions
|
@ -60,8 +60,8 @@ case $host in
|
|||
lt_cv_deplibs_check_method="pass_all"
|
||||
;;
|
||||
esac
|
||||
dnl Require C++11 compiler (no GNU extensions)
|
||||
AX_CXX_COMPILE_STDCXX([11], [noext], [mandatory], [nodefault])
|
||||
dnl Require C++14 compiler (no GNU extensions)
|
||||
AX_CXX_COMPILE_STDCXX([14], [noext], [mandatory], [nodefault])
|
||||
dnl Check if -latomic is required for <std::atomic>
|
||||
CHECK_ATOMIC
|
||||
|
||||
|
|
|
@ -149,7 +149,6 @@ BITCOIN_CORE_H = \
|
|||
policy/policy.h \
|
||||
policy/rbf.h \
|
||||
pow.h \
|
||||
prefixtrie.h \
|
||||
protocol.h \
|
||||
random.h \
|
||||
reverse_iterator.h \
|
||||
|
@ -171,6 +170,8 @@ 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 \
|
||||
|
@ -251,7 +252,6 @@ libbitcoin_server_a_SOURCES = \
|
|||
policy/policy.cpp \
|
||||
policy/rbf.cpp \
|
||||
pow.cpp \
|
||||
prefixtrie.cpp \
|
||||
rest.cpp \
|
||||
rpc/blockchain.cpp \
|
||||
rpc/claimtrie.cpp \
|
||||
|
@ -262,6 +262,7 @@ libbitcoin_server_a_SOURCES = \
|
|||
rpc/server.cpp \
|
||||
rpc/util.cpp \
|
||||
script/sigcache.cpp \
|
||||
sqlite/sqlite3.c \
|
||||
shutdown.cpp \
|
||||
timedata.cpp \
|
||||
torcontrol.cpp \
|
||||
|
|
|
@ -76,7 +76,6 @@ BITCOIN_TESTS =\
|
|||
test/pmt_tests.cpp \
|
||||
test/policyestimator_tests.cpp \
|
||||
test/pow_tests.cpp \
|
||||
test/prefixtrie_tests.cpp \
|
||||
test/prevector_tests.cpp \
|
||||
test/raii_event_tests.cpp \
|
||||
test/random_tests.cpp \
|
||||
|
|
|
@ -11,38 +11,44 @@ CClaimScriptAddOp::CClaimScriptAddOp(const COutPoint& point, CAmount nValue, int
|
|||
{
|
||||
}
|
||||
|
||||
bool CClaimScriptAddOp::claimName(CClaimTrieCache& trieCache, const std::string& name)
|
||||
bool CClaimScriptAddOp::claimName(CClaimTrieCache& trieCache, const std::string& name,
|
||||
const std::vector<unsigned char>& metadata)
|
||||
{
|
||||
return addClaim(trieCache, name, ClaimIdHash(point.hash, point.n));
|
||||
return addClaim(trieCache, name, ClaimIdHash(point.hash, point.n), metadata);
|
||||
}
|
||||
|
||||
bool CClaimScriptAddOp::updateClaim(CClaimTrieCache& trieCache, const std::string& name, const uint160& claimId)
|
||||
bool CClaimScriptAddOp::updateClaim(CClaimTrieCache& trieCache, const std::string& name, const uint160& claimId,
|
||||
const std::vector<unsigned char>& metadata)
|
||||
{
|
||||
return addClaim(trieCache, name, claimId);
|
||||
return addClaim(trieCache, name, claimId, metadata);
|
||||
}
|
||||
|
||||
bool CClaimScriptAddOp::addClaim(CClaimTrieCache& trieCache, const std::string& name, const uint160& claimId)
|
||||
bool CClaimScriptAddOp::addClaim(CClaimTrieCache& trieCache, const std::string& name, const uint160& claimId,
|
||||
const std::vector<unsigned char>& metadata)
|
||||
{
|
||||
return trieCache.addClaim(name, point, claimId, nValue, nHeight);
|
||||
return trieCache.addClaim(name, point, claimId, nValue, nHeight, metadata);
|
||||
}
|
||||
|
||||
bool CClaimScriptAddOp::supportClaim(CClaimTrieCache& trieCache, const std::string& name, const uint160& claimId)
|
||||
bool CClaimScriptAddOp::supportClaim(CClaimTrieCache& trieCache, const std::string& name, const uint160& claimId,
|
||||
const std::vector<unsigned char>& metadata)
|
||||
{
|
||||
return trieCache.addSupport(name, point, nValue, claimId, nHeight);
|
||||
return trieCache.addSupport(name, point, nValue, claimId, nHeight, metadata);
|
||||
}
|
||||
|
||||
CClaimScriptUndoAddOp::CClaimScriptUndoAddOp(const COutPoint& point, int nHeight) : point(point), nHeight(nHeight)
|
||||
{
|
||||
}
|
||||
|
||||
bool CClaimScriptUndoAddOp::claimName(CClaimTrieCache& trieCache, const std::string& name)
|
||||
bool CClaimScriptUndoAddOp::claimName(CClaimTrieCache& trieCache, const std::string& name,
|
||||
const std::vector<unsigned char>& metadata)
|
||||
{
|
||||
auto claimId = ClaimIdHash(point.hash, point.n);
|
||||
LogPrint(BCLog::CLAIMS, "--- [%lu]: OP_CLAIM_NAME \"%s\" with claimId %s and tx prevout %s at index %d\n", nHeight, name, claimId.GetHex(), point.hash.ToString(), point.n);
|
||||
return undoAddClaim(trieCache, name, claimId);
|
||||
}
|
||||
|
||||
bool CClaimScriptUndoAddOp::updateClaim(CClaimTrieCache& trieCache, const std::string& name, const uint160& claimId)
|
||||
bool CClaimScriptUndoAddOp::updateClaim(CClaimTrieCache& trieCache, const std::string& name, const uint160& claimId,
|
||||
const std::vector<unsigned char>& metadata)
|
||||
{
|
||||
LogPrint(BCLog::CLAIMS, "--- [%lu]: OP_UPDATE_CLAIM \"%s\" with claimId %s and tx prevout %s at index %d\n", nHeight, name, claimId.GetHex(), point.hash.ToString(), point.n);
|
||||
return undoAddClaim(trieCache, name, claimId);
|
||||
|
@ -51,13 +57,16 @@ bool CClaimScriptUndoAddOp::updateClaim(CClaimTrieCache& trieCache, const std::s
|
|||
bool CClaimScriptUndoAddOp::undoAddClaim(CClaimTrieCache& trieCache, const std::string& name, const uint160& claimId)
|
||||
{
|
||||
LogPrint(BCLog::CLAIMS, "%s: (txid: %s, nOut: %d) Removing %s, claimId: %s, from the claim trie due to block disconnect\n", __func__, point.hash.ToString(), point.n, name, claimId.ToString());
|
||||
bool res = trieCache.undoAddClaim(name, point, nHeight);
|
||||
std::string nodeName;
|
||||
int validHeight;
|
||||
bool res = trieCache.removeClaim(claimId, nodeName, validHeight);
|
||||
if (!res)
|
||||
LogPrint(BCLog::CLAIMS, "%s: Removing claim fails\n", __func__);
|
||||
return res;
|
||||
}
|
||||
|
||||
bool CClaimScriptUndoAddOp::supportClaim(CClaimTrieCache& trieCache, const std::string& name, const uint160& claimId)
|
||||
bool CClaimScriptUndoAddOp::supportClaim(CClaimTrieCache& trieCache, const std::string& name, const uint160& claimId,
|
||||
const std::vector<unsigned char>& metadata)
|
||||
{
|
||||
if (LogAcceptCategory(BCLog::CLAIMS)) {
|
||||
LogPrintf("--- [%lu]: OP_SUPPORT_CLAIM \"%s\" with claimId %s and tx prevout %s at index %d\n", nHeight, name,
|
||||
|
@ -66,7 +75,9 @@ bool CClaimScriptUndoAddOp::supportClaim(CClaimTrieCache& trieCache, const std::
|
|||
"%s: (txid: %s, nOut: %d) Removing support for %s, claimId: %s, from the claim trie due to block disconnect\n",
|
||||
__func__, point.hash.ToString(), point.n, name, claimId.ToString());
|
||||
}
|
||||
bool res = trieCache.undoAddSupport(name, point, nHeight);
|
||||
std::string nodeName;
|
||||
int validHeight;
|
||||
bool res = trieCache.removeSupport(point, nodeName, validHeight);
|
||||
if (!res)
|
||||
LogPrint(BCLog::CLAIMS, "%s: Removing support fails\n", __func__);
|
||||
return res;
|
||||
|
@ -77,14 +88,16 @@ CClaimScriptSpendOp::CClaimScriptSpendOp(const COutPoint& point, int nHeight, in
|
|||
{
|
||||
}
|
||||
|
||||
bool CClaimScriptSpendOp::claimName(CClaimTrieCache& trieCache, const std::string& name)
|
||||
bool CClaimScriptSpendOp::claimName(CClaimTrieCache& trieCache, const std::string& name,
|
||||
const std::vector<unsigned char>& metadata)
|
||||
{
|
||||
auto claimId = ClaimIdHash(point.hash, point.n);
|
||||
LogPrint(BCLog::CLAIMS, "+++ [%lu]: OP_CLAIM_NAME \"%s\" with claimId %s and tx prevout %s at index %d\n", nHeight, name, claimId.GetHex(), point.hash.ToString(), point.n);
|
||||
return spendClaim(trieCache, name, claimId);
|
||||
}
|
||||
|
||||
bool CClaimScriptSpendOp::updateClaim(CClaimTrieCache& trieCache, const std::string& name, const uint160& claimId)
|
||||
bool CClaimScriptSpendOp::updateClaim(CClaimTrieCache& trieCache, const std::string& name, const uint160& claimId,
|
||||
const std::vector<unsigned char>& metadata)
|
||||
{
|
||||
LogPrint(BCLog::CLAIMS, "+++ [%lu]: OP_UPDATE_CLAIM \"%s\" with claimId %s and tx prevout %s at index %d\n", nHeight, name, claimId.GetHex(), point.hash.ToString(), point.n);
|
||||
return spendClaim(trieCache, name, claimId);
|
||||
|
@ -92,14 +105,16 @@ bool CClaimScriptSpendOp::updateClaim(CClaimTrieCache& trieCache, const std::str
|
|||
|
||||
bool CClaimScriptSpendOp::spendClaim(CClaimTrieCache& trieCache, const std::string& name, const uint160& claimId)
|
||||
{
|
||||
LogPrint(BCLog::CLAIMS, "%s: (txid: %s, nOut: %d) Removing %s, claimId: %s, from the claim trie\n", __func__, point.hash.ToString(), point.n, name, claimId.ToString());
|
||||
bool res = trieCache.spendClaim(name, point, nHeight, nValidHeight);
|
||||
LogPrint(BCLog::CLAIMS, "%s: (txid: %s, nOut: %d) Spending %s, claimId: %s, from the claim trie\n", __func__, point.hash.ToString(), point.n, name, claimId.ToString());
|
||||
std::string nodeName;
|
||||
bool res = trieCache.removeClaim(claimId, nodeName, nValidHeight);
|
||||
if (!res)
|
||||
LogPrint(BCLog::CLAIMS, "%s: Removing fails\n", __func__);
|
||||
return res;
|
||||
}
|
||||
|
||||
bool CClaimScriptSpendOp::supportClaim(CClaimTrieCache& trieCache, const std::string& name, const uint160& claimId)
|
||||
bool CClaimScriptSpendOp::supportClaim(CClaimTrieCache& trieCache, const std::string& name, const uint160& claimId,
|
||||
const std::vector<unsigned char>& metadata)
|
||||
{
|
||||
if (LogAcceptCategory(BCLog::CLAIMS)) {
|
||||
LogPrintf("+++ [%lu]: OP_SUPPORT_CLAIM \"%s\" with claimId %s and tx prevout %s at index %d\n", nHeight, name,
|
||||
|
@ -107,7 +122,8 @@ bool CClaimScriptSpendOp::supportClaim(CClaimTrieCache& trieCache, const std::st
|
|||
LogPrintf("%s: (txid: %s, nOut: %d) Restoring support for %s, claimId: %s, to the claim trie\n", __func__,
|
||||
point.hash.ToString(), point.n, name, claimId.ToString());
|
||||
}
|
||||
bool res = trieCache.spendSupport(name, point, nHeight, nValidHeight);
|
||||
std::string nodeName;
|
||||
bool res = trieCache.removeSupport(point, nodeName, nValidHeight);
|
||||
if (!res)
|
||||
LogPrint(BCLog::CLAIMS, "%s: Removing support fails\n", __func__);
|
||||
return res;
|
||||
|
@ -118,26 +134,30 @@ CClaimScriptUndoSpendOp::CClaimScriptUndoSpendOp(const COutPoint& point, CAmount
|
|||
{
|
||||
}
|
||||
|
||||
bool CClaimScriptUndoSpendOp::claimName(CClaimTrieCache& trieCache, const std::string& name)
|
||||
bool CClaimScriptUndoSpendOp::claimName(CClaimTrieCache& trieCache, const std::string& name,
|
||||
const std::vector<unsigned char>& metadata)
|
||||
{
|
||||
return undoSpendClaim(trieCache, name, ClaimIdHash(point.hash, point.n));
|
||||
return undoSpendClaim(trieCache, name, ClaimIdHash(point.hash, point.n), metadata);
|
||||
}
|
||||
|
||||
bool CClaimScriptUndoSpendOp::updateClaim(CClaimTrieCache& trieCache, const std::string& name, const uint160& claimId)
|
||||
bool CClaimScriptUndoSpendOp::updateClaim(CClaimTrieCache& trieCache, const std::string& name, const uint160& claimId,
|
||||
const std::vector<unsigned char>& metadata)
|
||||
{
|
||||
return undoSpendClaim(trieCache, name, claimId);
|
||||
return undoSpendClaim(trieCache, name, claimId, metadata);
|
||||
}
|
||||
|
||||
bool CClaimScriptUndoSpendOp::undoSpendClaim(CClaimTrieCache& trieCache, const std::string& name, const uint160& claimId)
|
||||
bool CClaimScriptUndoSpendOp::undoSpendClaim(CClaimTrieCache& trieCache, const std::string& name, const uint160& claimId,
|
||||
const std::vector<unsigned char>& metadata)
|
||||
{
|
||||
LogPrint(BCLog::CLAIMS, "%s: (txid: %s, nOut: %d) Restoring %s, claimId: %s, to the claim trie due to block disconnect\n", __func__, point.hash.ToString(), point.n, name, claimId.ToString());
|
||||
return trieCache.undoSpendClaim(name, point, claimId, nValue, nHeight, nValidHeight);
|
||||
return trieCache.addClaim(name, point, claimId, nValue, nHeight, metadata);
|
||||
}
|
||||
|
||||
bool CClaimScriptUndoSpendOp::supportClaim(CClaimTrieCache& trieCache, const std::string& name, const uint160& claimId)
|
||||
bool CClaimScriptUndoSpendOp::supportClaim(CClaimTrieCache& trieCache, const std::string& name, const uint160& claimId,
|
||||
const std::vector<unsigned char>& metadata)
|
||||
{
|
||||
LogPrint(BCLog::CLAIMS, "%s: (txid: %s, nOut: %d) Restoring support for %s, claimId: %s, to the claim trie due to block disconnect\n", __func__, point.hash.ToString(), point.n, name, claimId.ToString());
|
||||
return trieCache.undoSpendSupport(name, point, claimId, nValue, nHeight, nValidHeight);
|
||||
return trieCache.addSupport(name, point, nValue, claimId, nHeight, metadata);
|
||||
}
|
||||
|
||||
static std::string vchToString(const std::vector<unsigned char>& name)
|
||||
|
@ -154,11 +174,13 @@ bool ProcessClaim(CClaimScriptOp& claimOp, CClaimTrieCache& trieCache, const CSc
|
|||
|
||||
switch (op) {
|
||||
case OP_CLAIM_NAME:
|
||||
return claimOp.claimName(trieCache, vchToString(vvchParams[0]));
|
||||
return claimOp.claimName(trieCache, vchToString(vvchParams[0]), vvchParams[1]);
|
||||
case OP_SUPPORT_CLAIM:
|
||||
return claimOp.supportClaim(trieCache, vchToString(vvchParams[0]), uint160(vvchParams[1]));
|
||||
return claimOp.supportClaim(trieCache, vchToString(vvchParams[0]), uint160(vvchParams[1]),
|
||||
vvchParams.size() > 2 ? vvchParams[2] : std::vector<unsigned char>());
|
||||
case OP_UPDATE_CLAIM:
|
||||
return claimOp.updateClaim(trieCache, vchToString(vvchParams[0]), uint160(vvchParams[1]));
|
||||
return claimOp.updateClaim(trieCache, vchToString(vvchParams[0]), uint160(vvchParams[1]),
|
||||
vvchParams[2]);
|
||||
}
|
||||
throw std::runtime_error("Unimplemented OP handler.");
|
||||
}
|
||||
|
@ -213,10 +235,11 @@ void UpdateCache(const CTransaction& tx, CClaimTrieCache& trieCache, const CCoin
|
|||
public:
|
||||
using CClaimScriptAddOp::CClaimScriptAddOp;
|
||||
|
||||
bool updateClaim(CClaimTrieCache& trieCache, const std::string& name, const uint160& claimId) override
|
||||
bool updateClaim(CClaimTrieCache& trieCache, const std::string& name, const uint160& claimId,
|
||||
const std::vector<unsigned char>& metadata) override
|
||||
{
|
||||
if (callback(name, claimId))
|
||||
return CClaimScriptAddOp::updateClaim(trieCache, name, claimId);
|
||||
return CClaimScriptAddOp::updateClaim(trieCache, name, claimId, metadata);
|
||||
return false;
|
||||
}
|
||||
std::function<bool(const std::string& name, const uint160& claimId)> callback;
|
||||
|
|
|
@ -22,27 +22,30 @@
|
|||
class CClaimScriptOp
|
||||
{
|
||||
public:
|
||||
virtual ~CClaimScriptOp() {}
|
||||
virtual ~CClaimScriptOp() = default;
|
||||
/**
|
||||
* Pure virtual, OP_CLAIM_NAME handler
|
||||
* @param[in] trieCache trie to operate on
|
||||
* @param[in] name name of the claim
|
||||
*/
|
||||
virtual bool claimName(CClaimTrieCache& trieCache, const std::string& name) = 0;
|
||||
virtual bool claimName(CClaimTrieCache& trieCache, const std::string& name,
|
||||
const std::vector<unsigned char>& metadata) = 0;
|
||||
/**
|
||||
* Pure virtual, OP_UPDATE_CLAIM handler
|
||||
* @param[in] trieCache trie to operate on
|
||||
* @param[in] name name of the claim
|
||||
* @param[in] claimId id of the claim
|
||||
*/
|
||||
virtual bool updateClaim(CClaimTrieCache& trieCache, const std::string& name, const uint160& claimId) = 0;
|
||||
virtual bool updateClaim(CClaimTrieCache& trieCache, const std::string& name, const uint160& claimId,
|
||||
const std::vector<unsigned char>& metadata) = 0;
|
||||
/**
|
||||
* Pure virtual, OP_SUPPORT_CLAIM handler
|
||||
* @param[in] trieCache trie to operate on
|
||||
* @param[in] name name of the claim
|
||||
* @param[in] claimId id of the claim
|
||||
*/
|
||||
virtual bool supportClaim(CClaimTrieCache& trieCache, const std::string& name, const uint160& claimId) = 0;
|
||||
virtual bool supportClaim(CClaimTrieCache& trieCache, const std::string& name, const uint160& claimId,
|
||||
const std::vector<unsigned char>& metadata) = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -62,17 +65,20 @@ public:
|
|||
* Implementation of OP_CLAIM_NAME handler
|
||||
* @see CClaimScriptOp::claimName
|
||||
*/
|
||||
bool claimName(CClaimTrieCache& trieCache, const std::string& name) override;
|
||||
bool claimName(CClaimTrieCache& trieCache, const std::string& name,
|
||||
const std::vector<unsigned char>& metadata) override;
|
||||
/**
|
||||
* Implementation of OP_UPDATE_CLAIM handler
|
||||
* @see CClaimScriptOp::updateClaim
|
||||
*/
|
||||
bool updateClaim(CClaimTrieCache& trieCache, const std::string& name, const uint160& claimId) override;
|
||||
bool updateClaim(CClaimTrieCache& trieCache, const std::string& name, const uint160& claimId,
|
||||
const std::vector<unsigned char>& metadata) override;
|
||||
/**
|
||||
* Implementation of OP_SUPPORT_CLAIM handler
|
||||
* @see CClaimScriptOp::supportClaim
|
||||
*/
|
||||
bool supportClaim(CClaimTrieCache& trieCache, const std::string& name, const uint160& claimId) override;
|
||||
bool supportClaim(CClaimTrieCache& trieCache, const std::string& name, const uint160& claimId,
|
||||
const std::vector<unsigned char>& metadata) override;
|
||||
|
||||
protected:
|
||||
/**
|
||||
|
@ -81,7 +87,8 @@ protected:
|
|||
* @param[in] name name of the claim
|
||||
* @param[in] claimId id of the claim
|
||||
*/
|
||||
virtual bool addClaim(CClaimTrieCache& trieCache, const std::string& name, const uint160& claimId);
|
||||
virtual bool addClaim(CClaimTrieCache& trieCache, const std::string& name, const uint160& claimId,
|
||||
const std::vector<unsigned char>& metadata);
|
||||
const COutPoint point;
|
||||
const CAmount nValue;
|
||||
const int nHeight;
|
||||
|
@ -103,17 +110,20 @@ public:
|
|||
* Implementation of OP_CLAIM_NAME handler
|
||||
* @see CClaimScriptOp::claimName
|
||||
*/
|
||||
bool claimName(CClaimTrieCache& trieCache, const std::string& name) override;
|
||||
bool claimName(CClaimTrieCache& trieCache, const std::string& name,
|
||||
const std::vector<unsigned char>& metadata) override;
|
||||
/**
|
||||
* Implementation of OP_UPDATE_CLAIM handler
|
||||
* @see CClaimScriptOp::updateClaim
|
||||
*/
|
||||
bool updateClaim(CClaimTrieCache& trieCache, const std::string& name, const uint160& claimId) override;
|
||||
bool updateClaim(CClaimTrieCache& trieCache, const std::string& name, const uint160& claimId,
|
||||
const std::vector<unsigned char>& metadata) override;
|
||||
/**
|
||||
* Implementation of OP_SUPPORT_CLAIM handler
|
||||
* @see CClaimScriptOp::supportClaim
|
||||
*/
|
||||
bool supportClaim(CClaimTrieCache& trieCache, const std::string& name, const uint160& claimId) override;
|
||||
bool supportClaim(CClaimTrieCache& trieCache, const std::string& name, const uint160& claimId,
|
||||
const std::vector<unsigned char>& metadata) override;
|
||||
|
||||
protected:
|
||||
/**
|
||||
|
@ -144,17 +154,20 @@ public:
|
|||
* Implementation of OP_CLAIM_NAME handler
|
||||
* @see CClaimScriptOp::claimName
|
||||
*/
|
||||
bool claimName(CClaimTrieCache& trieCache, const std::string& name) override;
|
||||
bool claimName(CClaimTrieCache& trieCache, const std::string& name,
|
||||
const std::vector<unsigned char>& metadata) override;
|
||||
/**
|
||||
* Implementation of OP_UPDATE_CLAIM handler
|
||||
* @see CClaimScriptOp::updateClaim
|
||||
*/
|
||||
bool updateClaim(CClaimTrieCache& trieCache, const std::string& name, const uint160& claimId) override;
|
||||
bool updateClaim(CClaimTrieCache& trieCache, const std::string& name, const uint160& claimId,
|
||||
const std::vector<unsigned char>& metadata) override;
|
||||
/**
|
||||
* Implementation of OP_SUPPORT_CLAIM handler
|
||||
* @see CClaimScriptOp::supportClaim
|
||||
*/
|
||||
bool supportClaim(CClaimTrieCache& trieCache, const std::string& name, const uint160& claimId) override;
|
||||
bool supportClaim(CClaimTrieCache& trieCache, const std::string& name, const uint160& claimId,
|
||||
const std::vector<unsigned char>& metadata) override;
|
||||
|
||||
protected:
|
||||
/**
|
||||
|
@ -187,17 +200,20 @@ public:
|
|||
* Implementation of OP_CLAIM_NAME handler
|
||||
* @see CClaimScriptOp::claimName
|
||||
*/
|
||||
bool claimName(CClaimTrieCache& trieCache, const std::string& name) override;
|
||||
bool claimName(CClaimTrieCache& trieCache, const std::string& name,
|
||||
const std::vector<unsigned char>& metadata) override;
|
||||
/**
|
||||
* Implementation of OP_UPDATE_CLAIM handler
|
||||
* @see CClaimScriptOp::updateClaim
|
||||
*/
|
||||
bool updateClaim(CClaimTrieCache& trieCache, const std::string& name, const uint160& claimId) override;
|
||||
bool updateClaim(CClaimTrieCache& trieCache, const std::string& name, const uint160& claimId,
|
||||
const std::vector<unsigned char>& metadata) override;
|
||||
/**
|
||||
* Implementation of OP_SUPPORT_CLAIM handler
|
||||
* @see CClaimScriptOp::supportClaim
|
||||
*/
|
||||
bool supportClaim(CClaimTrieCache& trieCache, const std::string& name, const uint160& claimId) override;
|
||||
bool supportClaim(CClaimTrieCache& trieCache, const std::string& name, const uint160& claimId,
|
||||
const std::vector<unsigned char>& metadata) override;
|
||||
|
||||
protected:
|
||||
/**
|
||||
|
@ -206,7 +222,8 @@ protected:
|
|||
* @param[in] name name of the claim
|
||||
* @param[in] claimId id of the claim
|
||||
*/
|
||||
virtual bool undoSpendClaim(CClaimTrieCache& trieCache, const std::string& name, const uint160& claimId);
|
||||
virtual bool undoSpendClaim(CClaimTrieCache& trieCache, const std::string& name, const uint160& claimId,
|
||||
const std::vector<unsigned char>& metadata);
|
||||
const COutPoint point;
|
||||
const CAmount nValue;
|
||||
const int nHeight;
|
||||
|
|
2120
src/claimtrie.cpp
2120
src/claimtrie.cpp
File diff suppressed because it is too large
Load diff
428
src/claimtrie.h
428
src/claimtrie.h
|
@ -4,8 +4,7 @@
|
|||
#include <amount.h>
|
||||
#include <chain.h>
|
||||
#include <chainparams.h>
|
||||
#include <dbwrapper.h>
|
||||
#include <prefixtrie.h>
|
||||
|
||||
#include <primitives/transaction.h>
|
||||
#include <serialize.h>
|
||||
#include <uint256.h>
|
||||
|
@ -17,17 +16,57 @@
|
|||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
|
||||
// leveldb keys
|
||||
#define TRIE_NODE 'n'
|
||||
#define TRIE_NODE_CHILDREN 'b'
|
||||
#define CLAIM_BY_ID 'i'
|
||||
#define CLAIM_QUEUE_ROW 'r'
|
||||
#define CLAIM_QUEUE_NAME_ROW 'm'
|
||||
#define CLAIM_EXP_QUEUE_ROW 'e'
|
||||
#define SUPPORT 's'
|
||||
#define SUPPORT_QUEUE_ROW 'u'
|
||||
#define SUPPORT_QUEUE_NAME_ROW 'p'
|
||||
#define SUPPORT_EXP_QUEUE_ROW 'x'
|
||||
#include <sqlite/sqlite3.h>
|
||||
|
||||
namespace sqlite
|
||||
{
|
||||
inline int bind_col_in_db(sqlite3_stmt* stmt, int inx, const uint160& vec) {
|
||||
void const* buf = reinterpret_cast<void const *>(vec.begin());
|
||||
return sqlite3_bind_blob(stmt, inx, buf, int(vec.size()), SQLITE_STATIC);
|
||||
}
|
||||
|
||||
inline int bind_col_in_db(sqlite3_stmt* stmt, int inx, const uint256& vec) {
|
||||
void const* buf = reinterpret_cast<void const *>(vec.begin());
|
||||
return sqlite3_bind_blob(stmt, inx, buf, int(vec.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);
|
||||
}
|
||||
|
||||
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>) {
|
||||
int bytes = sqlite3_column_bytes(stmt, inx);
|
||||
uint160 ret;
|
||||
assert(bytes == ret.size());
|
||||
auto ptr = sqlite3_column_blob(stmt, inx);
|
||||
std::memcpy(ret.begin(), ptr, bytes);
|
||||
return ret;
|
||||
}
|
||||
|
||||
inline uint256 get_col_from_db(sqlite3_stmt* stmt, int inx, result_type<uint256>) {
|
||||
int bytes = sqlite3_column_bytes(stmt, inx);
|
||||
uint256 ret;
|
||||
assert(bytes == ret.size());
|
||||
auto ptr = sqlite3_column_blob(stmt, inx);
|
||||
std::memcpy(ret.begin(), ptr, bytes);
|
||||
return ret;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
uint256 getValueHash(const COutPoint& outPoint, int nHeightOfLastTakeover);
|
||||
|
||||
|
@ -134,83 +173,6 @@ struct CSupportValue
|
|||
typedef std::vector<CClaimValue> claimEntryType;
|
||||
typedef std::vector<CSupportValue> supportEntryType;
|
||||
|
||||
struct CClaimTrieData
|
||||
{
|
||||
uint256 hash;
|
||||
claimEntryType claims;
|
||||
int nHeightOfLastTakeover = 0;
|
||||
|
||||
CClaimTrieData() = default;
|
||||
CClaimTrieData(CClaimTrieData&&) = default;
|
||||
CClaimTrieData(const CClaimTrieData&) = default;
|
||||
CClaimTrieData& operator=(CClaimTrieData&&) = default;
|
||||
CClaimTrieData& operator=(const CClaimTrieData& d) = default;
|
||||
|
||||
bool insertClaim(const CClaimValue& claim);
|
||||
bool removeClaim(const COutPoint& outPoint, CClaimValue& claim);
|
||||
bool getBestClaim(CClaimValue& claim) const;
|
||||
bool haveClaim(const COutPoint& outPoint) const;
|
||||
void reorderClaims(const supportEntryType& support);
|
||||
|
||||
ADD_SERIALIZE_METHODS;
|
||||
|
||||
template <typename Stream, typename Operation>
|
||||
inline void SerializationOp(Stream& s, Operation ser_action)
|
||||
{
|
||||
READWRITE(hash);
|
||||
|
||||
if (ser_action.ForRead()) {
|
||||
if (s.eof()) {
|
||||
claims.clear();
|
||||
nHeightOfLastTakeover = 0;
|
||||
return;
|
||||
}
|
||||
}
|
||||
else if (claims.empty())
|
||||
return;
|
||||
|
||||
READWRITE(claims);
|
||||
READWRITE(nHeightOfLastTakeover);
|
||||
}
|
||||
|
||||
bool operator==(const CClaimTrieData& other) const
|
||||
{
|
||||
return hash == other.hash && nHeightOfLastTakeover == other.nHeightOfLastTakeover && claims == other.claims;
|
||||
}
|
||||
|
||||
bool operator!=(const CClaimTrieData& other) const
|
||||
{
|
||||
return !(*this == other);
|
||||
}
|
||||
|
||||
bool empty() const
|
||||
{
|
||||
return claims.empty();
|
||||
}
|
||||
};
|
||||
|
||||
struct COutPointHeightType
|
||||
{
|
||||
COutPoint outPoint;
|
||||
int nHeight = 0;
|
||||
|
||||
COutPointHeightType() = default;
|
||||
|
||||
COutPointHeightType(const COutPoint& outPoint, int nHeight)
|
||||
: outPoint(outPoint), nHeight(nHeight)
|
||||
{
|
||||
}
|
||||
|
||||
ADD_SERIALIZE_METHODS;
|
||||
|
||||
template <typename Stream, typename Operation>
|
||||
inline void SerializationOp(Stream& s, Operation ser_action)
|
||||
{
|
||||
READWRITE(outPoint);
|
||||
READWRITE(nHeight);
|
||||
}
|
||||
};
|
||||
|
||||
struct CNameOutPointHeightType
|
||||
{
|
||||
std::string name;
|
||||
|
@ -262,28 +224,6 @@ struct CNameOutPointType
|
|||
}
|
||||
};
|
||||
|
||||
struct CClaimIndexElement
|
||||
{
|
||||
CClaimIndexElement() = default;
|
||||
|
||||
CClaimIndexElement(std::string name, CClaimValue claim)
|
||||
: name(std::move(name)), claim(std::move(claim))
|
||||
{
|
||||
}
|
||||
|
||||
ADD_SERIALIZE_METHODS;
|
||||
|
||||
template <typename Stream, typename Operation>
|
||||
inline void SerializationOp(Stream& s, Operation ser_action)
|
||||
{
|
||||
READWRITE(name);
|
||||
READWRITE(claim);
|
||||
}
|
||||
|
||||
std::string name;
|
||||
CClaimValue claim;
|
||||
};
|
||||
|
||||
struct CClaimNsupports
|
||||
{
|
||||
CClaimNsupports() = default;
|
||||
|
@ -303,6 +243,10 @@ struct CClaimNsupports
|
|||
return claim.claimId.IsNull();
|
||||
}
|
||||
|
||||
bool operator<(const CClaimNsupports& other) const {
|
||||
return claim < other.claim;
|
||||
}
|
||||
|
||||
CClaimValue claim;
|
||||
CAmount effectiveAmount = 0;
|
||||
std::vector<CSupportValue> supports;
|
||||
|
@ -343,35 +287,22 @@ struct CClaimSupportToName
|
|||
const std::vector<CSupportValue> unmatchedSupports;
|
||||
};
|
||||
|
||||
class CClaimTrie : public CPrefixTrie<std::string, CClaimTrieData>
|
||||
class CClaimTrie
|
||||
{
|
||||
public:
|
||||
CClaimTrie() = default;
|
||||
virtual ~CClaimTrie() = default;
|
||||
CClaimTrie() = delete;
|
||||
CClaimTrie(CClaimTrie&&) = delete;
|
||||
CClaimTrie(const CClaimTrie&) = delete;
|
||||
CClaimTrie(bool fMemory, bool fWipe, int proportionalDelayFactor = 32, std::size_t cacheMB=200);
|
||||
CClaimTrie(bool fMemory, bool fWipe, int height, int proportionalDelayFactor = 32, std::size_t cacheMB=50);
|
||||
|
||||
CClaimTrie& operator=(CClaimTrie&&) = delete;
|
||||
CClaimTrie& operator=(const CClaimTrie&) = delete;
|
||||
|
||||
bool SyncToDisk();
|
||||
|
||||
friend class CClaimTrieCacheBase;
|
||||
friend struct ClaimTrieChainFixture;
|
||||
friend class CClaimTrieCacheExpirationFork;
|
||||
friend class CClaimTrieCacheNormalizationFork;
|
||||
friend bool getClaimById(const uint160&, std::string&, CClaimValue*);
|
||||
friend bool getClaimById(const std::string&, std::string&, CClaimValue*);
|
||||
|
||||
std::size_t getTotalNamesInTrie() const;
|
||||
std::size_t getTotalClaimsInTrie() const;
|
||||
CAmount getTotalValueOfClaimsInTrie(bool fControllingOnly) const;
|
||||
|
||||
protected:
|
||||
bool empty(); // for tests
|
||||
sqlite::database _db;
|
||||
int nNextHeight = 0;
|
||||
int nProportionalDelayFactor = 0;
|
||||
std::unique_ptr<CDBWrapper> db;
|
||||
};
|
||||
|
||||
struct CClaimTrieProofNode
|
||||
|
@ -406,88 +337,24 @@ struct CClaimTrieProof
|
|||
COutPoint outPoint;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
class COptional
|
||||
{
|
||||
bool own;
|
||||
T* value;
|
||||
public:
|
||||
COptional(T* value = nullptr) : own(false), value(value) {}
|
||||
COptional(COptional&& o)
|
||||
{
|
||||
own = o.own;
|
||||
value = o.value;
|
||||
o.own = false;
|
||||
o.value = nullptr;
|
||||
}
|
||||
COptional(T&& o) : own(true)
|
||||
{
|
||||
value = new T(std::move(o));
|
||||
}
|
||||
~COptional()
|
||||
{
|
||||
if (own)
|
||||
delete value;
|
||||
}
|
||||
COptional& operator=(COptional&&) = delete;
|
||||
bool unique() const
|
||||
{
|
||||
return own;
|
||||
}
|
||||
operator bool() const
|
||||
{
|
||||
return value;
|
||||
}
|
||||
operator T*() const
|
||||
{
|
||||
return value;
|
||||
}
|
||||
T* operator->() const
|
||||
{
|
||||
return value;
|
||||
}
|
||||
operator T&() const
|
||||
{
|
||||
return *value;
|
||||
}
|
||||
T& operator*() const
|
||||
{
|
||||
return *value;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
using queueEntryType = std::pair<std::string, T>;
|
||||
|
||||
typedef std::vector<queueEntryType<CClaimValue>> claimQueueRowType;
|
||||
typedef std::map<int, claimQueueRowType> claimQueueType;
|
||||
|
||||
typedef std::vector<queueEntryType<CSupportValue>> supportQueueRowType;
|
||||
typedef std::map<int, supportQueueRowType> supportQueueType;
|
||||
|
||||
typedef std::vector<COutPointHeightType> queueNameRowType;
|
||||
typedef std::map<std::string, queueNameRowType> queueNameType;
|
||||
|
||||
typedef std::vector<CNameOutPointHeightType> insertUndoType;
|
||||
|
||||
typedef std::vector<CNameOutPointType> expirationQueueRowType;
|
||||
typedef std::map<int, expirationQueueRowType> expirationQueueType;
|
||||
|
||||
typedef std::set<CClaimValue> claimIndexClaimListType;
|
||||
typedef std::vector<CClaimIndexElement> claimIndexElementListType;
|
||||
|
||||
class CClaimTrieCacheBase
|
||||
{
|
||||
public:
|
||||
explicit CClaimTrieCacheBase(CClaimTrie* base);
|
||||
virtual ~CClaimTrieCacheBase() = default;
|
||||
virtual ~CClaimTrieCacheBase();
|
||||
|
||||
uint256 getMerkleHash();
|
||||
|
||||
bool flush();
|
||||
bool empty() const;
|
||||
bool checkConsistency() const;
|
||||
bool ReadFromDisk(const CBlockIndex* tip);
|
||||
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;
|
||||
|
@ -495,17 +362,13 @@ public:
|
|||
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);
|
||||
bool undoAddClaim(const std::string& name, const COutPoint& outPoint, int nHeight);
|
||||
bool addClaim(const std::string& name, const COutPoint& outPoint, const uint160& claimId, CAmount nAmount,
|
||||
int nHeight, const std::vector<unsigned char>& metadata);
|
||||
bool addSupport(const std::string& name, const COutPoint& outPoint, CAmount nAmount,
|
||||
const uint160& supportedClaimId, int nHeight, const std::vector<unsigned char>& metadata);
|
||||
|
||||
bool spendClaim(const std::string& name, const COutPoint& outPoint, int nHeight, int& nValidAtHeight);
|
||||
bool undoSpendClaim(const std::string& name, const COutPoint& outPoint, const uint160& claimId, CAmount nAmount, int nHeight, int nValidAtHeight);
|
||||
|
||||
bool addSupport(const std::string& name, const COutPoint& outPoint, CAmount nAmount, const uint160& supportedClaimId, int nHeight);
|
||||
bool undoAddSupport(const std::string& name, const COutPoint& outPoint, int nHeight);
|
||||
|
||||
bool spendSupport(const std::string& name, const COutPoint& outPoint, int nHeight, int& nValidAtHeight);
|
||||
bool undoSpendSupport(const std::string& name, const COutPoint& outPoint, const uint160& supportedClaimId, CAmount nAmount, int nHeight, int nValidAtHeight);
|
||||
bool removeSupport(const COutPoint& outPoint, std::string& nodeName, int& validHeight);
|
||||
bool removeClaim(const uint160& claimId, std::string& nodeName, int& validHeight);
|
||||
|
||||
virtual bool incrementBlock(insertUndoType& insertUndo,
|
||||
claimQueueRowType& expireUndo,
|
||||
|
@ -518,140 +381,49 @@ public:
|
|||
insertUndoType& insertSupportUndo,
|
||||
supportQueueRowType& expireSupportUndo);
|
||||
|
||||
virtual bool getProofForName(const std::string& name, CClaimTrieProof& proof);
|
||||
virtual bool getInfoForName(const std::string& name, CClaimValue& claim) const;
|
||||
virtual bool getProofForName(const std::string& name, const uint160& finalClaim, CClaimTrieProof& proof);
|
||||
|
||||
virtual int expirationTime() const;
|
||||
|
||||
virtual bool finalizeDecrement(std::vector<std::pair<std::string, int>>& takeoverHeightUndo);
|
||||
|
||||
virtual CClaimSupportToName getClaimsForName(const std::string& name) const;
|
||||
|
||||
CClaimTrie::const_iterator find(const std::string& name) const;
|
||||
void iterate(std::function<void(const std::string&, const CClaimTrieData&)> callback) const;
|
||||
|
||||
void dumpToLog(CClaimTrie::const_iterator it, bool diffFromBase = true) 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(const 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;
|
||||
CClaimTrie nodesToAddOrUpdate; // nodes pulled in from base (and possibly modified thereafter), written to base on flush
|
||||
std::unordered_set<std::string> nodesAlreadyCached; // set of nodes already pulled into cache from base
|
||||
std::unordered_set<std::string> namesToCheckForTakeover; // takeover numbers are updated on increment
|
||||
bool dirtyNodes;
|
||||
|
||||
virtual uint256 recursiveComputeMerkleHash(CClaimTrie::iterator& it);
|
||||
virtual bool recursiveCheckConsistency(CClaimTrie::const_iterator& it, std::string& failed) const;
|
||||
|
||||
virtual bool insertClaimIntoTrie(const std::string& name, const CClaimValue& claim, bool fCheckTakeover);
|
||||
virtual bool removeClaimFromTrie(const std::string& name, const COutPoint& outPoint, CClaimValue& claim, bool fCheckTakeover);
|
||||
|
||||
virtual bool insertSupportIntoMap(const std::string& name, const CSupportValue& support, bool fCheckTakeover);
|
||||
virtual bool removeSupportFromMap(const std::string& name, const COutPoint& outPoint, CSupportValue& support, bool fCheckTakeover);
|
||||
virtual uint256 recursiveComputeMerkleHash(const std::string& name, int lastTakeoverHeight, bool checkOnly);
|
||||
|
||||
supportEntryType getSupportsForName(const std::string& name) const;
|
||||
|
||||
int getDelayForName(const std::string& name) const;
|
||||
virtual int getDelayForName(const std::string& name, const uint160& claimId) const;
|
||||
|
||||
CClaimTrie::iterator cacheData(const std::string& name, bool create = true);
|
||||
|
||||
bool getLastTakeoverForName(const std::string& name, uint160& claimId, int& takeoverHeight) const;
|
||||
|
||||
int getNumBlocksOfContinuousOwnership(const std::string& name) const;
|
||||
|
||||
void reactivateClaim(const expirationQueueRowType& row, int height, bool increment);
|
||||
void reactivateSupport(const expirationQueueRowType& row, int height, bool increment);
|
||||
|
||||
expirationQueueType expirationQueueCache;
|
||||
expirationQueueType supportExpirationQueueCache;
|
||||
|
||||
bool deleteNodeIfPossible(const std::string& name, std::string& parent, std::vector<std::string>& claims);
|
||||
void ensureTreeStructureIsUpToDate();
|
||||
int nNextHeight; // Height of the block that is being worked on, which is
|
||||
// one greater than the height of the chain's tip
|
||||
|
||||
private:
|
||||
uint256 hashBlock;
|
||||
|
||||
std::unordered_map<std::string, std::pair<uint160, int>> takeoverCache;
|
||||
|
||||
claimQueueType claimQueueCache; // claims not active yet: to be written to disk on flush
|
||||
queueNameType claimQueueNameCache;
|
||||
supportQueueType supportQueueCache; // supports not active yet: to be written to disk on flush
|
||||
queueNameType supportQueueNameCache;
|
||||
claimIndexElementListType claimsToAddToByIdIndex; // written to index on flush
|
||||
claimIndexClaimListType claimsToDeleteFromByIdIndex;
|
||||
|
||||
std::unordered_map<std::string, supportEntryType> supportCache; // to be added/updated to base (and disk) on flush
|
||||
std::unordered_set<std::string> nodesToDelete; // to be removed from base (and disk) on flush
|
||||
std::unordered_map<std::string, bool> takeoverWorkaround;
|
||||
std::unordered_set<std::string> removalWorkaround;
|
||||
|
||||
bool shouldUseTakeoverWorkaround(const std::string& key) const;
|
||||
void addTakeoverWorkaroundPotential(const std::string& key);
|
||||
void confirmTakeoverWorkaroundNeeded(const std::string& key);
|
||||
|
||||
bool clear();
|
||||
|
||||
void markAsDirty(const std::string& name, bool fCheckTakeover);
|
||||
bool removeSupport(const std::string& name, const COutPoint& outPoint, int nHeight, int& nValidAtHeight, bool fCheckTakeover);
|
||||
bool removeClaim(const std::string& name, const COutPoint& outPoint, int nHeight, int& nValidAtHeight, bool fCheckTakeover);
|
||||
|
||||
template <typename T>
|
||||
void insertRowsFromQueue(std::vector<T>& result, const std::string& name) const;
|
||||
|
||||
template <typename T>
|
||||
std::vector<queueEntryType<T>>* getQueueCacheRow(int nHeight, bool createIfNotExists);
|
||||
|
||||
template <typename T>
|
||||
COptional<const std::vector<queueEntryType<T>>> getQueueCacheRow(int nHeight) const;
|
||||
|
||||
template <typename T>
|
||||
queueNameRowType* getQueueCacheNameRow(const std::string& name, bool createIfNotExists);
|
||||
|
||||
template <typename T>
|
||||
COptional<const queueNameRowType> getQueueCacheNameRow(const std::string& name) const;
|
||||
|
||||
template <typename T>
|
||||
expirationQueueRowType* getExpirationQueueCacheRow(int nHeight, bool createIfNotExists);
|
||||
|
||||
template <typename T>
|
||||
bool haveInQueue(const std::string& name, const COutPoint& outPoint, int& nValidAtHeight) const;
|
||||
|
||||
template <typename T>
|
||||
T add(const std::string& name, const COutPoint& outPoint, const uint160& claimId, CAmount nAmount, int nHeight);
|
||||
|
||||
template <typename T>
|
||||
bool remove(T& value, const std::string& name, const COutPoint& outPoint, int nHeight, int& nValidAtHeight, bool fCheckTakeover = false);
|
||||
|
||||
template <typename T>
|
||||
bool addToQueue(const std::string& name, const T& value);
|
||||
|
||||
template <typename T>
|
||||
bool removeFromQueue(const std::string& name, const COutPoint& outPoint, T& value);
|
||||
|
||||
template <typename T>
|
||||
bool addToCache(const std::string& name, const T& value, bool fCheckTakeover = false);
|
||||
|
||||
template <typename T>
|
||||
bool removeFromCache(const std::string& name, const COutPoint& outPoint, T& value, bool fCheckTakeover = false);
|
||||
|
||||
template <typename T>
|
||||
bool undoSpend(const std::string& name, const T& value, int nValidAtHeight);
|
||||
|
||||
template <typename T>
|
||||
void undoIncrement(insertUndoType& insertUndo, std::vector<queueEntryType<T>>& expireUndo, std::set<T>* deleted = nullptr);
|
||||
|
||||
template <typename T>
|
||||
void undoDecrement(insertUndoType& insertUndo, std::vector<queueEntryType<T>>& expireUndo, std::vector<CClaimIndexElement>* added = nullptr, std::set<T>* deleted = nullptr);
|
||||
|
||||
template <typename T>
|
||||
void undoIncrement(const std::string& name, insertUndoType& insertUndo, std::vector<queueEntryType<T>>& expireUndo);
|
||||
|
||||
template <typename T>
|
||||
void reactivate(const expirationQueueRowType& row, int height, bool increment);
|
||||
|
||||
// for unit test
|
||||
friend struct ClaimTrieChainFixture;
|
||||
friend class CClaimTrieCacheTest;
|
||||
|
||||
void activateAllFor(insertUndoType& insertUndo, insertUndoType& insertSupportUndo,
|
||||
const std::string& takeover);
|
||||
};
|
||||
|
||||
class CClaimTrieCacheExpirationFork : public CClaimTrieCacheBase
|
||||
|
@ -685,7 +457,7 @@ class CClaimTrieCacheNormalizationFork : public CClaimTrieCacheExpirationFork
|
|||
{
|
||||
public:
|
||||
explicit CClaimTrieCacheNormalizationFork(CClaimTrie* base)
|
||||
: CClaimTrieCacheExpirationFork(base), overrideInsertNormalization(false), overrideRemoveNormalization(false)
|
||||
: CClaimTrieCacheExpirationFork(base)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -706,29 +478,16 @@ public:
|
|||
insertUndoType& insertSupportUndo,
|
||||
supportQueueRowType& expireSupportUndo) override;
|
||||
|
||||
bool getProofForName(const std::string& name, CClaimTrieProof& proof) override;
|
||||
bool getProofForName(const std::string& name, const uint160& finalClaim, CClaimTrieProof& proof) override;
|
||||
bool getInfoForName(const std::string& name, CClaimValue& claim) const override;
|
||||
CClaimSupportToName getClaimsForName(const std::string& name) const override;
|
||||
std::string adjustNameForValidHeight(const std::string& name, int validHeight) const override;
|
||||
|
||||
protected:
|
||||
bool insertClaimIntoTrie(const std::string& name, const CClaimValue& claim, bool fCheckTakeover) override;
|
||||
bool removeClaimFromTrie(const std::string& name, const COutPoint& outPoint, CClaimValue& claim, bool fCheckTakeover) override;
|
||||
|
||||
bool insertSupportIntoMap(const std::string& name, const CSupportValue& support, bool fCheckTakeover) override;
|
||||
bool removeSupportFromMap(const std::string& name, const COutPoint& outPoint, CSupportValue& support, bool fCheckTakeover) override;
|
||||
|
||||
int getDelayForName(const std::string& name, const uint160& claimId) const override;
|
||||
|
||||
private:
|
||||
bool overrideInsertNormalization;
|
||||
bool overrideRemoveNormalization;
|
||||
|
||||
bool normalizeAllNamesInTrieIfNecessary(insertUndoType& insertUndo,
|
||||
claimQueueRowType& removeUndo,
|
||||
insertUndoType& insertSupportUndo,
|
||||
supportQueueRowType& expireSupportUndo,
|
||||
std::vector<std::pair<std::string, int>>& takeoverHeightUndo);
|
||||
bool normalizeAllNamesInTrieIfNecessary(bool forward);
|
||||
};
|
||||
|
||||
class CClaimTrieCacheHashFork : public CClaimTrieCacheNormalizationFork
|
||||
|
@ -736,19 +495,14 @@ class CClaimTrieCacheHashFork : public CClaimTrieCacheNormalizationFork
|
|||
public:
|
||||
explicit CClaimTrieCacheHashFork(CClaimTrie* base);
|
||||
|
||||
bool getProofForName(const std::string& name, CClaimTrieProof& proof) override;
|
||||
bool getProofForName(const std::string& name, CClaimTrieProof& proof, const std::function<bool(const CClaimValue&)>& comp);
|
||||
bool getProofForName(const std::string& name, const uint160& finalClaim, CClaimTrieProof& proof) override;
|
||||
void initializeIncrement() override;
|
||||
bool finalizeDecrement(std::vector<std::pair<std::string, int>>& takeoverHeightUndo) override;
|
||||
|
||||
bool allowSupportMetadata() const;
|
||||
|
||||
protected:
|
||||
uint256 recursiveComputeMerkleHash(CClaimTrie::iterator& it) override;
|
||||
bool recursiveCheckConsistency(CClaimTrie::const_iterator& it, std::string& failed) const override;
|
||||
|
||||
private:
|
||||
void copyAllBaseToCache();
|
||||
uint256 recursiveComputeMerkleHash(const std::string& name, int lastTakeoverHeight, bool checkOnly) override;
|
||||
};
|
||||
|
||||
typedef CClaimTrieCacheHashFork CClaimTrieCache;
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
#include <boost/locale.hpp>
|
||||
#include <boost/locale/conversion.hpp>
|
||||
#include <boost/locale/localization_backend.hpp>
|
||||
#include <boost/scope_exit.hpp>
|
||||
#include <boost/scoped_ptr.hpp>
|
||||
|
||||
CClaimTrieCacheExpirationFork::CClaimTrieCacheExpirationFork(CClaimTrie* base)
|
||||
|
@ -71,30 +70,12 @@ bool CClaimTrieCacheExpirationFork::forkForExpirationChange(bool increment)
|
|||
will have their expiration extension removed.
|
||||
*/
|
||||
|
||||
//look through db for expiration queues, if we haven't already found it in dirty expiration queue
|
||||
boost::scoped_ptr<CDBIterator> pcursor(base->db->NewIterator());
|
||||
for (pcursor->SeekToFirst(); pcursor->Valid(); pcursor->Next()) {
|
||||
std::pair<uint8_t, int> key;
|
||||
if (!pcursor->GetKey(key))
|
||||
continue;
|
||||
int height = key.second;
|
||||
if (key.first == CLAIM_EXP_QUEUE_ROW) {
|
||||
expirationQueueRowType row;
|
||||
if (pcursor->GetValue(row)) {
|
||||
reactivateClaim(row, height, increment);
|
||||
} else {
|
||||
return error("%s(): error reading expiration queue rows from disk", __func__);
|
||||
}
|
||||
} else if (key.first == SUPPORT_EXP_QUEUE_ROW) {
|
||||
expirationQueueRowType row;
|
||||
if (pcursor->GetValue(row)) {
|
||||
reactivateSupport(row, height, increment);
|
||||
} else {
|
||||
return error("%s(): error reading support expiration queue rows from disk", __func__);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto extension = Params().GetConsensus().nExtendedClaimExpirationTime - Params().GetConsensus().nOriginalClaimExpirationTime;
|
||||
if (!increment) extension = -extension;
|
||||
base->_db << "UPDATE claims SET expirationHeight = expirationHeight + ? WHERE expirationHeight >= ?" << extension << nNextHeight;
|
||||
base->_db << "UPDATE supports SET expirationHeight = expirationHeight + ? WHERE expirationHeight >= ?" << extension << nNextHeight;
|
||||
base->_db << "UPDATE nodes SET hash = NULL, claimHash = NULL"; // recompute all hashes (as there aren't that many at this point)
|
||||
dirtyNodes = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -144,27 +125,7 @@ std::string CClaimTrieCacheNormalizationFork::normalizeClaimName(const std::stri
|
|||
return normalized;
|
||||
}
|
||||
|
||||
bool CClaimTrieCacheNormalizationFork::insertClaimIntoTrie(const std::string& name, const CClaimValue& claim, bool fCheckTakeover)
|
||||
{
|
||||
return CClaimTrieCacheExpirationFork::insertClaimIntoTrie(normalizeClaimName(name, overrideInsertNormalization), claim, fCheckTakeover);
|
||||
}
|
||||
|
||||
bool CClaimTrieCacheNormalizationFork::removeClaimFromTrie(const std::string& name, const COutPoint& outPoint, CClaimValue& claim, bool fCheckTakeover)
|
||||
{
|
||||
return CClaimTrieCacheExpirationFork::removeClaimFromTrie(normalizeClaimName(name, overrideRemoveNormalization), outPoint, claim, fCheckTakeover);
|
||||
}
|
||||
|
||||
bool CClaimTrieCacheNormalizationFork::insertSupportIntoMap(const std::string& name, const CSupportValue& support, bool fCheckTakeover)
|
||||
{
|
||||
return CClaimTrieCacheExpirationFork::insertSupportIntoMap(normalizeClaimName(name, overrideInsertNormalization), support, fCheckTakeover);
|
||||
}
|
||||
|
||||
bool CClaimTrieCacheNormalizationFork::removeSupportFromMap(const std::string& name, const COutPoint& outPoint, CSupportValue& support, bool fCheckTakeover)
|
||||
{
|
||||
return CClaimTrieCacheExpirationFork::removeSupportFromMap(normalizeClaimName(name, overrideRemoveNormalization), outPoint, support, fCheckTakeover);
|
||||
}
|
||||
|
||||
bool CClaimTrieCacheNormalizationFork::normalizeAllNamesInTrieIfNecessary(insertUndoType& insertUndo, claimQueueRowType& removeUndo, insertUndoType& insertSupportUndo, supportQueueRowType& expireSupportUndo, std::vector<std::pair<std::string, int>>& takeoverHeightUndo)
|
||||
bool CClaimTrieCacheNormalizationFork::normalizeAllNamesInTrieIfNecessary(bool forward)
|
||||
{
|
||||
if (nNextHeight != Params().GetConsensus().nNormalizedNameForkHeight)
|
||||
return false;
|
||||
|
@ -172,66 +133,40 @@ bool CClaimTrieCacheNormalizationFork::normalizeAllNamesInTrieIfNecessary(insert
|
|||
// run the one-time upgrade of all names that need to change
|
||||
// it modifies the (cache) trie as it goes, so we need to grab everything to be modified first
|
||||
|
||||
for (auto it = base->cbegin(); it != base->cend(); ++it) {
|
||||
const std::string normalized = normalizeClaimName(it.key(), true);
|
||||
if (normalized == it.key())
|
||||
continue;
|
||||
base->_db.define("NORMALIZED", [this](const std::string& str) { return normalizeClaimName(str, true); });
|
||||
|
||||
auto& name = it.key();
|
||||
auto supports = getSupportsForName(name);
|
||||
for (auto support : supports) {
|
||||
// if it's already going to expire just skip it
|
||||
if (support.nHeight + expirationTime() <= nNextHeight)
|
||||
continue;
|
||||
|
||||
assert(removeSupportFromMap(name, support.outPoint, support, false));
|
||||
expireSupportUndo.emplace_back(name, support);
|
||||
assert(insertSupportIntoMap(normalized, support, false));
|
||||
insertSupportUndo.emplace_back(name, support.outPoint, -1);
|
||||
auto query = base->_db << "SELECT NORMALIZED(name), name, claimID as nn FROM claims HAVING nodeName != nn";
|
||||
for(auto&& row: query) {
|
||||
std::string newName, oldName;
|
||||
uint160 claimID;
|
||||
row >> newName >> oldName >> claimID;
|
||||
if (!forward) std::swap(newName, oldName);
|
||||
base->_db << "UPDATE claims SET nodeName = ? WHERE claimID = ?" << newName << claimID;
|
||||
base->_db << "DELETE FROM nodes WHERE name = ?" << oldName;
|
||||
base->_db << "INSERT INTO nodes(name) VALUES(?) ON CONFLICT DO UPDATE hash = NULL, claimHash = NULL" << newName;
|
||||
}
|
||||
dirtyNodes = true;
|
||||
|
||||
namesToCheckForTakeover.insert(normalized);
|
||||
|
||||
auto cached = cacheData(name, false);
|
||||
if (!cached || cached->empty())
|
||||
continue;
|
||||
|
||||
auto claimsCopy = cached->claims;
|
||||
auto takeoverHeightCopy = cached->nHeightOfLastTakeover;
|
||||
for (auto claim : claimsCopy) {
|
||||
if (claim.nHeight + expirationTime() <= nNextHeight)
|
||||
continue;
|
||||
|
||||
assert(removeClaimFromTrie(name, claim.outPoint, claim, false));
|
||||
removeUndo.emplace_back(name, claim);
|
||||
assert(insertClaimIntoTrie(normalized, claim, true));
|
||||
insertUndo.emplace_back(name, claim.outPoint, -1);
|
||||
}
|
||||
|
||||
takeoverHeightUndo.emplace_back(name, takeoverHeightCopy);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CClaimTrieCacheNormalizationFork::incrementBlock(insertUndoType& insertUndo, claimQueueRowType& expireUndo, insertUndoType& insertSupportUndo, supportQueueRowType& expireSupportUndo, std::vector<std::pair<std::string, int>>& takeoverHeightUndo)
|
||||
{
|
||||
overrideInsertNormalization = normalizeAllNamesInTrieIfNecessary(insertUndo, expireUndo, insertSupportUndo, expireSupportUndo, takeoverHeightUndo);
|
||||
BOOST_SCOPE_EXIT(&overrideInsertNormalization) { overrideInsertNormalization = false; }
|
||||
BOOST_SCOPE_EXIT_END
|
||||
normalizeAllNamesInTrieIfNecessary(true);
|
||||
return CClaimTrieCacheExpirationFork::incrementBlock(insertUndo, expireUndo, insertSupportUndo, expireSupportUndo, takeoverHeightUndo);
|
||||
}
|
||||
|
||||
bool CClaimTrieCacheNormalizationFork::decrementBlock(insertUndoType& insertUndo, claimQueueRowType& expireUndo, insertUndoType& insertSupportUndo, supportQueueRowType& expireSupportUndo)
|
||||
{
|
||||
overrideRemoveNormalization = shouldNormalize();
|
||||
BOOST_SCOPE_EXIT(&overrideRemoveNormalization) { overrideRemoveNormalization = false; }
|
||||
BOOST_SCOPE_EXIT_END
|
||||
return CClaimTrieCacheExpirationFork::decrementBlock(insertUndo, expireUndo, insertSupportUndo, expireSupportUndo);
|
||||
auto ret = CClaimTrieCacheExpirationFork::decrementBlock(insertUndo, expireUndo, insertSupportUndo, expireSupportUndo);
|
||||
if (ret)
|
||||
normalizeAllNamesInTrieIfNecessary(false);
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool CClaimTrieCacheNormalizationFork::getProofForName(const std::string& name, CClaimTrieProof& proof)
|
||||
bool CClaimTrieCacheNormalizationFork::getProofForName(const std::string& name, const uint160& finalClaim, CClaimTrieProof& proof)
|
||||
{
|
||||
return CClaimTrieCacheExpirationFork::getProofForName(normalizeClaimName(name), proof);
|
||||
return CClaimTrieCacheExpirationFork::getProofForName(normalizeClaimName(name), finalClaim, proof);
|
||||
}
|
||||
|
||||
bool CClaimTrieCacheNormalizationFork::getInfoForName(const std::string& name, CClaimValue& claim) const
|
||||
|
@ -261,72 +196,46 @@ CClaimTrieCacheHashFork::CClaimTrieCacheHashFork(CClaimTrie* base) : CClaimTrieC
|
|||
static const uint256 leafHash = uint256S("0000000000000000000000000000000000000000000000000000000000000002");
|
||||
static const uint256 emptyHash = uint256S("0000000000000000000000000000000000000000000000000000000000000003");
|
||||
|
||||
std::vector<uint256> getClaimHashes(const CClaimTrieData& data)
|
||||
uint256 CClaimTrieCacheHashFork::recursiveComputeMerkleHash(const std::string& name, int lastTakeoverHeight, bool checkOnly)
|
||||
{
|
||||
std::vector<uint256> hashes;
|
||||
for (auto& claim : data.claims)
|
||||
hashes.push_back(getValueHash(claim.outPoint, data.nHeightOfLastTakeover));
|
||||
return hashes;
|
||||
if (nNextHeight < Params().GetConsensus().nAllClaimsInMerkleForkHeight)
|
||||
return CClaimTrieCacheNormalizationFork::recursiveComputeMerkleHash(name, lastTakeoverHeight, checkOnly);
|
||||
|
||||
auto childQuery = base->_db << "SELECT name, hash, lastTakeoverHeight FROM nodes WHERE parent = ? ORDER BY name" << name;
|
||||
|
||||
std::vector<uint256> childHashes;
|
||||
for (auto&& row: childQuery) {
|
||||
std::string key;
|
||||
int keyLastTakeoverHeight;
|
||||
std::unique_ptr<uint256> hash;
|
||||
row >> key >> hash >> keyLastTakeoverHeight;
|
||||
if (hash == nullptr) hash = std::make_unique<uint256>();
|
||||
if (hash->IsNull()) {
|
||||
*hash = recursiveComputeMerkleHash(key, keyLastTakeoverHeight, checkOnly);
|
||||
}
|
||||
childHashes.push_back(*hash);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
using iCbType = std::function<uint256(T&)>;
|
||||
|
||||
template <typename TIterator>
|
||||
uint256 recursiveBinaryTreeHash(TIterator& it, const iCbType<TIterator>& process)
|
||||
{
|
||||
std::vector<uint256> childHashes;
|
||||
for (auto& child : it.children())
|
||||
childHashes.emplace_back(process(child));
|
||||
auto claimQuery = base->_db << "SELECT c.txID, c.txN, c.validHeight, c.amount + "
|
||||
"SUM(SELECT s.amount FROM supports s WHERE s.supportedClaimID = c.claimID AND s.validHeight < ?) as effectiveAmount"
|
||||
"FROM claims c WHERE c.nodeName = ? AND c.validHeight < ? "
|
||||
"ORDER BY effectiveAmount DESC, c.blockHeight, c.txID, c.txN" << nNextHeight << name << nNextHeight;
|
||||
|
||||
std::vector<uint256> claimHashes;
|
||||
if (!it->empty())
|
||||
claimHashes = getClaimHashes(it.data());
|
||||
else if (!it.hasChildren())
|
||||
return {};
|
||||
for (auto&& row: claimQuery) {
|
||||
COutPoint p;
|
||||
row >> p.hash >> p.n;
|
||||
auto claimHash = getValueHash(p, lastTakeoverHeight);
|
||||
claimHashes.push_back(claimHash);
|
||||
}
|
||||
|
||||
auto left = childHashes.empty() ? leafHash : ComputeMerkleRoot(childHashes);
|
||||
auto right = claimHashes.empty() ? emptyHash : ComputeMerkleRoot(claimHashes);
|
||||
|
||||
return Hash(left.begin(), left.end(), right.begin(), right.end());
|
||||
}
|
||||
|
||||
uint256 CClaimTrieCacheHashFork::recursiveComputeMerkleHash(CClaimTrie::iterator& it)
|
||||
{
|
||||
if (nNextHeight < Params().GetConsensus().nAllClaimsInMerkleForkHeight)
|
||||
return CClaimTrieCacheNormalizationFork::recursiveComputeMerkleHash(it);
|
||||
|
||||
using iterator = CClaimTrie::iterator;
|
||||
iCbType<iterator> process = [&process](iterator& it) -> uint256 {
|
||||
if (it->hash.IsNull())
|
||||
it->hash = recursiveBinaryTreeHash(it, process);
|
||||
assert(!it->hash.IsNull());
|
||||
return it->hash;
|
||||
};
|
||||
return process(it);
|
||||
}
|
||||
|
||||
bool CClaimTrieCacheHashFork::recursiveCheckConsistency(CClaimTrie::const_iterator& it, std::string& failed) const
|
||||
{
|
||||
if (nNextHeight < Params().GetConsensus().nAllClaimsInMerkleForkHeight)
|
||||
return CClaimTrieCacheNormalizationFork::recursiveCheckConsistency(it, failed);
|
||||
|
||||
struct CRecursiveBreak {};
|
||||
using iterator = CClaimTrie::const_iterator;
|
||||
iCbType<iterator> process = [&failed, &process](iterator& it) -> uint256 {
|
||||
if (it->hash.IsNull() || it->hash != recursiveBinaryTreeHash(it, process)) {
|
||||
failed = it.key();
|
||||
throw CRecursiveBreak();
|
||||
}
|
||||
return it->hash;
|
||||
};
|
||||
|
||||
try {
|
||||
process(it);
|
||||
} catch (const CRecursiveBreak&) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
auto computedHash = Hash(left.begin(), left.end(), right.begin(), right.end());
|
||||
if (!checkOnly)
|
||||
base->_db << "UPDATE nodes SET hash = ? WHERE name = ?" << computedHash << name;
|
||||
return computedHash;
|
||||
}
|
||||
|
||||
std::vector<uint256> ComputeMerklePath(const std::vector<uint256>& hashes, uint32_t idx)
|
||||
|
@ -384,15 +293,10 @@ std::vector<uint256> ComputeMerklePath(const std::vector<uint256>& hashes, uint3
|
|||
return res;
|
||||
}
|
||||
|
||||
bool CClaimTrieCacheHashFork::getProofForName(const std::string& name, CClaimTrieProof& proof)
|
||||
{
|
||||
return getProofForName(name, proof, nullptr);
|
||||
}
|
||||
|
||||
bool CClaimTrieCacheHashFork::getProofForName(const std::string& name, CClaimTrieProof& proof, const std::function<bool(const CClaimValue&)>& comp)
|
||||
bool CClaimTrieCacheHashFork::getProofForName(const std::string& name, const uint160& finalClaim, CClaimTrieProof& proof)
|
||||
{
|
||||
if (nNextHeight < Params().GetConsensus().nAllClaimsInMerkleForkHeight)
|
||||
return CClaimTrieCacheNormalizationFork::getProofForName(name, proof);
|
||||
return CClaimTrieCacheNormalizationFork::getProofForName(name, finalClaim, proof);
|
||||
|
||||
auto fillPairs = [&proof](const std::vector<uint256>& hashes, uint32_t idx) {
|
||||
auto partials = ComputeMerklePath(hashes, idx);
|
||||
|
@ -401,39 +305,51 @@ bool CClaimTrieCacheHashFork::getProofForName(const std::string& name, CClaimTri
|
|||
};
|
||||
|
||||
// cache the parent nodes
|
||||
cacheData(name, false);
|
||||
getMerkleHash();
|
||||
proof = CClaimTrieProof();
|
||||
for (auto& it : static_cast<const CClaimTrie&>(nodesToAddOrUpdate).nodes(name)) {
|
||||
auto nodeQuery = base->_db << "SELECT name, lastTakeoverHeight FROM nodes WHERE "
|
||||
"name IN (WITH RECURSIVE prefix(p) AS (VALUES(?) UNION ALL "
|
||||
"SELECT SUBSTR(p, 0, LENGTH(p)) FROM prefix WHERE p != '') SELECT p FROM prefix) "
|
||||
"ORDER BY LENGTH(name)" << name;
|
||||
for (auto&& row: nodeQuery) {
|
||||
std::string key; int lastTakeover;
|
||||
row >> key >> lastTakeover;
|
||||
std::vector<uint256> childHashes;
|
||||
uint32_t nextCurrentIdx = 0;
|
||||
for (auto& child : it.children()) {
|
||||
if (name.find(child.key()) == 0)
|
||||
auto childQuery = base->_db << "SELECT name, hash FROM nodes WHERE parent = ?" << key;
|
||||
for (auto&& child : childQuery) {
|
||||
std::string childKey;
|
||||
uint256 childHash;
|
||||
child >> childKey >> childHash;
|
||||
if (name.find(childKey) == 0)
|
||||
nextCurrentIdx = uint32_t(childHashes.size());
|
||||
childHashes.push_back(child->hash);
|
||||
childHashes.push_back(childHash);
|
||||
}
|
||||
|
||||
auto cns = getClaimsForName(key);
|
||||
std::vector<uint256> claimHashes;
|
||||
if (!it->empty())
|
||||
claimHashes = getClaimHashes(it.data());
|
||||
uint32_t finalClaimIdx = 0;
|
||||
COutPoint finalOutPoint;
|
||||
for (uint32_t i = 0; i < cns.claimsNsupports.size(); ++i) {
|
||||
auto& child = cns.claimsNsupports[i].claim;
|
||||
claimHashes.push_back(getValueHash(child.outPoint, lastTakeover));
|
||||
if (child.claimId == finalClaim) {
|
||||
finalClaimIdx = i;
|
||||
finalOutPoint = child.outPoint;
|
||||
}
|
||||
}
|
||||
|
||||
// I am on a node; I need a hash(children, claims)
|
||||
// if I am the last node on the list, it will be hash(children, x)
|
||||
// else it will be hash(x, claims)
|
||||
if (it.key() == name) {
|
||||
uint32_t nClaimIndex = 0;
|
||||
auto& claims = it->claims;
|
||||
auto itClaim = !comp ? claims.begin() : std::find_if(claims.begin(), claims.end(), comp);
|
||||
if (itClaim != claims.end()) {
|
||||
if (key == name) {
|
||||
proof.outPoint = finalOutPoint;
|
||||
proof.nHeightOfLastTakeover = lastTakeover;
|
||||
proof.hasValue = true;
|
||||
proof.outPoint = itClaim->outPoint;
|
||||
proof.nHeightOfLastTakeover = it->nHeightOfLastTakeover;
|
||||
nClaimIndex = std::distance(claims.begin(), itClaim);
|
||||
}
|
||||
auto hash = childHashes.empty() ? leafHash : ComputeMerkleRoot(childHashes);
|
||||
proof.pairs.emplace_back(true, hash);
|
||||
if (!claimHashes.empty())
|
||||
fillPairs(claimHashes, nClaimIndex);
|
||||
fillPairs(claimHashes, finalClaimIdx);
|
||||
} else {
|
||||
auto hash = claimHashes.empty() ? emptyHash : ComputeMerkleRoot(claimHashes);
|
||||
proof.pairs.emplace_back(false, hash);
|
||||
|
@ -445,33 +361,19 @@ bool CClaimTrieCacheHashFork::getProofForName(const std::string& name, CClaimTri
|
|||
return true;
|
||||
}
|
||||
|
||||
void CClaimTrieCacheHashFork::copyAllBaseToCache()
|
||||
{
|
||||
for (auto it = base->cbegin(); it != base->cend(); ++it)
|
||||
if (nodesAlreadyCached.insert(it.key()).second)
|
||||
nodesToAddOrUpdate.insert(it.key(), it.data());
|
||||
|
||||
for (auto it = nodesToAddOrUpdate.begin(); it != nodesToAddOrUpdate.end(); ++it)
|
||||
it->hash.SetNull();
|
||||
}
|
||||
|
||||
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)
|
||||
return;
|
||||
|
||||
// if we are forking, we load the entire base trie into the cache trie
|
||||
// we reset its hash computation so it can be recomputed completely
|
||||
copyAllBaseToCache();
|
||||
if (nNextHeight == Params().GetConsensus().nAllClaimsInMerkleForkHeight - 1)
|
||||
base->_db << "UPDATE nodes SET hash = NULL";
|
||||
}
|
||||
|
||||
bool CClaimTrieCacheHashFork::finalizeDecrement(std::vector<std::pair<std::string, int>>& takeoverHeightUndo)
|
||||
{
|
||||
auto ret = CClaimTrieCacheNormalizationFork::finalizeDecrement(takeoverHeightUndo);
|
||||
if (ret && nNextHeight == Params().GetConsensus().nAllClaimsInMerkleForkHeight - 1)
|
||||
copyAllBaseToCache();
|
||||
base->_db << "UPDATE nodes SET hash = NULL";
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
|
@ -1538,7 +1538,7 @@ bool AppInitMain()
|
|||
}
|
||||
|
||||
CClaimTrieCache trieCache(pclaimTrie);
|
||||
if (!trieCache.ReadFromDisk(chainActive.Tip()))
|
||||
if (!trieCache.ValidateTipMatches(chainActive.Tip()))
|
||||
{
|
||||
strLoadError = _("Error loading the claim trie from disk");
|
||||
break;
|
||||
|
|
|
@ -207,8 +207,6 @@ std::unique_ptr<CBlockTemplate> BlockAssembler::CreateNewBlock(const CScript& sc
|
|||
|
||||
CValidationState state;
|
||||
if (!TestBlockValidity(state, chainparams, *pblock, pindexPrev, false, false)) {
|
||||
if (!trieCache.empty())
|
||||
trieCache.dumpToLog(trieCache.find({}));
|
||||
throw std::runtime_error(strprintf("%s: TestBlockValidity failed: %s", __func__, FormatStateMessage(state)));
|
||||
}
|
||||
int64_t nTime2 = GetTimeMicros();
|
||||
|
|
|
@ -1,577 +0,0 @@
|
|||
|
||||
#include <claimtrie.h>
|
||||
#include <fs.h>
|
||||
#include <lbry.h>
|
||||
#include <limits>
|
||||
#include <memory>
|
||||
#include <prefixtrie.h>
|
||||
|
||||
#include <boost/interprocess/allocators/private_node_allocator.hpp>
|
||||
#include <boost/interprocess/indexes/null_index.hpp>
|
||||
#include <boost/interprocess/managed_mapped_file.hpp>
|
||||
|
||||
namespace bip = boost::interprocess;
|
||||
|
||||
typedef bip::basic_managed_mapped_file <
|
||||
char,
|
||||
bip::rbtree_best_fit<bip::null_mutex_family, bip::offset_ptr<void>>,
|
||||
bip::null_index
|
||||
> managed_mapped_file;
|
||||
|
||||
template <typename T>
|
||||
using node_allocator = bip::private_node_allocator<T, managed_mapped_file::segment_manager>;
|
||||
|
||||
static managed_mapped_file::segment_manager* segmentManager()
|
||||
{
|
||||
struct CSharedMemoryFile
|
||||
{
|
||||
CSharedMemoryFile() : file(GetDataDir() / "shared.mem")
|
||||
{
|
||||
fs::remove(file);
|
||||
auto size = (uint64_t)g_memfileSize * 1024ULL * 1024ULL * 1024ULL;
|
||||
// using string() to remove w_char filename encoding on Windows
|
||||
menaged_file.reset(new managed_mapped_file(bip::create_only, file.string().c_str(), size));
|
||||
}
|
||||
~CSharedMemoryFile()
|
||||
{
|
||||
menaged_file.reset();
|
||||
fs::remove(file);
|
||||
}
|
||||
managed_mapped_file::segment_manager* segmentManager()
|
||||
{
|
||||
return menaged_file->get_segment_manager();
|
||||
}
|
||||
const fs::path file;
|
||||
std::unique_ptr<managed_mapped_file> menaged_file;
|
||||
};
|
||||
static CSharedMemoryFile shem;
|
||||
return shem.segmentManager();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static node_allocator<T>& nodeAllocator()
|
||||
{
|
||||
static node_allocator<T> allocator(segmentManager());
|
||||
return allocator;
|
||||
}
|
||||
|
||||
template <typename T, class... Args>
|
||||
static std::shared_ptr<T> nodeAllocate(Args&&... args)
|
||||
{
|
||||
return std::allocate_shared<T>(nodeAllocator<T>(), std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template <typename T, class... Args>
|
||||
static std::shared_ptr<T> allocateShared(Args&&... args)
|
||||
{
|
||||
static auto allocate = g_memfileSize ? nodeAllocate<T, Args...> : std::make_shared<T, Args...>;
|
||||
try {
|
||||
return allocate(std::forward<Args>(args)...);
|
||||
}
|
||||
catch (const bip::bad_alloc&) {
|
||||
allocate = std::make_shared<T, Args...>; // in case we fill up the memfile
|
||||
LogPrint(BCLog::BENCH, "WARNING: The memfile is full; reverting to the RAM allocator for %s.\n", typeid(T).name());
|
||||
return allocate(std::forward<Args>(args)...);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename TKey, typename TData>
|
||||
template <bool IsConst>
|
||||
CPrefixTrie<TKey, TData>::Iterator<IsConst>::Iterator(const TKey& name, const std::shared_ptr<Node>& node) noexcept : name(name), node(node)
|
||||
{
|
||||
}
|
||||
|
||||
template <typename TKey, typename TData>
|
||||
template <bool IsConst>
|
||||
template <bool C>
|
||||
typename CPrefixTrie<TKey, TData>::template Iterator<IsConst>& CPrefixTrie<TKey, TData>::Iterator<IsConst>::operator=(const CPrefixTrie<TKey, TData>::Iterator<C>& o) noexcept
|
||||
{
|
||||
name = o.name;
|
||||
node = o.node;
|
||||
stack.clear();
|
||||
stack.reserve(o.stack.size());
|
||||
for (auto& i : o.stack)
|
||||
stack.push_back(Bookmark{i.name, i.it, i.end});
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename TKey, typename TData>
|
||||
template <bool IsConst>
|
||||
bool CPrefixTrie<TKey, TData>::Iterator<IsConst>::hasNext() const
|
||||
{
|
||||
auto shared = node.lock();
|
||||
if (!shared) return false;
|
||||
if (!shared->children.empty()) return true;
|
||||
for (auto it = stack.rbegin(); it != stack.rend(); ++it) {
|
||||
auto mark = *it; // copy
|
||||
if (++mark.it != mark.end)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
template <typename TKey, typename TData>
|
||||
template <bool IsConst>
|
||||
typename CPrefixTrie<TKey, TData>::template Iterator<IsConst>& CPrefixTrie<TKey, TData>::Iterator<IsConst>::operator++()
|
||||
{
|
||||
auto shared = node.lock();
|
||||
assert(shared);
|
||||
// going in pre-order (NLR). See https://en.wikipedia.org/wiki/Tree_traversal
|
||||
// if there are any children we have to go there first
|
||||
if (!shared->children.empty()) {
|
||||
auto& children = shared->children;
|
||||
auto it = children.begin();
|
||||
stack.emplace_back(Bookmark{name, it, children.end()});
|
||||
auto& postfix = it->first;
|
||||
name.insert(name.end(), postfix.begin(), postfix.end());
|
||||
node = it->second;
|
||||
return *this;
|
||||
}
|
||||
|
||||
// move to next sibling:
|
||||
while (!stack.empty()) {
|
||||
auto& back = stack.back();
|
||||
if (++back.it != back.end) {
|
||||
name = back.name;
|
||||
auto& postfix = back.it->first;
|
||||
name.insert(name.end(), postfix.begin(), postfix.end());
|
||||
node = back.it->second;
|
||||
return *this;
|
||||
}
|
||||
stack.pop_back();
|
||||
}
|
||||
|
||||
// must be at the end:
|
||||
node.reset();
|
||||
name = TKey();
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename TKey, typename TData>
|
||||
template <bool IsConst>
|
||||
typename CPrefixTrie<TKey, TData>::template Iterator<IsConst> CPrefixTrie<TKey, TData>::Iterator<IsConst>::operator++(int x)
|
||||
{
|
||||
auto ret = *this;
|
||||
++(*this);
|
||||
return ret;
|
||||
}
|
||||
|
||||
template <typename TKey, typename TData>
|
||||
template <bool IsConst>
|
||||
CPrefixTrie<TKey, TData>::Iterator<IsConst>::operator bool() const
|
||||
{
|
||||
return !node.expired();
|
||||
}
|
||||
|
||||
template <typename TKey, typename TData>
|
||||
template <bool IsConst>
|
||||
bool CPrefixTrie<TKey, TData>::Iterator<IsConst>::operator==(const Iterator& o) const
|
||||
{
|
||||
return node.lock() == o.node.lock();
|
||||
}
|
||||
|
||||
template <typename TKey, typename TData>
|
||||
template <bool IsConst>
|
||||
bool CPrefixTrie<TKey, TData>::Iterator<IsConst>::operator!=(const Iterator& o) const
|
||||
{
|
||||
return !(*this == o);
|
||||
}
|
||||
|
||||
template <typename TKey, typename TData>
|
||||
template <bool IsConst>
|
||||
typename CPrefixTrie<TKey, TData>::template Iterator<IsConst>::reference CPrefixTrie<TKey, TData>::Iterator<IsConst>::operator*()
|
||||
{
|
||||
return reference{name, data()};
|
||||
}
|
||||
|
||||
template <typename TKey, typename TData>
|
||||
template <bool IsConst>
|
||||
typename CPrefixTrie<TKey, TData>::template Iterator<IsConst>::const_reference CPrefixTrie<TKey, TData>::Iterator<IsConst>::operator*() const
|
||||
{
|
||||
return const_reference{name, data()};
|
||||
}
|
||||
|
||||
template <typename TKey, typename TData>
|
||||
template <bool IsConst>
|
||||
typename CPrefixTrie<TKey, TData>::template Iterator<IsConst>::pointer CPrefixTrie<TKey, TData>::Iterator<IsConst>::operator->()
|
||||
{
|
||||
return &(data());
|
||||
}
|
||||
|
||||
template <typename TKey, typename TData>
|
||||
template <bool IsConst>
|
||||
typename CPrefixTrie<TKey, TData>::template Iterator<IsConst>::const_pointer CPrefixTrie<TKey, TData>::Iterator<IsConst>::operator->() const
|
||||
{
|
||||
return &(data());
|
||||
}
|
||||
|
||||
template <typename TKey, typename TData>
|
||||
template <bool IsConst>
|
||||
const TKey& CPrefixTrie<TKey, TData>::Iterator<IsConst>::key() const
|
||||
{
|
||||
return name;
|
||||
}
|
||||
|
||||
template <typename TKey, typename TData>
|
||||
template <bool IsConst>
|
||||
typename CPrefixTrie<TKey, TData>::template Iterator<IsConst>::data_reference CPrefixTrie<TKey, TData>::Iterator<IsConst>::data()
|
||||
{
|
||||
auto shared = node.lock();
|
||||
assert(shared);
|
||||
return *(shared->data);
|
||||
}
|
||||
|
||||
template <typename TKey, typename TData>
|
||||
template <bool IsConst>
|
||||
const TData& CPrefixTrie<TKey, TData>::Iterator<IsConst>::data() const
|
||||
{
|
||||
auto shared = node.lock();
|
||||
assert(shared);
|
||||
return *(shared->data);
|
||||
}
|
||||
|
||||
template <typename TKey, typename TData>
|
||||
template <bool IsConst>
|
||||
std::size_t CPrefixTrie<TKey, TData>::Iterator<IsConst>::depth() const
|
||||
{
|
||||
return stack.size();
|
||||
}
|
||||
|
||||
template <typename TKey, typename TData>
|
||||
template <bool IsConst>
|
||||
bool CPrefixTrie<TKey, TData>::Iterator<IsConst>::hasChildren() const
|
||||
{
|
||||
auto shared = node.lock();
|
||||
return shared && !shared->children.empty();
|
||||
}
|
||||
|
||||
template <typename TKey, typename TData>
|
||||
template <bool IsConst>
|
||||
std::vector<typename CPrefixTrie<TKey, TData>::template Iterator<IsConst>> CPrefixTrie<TKey, TData>::Iterator<IsConst>::children() const
|
||||
{
|
||||
auto shared = node.lock();
|
||||
if (!shared) return {};
|
||||
std::vector<Iterator<IsConst>> ret;
|
||||
ret.reserve(shared->children.size());
|
||||
for (auto& child : shared->children) {
|
||||
auto key = name;
|
||||
key.insert(key.end(), child.first.begin(), child.first.end());
|
||||
ret.emplace_back(key, child.second);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
template <typename TKey, typename TData>
|
||||
template <typename TIterator, typename TNode>
|
||||
TIterator CPrefixTrie<TKey, TData>::find(const TKey& key, TNode node, TIterator end)
|
||||
{
|
||||
TIterator it(key, TNode());
|
||||
using CBType = callback<TNode>;
|
||||
CBType cb = [&it](const TKey&, TNode node) {
|
||||
it.node = node;
|
||||
};
|
||||
return find(key, node, cb) ? it : end;
|
||||
}
|
||||
|
||||
template <typename TKey, typename TData>
|
||||
template <typename TNode>
|
||||
bool CPrefixTrie<TKey, TData>::find(const TKey& key, TNode node, const callback<TNode>& cb)
|
||||
{
|
||||
auto& children = node->children;
|
||||
if (children.empty()) return false;
|
||||
auto it = children.lower_bound(key);
|
||||
if (it != children.end() && it->first == key) {
|
||||
cb(key, it->second);
|
||||
return true;
|
||||
}
|
||||
if (it != children.begin()) --it;
|
||||
const auto count = match(key, it->first);
|
||||
if (count != it->first.size()) return false;
|
||||
if (count == key.size()) return false;
|
||||
cb(it->first, it->second);
|
||||
return find(TKey(key.begin() + count, key.end()), it->second, cb);
|
||||
}
|
||||
|
||||
template <typename TKey, typename TData>
|
||||
template <typename TIterator, typename TNode>
|
||||
std::vector<TIterator> CPrefixTrie<TKey, TData>::nodes(const TKey& key, TNode root)
|
||||
{
|
||||
std::vector<TIterator> ret;
|
||||
ret.reserve(1 + key.size());
|
||||
ret.emplace_back(TKey{}, root);
|
||||
if (key.empty()) return ret;
|
||||
TKey name;
|
||||
using CBType = callback<TNode>;
|
||||
CBType cb = [&name, &ret](const TKey& key, TNode node) {
|
||||
name.insert(name.end(), key.begin(), key.end());
|
||||
ret.emplace_back(name, node);
|
||||
};
|
||||
find(key, root, cb);
|
||||
return ret;
|
||||
}
|
||||
|
||||
template <typename TKey, typename TData>
|
||||
std::shared_ptr<typename CPrefixTrie<TKey, TData>::Node>& CPrefixTrie<TKey, TData>::insert(const TKey& key, std::shared_ptr<typename CPrefixTrie<TKey, TData>::Node>& node)
|
||||
{
|
||||
std::size_t count = 0;
|
||||
auto& children = node->children;
|
||||
auto it = children.lower_bound(key);
|
||||
if (it != children.end()) {
|
||||
if (it->first == key)
|
||||
return it->second;
|
||||
count = match(key, it->first);
|
||||
}
|
||||
if (count == 0 && it != children.begin()) {
|
||||
--it;
|
||||
count = match(key, it->first);
|
||||
}
|
||||
if (count == 0) {
|
||||
++size;
|
||||
it = children.emplace(key, allocateShared<Node>()).first;
|
||||
return it->second;
|
||||
}
|
||||
if (count < it->first.size()) {
|
||||
TKey prefix(key.begin(), key.begin() + count);
|
||||
TKey postfix(it->first.begin() + count, it->first.end());
|
||||
auto nodes = std::move(it->second);
|
||||
children.erase(it);
|
||||
++size;
|
||||
it = children.emplace(std::move(prefix), allocateShared<Node>()).first;
|
||||
it->second->children.emplace(std::move(postfix), std::move(nodes));
|
||||
if (key.size() == count)
|
||||
return it->second;
|
||||
it->second->data = allocateShared<TData>();
|
||||
}
|
||||
return insert(TKey(key.begin() + count, key.end()), it->second);
|
||||
}
|
||||
|
||||
template <typename TKey, typename TData>
|
||||
void CPrefixTrie<TKey, TData>::erase(const TKey& key, std::shared_ptr<Node>& node)
|
||||
{
|
||||
std::vector<typename TChildren::value_type> nodes;
|
||||
nodes.emplace_back(TKey(), node);
|
||||
using CBType = callback<std::shared_ptr<Node>>;
|
||||
CBType cb = [&nodes](const TKey& k, std::shared_ptr<Node> n) {
|
||||
nodes.emplace_back(k, n);
|
||||
};
|
||||
if (!find(key, node, cb))
|
||||
return;
|
||||
|
||||
nodes.back().second->data = allocateShared<TData>();
|
||||
for (; nodes.size() > 1; nodes.pop_back()) {
|
||||
// if we have only one child and no data ourselves, bring them up to our level
|
||||
auto& cNode = nodes.back().second;
|
||||
auto onlyOneChild = cNode->children.size() == 1;
|
||||
auto noData = cNode->data->empty();
|
||||
if (onlyOneChild && noData) {
|
||||
auto child = cNode->children.begin();
|
||||
auto& prefix = nodes.back().first;
|
||||
auto newKey = prefix;
|
||||
auto& postfix = child->first;
|
||||
newKey.insert(newKey.end(), postfix.begin(), postfix.end());
|
||||
auto& pNode = nodes[nodes.size() - 2].second;
|
||||
pNode->children.emplace(std::move(newKey), std::move(child->second));
|
||||
pNode->children.erase(prefix);
|
||||
--size;
|
||||
continue;
|
||||
}
|
||||
|
||||
auto noChildren = cNode->children.empty();
|
||||
if (noChildren && noData) {
|
||||
auto& pNode = nodes[nodes.size() - 2].second;
|
||||
pNode->children.erase(nodes.back().first);
|
||||
--size;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename TKey, typename TData>
|
||||
CPrefixTrie<TKey, TData>::CPrefixTrie() : size(0), root(allocateShared<Node>())
|
||||
{
|
||||
root->data = allocateShared<TData>();
|
||||
}
|
||||
|
||||
template <typename TKey, typename TData>
|
||||
template <typename TDataUni>
|
||||
typename CPrefixTrie<TKey, TData>::iterator CPrefixTrie<TKey, TData>::insert(const TKey& key, TDataUni&& data)
|
||||
{
|
||||
auto& node = key.empty() ? root : insert(key, root);
|
||||
node->data = allocateShared<TData>(std::forward<TDataUni>(data));
|
||||
return key.empty() ? begin() : iterator{key, node};
|
||||
}
|
||||
|
||||
template <typename TKey, typename TData>
|
||||
typename CPrefixTrie<TKey, TData>::iterator CPrefixTrie<TKey, TData>::copy(CPrefixTrie<TKey, TData>::const_iterator it)
|
||||
{
|
||||
auto& key = it.key();
|
||||
auto& node = key.empty() ? root : insert(key, root);
|
||||
node->data = it.node.lock()->data;
|
||||
return key.empty() ? begin() : iterator{key, node};
|
||||
}
|
||||
|
||||
template <typename TKey, typename TData>
|
||||
template <typename TDataUni>
|
||||
typename CPrefixTrie<TKey, TData>::iterator CPrefixTrie<TKey, TData>::insert(CPrefixTrie<TKey, TData>::iterator& it, const TKey& key, TDataUni&& data)
|
||||
{
|
||||
auto shared = it.node.lock();
|
||||
assert(shared);
|
||||
auto copy = it;
|
||||
if (!key.empty()) {
|
||||
auto name = it.key();
|
||||
name.insert(name.end(), key.begin(), key.end());
|
||||
auto& node = insert(key, shared);
|
||||
copy = iterator{std::move(name), node};
|
||||
}
|
||||
copy.node.lock()->data = allocateShared<TData>(std::forward<TDataUni>(data));
|
||||
return copy;
|
||||
}
|
||||
|
||||
template <typename TKey, typename TData>
|
||||
typename CPrefixTrie<TKey, TData>::iterator CPrefixTrie<TKey, TData>::find(const TKey& key)
|
||||
{
|
||||
if (empty()) return end();
|
||||
if (key.empty()) return {key, root};
|
||||
return find(key, root, end());
|
||||
}
|
||||
|
||||
template <typename TKey, typename TData>
|
||||
typename CPrefixTrie<TKey, TData>::const_iterator CPrefixTrie<TKey, TData>::find(const TKey& key) const
|
||||
{
|
||||
if (empty()) return end();
|
||||
if (key.empty()) return {key, root};
|
||||
return find(key, root, end());
|
||||
}
|
||||
|
||||
template <typename TKey, typename TData>
|
||||
typename CPrefixTrie<TKey, TData>::iterator CPrefixTrie<TKey, TData>::find(CPrefixTrie<TKey, TData>::iterator& it, const TKey& key)
|
||||
{
|
||||
if (key.empty()) return it;
|
||||
auto shared = it.node.lock();
|
||||
assert(shared);
|
||||
return find(key, shared, end());
|
||||
}
|
||||
|
||||
template <typename TKey, typename TData>
|
||||
typename CPrefixTrie<TKey, TData>::const_iterator CPrefixTrie<TKey, TData>::find(CPrefixTrie<TKey, TData>::const_iterator& it, const TKey& key) const
|
||||
{
|
||||
if (key.empty()) return it;
|
||||
auto shared = it.node.lock();
|
||||
assert(shared);
|
||||
return find(key, shared, end());
|
||||
}
|
||||
|
||||
template <typename TKey, typename TData>
|
||||
bool CPrefixTrie<TKey, TData>::contains(const TKey& key) const
|
||||
{
|
||||
return find(key) != end();
|
||||
}
|
||||
|
||||
template <typename TKey, typename TData>
|
||||
TData& CPrefixTrie<TKey, TData>::at(const TKey& key)
|
||||
{
|
||||
return find(key).data();
|
||||
}
|
||||
|
||||
template <typename TKey, typename TData>
|
||||
std::vector<typename CPrefixTrie<TKey, TData>::iterator> CPrefixTrie<TKey, TData>::nodes(const TKey& key)
|
||||
{
|
||||
if (empty()) return {};
|
||||
return nodes<iterator>(key, root);
|
||||
}
|
||||
|
||||
template <typename TKey, typename TData>
|
||||
std::vector<typename CPrefixTrie<TKey, TData>::const_iterator> CPrefixTrie<TKey, TData>::nodes(const TKey& key) const
|
||||
{
|
||||
if (empty()) return {};
|
||||
return nodes<const_iterator>(key, root);
|
||||
}
|
||||
|
||||
template <typename TKey, typename TData>
|
||||
bool CPrefixTrie<TKey, TData>::erase(const TKey& key)
|
||||
{
|
||||
auto size_was = height();
|
||||
if (key.empty()) {
|
||||
root->data = allocateShared<TData>();
|
||||
} else {
|
||||
erase(key, root);
|
||||
}
|
||||
return size_was != height();
|
||||
}
|
||||
|
||||
template <typename TKey, typename TData>
|
||||
void CPrefixTrie<TKey, TData>::clear()
|
||||
{
|
||||
size = 0;
|
||||
root->data = allocateShared<TData>();
|
||||
root->children.clear();
|
||||
}
|
||||
|
||||
template <typename TKey, typename TData>
|
||||
bool CPrefixTrie<TKey, TData>::empty() const
|
||||
{
|
||||
return height() == 0;
|
||||
}
|
||||
|
||||
template <typename TKey, typename TData>
|
||||
std::size_t CPrefixTrie<TKey, TData>::height() const
|
||||
{
|
||||
return size + (root->data->empty() ? 0 : 1);
|
||||
}
|
||||
|
||||
template <typename TKey, typename TData>
|
||||
typename CPrefixTrie<TKey, TData>::iterator CPrefixTrie<TKey, TData>::begin()
|
||||
{
|
||||
return find(TKey());
|
||||
}
|
||||
|
||||
template <typename TKey, typename TData>
|
||||
typename CPrefixTrie<TKey, TData>::iterator CPrefixTrie<TKey, TData>::end()
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
template <typename TKey, typename TData>
|
||||
typename CPrefixTrie<TKey, TData>::const_iterator CPrefixTrie<TKey, TData>::cbegin()
|
||||
{
|
||||
return find(TKey());
|
||||
}
|
||||
|
||||
template <typename TKey, typename TData>
|
||||
typename CPrefixTrie<TKey, TData>::const_iterator CPrefixTrie<TKey, TData>::cend()
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
template <typename TKey, typename TData>
|
||||
typename CPrefixTrie<TKey, TData>::const_iterator CPrefixTrie<TKey, TData>::begin() const
|
||||
{
|
||||
return find(TKey());
|
||||
}
|
||||
|
||||
template <typename TKey, typename TData>
|
||||
typename CPrefixTrie<TKey, TData>::const_iterator CPrefixTrie<TKey, TData>::end() const
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
using Key = std::string;
|
||||
using Data = CClaimTrieData;
|
||||
using Trie = CPrefixTrie<Key, Data>;
|
||||
using iterator = Trie::iterator;
|
||||
using const_iterator = Trie::const_iterator;
|
||||
|
||||
template class CPrefixTrie<Key, Data>;
|
||||
|
||||
template class Trie::Iterator<true>;
|
||||
template class Trie::Iterator<false>;
|
||||
|
||||
template const_iterator& const_iterator::operator=<>(const iterator&) noexcept;
|
||||
|
||||
template iterator Trie::insert<>(const Key&, Data&);
|
||||
template iterator Trie::insert<>(const Key&, Data&&);
|
||||
template iterator Trie::insert<>(const Key&, const Data&);
|
||||
template iterator Trie::insert<>(iterator&, const Key&, Data&);
|
||||
template iterator Trie::insert<>(iterator&, const Key&, Data&&);
|
||||
template iterator Trie::insert<>(iterator&, const Key&, const Data&);
|
225
src/prefixtrie.h
225
src/prefixtrie.h
|
@ -1,225 +0,0 @@
|
|||
#ifndef BITCOIN_PREFIXTRIE_H
|
||||
#define BITCOIN_PREFIXTRIE_H
|
||||
|
||||
#include <algorithm>
|
||||
#include <functional>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
#include <vector>
|
||||
|
||||
#include <boost/container/flat_map.hpp>
|
||||
|
||||
namespace bc = boost::container;
|
||||
|
||||
template <typename TKey, typename TData>
|
||||
class CPrefixTrie
|
||||
{
|
||||
class Node
|
||||
{
|
||||
template <bool>
|
||||
friend class Iterator;
|
||||
friend class CPrefixTrie<TKey, TData>;
|
||||
bc::flat_map<TKey, std::shared_ptr<Node>> children;
|
||||
|
||||
public:
|
||||
Node() = default;
|
||||
Node(const Node&) = delete;
|
||||
Node(Node&& o) noexcept = default;
|
||||
Node& operator=(Node&&) noexcept = default;
|
||||
Node& operator=(const Node&) = delete;
|
||||
std::shared_ptr<TData> data;
|
||||
};
|
||||
|
||||
using TChildren = decltype(Node::children);
|
||||
|
||||
template <bool IsConst>
|
||||
class Iterator
|
||||
{
|
||||
template <bool>
|
||||
friend class Iterator;
|
||||
friend class CPrefixTrie<TKey, TData>;
|
||||
|
||||
using TKeyRef = std::reference_wrapper<const TKey>;
|
||||
using TDataRef = std::reference_wrapper<typename std::conditional<IsConst, const TData, TData>::type>;
|
||||
using TPair = std::pair<TKeyRef, TDataRef>;
|
||||
using ConstTPair = std::pair<TKeyRef, const TData>;
|
||||
|
||||
TKey name;
|
||||
std::weak_ptr<Node> node;
|
||||
|
||||
struct Bookmark {
|
||||
TKey name;
|
||||
typename TChildren::iterator it;
|
||||
typename TChildren::iterator end;
|
||||
};
|
||||
|
||||
std::vector<Bookmark> stack;
|
||||
|
||||
public:
|
||||
// Iterator traits
|
||||
using value_type = TPair;
|
||||
using const_pointer = const TData* const;
|
||||
using const_reference = ConstTPair;
|
||||
using data_reference = typename std::conditional<IsConst, const TData&, TData&>::type;
|
||||
using pointer = typename std::conditional<IsConst, const TData* const, TData* const>::type;
|
||||
using reference = typename std::conditional<IsConst, ConstTPair, TPair>::type;
|
||||
using difference_type = std::ptrdiff_t;
|
||||
using iterator_category = std::forward_iterator_tag;
|
||||
|
||||
Iterator() = default;
|
||||
Iterator(const Iterator&) = default;
|
||||
Iterator(Iterator&& o) noexcept = default;
|
||||
Iterator(const TKey& name, const std::shared_ptr<Node>& node) noexcept;
|
||||
template <bool C>
|
||||
inline Iterator(const Iterator<C>& o) noexcept
|
||||
{
|
||||
*this = o;
|
||||
}
|
||||
|
||||
Iterator& operator=(const Iterator&) = default;
|
||||
Iterator& operator=(Iterator&& o) = default;
|
||||
template <bool C>
|
||||
Iterator& operator=(const Iterator<C>& o) noexcept;
|
||||
|
||||
bool hasNext() const;
|
||||
Iterator& operator++();
|
||||
Iterator operator++(int);
|
||||
|
||||
operator bool() const;
|
||||
|
||||
bool operator==(const Iterator& o) const;
|
||||
bool operator!=(const Iterator& o) const;
|
||||
|
||||
reference operator*();
|
||||
const_reference operator*() const;
|
||||
|
||||
pointer operator->();
|
||||
const_pointer operator->() const;
|
||||
|
||||
const TKey& key() const;
|
||||
|
||||
data_reference data();
|
||||
const TData& data() const;
|
||||
|
||||
std::size_t depth() const;
|
||||
|
||||
bool hasChildren() const;
|
||||
std::vector<Iterator> children() const;
|
||||
};
|
||||
|
||||
size_t size;
|
||||
std::shared_ptr<Node> root;
|
||||
|
||||
template <typename TNode>
|
||||
using callback = std::function<void(const TKey&, TNode)>;
|
||||
|
||||
template <typename TIterator, typename TNode>
|
||||
static TIterator find(const TKey& key, TNode node, TIterator end);
|
||||
|
||||
template <typename TNode>
|
||||
static bool find(const TKey& key, TNode node, const callback<TNode>& cb);
|
||||
|
||||
template <typename TIterator, typename TNode>
|
||||
static std::vector<TIterator> nodes(const TKey& key, TNode root);
|
||||
|
||||
std::shared_ptr<Node>& insert(const TKey& key, std::shared_ptr<Node>& node);
|
||||
void erase(const TKey& key, std::shared_ptr<Node>& node);
|
||||
|
||||
public:
|
||||
using iterator = Iterator<false>;
|
||||
using const_iterator = Iterator<true>;
|
||||
|
||||
CPrefixTrie();
|
||||
|
||||
template <typename TDataUni>
|
||||
iterator insert(const TKey& key, TDataUni&& data);
|
||||
template <typename TDataUni>
|
||||
iterator insert(iterator& it, const TKey& key, TDataUni&& data);
|
||||
|
||||
iterator copy(const_iterator it);
|
||||
|
||||
iterator find(const TKey& key);
|
||||
const_iterator find(const TKey& key) const;
|
||||
iterator find(iterator& it, const TKey& key);
|
||||
const_iterator find(const_iterator& it, const TKey& key) const;
|
||||
|
||||
bool contains(const TKey& key) const;
|
||||
|
||||
TData& at(const TKey& key);
|
||||
|
||||
std::vector<iterator> nodes(const TKey& key);
|
||||
std::vector<const_iterator> nodes(const TKey& key) const;
|
||||
|
||||
bool erase(const TKey& key);
|
||||
|
||||
void clear();
|
||||
bool empty() const;
|
||||
|
||||
size_t height() const;
|
||||
|
||||
iterator begin();
|
||||
iterator end();
|
||||
|
||||
const_iterator cbegin();
|
||||
const_iterator cend();
|
||||
|
||||
const_iterator begin() const;
|
||||
const_iterator end() const;
|
||||
};
|
||||
|
||||
template <typename T, typename O>
|
||||
inline bool operator==(const std::reference_wrapper<T>& ref, const O& obj)
|
||||
{
|
||||
return ref.get() == obj;
|
||||
}
|
||||
|
||||
template <typename T, typename O>
|
||||
inline bool operator!=(const std::reference_wrapper<T>& ref, const O& obj)
|
||||
{
|
||||
return !(ref == obj);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline bool operator==(const std::reference_wrapper<std::shared_ptr<T>>& ref, const T& obj)
|
||||
{
|
||||
auto ptr = ref.get();
|
||||
return ptr && *ptr == obj;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline bool operator!=(const std::reference_wrapper<std::shared_ptr<T>>& ref, const T& obj)
|
||||
{
|
||||
return !(ref == obj);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline bool operator==(const std::reference_wrapper<std::unique_ptr<T>>& ref, const T& obj)
|
||||
{
|
||||
auto ptr = ref.get();
|
||||
return ptr && *ptr == obj;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline bool operator!=(const std::reference_wrapper<std::unique_ptr<T>>& ref, const T& obj)
|
||||
{
|
||||
return !(ref == obj);
|
||||
}
|
||||
|
||||
template <typename TKey>
|
||||
static std::size_t match(const TKey& a, const TKey& b)
|
||||
{
|
||||
std::size_t count = 0;
|
||||
auto ait = a.cbegin(), aend = a.cend();
|
||||
auto bit = b.cbegin(), bend = b.cend();
|
||||
while (ait != aend && bit != bend) {
|
||||
if (*ait != *bit) break;
|
||||
++count;
|
||||
++ait;
|
||||
++bit;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
#endif // BITCOIN_PREFIXTRIE_H
|
|
@ -48,8 +48,7 @@
|
|||
#define T_PENDINGAMOUNT "pendingAmount"
|
||||
|
||||
enum {
|
||||
GETCLAIMSINTRIE = 0,
|
||||
GETNAMESINTRIE,
|
||||
GETNAMESINTRIE = 0,
|
||||
GETVALUEFORNAME,
|
||||
GETCLAIMSFORNAME,
|
||||
GETCLAIMBYID,
|
||||
|
@ -127,26 +126,6 @@ S3(" ", T_LASTTAKEOVERHEIGHT, " (numeric) the last height at which owners
|
|||
|
||||
static const char* const rpc_help[] = {
|
||||
|
||||
// GETCLAIMSINTRIE
|
||||
S1("getclaimsintrie ( \"" T_BLOCKHASH R"(" )
|
||||
Return all claims in the name trie. Deprecated
|
||||
Arguments:)")
|
||||
S3("1. ", T_BLOCKHASH, BLOCKHASH_TEXT)
|
||||
S1("Result: [")
|
||||
S3(" ", T_NORMALIZEDNAME, " (string) the name of the claim(s) (after normalization)")
|
||||
S3(" ", T_CLAIMS, ": [ (array of object) the claims for this name")
|
||||
S3(" ", T_NAME, " (string) the original name of this claim (before normalization)")
|
||||
S3(" ", T_VALUE, " (string) the value of this claim")
|
||||
S3(" ", T_ADDRESS, " (string) the destination address of this claim")
|
||||
S3(" ", T_CLAIMID, " (string) the claimId of the claim")
|
||||
S3(" ", T_TXID, " (string) the txid of the claim")
|
||||
S3(" ", T_N, " (numeric) the index of the claim in the transaction's list of outputs")
|
||||
S3(" ", T_HEIGHT, " (numeric) the height of the block in which this transaction is located")
|
||||
S3(" ", T_VALIDATHEIGHT, " (numeric) the height at which the claim became/becomes valid")
|
||||
S3(" ", T_AMOUNT, " (numeric) the amount of the claim")
|
||||
S1(" ]")
|
||||
"]",
|
||||
|
||||
// GETNAMESINTRIE
|
||||
S1("getnamesintrie ( \"" T_BLOCKHASH R"(" )
|
||||
Return all claim names in the trie.
|
||||
|
|
|
@ -15,7 +15,6 @@
|
|||
#include <validation.h>
|
||||
|
||||
#include <boost/locale.hpp>
|
||||
#include <boost/locale/conversion.hpp>
|
||||
#include <boost/thread.hpp>
|
||||
#include <cmath>
|
||||
|
||||
|
@ -108,13 +107,14 @@ std::string escapeNonUtf8(const std::string& name)
|
|||
}
|
||||
}
|
||||
|
||||
static bool extractValue(const CScript& scriptPubKey, std::string& sValue)
|
||||
static bool extractValue(const CScript& scriptPubKey, std::string& name, std::string& sValue)
|
||||
{
|
||||
int op;
|
||||
std::vector<std::vector<unsigned char>> vvchParams;
|
||||
if (!DecodeClaimScript(scriptPubKey, op, vvchParams))
|
||||
return false;
|
||||
|
||||
name = std::string(vvchParams[0].begin(), vvchParams[0].end());
|
||||
if (op == OP_CLAIM_NAME)
|
||||
sValue = HexStr(vvchParams[1].begin(), vvchParams[1].end());
|
||||
else if (vvchParams.size() > 2) // both UPDATE and SUPPORT
|
||||
|
@ -124,52 +124,6 @@ static bool extractValue(const CScript& scriptPubKey, std::string& sValue)
|
|||
return true;
|
||||
}
|
||||
|
||||
bool getClaimById(const uint160& claimId, std::string& name, CClaimValue* claim = nullptr)
|
||||
{
|
||||
if (claimId.IsNull())
|
||||
return false;
|
||||
|
||||
CClaimIndexElement element;
|
||||
if (!pclaimTrie->db->Read(std::make_pair(CLAIM_BY_ID, claimId), element))
|
||||
return false;
|
||||
if (element.claim.claimId == claimId) {
|
||||
name = element.name;
|
||||
if (claim)
|
||||
*claim = element.claim;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// name can be setted explicitly
|
||||
bool getClaimById(const std::string& partialId, std::string& name, CClaimValue* claim = nullptr)
|
||||
{
|
||||
if (partialId.empty())
|
||||
return false;
|
||||
|
||||
std::unique_ptr<CDBIterator> pcursor(pclaimTrie->db->NewIterator());
|
||||
|
||||
for (pcursor->SeekToFirst(); pcursor->Valid(); pcursor->Next()) {
|
||||
std::pair<uint8_t, uint160> key;
|
||||
if (!pcursor->GetKey(key) || key.first != CLAIM_BY_ID)
|
||||
continue;
|
||||
|
||||
if (key.second.GetHex().find(partialId) != 0)
|
||||
continue;
|
||||
|
||||
CClaimIndexElement element;
|
||||
if (pcursor->GetValue(element)) {
|
||||
if (!name.empty() && name != element.name)
|
||||
continue;
|
||||
name = element.name;
|
||||
if (claim)
|
||||
*claim = element.claim;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
std::vector<CClaimNsupports> seqSort(const std::vector<CClaimNsupports>& source)
|
||||
{
|
||||
auto claimsNsupports = source;
|
||||
|
@ -196,15 +150,13 @@ UniValue claimToJSON(const CCoinsViewCache& coinsCache, const CClaimValue& claim
|
|||
{
|
||||
UniValue result(UniValue::VOBJ);
|
||||
|
||||
std::string targetName;
|
||||
if (getClaimById(claim.claimId, targetName))
|
||||
result.pushKV(T_NAME, escapeNonUtf8(targetName));
|
||||
|
||||
auto& coin = coinsCache.AccessCoin(claim.outPoint);
|
||||
if (!coin.IsSpent()) {
|
||||
std::string value;
|
||||
if (extractValue(coin.out.scriptPubKey, value))
|
||||
std::string name, value;
|
||||
if (extractValue(coin.out.scriptPubKey, name, value)) {
|
||||
result.pushKV(T_NAME, escapeNonUtf8(name));
|
||||
result.pushKV(T_VALUE, value);
|
||||
}
|
||||
|
||||
CTxDestination address;
|
||||
if (ExtractDestination(coin.out.scriptPubKey, address))
|
||||
|
@ -227,9 +179,11 @@ UniValue supportToJSON(const CCoinsViewCache& coinsCache, const CSupportValue& s
|
|||
|
||||
auto& coin = coinsCache.AccessCoin(support.outPoint);
|
||||
if (!coin.IsSpent()) {
|
||||
std::string value;
|
||||
if (extractValue(coin.out.scriptPubKey, value))
|
||||
std::string name, value;
|
||||
if (extractValue(coin.out.scriptPubKey, name, value)) {
|
||||
ret.pushKV(T_NAME, name);
|
||||
ret.pushKV(T_VALUE, value);
|
||||
}
|
||||
|
||||
CTxDestination address;
|
||||
if (ExtractDestination(coin.out.scriptPubKey, address))
|
||||
|
@ -286,48 +240,6 @@ void validateRequest(const JSONRPCRequest& request, int findex, uint8_t required
|
|||
throw std::runtime_error(rpc_help[findex]);
|
||||
}
|
||||
|
||||
static UniValue getclaimsintrie(const JSONRPCRequest& request)
|
||||
{
|
||||
validateRequest(request, GETCLAIMSINTRIE, 0, 1);
|
||||
|
||||
if (!IsDeprecatedRPCEnabled("getclaimsintrie")) {
|
||||
const auto msg = "getclaimsintrie is deprecated and will be removed in v0.18. To use this command, start with -deprecatedrpc=getclaimsintrie";
|
||||
if (request.fHelp)
|
||||
throw std::runtime_error(msg);
|
||||
throw JSONRPCError(RPC_METHOD_DEPRECATED, msg);
|
||||
}
|
||||
|
||||
LOCK(cs_main);
|
||||
CCoinsViewCache coinsCache(pcoinsTip.get());
|
||||
CClaimTrieCache trieCache(pclaimTrie);
|
||||
|
||||
if (!request.params.empty()) {
|
||||
CBlockIndex* blockIndex = BlockHashIndex(ParseHashV(request.params[0], T_BLOCKHASH " (optional parameter 1)"));
|
||||
RollBackTo(blockIndex, coinsCache, trieCache);
|
||||
}
|
||||
|
||||
UniValue ret(UniValue::VARR);
|
||||
trieCache.iterate([&ret, &trieCache, &coinsCache] (const std::string& name, const CClaimTrieData& data) {
|
||||
if (ShutdownRequested())
|
||||
throw JSONRPCError(RPC_INTERNAL_ERROR, "Shutdown requested");
|
||||
|
||||
boost::this_thread::interruption_point();
|
||||
|
||||
if (data.empty())
|
||||
return;
|
||||
|
||||
UniValue claims(UniValue::VARR);
|
||||
for (auto& claim : data.claims)
|
||||
claims.push_back(claimToJSON(coinsCache, claim));
|
||||
|
||||
UniValue nodeObj(UniValue::VOBJ);
|
||||
nodeObj.pushKV(T_NORMALIZEDNAME, escapeNonUtf8(name));
|
||||
nodeObj.pushKV(T_CLAIMS, claims);
|
||||
ret.push_back(nodeObj);
|
||||
});
|
||||
return ret;
|
||||
}
|
||||
|
||||
static UniValue getclaimtrie(const JSONRPCRequest& request)
|
||||
{
|
||||
throw JSONRPCError(RPC_METHOD_DEPRECATED, "getclaimtrie was removed in v0.17.\n"
|
||||
|
@ -348,12 +260,11 @@ static UniValue getnamesintrie(const JSONRPCRequest& request)
|
|||
}
|
||||
|
||||
UniValue ret(UniValue::VARR);
|
||||
trieCache.iterate([&ret](const std::string &name, const CClaimTrieData &data) {
|
||||
if (!data.empty())
|
||||
trieCache.getNamesInTrie([&ret](const std::string& name) {
|
||||
ret.push_back(escapeNonUtf8(name));
|
||||
|
||||
if (ShutdownRequested())
|
||||
throw JSONRPCError(RPC_INTERNAL_ERROR, "Shutdown requested");
|
||||
|
||||
boost::this_thread::interruption_point();
|
||||
});
|
||||
|
||||
|
@ -393,10 +304,10 @@ static UniValue getvalueforname(const JSONRPCRequest& request)
|
|||
|
||||
std::size_t seq = 0, bid = 0;
|
||||
if (csToName.claimsNsupports.size() > 1) {
|
||||
auto& claimId = claimNsupports.claim.claimId;
|
||||
auto& claimIdIn = claimNsupports.claim.claimId;
|
||||
auto seqOrder = seqSort(csToName.claimsNsupports);
|
||||
seq = indexOf(seqOrder, claimId);
|
||||
bid = indexOf(csToName.claimsNsupports, claimId);
|
||||
seq = indexOf(seqOrder, claimIdIn);
|
||||
bid = indexOf(csToName.claimsNsupports, claimIdIn);
|
||||
}
|
||||
|
||||
ret.pushKV(T_NORMALIZEDNAME, escapeNonUtf8(csToName.name));
|
||||
|
@ -550,19 +461,19 @@ UniValue getclaimbyid(const JSONRPCRequest& request)
|
|||
if (claimId.length() < 3)
|
||||
throw JSONRPCError(RPC_INVALID_PARAMETER, T_CLAIMID " (parameter 1) should be at least 3 chars");
|
||||
|
||||
std::string name;
|
||||
CClaimValue claim;
|
||||
std::string foundName;
|
||||
CClaimValue foundClaim;
|
||||
UniValue ret(UniValue::VOBJ);
|
||||
bool found = claimId.length() == claimIdHexLength && getClaimById(uint160S(claimId), name, &claim);
|
||||
if (found || getClaimById(claimId, name, &claim)) {
|
||||
auto csToName = trieCache.getClaimsForName(name);
|
||||
auto& claimNsupports = csToName.find(claim.claimId);
|
||||
auto parsed = ParseHex(claimId);
|
||||
if (trieCache.findNameForClaim(parsed, foundClaim, foundName)) {
|
||||
auto csToName = trieCache.getClaimsForName(foundName);
|
||||
auto& claimNsupports = csToName.find(foundClaim.claimId);
|
||||
if (!claimNsupports.IsNull()) {
|
||||
std::size_t seq = 0, bid = 0;
|
||||
if (csToName.claimsNsupports.size() > 1) {
|
||||
auto seqOrder = seqSort(csToName.claimsNsupports);
|
||||
seq = indexOf(seqOrder, claim.claimId);
|
||||
bid = indexOf(csToName.claimsNsupports, claim.claimId);
|
||||
seq = indexOf(seqOrder, foundClaim.claimId);
|
||||
bid = indexOf(csToName.claimsNsupports, foundClaim.claimId);
|
||||
}
|
||||
ret.pushKV(T_NORMALIZEDNAME, escapeNonUtf8(csToName.name));
|
||||
ret.pushKVs(claimAndSupportsToJSON(coinsCache, claimNsupports));
|
||||
|
@ -579,7 +490,8 @@ UniValue gettotalclaimednames(const JSONRPCRequest& request)
|
|||
validateRequest(request, GETTOTALCLAIMEDNAMES, 0, 0);
|
||||
|
||||
LOCK(cs_main);
|
||||
auto num_names = pclaimTrie->getTotalNamesInTrie();
|
||||
CClaimTrieCache trieCache(pclaimTrie); // TODO: add rollback support here
|
||||
auto num_names = trieCache.getTotalNamesInTrie();
|
||||
return int(num_names);
|
||||
}
|
||||
|
||||
|
@ -588,7 +500,8 @@ UniValue gettotalclaims(const JSONRPCRequest& request)
|
|||
validateRequest(request, GETTOTALCLAIMS, 0, 0);
|
||||
|
||||
LOCK(cs_main);
|
||||
auto num_claims = pclaimTrie->getTotalClaimsInTrie();
|
||||
CClaimTrieCache trieCache(pclaimTrie); // TODO: add rollback support here
|
||||
auto num_claims = trieCache.getTotalClaimsInTrie();
|
||||
return int(num_claims);
|
||||
}
|
||||
|
||||
|
@ -600,7 +513,8 @@ UniValue gettotalvalueofclaims(const JSONRPCRequest& request)
|
|||
bool controlling_only = false;
|
||||
if (request.params.size() == 1)
|
||||
controlling_only = request.params[0].get_bool();
|
||||
auto total_amount = pclaimTrie->getTotalValueOfClaimsInTrie(controlling_only);
|
||||
CClaimTrieCache trieCache(pclaimTrie); // TODO: add rollback support here
|
||||
auto total_amount = trieCache.getTotalValueOfClaimsInTrie(controlling_only);
|
||||
return ValueFromAmount(total_amount);
|
||||
}
|
||||
|
||||
|
@ -739,30 +653,28 @@ UniValue getnameproof(const JSONRPCRequest& request)
|
|||
CCoinsViewCache coinsCache(pcoinsTip.get());
|
||||
CClaimTrieCache trieCache(pclaimTrie);
|
||||
|
||||
int validHeight = pclaimTrie->nNextHeight - 1;
|
||||
if (request.params.size() > 1) {
|
||||
CBlockIndex* pblockIndex = BlockHashIndex(ParseHashV(request.params[1], T_BLOCKHASH " (optional parameter 2)"));
|
||||
RollBackTo(pblockIndex, coinsCache, trieCache);
|
||||
validHeight = pblockIndex->nHeight;
|
||||
}
|
||||
|
||||
std::string name = request.params[0].get_str();
|
||||
|
||||
CClaimValue claim;
|
||||
if (request.params.size() > 2) {
|
||||
std::string claimId;
|
||||
if (request.params.size() > 2)
|
||||
ParseClaimtrieId(request.params[2], claimId, T_CLAIMID " (optional parameter 3)");
|
||||
|
||||
std::function<bool(const CClaimValue&)> comp;
|
||||
if (claimId.length() == claimIdHexLength) {
|
||||
auto claimIdx = uint160S(claimId);
|
||||
comp = [claimIdx](const CClaimValue& claim) {
|
||||
return claim.claimId == claimIdx;
|
||||
};
|
||||
} else if (!claimId.empty()) {
|
||||
comp = [&claimId](const CClaimValue& claim) {
|
||||
return claim.claimId.GetHex().find(claimId) == 0;
|
||||
};
|
||||
std::string foundClaimName;
|
||||
if (!trieCache.findNameForClaim(ParseHex(claimId), claim, foundClaimName)
|
||||
|| foundClaimName != trieCache.adjustNameForValidHeight(name, validHeight))
|
||||
throw JSONRPCError(RPC_INVALID_PARAMETER, "Failed to locate a claim with ID " + claimId);
|
||||
}
|
||||
else trieCache.getInfoForName(name, claim);
|
||||
|
||||
CClaimTrieProof proof;
|
||||
std::string name = request.params[0].get_str();
|
||||
if (!trieCache.getProofForName(name, proof, comp))
|
||||
if (!trieCache.getProofForName(name, claim.claimId, proof))
|
||||
throw JSONRPCError(RPC_INTERNAL_ERROR, "Failed to generate proof");
|
||||
|
||||
return proofToJSON(proof);
|
||||
|
@ -790,19 +702,13 @@ UniValue getclaimproofbybid(const JSONRPCRequest& request)
|
|||
|
||||
std::string name = request.params[0].get_str();
|
||||
|
||||
std::function<bool(const CClaimValue&)> comp;
|
||||
if (bid) {
|
||||
auto csToName = trieCache.getClaimsForName(name);
|
||||
if (uint32_t(bid) >= csToName.claimsNsupports.size())
|
||||
if (std::size_t(bid) >= csToName.claimsNsupports.size())
|
||||
return {UniValue::VARR};
|
||||
auto claimId = csToName.claimsNsupports[bid].claim.claimId;
|
||||
comp = [claimId](const CClaimValue& claim) {
|
||||
return claim.claimId == claimId;
|
||||
};
|
||||
}
|
||||
auto match = csToName.claimsNsupports[bid].claim.claimId;
|
||||
|
||||
CClaimTrieProof proof;
|
||||
if (!trieCache.getProofForName(name, proof, comp))
|
||||
if (!trieCache.getProofForName(name, match, proof))
|
||||
throw JSONRPCError(RPC_INTERNAL_ERROR, "Failed to generate proof");
|
||||
|
||||
return proofToJSON(proof);
|
||||
|
@ -830,18 +736,14 @@ UniValue getclaimproofbyseq(const JSONRPCRequest& request)
|
|||
|
||||
std::string name = request.params[0].get_str();
|
||||
auto csToName = trieCache.getClaimsForName(name);
|
||||
if (uint32_t(seq) >= csToName.claimsNsupports.size())
|
||||
if (std::size_t(seq) >= csToName.claimsNsupports.size())
|
||||
return {UniValue::VARR};
|
||||
|
||||
std::function<bool(const CClaimValue&)> comp;
|
||||
auto claimId = (csToName.claimsNsupports.size() == 1 ?
|
||||
csToName.claimsNsupports[0] : seqSort(csToName.claimsNsupports)[seq]).claim.claimId;
|
||||
comp = [&claimId](const CClaimValue& claim) {
|
||||
return claim.claimId == claimId;
|
||||
};
|
||||
auto sorted = seqSort(csToName.claimsNsupports);
|
||||
auto match = sorted[seq].claim.claimId;
|
||||
|
||||
CClaimTrieProof proof;
|
||||
if (!trieCache.getProofForName(name, proof, comp))
|
||||
if (!trieCache.getProofForName(name, match, proof))
|
||||
throw JSONRPCError(RPC_INTERNAL_ERROR, "Failed to generate proof");
|
||||
|
||||
return proofToJSON(proof);
|
||||
|
@ -905,7 +807,6 @@ UniValue checknormalization(const JSONRPCRequest& request)
|
|||
static const CRPCCommand commands[] =
|
||||
{ // category name actor (function) argNames
|
||||
// --------------------- ------------------------ ----------------------- ----------
|
||||
{ "Claimtrie", "getclaimsintrie", &getclaimsintrie, { T_BLOCKHASH } },
|
||||
{ "Claimtrie", "getnamesintrie", &getnamesintrie, { T_BLOCKHASH } },
|
||||
{ "hidden", "getclaimtrie", &getclaimtrie, { } },
|
||||
{ "Claimtrie", "getvalueforname", &getvalueforname, { T_NAME,T_BLOCKHASH,T_CLAIMID } },
|
||||
|
|
682
src/sqlite/hdr/sqlite_modern_cpp.h
Normal file
682
src/sqlite/hdr/sqlite_modern_cpp.h
Normal file
|
@ -0,0 +1,682 @@
|
|||
#pragma once
|
||||
|
||||
#include <algorithm>
|
||||
#include <cctype>
|
||||
#include <string>
|
||||
#include <functional>
|
||||
#include <tuple>
|
||||
#include <memory>
|
||||
|
||||
#define MODERN_SQLITE_VERSION 3002008
|
||||
|
||||
#include <sqlite/sqlite3.h>
|
||||
|
||||
#include "sqlite_modern_cpp/type_wrapper.h"
|
||||
#include "sqlite_modern_cpp/errors.h"
|
||||
#include "sqlite_modern_cpp/utility/function_traits.h"
|
||||
#include "sqlite_modern_cpp/utility/uncaught_exceptions.h"
|
||||
#include "sqlite_modern_cpp/utility/utf16_utf8.h"
|
||||
|
||||
namespace sqlite {
|
||||
|
||||
class database;
|
||||
class database_binder;
|
||||
|
||||
template<std::size_t> class binder;
|
||||
|
||||
typedef std::shared_ptr<sqlite3> connection_type;
|
||||
|
||||
template<class T, bool Name = false>
|
||||
struct index_binding_helper {
|
||||
index_binding_helper(const index_binding_helper &) = delete;
|
||||
#if __cplusplus < 201703
|
||||
index_binding_helper(index_binding_helper &&) = default;
|
||||
#endif
|
||||
typename std::conditional<Name, const char *, int>::type index;
|
||||
T value;
|
||||
};
|
||||
|
||||
template<class T>
|
||||
auto named_parameter(const char *name, T &&arg) {
|
||||
return index_binding_helper<decltype(arg), true>{name, std::forward<decltype(arg)>(arg)};
|
||||
}
|
||||
template<class T>
|
||||
auto indexed_parameter(int index, T &&arg) {
|
||||
return index_binding_helper<decltype(arg)>{index, std::forward<decltype(arg)>(arg)};
|
||||
}
|
||||
|
||||
class row_iterator;
|
||||
class database_binder {
|
||||
|
||||
public:
|
||||
// database_binder is not copyable
|
||||
database_binder() = delete;
|
||||
database_binder(const database_binder& other) = delete;
|
||||
database_binder& operator=(const database_binder&) = delete;
|
||||
|
||||
database_binder(database_binder&& other) :
|
||||
_db(std::move(other._db)),
|
||||
_stmt(std::move(other._stmt)),
|
||||
_inx(other._inx), execution_started(other.execution_started) { }
|
||||
|
||||
void execute();
|
||||
|
||||
std::string sql() {
|
||||
#if SQLITE_VERSION_NUMBER >= 3014000
|
||||
auto sqlite_deleter = [](void *ptr) {sqlite3_free(ptr);};
|
||||
std::unique_ptr<char, decltype(sqlite_deleter)> str(sqlite3_expanded_sql(_stmt.get()), sqlite_deleter);
|
||||
return str ? str.get() : original_sql();
|
||||
#else
|
||||
return original_sql();
|
||||
#endif
|
||||
}
|
||||
|
||||
std::string original_sql() {
|
||||
return sqlite3_sql(_stmt.get());
|
||||
}
|
||||
|
||||
void used(bool state) {
|
||||
if(!state) {
|
||||
// We may have to reset first if we haven't done so already:
|
||||
_next_index();
|
||||
--_inx;
|
||||
}
|
||||
execution_started = state;
|
||||
}
|
||||
bool used() const { return execution_started; }
|
||||
row_iterator begin();
|
||||
row_iterator end();
|
||||
|
||||
private:
|
||||
std::shared_ptr<sqlite3> _db;
|
||||
std::unique_ptr<sqlite3_stmt, decltype(&sqlite3_finalize)> _stmt;
|
||||
utility::UncaughtExceptionDetector _has_uncaught_exception;
|
||||
|
||||
int _inx;
|
||||
|
||||
bool execution_started = false;
|
||||
|
||||
int _next_index() {
|
||||
if(execution_started && !_inx) {
|
||||
sqlite3_reset(_stmt.get());
|
||||
sqlite3_clear_bindings(_stmt.get());
|
||||
}
|
||||
return ++_inx;
|
||||
}
|
||||
|
||||
sqlite3_stmt* _prepare(u16str_ref sql) {
|
||||
return _prepare(utility::utf16_to_utf8(sql));
|
||||
}
|
||||
|
||||
sqlite3_stmt* _prepare(str_ref sql) {
|
||||
int hresult;
|
||||
sqlite3_stmt* tmp = nullptr;
|
||||
const char *remaining;
|
||||
hresult = sqlite3_prepare_v2(_db.get(), sql.data(), sql.length(), &tmp, &remaining);
|
||||
if(hresult != SQLITE_OK) errors::throw_sqlite_error(hresult, sql);
|
||||
if(!std::all_of(remaining, sql.data() + sql.size(), [](char ch) {return std::isspace(ch);}))
|
||||
throw errors::more_statements("Multiple semicolon separated statements are unsupported", sql);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
template<typename T> friend database_binder& operator<<(database_binder& db, T&&);
|
||||
template<typename T> friend database_binder& operator<<(database_binder& db, index_binding_helper<T>);
|
||||
template<typename T> friend database_binder& operator<<(database_binder& db, index_binding_helper<T, true>);
|
||||
friend void operator++(database_binder& db, int);
|
||||
|
||||
public:
|
||||
|
||||
database_binder(std::shared_ptr<sqlite3> db, u16str_ref sql):
|
||||
_db(db),
|
||||
_stmt(_prepare(sql), sqlite3_finalize),
|
||||
_inx(0) {
|
||||
}
|
||||
|
||||
database_binder(std::shared_ptr<sqlite3> db, str_ref sql):
|
||||
_db(db),
|
||||
_stmt(_prepare(sql), sqlite3_finalize),
|
||||
_inx(0) {
|
||||
}
|
||||
|
||||
~database_binder() noexcept(false) {
|
||||
/* Will be executed if no >>op is found, but not if an exception
|
||||
is in mid flight */
|
||||
if(!used() && !_has_uncaught_exception && _stmt) {
|
||||
execute();
|
||||
}
|
||||
}
|
||||
|
||||
friend class row_iterator;
|
||||
};
|
||||
|
||||
class row_iterator {
|
||||
public:
|
||||
class value_type {
|
||||
public:
|
||||
value_type(database_binder *_binder): _binder(_binder) {};
|
||||
template<class T>
|
||||
typename std::enable_if<is_sqlite_value<T>::value, value_type &>::type operator >>(T &result) {
|
||||
result = get_col_from_db(_binder->_stmt.get(), next_index++, result_type<T>());
|
||||
return *this;
|
||||
}
|
||||
template<class ...Types>
|
||||
value_type &operator >>(std::tuple<Types...>& values) {
|
||||
values = handle_tuple<std::tuple<typename std::decay<Types>::type...>>(std::index_sequence_for<Types...>());
|
||||
next_index += sizeof...(Types);
|
||||
return *this;
|
||||
}
|
||||
template<class ...Types>
|
||||
value_type &operator >>(std::tuple<Types...>&& values) {
|
||||
return *this >> values;
|
||||
}
|
||||
template<class ...Types>
|
||||
operator std::tuple<Types...>() {
|
||||
std::tuple<Types...> value;
|
||||
*this >> value;
|
||||
return value;
|
||||
}
|
||||
explicit operator bool() {
|
||||
return sqlite3_column_count(_binder->_stmt.get()) >= next_index;
|
||||
}
|
||||
private:
|
||||
template<class Tuple, std::size_t ...Index>
|
||||
Tuple handle_tuple(std::index_sequence<Index...>) {
|
||||
return Tuple(
|
||||
get_col_from_db(
|
||||
_binder->_stmt.get(),
|
||||
next_index + Index,
|
||||
result_type<typename std::tuple_element<Index, Tuple>::type>())...);
|
||||
}
|
||||
database_binder *_binder;
|
||||
int next_index = 0;
|
||||
};
|
||||
using difference_type = std::ptrdiff_t;
|
||||
using pointer = value_type*;
|
||||
using reference = value_type&;
|
||||
using iterator_category = std::input_iterator_tag;
|
||||
|
||||
row_iterator() = default;
|
||||
explicit row_iterator(database_binder &binder): _binder(&binder) {
|
||||
_binder->_next_index();
|
||||
_binder->_inx = 0;
|
||||
_binder->used(true);
|
||||
++*this;
|
||||
}
|
||||
|
||||
reference operator*() const { return value;}
|
||||
pointer operator->() const { return std::addressof(**this); }
|
||||
row_iterator &operator++() {
|
||||
switch(int result = sqlite3_step(_binder->_stmt.get())) {
|
||||
case SQLITE_ROW:
|
||||
value = {_binder};
|
||||
break;
|
||||
case SQLITE_DONE:
|
||||
_binder = nullptr;
|
||||
break;
|
||||
default:
|
||||
exceptions::throw_sqlite_error(result, _binder->sql());
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
friend inline bool operator ==(const row_iterator &a, const row_iterator &b) {
|
||||
return a._binder == b._binder;
|
||||
}
|
||||
friend inline bool operator !=(const row_iterator &a, const row_iterator &b) {
|
||||
return !(a==b);
|
||||
}
|
||||
|
||||
private:
|
||||
database_binder *_binder = nullptr;
|
||||
mutable value_type value{_binder}; // mutable, because `changing` the value is just reading it
|
||||
};
|
||||
|
||||
inline row_iterator database_binder::begin() {
|
||||
return row_iterator(*this);
|
||||
}
|
||||
|
||||
inline row_iterator database_binder::end() {
|
||||
return row_iterator();
|
||||
}
|
||||
|
||||
namespace detail {
|
||||
template<class Callback>
|
||||
void _extract_single_value(database_binder &binder, Callback call_back) {
|
||||
auto iter = binder.begin();
|
||||
if(iter == binder.end())
|
||||
throw errors::no_rows("no rows to extract: exactly 1 row expected", binder.sql(), SQLITE_DONE);
|
||||
|
||||
call_back(*iter);
|
||||
|
||||
if(++iter != binder.end())
|
||||
throw errors::more_rows("not all rows extracted", binder.sql(), SQLITE_ROW);
|
||||
}
|
||||
}
|
||||
inline void database_binder::execute() {
|
||||
for(auto &&row : *this)
|
||||
(void)row;
|
||||
}
|
||||
namespace detail {
|
||||
template<class T> using void_t = void;
|
||||
template<class T, class = void>
|
||||
struct sqlite_direct_result : std::false_type {};
|
||||
template<class T>
|
||||
struct sqlite_direct_result<
|
||||
T,
|
||||
void_t<decltype(std::declval<row_iterator::value_type&>() >> std::declval<T&&>())>
|
||||
> : std::true_type {};
|
||||
}
|
||||
template <typename Result>
|
||||
inline typename std::enable_if<detail::sqlite_direct_result<Result>::value>::type operator>>(database_binder &binder, Result&& value) {
|
||||
detail::_extract_single_value(binder, [&value] (row_iterator::value_type &row) {
|
||||
row >> std::forward<Result>(value);
|
||||
});
|
||||
}
|
||||
|
||||
template <typename Function>
|
||||
inline typename std::enable_if<!detail::sqlite_direct_result<Function>::value>::type operator>>(database_binder &db_binder, Function&& func) {
|
||||
using traits = utility::function_traits<Function>;
|
||||
|
||||
for(auto &&row : db_binder) {
|
||||
binder<traits::arity>::run(row, func);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Result>
|
||||
inline decltype(auto) operator>>(database_binder &&binder, Result&& value) {
|
||||
return binder >> std::forward<Result>(value);
|
||||
}
|
||||
|
||||
namespace sql_function_binder {
|
||||
template<
|
||||
typename ContextType,
|
||||
std::size_t Count,
|
||||
typename Functions
|
||||
>
|
||||
inline void step(
|
||||
sqlite3_context* db,
|
||||
int count,
|
||||
sqlite3_value** vals
|
||||
);
|
||||
|
||||
template<
|
||||
std::size_t Count,
|
||||
typename Functions,
|
||||
typename... Values
|
||||
>
|
||||
inline typename std::enable_if<(sizeof...(Values) && sizeof...(Values) < Count), void>::type step(
|
||||
sqlite3_context* db,
|
||||
int count,
|
||||
sqlite3_value** vals,
|
||||
Values&&... values
|
||||
);
|
||||
|
||||
template<
|
||||
std::size_t Count,
|
||||
typename Functions,
|
||||
typename... Values
|
||||
>
|
||||
inline typename std::enable_if<(sizeof...(Values) == Count), void>::type step(
|
||||
sqlite3_context* db,
|
||||
int,
|
||||
sqlite3_value**,
|
||||
Values&&... values
|
||||
);
|
||||
|
||||
template<
|
||||
typename ContextType,
|
||||
typename Functions
|
||||
>
|
||||
inline void final(sqlite3_context* db);
|
||||
|
||||
template<
|
||||
std::size_t Count,
|
||||
typename Function,
|
||||
typename... Values
|
||||
>
|
||||
inline typename std::enable_if<(sizeof...(Values) < Count), void>::type scalar(
|
||||
sqlite3_context* db,
|
||||
int count,
|
||||
sqlite3_value** vals,
|
||||
Values&&... values
|
||||
);
|
||||
|
||||
template<
|
||||
std::size_t Count,
|
||||
typename Function,
|
||||
typename... Values
|
||||
>
|
||||
inline typename std::enable_if<(sizeof...(Values) == Count), void>::type scalar(
|
||||
sqlite3_context* db,
|
||||
int,
|
||||
sqlite3_value**,
|
||||
Values&&... values
|
||||
);
|
||||
}
|
||||
|
||||
enum class OpenFlags {
|
||||
READONLY = SQLITE_OPEN_READONLY,
|
||||
READWRITE = SQLITE_OPEN_READWRITE,
|
||||
CREATE = SQLITE_OPEN_CREATE,
|
||||
NOMUTEX = SQLITE_OPEN_NOMUTEX,
|
||||
FULLMUTEX = SQLITE_OPEN_FULLMUTEX,
|
||||
SHAREDCACHE = SQLITE_OPEN_SHAREDCACHE,
|
||||
PRIVATECACH = SQLITE_OPEN_PRIVATECACHE,
|
||||
URI = SQLITE_OPEN_URI
|
||||
};
|
||||
inline OpenFlags operator|(const OpenFlags& a, const OpenFlags& b) {
|
||||
return static_cast<OpenFlags>(static_cast<int>(a) | static_cast<int>(b));
|
||||
}
|
||||
enum class Encoding {
|
||||
ANY = SQLITE_ANY,
|
||||
UTF8 = SQLITE_UTF8,
|
||||
UTF16 = SQLITE_UTF16
|
||||
};
|
||||
struct sqlite_config {
|
||||
OpenFlags flags = OpenFlags::READWRITE | OpenFlags::CREATE;
|
||||
const char *zVfs = nullptr;
|
||||
Encoding encoding = Encoding::ANY;
|
||||
};
|
||||
|
||||
class database {
|
||||
protected:
|
||||
std::shared_ptr<sqlite3> _db;
|
||||
|
||||
public:
|
||||
database(const std::string &db_name, const sqlite_config &config = {}): _db(nullptr) {
|
||||
sqlite3* tmp = nullptr;
|
||||
auto ret = sqlite3_open_v2(db_name.data(), &tmp, static_cast<int>(config.flags), config.zVfs);
|
||||
_db = std::shared_ptr<sqlite3>(tmp, [=](sqlite3* ptr) { sqlite3_close_v2(ptr); }); // this will close the connection eventually when no longer needed.
|
||||
if(ret != SQLITE_OK) errors::throw_sqlite_error(_db ? sqlite3_extended_errcode(_db.get()) : ret);
|
||||
sqlite3_extended_result_codes(_db.get(), true);
|
||||
if(config.encoding == Encoding::UTF16)
|
||||
*this << R"(PRAGMA encoding = "UTF-16";)";
|
||||
}
|
||||
|
||||
database(const std::u16string &db_name, const sqlite_config &config = {}): database(utility::utf16_to_utf8(db_name), config) {
|
||||
if (config.encoding == Encoding::ANY)
|
||||
*this << R"(PRAGMA encoding = "UTF-16";)";
|
||||
}
|
||||
|
||||
database(std::shared_ptr<sqlite3> db):
|
||||
_db(db) {}
|
||||
|
||||
database_binder operator<<(str_ref sql) {
|
||||
return database_binder(_db, sql);
|
||||
}
|
||||
|
||||
database_binder operator<<(u16str_ref sql) {
|
||||
return database_binder(_db, sql);
|
||||
}
|
||||
|
||||
connection_type connection() const { return _db; }
|
||||
|
||||
sqlite3_int64 last_insert_rowid() const {
|
||||
return sqlite3_last_insert_rowid(_db.get());
|
||||
}
|
||||
|
||||
int rows_modified() const {
|
||||
return sqlite3_changes(_db.get());
|
||||
}
|
||||
|
||||
template <typename Function>
|
||||
void define(const std::string &name, Function&& func) {
|
||||
typedef utility::function_traits<Function> traits;
|
||||
|
||||
auto funcPtr = new auto(std::forward<Function>(func));
|
||||
if(int result = sqlite3_create_function_v2(
|
||||
_db.get(), name.data(), traits::arity, SQLITE_UTF8 | SQLITE_DETERMINISTIC, funcPtr,
|
||||
sql_function_binder::scalar<traits::arity, typename std::remove_reference<Function>::type>,
|
||||
nullptr, nullptr, [](void* ptr){
|
||||
delete static_cast<decltype(funcPtr)>(ptr);
|
||||
}))
|
||||
errors::throw_sqlite_error(result);
|
||||
}
|
||||
|
||||
template <typename StepFunction, typename FinalFunction>
|
||||
void define(const std::string &name, StepFunction&& step, FinalFunction&& final) {
|
||||
typedef utility::function_traits<StepFunction> traits;
|
||||
using ContextType = typename std::remove_reference<typename traits::template argument<0>>::type;
|
||||
|
||||
auto funcPtr = new auto(std::make_pair(std::forward<StepFunction>(step), std::forward<FinalFunction>(final)));
|
||||
if(int result = sqlite3_create_function_v2(
|
||||
_db.get(), name.c_str(), traits::arity - 1, SQLITE_UTF8 | SQLITE_DETERMINISTIC, funcPtr, nullptr,
|
||||
sql_function_binder::step<ContextType, traits::arity, typename std::remove_reference<decltype(*funcPtr)>::type>,
|
||||
sql_function_binder::final<ContextType, typename std::remove_reference<decltype(*funcPtr)>::type>,
|
||||
[](void* ptr){
|
||||
delete static_cast<decltype(funcPtr)>(ptr);
|
||||
}))
|
||||
errors::throw_sqlite_error(result);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
template<std::size_t Count>
|
||||
class binder {
|
||||
private:
|
||||
template <
|
||||
typename Function,
|
||||
std::size_t Index
|
||||
>
|
||||
using nth_argument_type = typename utility::function_traits<
|
||||
Function
|
||||
>::template argument<Index>;
|
||||
|
||||
public:
|
||||
// `Boundary` needs to be defaulted to `Count` so that the `run` function
|
||||
// template is not implicitly instantiated on class template instantiation.
|
||||
// Look up section 14.7.1 _Implicit instantiation_ of the ISO C++14 Standard
|
||||
// and the [dicussion](https://github.com/aminroosta/sqlite_modern_cpp/issues/8)
|
||||
// on Github.
|
||||
|
||||
template<
|
||||
typename Function,
|
||||
typename... Values,
|
||||
std::size_t Boundary = Count
|
||||
>
|
||||
static typename std::enable_if<(sizeof...(Values) < Boundary), void>::type run(
|
||||
row_iterator::value_type& row,
|
||||
Function&& function,
|
||||
Values&&... values
|
||||
) {
|
||||
typename std::decay<nth_argument_type<Function, sizeof...(Values)>>::type value;
|
||||
row >> value;
|
||||
run<Function>(row, function, std::forward<Values>(values)..., std::move(value));
|
||||
}
|
||||
|
||||
template<
|
||||
typename Function,
|
||||
typename... Values,
|
||||
std::size_t Boundary = Count
|
||||
>
|
||||
static typename std::enable_if<(sizeof...(Values) == Boundary), void>::type run(
|
||||
row_iterator::value_type&,
|
||||
Function&& function,
|
||||
Values&&... values
|
||||
) {
|
||||
function(std::move(values)...);
|
||||
}
|
||||
};
|
||||
|
||||
// Some ppl are lazy so we have a operator for proper prep. statemant handling.
|
||||
void inline operator++(database_binder& db, int) { db.execute(); }
|
||||
|
||||
template<typename T> database_binder &operator<<(database_binder& db, index_binding_helper<T> val) {
|
||||
db._next_index(); --db._inx;
|
||||
int result = bind_col_in_db(db._stmt.get(), val.index, std::forward<T>(val.value));
|
||||
if(result != SQLITE_OK)
|
||||
exceptions::throw_sqlite_error(result, db.sql());
|
||||
return db;
|
||||
}
|
||||
|
||||
template<typename T> database_binder &operator<<(database_binder& db, index_binding_helper<T, true> val) {
|
||||
db._next_index(); --db._inx;
|
||||
int index = sqlite3_bind_parameter_index(db._stmt.get(), val.index);
|
||||
if(!index)
|
||||
throw errors::unknown_binding("The given binding name is not valid for this statement", db.sql());
|
||||
int result = bind_col_in_db(db._stmt.get(), index, std::forward<T>(val.value));
|
||||
if(result != SQLITE_OK)
|
||||
exceptions::throw_sqlite_error(result, db.sql());
|
||||
return db;
|
||||
}
|
||||
|
||||
template<typename T> database_binder &operator<<(database_binder& db, T&& val) {
|
||||
int result = bind_col_in_db(db._stmt.get(), db._next_index(), std::forward<T>(val));
|
||||
if(result != SQLITE_OK)
|
||||
exceptions::throw_sqlite_error(result, db.sql());
|
||||
return db;
|
||||
}
|
||||
// Convert the rValue binder to a reference and call first op<<, its needed for the call that creates the binder (be carefull of recursion here!)
|
||||
template<typename T> database_binder operator << (database_binder&& db, const T& val) { db << val; return std::move(db); }
|
||||
template<typename T, bool Name> database_binder operator << (database_binder&& db, index_binding_helper<T, Name> val) { db << index_binding_helper<T, Name>{val.index, std::forward<T>(val.value)}; return std::move(db); }
|
||||
|
||||
namespace sql_function_binder {
|
||||
template<class T>
|
||||
struct AggregateCtxt {
|
||||
T obj;
|
||||
bool constructed = true;
|
||||
};
|
||||
|
||||
template<
|
||||
typename ContextType,
|
||||
std::size_t Count,
|
||||
typename Functions
|
||||
>
|
||||
inline void step(
|
||||
sqlite3_context* db,
|
||||
int count,
|
||||
sqlite3_value** vals
|
||||
) {
|
||||
auto ctxt = static_cast<AggregateCtxt<ContextType>*>(sqlite3_aggregate_context(db, sizeof(AggregateCtxt<ContextType>)));
|
||||
if(!ctxt) return;
|
||||
try {
|
||||
if(!ctxt->constructed) new(ctxt) AggregateCtxt<ContextType>();
|
||||
step<Count, Functions>(db, count, vals, ctxt->obj);
|
||||
return;
|
||||
} catch(const sqlite_exception &e) {
|
||||
sqlite3_result_error_code(db, e.get_code());
|
||||
sqlite3_result_error(db, e.what(), -1);
|
||||
} catch(const std::exception &e) {
|
||||
sqlite3_result_error(db, e.what(), -1);
|
||||
} catch(...) {
|
||||
sqlite3_result_error(db, "Unknown error", -1);
|
||||
}
|
||||
if(ctxt && ctxt->constructed)
|
||||
ctxt->~AggregateCtxt();
|
||||
}
|
||||
|
||||
template<
|
||||
std::size_t Count,
|
||||
typename Functions,
|
||||
typename... Values
|
||||
>
|
||||
inline typename std::enable_if<(sizeof...(Values) && sizeof...(Values) < Count), void>::type step(
|
||||
sqlite3_context* db,
|
||||
int count,
|
||||
sqlite3_value** vals,
|
||||
Values&&... values
|
||||
) {
|
||||
using arg_type = typename std::remove_cv<
|
||||
typename std::remove_reference<
|
||||
typename utility::function_traits<
|
||||
typename Functions::first_type
|
||||
>::template argument<sizeof...(Values)>
|
||||
>::type
|
||||
>::type;
|
||||
|
||||
step<Count, Functions>(
|
||||
db,
|
||||
count,
|
||||
vals,
|
||||
std::forward<Values>(values)...,
|
||||
get_val_from_db(vals[sizeof...(Values) - 1], result_type<arg_type>()));
|
||||
}
|
||||
|
||||
template<
|
||||
std::size_t Count,
|
||||
typename Functions,
|
||||
typename... Values
|
||||
>
|
||||
inline typename std::enable_if<(sizeof...(Values) == Count), void>::type step(
|
||||
sqlite3_context* db,
|
||||
int,
|
||||
sqlite3_value**,
|
||||
Values&&... values
|
||||
) {
|
||||
static_cast<Functions*>(sqlite3_user_data(db))->first(std::forward<Values>(values)...);
|
||||
}
|
||||
|
||||
template<
|
||||
typename ContextType,
|
||||
typename Functions
|
||||
>
|
||||
inline void final(sqlite3_context* db) {
|
||||
auto ctxt = static_cast<AggregateCtxt<ContextType>*>(sqlite3_aggregate_context(db, sizeof(AggregateCtxt<ContextType>)));
|
||||
try {
|
||||
if(!ctxt) return;
|
||||
if(!ctxt->constructed) new(ctxt) AggregateCtxt<ContextType>();
|
||||
store_result_in_db(db,
|
||||
static_cast<Functions*>(sqlite3_user_data(db))->second(ctxt->obj));
|
||||
} catch(const sqlite_exception &e) {
|
||||
sqlite3_result_error_code(db, e.get_code());
|
||||
sqlite3_result_error(db, e.what(), -1);
|
||||
} catch(const std::exception &e) {
|
||||
sqlite3_result_error(db, e.what(), -1);
|
||||
} catch(...) {
|
||||
sqlite3_result_error(db, "Unknown error", -1);
|
||||
}
|
||||
if(ctxt && ctxt->constructed)
|
||||
ctxt->~AggregateCtxt();
|
||||
}
|
||||
|
||||
template<
|
||||
std::size_t Count,
|
||||
typename Function,
|
||||
typename... Values
|
||||
>
|
||||
inline typename std::enable_if<(sizeof...(Values) < Count), void>::type scalar(
|
||||
sqlite3_context* db,
|
||||
int count,
|
||||
sqlite3_value** vals,
|
||||
Values&&... values
|
||||
) {
|
||||
using arg_type = typename std::remove_cv<
|
||||
typename std::remove_reference<
|
||||
typename utility::function_traits<Function>::template argument<sizeof...(Values)>
|
||||
>::type
|
||||
>::type;
|
||||
|
||||
scalar<Count, Function>(
|
||||
db,
|
||||
count,
|
||||
vals,
|
||||
std::forward<Values>(values)...,
|
||||
get_val_from_db(vals[sizeof...(Values)], result_type<arg_type>()));
|
||||
}
|
||||
|
||||
template<
|
||||
std::size_t Count,
|
||||
typename Function,
|
||||
typename... Values
|
||||
>
|
||||
inline typename std::enable_if<(sizeof...(Values) == Count), void>::type scalar(
|
||||
sqlite3_context* db,
|
||||
int,
|
||||
sqlite3_value**,
|
||||
Values&&... values
|
||||
) {
|
||||
try {
|
||||
store_result_in_db(db,
|
||||
(*static_cast<Function*>(sqlite3_user_data(db)))(std::forward<Values>(values)...));
|
||||
} catch(const sqlite_exception &e) {
|
||||
sqlite3_result_error_code(db, e.get_code());
|
||||
sqlite3_result_error(db, e.what(), -1);
|
||||
} catch(const std::exception &e) {
|
||||
sqlite3_result_error(db, e.what(), -1);
|
||||
} catch(...) {
|
||||
sqlite3_result_error(db, "Unknown error", -1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
69
src/sqlite/hdr/sqlite_modern_cpp/errors.h
Normal file
69
src/sqlite/hdr/sqlite_modern_cpp/errors.h
Normal file
|
@ -0,0 +1,69 @@
|
|||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <stdexcept>
|
||||
|
||||
#include <sqlite/sqlite3.h>
|
||||
|
||||
namespace sqlite {
|
||||
|
||||
class sqlite_exception: public std::runtime_error {
|
||||
public:
|
||||
sqlite_exception(const char* msg, str_ref sql, int code = -1): runtime_error(msg), code(code), sql(sql) {}
|
||||
sqlite_exception(int code, str_ref sql): runtime_error(sqlite3_errstr(code)), code(code), sql(sql) {}
|
||||
int get_code() const {return code & 0xFF;}
|
||||
int get_extended_code() const {return code;}
|
||||
std::string get_sql() const {return sql;}
|
||||
private:
|
||||
int code;
|
||||
std::string sql;
|
||||
};
|
||||
|
||||
namespace errors {
|
||||
//One more or less trivial derived error class for each SQLITE error.
|
||||
//Note the following are not errors so have no classes:
|
||||
//SQLITE_OK, SQLITE_NOTICE, SQLITE_WARNING, SQLITE_ROW, SQLITE_DONE
|
||||
//
|
||||
//Note these names are exact matches to the names of the SQLITE error codes.
|
||||
#define SQLITE_MODERN_CPP_ERROR_CODE(NAME,name,derived) \
|
||||
class name: public sqlite_exception { using sqlite_exception::sqlite_exception; };\
|
||||
derived
|
||||
#define SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED(BASE,SUB,base,sub) \
|
||||
class base ## _ ## sub: public base { using base::base; };
|
||||
#include "lists/error_codes.h"
|
||||
#undef SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED
|
||||
#undef SQLITE_MODERN_CPP_ERROR_CODE
|
||||
|
||||
//Some additional errors are here for the C++ interface
|
||||
class more_rows: public sqlite_exception { using sqlite_exception::sqlite_exception; };
|
||||
class no_rows: public sqlite_exception { using sqlite_exception::sqlite_exception; };
|
||||
class more_statements: public sqlite_exception { using sqlite_exception::sqlite_exception; }; // Prepared statements can only contain one statement
|
||||
class invalid_utf16: public sqlite_exception { using sqlite_exception::sqlite_exception; };
|
||||
class unknown_binding: public sqlite_exception { using sqlite_exception::sqlite_exception; };
|
||||
|
||||
static void throw_sqlite_error(const int& error_code, str_ref sql = "") {
|
||||
switch(error_code & 0xFF) {
|
||||
#define SQLITE_MODERN_CPP_ERROR_CODE(NAME,name,derived) \
|
||||
case SQLITE_ ## NAME: switch(error_code) { \
|
||||
derived \
|
||||
case SQLITE_ ## NAME: \
|
||||
default: throw name(error_code, sql); \
|
||||
}
|
||||
|
||||
#if SQLITE_VERSION_NUMBER < 3010000
|
||||
#define SQLITE_IOERR_VNODE (SQLITE_IOERR | (27<<8))
|
||||
#define SQLITE_IOERR_AUTH (SQLITE_IOERR | (28<<8))
|
||||
#define SQLITE_AUTH_USER (SQLITE_AUTH | (1<<8))
|
||||
#endif
|
||||
|
||||
#define SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED(BASE,SUB,base,sub) \
|
||||
case SQLITE_ ## BASE ## _ ## SUB: throw base ## _ ## sub(error_code, sql);
|
||||
#include "lists/error_codes.h"
|
||||
#undef SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED
|
||||
#undef SQLITE_MODERN_CPP_ERROR_CODE
|
||||
default: throw sqlite_exception(error_code, sql);
|
||||
}
|
||||
}
|
||||
}
|
||||
namespace exceptions = errors;
|
||||
}
|
88
src/sqlite/hdr/sqlite_modern_cpp/lists/error_codes.h
Normal file
88
src/sqlite/hdr/sqlite_modern_cpp/lists/error_codes.h
Normal file
|
@ -0,0 +1,88 @@
|
|||
SQLITE_MODERN_CPP_ERROR_CODE(ERROR,error,)
|
||||
SQLITE_MODERN_CPP_ERROR_CODE(INTERNAL,internal,)
|
||||
SQLITE_MODERN_CPP_ERROR_CODE(PERM,perm,)
|
||||
SQLITE_MODERN_CPP_ERROR_CODE(ABORT,abort,
|
||||
SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED(ABORT,ROLLBACK,abort,rollback)
|
||||
)
|
||||
SQLITE_MODERN_CPP_ERROR_CODE(BUSY,busy,
|
||||
SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED(BUSY,RECOVERY,busy,recovery)
|
||||
SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED(BUSY,SNAPSHOT,busy,snapshot)
|
||||
)
|
||||
SQLITE_MODERN_CPP_ERROR_CODE(LOCKED,locked,
|
||||
SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED(LOCKED,SHAREDCACHE,locked,sharedcache)
|
||||
)
|
||||
SQLITE_MODERN_CPP_ERROR_CODE(NOMEM,nomem,)
|
||||
SQLITE_MODERN_CPP_ERROR_CODE(READONLY,readonly,)
|
||||
SQLITE_MODERN_CPP_ERROR_CODE(INTERRUPT,interrupt,)
|
||||
SQLITE_MODERN_CPP_ERROR_CODE(IOERR,ioerr,
|
||||
SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED(IOERR,READ,ioerr,read)
|
||||
SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED(IOERR,SHORT_READ,ioerr,short_read)
|
||||
SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED(IOERR,WRITE,ioerr,write)
|
||||
SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED(IOERR,FSYNC,ioerr,fsync)
|
||||
SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED(IOERR,DIR_FSYNC,ioerr,dir_fsync)
|
||||
SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED(IOERR,TRUNCATE,ioerr,truncate)
|
||||
SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED(IOERR,FSTAT,ioerr,fstat)
|
||||
SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED(IOERR,UNLOCK,ioerr,unlock)
|
||||
SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED(IOERR,RDLOCK,ioerr,rdlock)
|
||||
SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED(IOERR,DELETE,ioerr,delete)
|
||||
SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED(IOERR,BLOCKED,ioerr,blocked)
|
||||
SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED(IOERR,NOMEM,ioerr,nomem)
|
||||
SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED(IOERR,ACCESS,ioerr,access)
|
||||
SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED(IOERR,CHECKRESERVEDLOCK,ioerr,checkreservedlock)
|
||||
SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED(IOERR,LOCK,ioerr,lock)
|
||||
SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED(IOERR,CLOSE,ioerr,close)
|
||||
SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED(IOERR,DIR_CLOSE,ioerr,dir_close)
|
||||
SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED(IOERR,SHMOPEN,ioerr,shmopen)
|
||||
SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED(IOERR,SHMSIZE,ioerr,shmsize)
|
||||
SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED(IOERR,SHMLOCK,ioerr,shmlock)
|
||||
SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED(IOERR,SHMMAP,ioerr,shmmap)
|
||||
SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED(IOERR,SEEK,ioerr,seek)
|
||||
SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED(IOERR,DELETE_NOENT,ioerr,delete_noent)
|
||||
SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED(IOERR,MMAP,ioerr,mmap)
|
||||
SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED(IOERR,GETTEMPPATH,ioerr,gettemppath)
|
||||
SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED(IOERR,CONVPATH,ioerr,convpath)
|
||||
SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED(IOERR,VNODE,ioerr,vnode)
|
||||
SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED(IOERR,AUTH,ioerr,auth)
|
||||
)
|
||||
SQLITE_MODERN_CPP_ERROR_CODE(CORRUPT,corrupt,
|
||||
SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED(CORRUPT,VTAB,corrupt,vtab)
|
||||
)
|
||||
SQLITE_MODERN_CPP_ERROR_CODE(NOTFOUND,notfound,)
|
||||
SQLITE_MODERN_CPP_ERROR_CODE(FULL,full,)
|
||||
SQLITE_MODERN_CPP_ERROR_CODE(CANTOPEN,cantopen,
|
||||
SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED(CANTOPEN,NOTEMPDIR,cantopen,notempdir)
|
||||
SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED(CANTOPEN,ISDIR,cantopen,isdir)
|
||||
SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED(CANTOPEN,FULLPATH,cantopen,fullpath)
|
||||
SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED(CANTOPEN,CONVPATH,cantopen,convpath)
|
||||
)
|
||||
SQLITE_MODERN_CPP_ERROR_CODE(PROTOCOL,protocol,)
|
||||
SQLITE_MODERN_CPP_ERROR_CODE(EMPTY,empty,)
|
||||
SQLITE_MODERN_CPP_ERROR_CODE(SCHEMA,schema,)
|
||||
SQLITE_MODERN_CPP_ERROR_CODE(TOOBIG,toobig,)
|
||||
SQLITE_MODERN_CPP_ERROR_CODE(CONSTRAINT,constraint,
|
||||
SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED(CONSTRAINT,CHECK,constraint,check)
|
||||
SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED(CONSTRAINT,COMMITHOOK,constraint,commithook)
|
||||
SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED(CONSTRAINT,FOREIGNKEY,constraint,foreignkey)
|
||||
SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED(CONSTRAINT,FUNCTION,constraint,function)
|
||||
SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED(CONSTRAINT,NOTNULL,constraint,notnull)
|
||||
SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED(CONSTRAINT,PRIMARYKEY,constraint,primarykey)
|
||||
SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED(CONSTRAINT,TRIGGER,constraint,trigger)
|
||||
SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED(CONSTRAINT,UNIQUE,constraint,unique)
|
||||
SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED(CONSTRAINT,VTAB,constraint,vtab)
|
||||
SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED(CONSTRAINT,ROWID,constraint,rowid)
|
||||
)
|
||||
SQLITE_MODERN_CPP_ERROR_CODE(MISMATCH,mismatch,)
|
||||
SQLITE_MODERN_CPP_ERROR_CODE(MISUSE,misuse,)
|
||||
SQLITE_MODERN_CPP_ERROR_CODE(NOLFS,nolfs,)
|
||||
SQLITE_MODERN_CPP_ERROR_CODE(AUTH,auth,
|
||||
)
|
||||
SQLITE_MODERN_CPP_ERROR_CODE(FORMAT,format,)
|
||||
SQLITE_MODERN_CPP_ERROR_CODE(RANGE,range,)
|
||||
SQLITE_MODERN_CPP_ERROR_CODE(NOTADB,notadb,)
|
||||
SQLITE_MODERN_CPP_ERROR_CODE(NOTICE,notice,
|
||||
SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED(NOTICE,RECOVER_WAL,notice,recover_wal)
|
||||
SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED(NOTICE,RECOVER_ROLLBACK,notice,recover_rollback)
|
||||
)
|
||||
SQLITE_MODERN_CPP_ERROR_CODE(WARNING,warning,
|
||||
SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED(WARNING,AUTOINDEX,warning,autoindex)
|
||||
)
|
101
src/sqlite/hdr/sqlite_modern_cpp/log.h
Normal file
101
src/sqlite/hdr/sqlite_modern_cpp/log.h
Normal file
|
@ -0,0 +1,101 @@
|
|||
#include "errors.h"
|
||||
|
||||
#include <sqlite/sqlite3.h>
|
||||
|
||||
#include <utility>
|
||||
#include <tuple>
|
||||
#include <type_traits>
|
||||
|
||||
namespace sqlite {
|
||||
namespace detail {
|
||||
template<class>
|
||||
using void_t = void;
|
||||
template<class T, class = void>
|
||||
struct is_callable : std::false_type {};
|
||||
template<class Functor, class ...Arguments>
|
||||
struct is_callable<Functor(Arguments...), void_t<decltype(std::declval<Functor>()(std::declval<Arguments>()...))>> : std::true_type {};
|
||||
template<class Functor, class ...Functors>
|
||||
class FunctorOverload: public Functor, public FunctorOverload<Functors...> {
|
||||
public:
|
||||
template<class Functor1, class ...Remaining>
|
||||
FunctorOverload(Functor1 &&functor, Remaining &&... remaining):
|
||||
Functor(std::forward<Functor1>(functor)),
|
||||
FunctorOverload<Functors...>(std::forward<Remaining>(remaining)...) {}
|
||||
using Functor::operator();
|
||||
using FunctorOverload<Functors...>::operator();
|
||||
};
|
||||
template<class Functor>
|
||||
class FunctorOverload<Functor>: public Functor {
|
||||
public:
|
||||
template<class Functor1>
|
||||
FunctorOverload(Functor1 &&functor):
|
||||
Functor(std::forward<Functor1>(functor)) {}
|
||||
using Functor::operator();
|
||||
};
|
||||
template<class Functor>
|
||||
class WrapIntoFunctor: public Functor {
|
||||
public:
|
||||
template<class Functor1>
|
||||
WrapIntoFunctor(Functor1 &&functor):
|
||||
Functor(std::forward<Functor1>(functor)) {}
|
||||
using Functor::operator();
|
||||
};
|
||||
template<class ReturnType, class ...Arguments>
|
||||
class WrapIntoFunctor<ReturnType(*)(Arguments...)> {
|
||||
ReturnType(*ptr)(Arguments...);
|
||||
public:
|
||||
WrapIntoFunctor(ReturnType(*ptr)(Arguments...)): ptr(ptr) {}
|
||||
ReturnType operator()(Arguments... arguments) { return (*ptr)(std::forward<Arguments>(arguments)...); }
|
||||
};
|
||||
inline void store_error_log_data_pointer(std::shared_ptr<void> ptr) {
|
||||
static std::shared_ptr<void> stored;
|
||||
stored = std::move(ptr);
|
||||
}
|
||||
template<class T>
|
||||
std::shared_ptr<typename std::decay<T>::type> make_shared_inferred(T &&t) {
|
||||
return std::make_shared<typename std::decay<T>::type>(std::forward<T>(t));
|
||||
}
|
||||
}
|
||||
template<class Handler>
|
||||
typename std::enable_if<!detail::is_callable<Handler(const sqlite_exception&)>::value>::type
|
||||
error_log(Handler &&handler);
|
||||
template<class Handler>
|
||||
typename std::enable_if<detail::is_callable<Handler(const sqlite_exception&)>::value>::type
|
||||
error_log(Handler &&handler);
|
||||
template<class ...Handler>
|
||||
typename std::enable_if<sizeof...(Handler)>=2>::type
|
||||
error_log(Handler &&...handler) {
|
||||
return error_log(detail::FunctorOverload<detail::WrapIntoFunctor<typename std::decay<Handler>::type>...>(std::forward<Handler>(handler)...));
|
||||
}
|
||||
template<class Handler>
|
||||
typename std::enable_if<!detail::is_callable<Handler(const sqlite_exception&)>::value>::type
|
||||
error_log(Handler &&handler) {
|
||||
return error_log(std::forward<Handler>(handler), [](const sqlite_exception&) {});
|
||||
}
|
||||
template<class Handler>
|
||||
typename std::enable_if<detail::is_callable<Handler(const sqlite_exception&)>::value>::type
|
||||
error_log(Handler &&handler) {
|
||||
auto ptr = detail::make_shared_inferred([handler = std::forward<Handler>(handler)](int error_code, const char *errstr) mutable {
|
||||
switch(error_code & 0xFF) {
|
||||
#define SQLITE_MODERN_CPP_ERROR_CODE(NAME,name,derived) \
|
||||
case SQLITE_ ## NAME: switch(error_code) { \
|
||||
derived \
|
||||
default: handler(errors::name(errstr, "", error_code)); \
|
||||
};break;
|
||||
#define SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED(BASE,SUB,base,sub) \
|
||||
case SQLITE_ ## BASE ## _ ## SUB: \
|
||||
handler(errors::base ## _ ## sub(errstr, "", error_code)); \
|
||||
break;
|
||||
#include "lists/error_codes.h"
|
||||
#undef SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED
|
||||
#undef SQLITE_MODERN_CPP_ERROR_CODE
|
||||
default: handler(sqlite_exception(errstr, "", error_code)); \
|
||||
}
|
||||
});
|
||||
|
||||
sqlite3_config(SQLITE_CONFIG_LOG, static_cast<void(*)(void*,int,const char*)>([](void *functor, int error_code, const char *errstr) {
|
||||
(*static_cast<decltype(ptr.get())>(functor))(error_code, errstr);
|
||||
}), ptr.get());
|
||||
detail::store_error_log_data_pointer(std::move(ptr));
|
||||
}
|
||||
}
|
44
src/sqlite/hdr/sqlite_modern_cpp/sqlcipher.h
Normal file
44
src/sqlite/hdr/sqlite_modern_cpp/sqlcipher.h
Normal file
|
@ -0,0 +1,44 @@
|
|||
#pragma once
|
||||
|
||||
#ifndef SQLITE_HAS_CODEC
|
||||
#define SQLITE_HAS_CODEC
|
||||
#endif
|
||||
|
||||
#include "../sqlite_modern_cpp.h"
|
||||
|
||||
namespace sqlite {
|
||||
struct sqlcipher_config : public sqlite_config {
|
||||
std::string key;
|
||||
};
|
||||
|
||||
class sqlcipher_database : public database {
|
||||
public:
|
||||
sqlcipher_database(std::string db, const sqlcipher_config &config): database(db, config) {
|
||||
set_key(config.key);
|
||||
}
|
||||
|
||||
sqlcipher_database(std::u16string db, const sqlcipher_config &config): database(db, config) {
|
||||
set_key(config.key);
|
||||
}
|
||||
|
||||
void set_key(const std::string &key) {
|
||||
if(auto ret = sqlite3_key(_db.get(), key.data(), key.size()))
|
||||
errors::throw_sqlite_error(ret);
|
||||
}
|
||||
|
||||
void set_key(const std::string &key, const std::string &db_name) {
|
||||
if(auto ret = sqlite3_key_v2(_db.get(), db_name.c_str(), key.data(), key.size()))
|
||||
errors::throw_sqlite_error(ret);
|
||||
}
|
||||
|
||||
void rekey(const std::string &new_key) {
|
||||
if(auto ret = sqlite3_rekey(_db.get(), new_key.data(), new_key.size()))
|
||||
errors::throw_sqlite_error(ret);
|
||||
}
|
||||
|
||||
void rekey(const std::string &new_key, const std::string &db_name) {
|
||||
if(auto ret = sqlite3_rekey_v2(_db.get(), db_name.c_str(), new_key.data(), new_key.size()))
|
||||
errors::throw_sqlite_error(ret);
|
||||
}
|
||||
};
|
||||
}
|
418
src/sqlite/hdr/sqlite_modern_cpp/type_wrapper.h
Normal file
418
src/sqlite/hdr/sqlite_modern_cpp/type_wrapper.h
Normal file
|
@ -0,0 +1,418 @@
|
|||
#pragma once
|
||||
|
||||
#include <type_traits>
|
||||
#include <string>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#ifdef __has_include
|
||||
#if __cplusplus >= 201703 && __has_include(<string_view>)
|
||||
#define MODERN_SQLITE_STRINGVIEW_SUPPORT
|
||||
#endif
|
||||
#endif
|
||||
#ifdef __has_include
|
||||
#if __cplusplus > 201402 && __has_include(<optional>)
|
||||
#define MODERN_SQLITE_STD_OPTIONAL_SUPPORT
|
||||
#elif __has_include(<experimental/optional>)
|
||||
#define MODERN_SQLITE_EXPERIMENTAL_OPTIONAL_SUPPORT
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef __has_include
|
||||
#if __cplusplus > 201402 && __has_include(<variant>)
|
||||
#define MODERN_SQLITE_STD_VARIANT_SUPPORT
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef MODERN_SQLITE_STD_OPTIONAL_SUPPORT
|
||||
#include <optional>
|
||||
#endif
|
||||
|
||||
#ifdef MODERN_SQLITE_EXPERIMENTAL_OPTIONAL_SUPPORT
|
||||
#include <experimental/optional>
|
||||
#define MODERN_SQLITE_STD_OPTIONAL_SUPPORT
|
||||
#endif
|
||||
|
||||
#ifdef MODERN_SQLITE_STD_VARIANT_SUPPORT
|
||||
#include <variant>
|
||||
#endif
|
||||
#ifdef MODERN_SQLITE_STRINGVIEW_SUPPORT
|
||||
#include <string_view>
|
||||
namespace sqlite
|
||||
{
|
||||
typedef const std::string_view str_ref;
|
||||
typedef const std::u16string_view u16str_ref;
|
||||
}
|
||||
#else
|
||||
namespace sqlite
|
||||
{
|
||||
typedef const std::string& str_ref;
|
||||
typedef const std::u16string& u16str_ref;
|
||||
}
|
||||
#endif
|
||||
#include <sqlite/sqlite3.h>
|
||||
#include "errors.h"
|
||||
|
||||
namespace sqlite {
|
||||
template<class T, int Type, class = void>
|
||||
struct has_sqlite_type : std::false_type {};
|
||||
|
||||
template<class T>
|
||||
using is_sqlite_value = std::integral_constant<bool, false
|
||||
|| has_sqlite_type<T, SQLITE_NULL>::value
|
||||
|| has_sqlite_type<T, SQLITE_INTEGER>::value
|
||||
|| has_sqlite_type<T, SQLITE_FLOAT>::value
|
||||
|| has_sqlite_type<T, SQLITE_TEXT>::value
|
||||
|| has_sqlite_type<T, SQLITE_BLOB>::value
|
||||
>;
|
||||
|
||||
template<class T, int Type>
|
||||
struct has_sqlite_type<T&, Type> : has_sqlite_type<T, Type> {};
|
||||
template<class T, int Type>
|
||||
struct has_sqlite_type<const T, Type> : has_sqlite_type<T, Type> {};
|
||||
template<class T, int Type>
|
||||
struct has_sqlite_type<volatile T, Type> : has_sqlite_type<T, Type> {};
|
||||
|
||||
template<class T>
|
||||
struct result_type {
|
||||
using type = T;
|
||||
constexpr result_type() = default;
|
||||
template<class U, class = typename std::enable_if<std::is_assignable<U, T>::value>>
|
||||
constexpr result_type(result_type<U>) { }
|
||||
};
|
||||
|
||||
// int
|
||||
template<>
|
||||
struct has_sqlite_type<int, SQLITE_INTEGER> : std::true_type {};
|
||||
|
||||
inline int bind_col_in_db(sqlite3_stmt* stmt, int inx, const int& val) {
|
||||
return sqlite3_bind_int(stmt, inx, val);
|
||||
}
|
||||
inline void store_result_in_db(sqlite3_context* db, const int& val) {
|
||||
sqlite3_result_int(db, val);
|
||||
}
|
||||
inline int get_col_from_db(sqlite3_stmt* stmt, int inx, result_type<int>) {
|
||||
return sqlite3_column_type(stmt, inx) == SQLITE_NULL ? 0 :
|
||||
sqlite3_column_int(stmt, inx);
|
||||
}
|
||||
inline int get_val_from_db(sqlite3_value *value, result_type<int>) {
|
||||
return sqlite3_value_type(value) == SQLITE_NULL ? 0 :
|
||||
sqlite3_value_int(value);
|
||||
}
|
||||
|
||||
// sqlite_int64
|
||||
template<>
|
||||
struct has_sqlite_type<sqlite_int64, SQLITE_INTEGER, void> : std::true_type {};
|
||||
|
||||
inline int bind_col_in_db(sqlite3_stmt* stmt, int inx, const sqlite_int64& val) {
|
||||
return sqlite3_bind_int64(stmt, inx, val);
|
||||
}
|
||||
inline void store_result_in_db(sqlite3_context* db, const sqlite_int64& val) {
|
||||
sqlite3_result_int64(db, val);
|
||||
}
|
||||
inline sqlite_int64 get_col_from_db(sqlite3_stmt* stmt, int inx, result_type<sqlite_int64 >) {
|
||||
return sqlite3_column_type(stmt, inx) == SQLITE_NULL ? 0 :
|
||||
sqlite3_column_int64(stmt, inx);
|
||||
}
|
||||
inline sqlite3_int64 get_val_from_db(sqlite3_value *value, result_type<sqlite3_int64>) {
|
||||
return sqlite3_value_type(value) == SQLITE_NULL ? 0 :
|
||||
sqlite3_value_int64(value);
|
||||
}
|
||||
|
||||
// float
|
||||
template<>
|
||||
struct has_sqlite_type<float, SQLITE_FLOAT, void> : std::true_type {};
|
||||
|
||||
inline int bind_col_in_db(sqlite3_stmt* stmt, int inx, const float& val) {
|
||||
return sqlite3_bind_double(stmt, inx, double(val));
|
||||
}
|
||||
inline void store_result_in_db(sqlite3_context* db, const float& val) {
|
||||
sqlite3_result_double(db, val);
|
||||
}
|
||||
inline float get_col_from_db(sqlite3_stmt* stmt, int inx, result_type<float>) {
|
||||
return sqlite3_column_type(stmt, inx) == SQLITE_NULL ? 0 :
|
||||
sqlite3_column_double(stmt, inx);
|
||||
}
|
||||
inline float get_val_from_db(sqlite3_value *value, result_type<float>) {
|
||||
return sqlite3_value_type(value) == SQLITE_NULL ? 0 :
|
||||
sqlite3_value_double(value);
|
||||
}
|
||||
|
||||
// double
|
||||
template<>
|
||||
struct has_sqlite_type<double, SQLITE_FLOAT, void> : std::true_type {};
|
||||
|
||||
inline int bind_col_in_db(sqlite3_stmt* stmt, int inx, const double& val) {
|
||||
return sqlite3_bind_double(stmt, inx, val);
|
||||
}
|
||||
inline void store_result_in_db(sqlite3_context* db, const double& val) {
|
||||
sqlite3_result_double(db, val);
|
||||
}
|
||||
inline double get_col_from_db(sqlite3_stmt* stmt, int inx, result_type<double>) {
|
||||
return sqlite3_column_type(stmt, inx) == SQLITE_NULL ? 0 :
|
||||
sqlite3_column_double(stmt, inx);
|
||||
}
|
||||
inline double get_val_from_db(sqlite3_value *value, result_type<double>) {
|
||||
return sqlite3_value_type(value) == SQLITE_NULL ? 0 :
|
||||
sqlite3_value_double(value);
|
||||
}
|
||||
|
||||
/* for nullptr support */
|
||||
template<>
|
||||
struct has_sqlite_type<std::nullptr_t, SQLITE_NULL, void> : std::true_type {};
|
||||
|
||||
inline int bind_col_in_db(sqlite3_stmt* stmt, int inx, std::nullptr_t) {
|
||||
return sqlite3_bind_null(stmt, inx);
|
||||
}
|
||||
inline void store_result_in_db(sqlite3_context* db, std::nullptr_t) {
|
||||
sqlite3_result_null(db);
|
||||
}
|
||||
|
||||
#ifdef MODERN_SQLITE_STD_VARIANT_SUPPORT
|
||||
template<>
|
||||
struct has_sqlite_type<std::monostate, SQLITE_NULL, void> : std::true_type {};
|
||||
|
||||
inline int bind_col_in_db(sqlite3_stmt* stmt, int inx, std::monostate) {
|
||||
return sqlite3_bind_null(stmt, inx);
|
||||
}
|
||||
inline void store_result_in_db(sqlite3_context* db, std::monostate) {
|
||||
sqlite3_result_null(db);
|
||||
}
|
||||
inline std::monostate get_col_from_db(sqlite3_stmt* stmt, int inx, result_type<std::monostate>) {
|
||||
return std::monostate();
|
||||
}
|
||||
inline std::monostate get_val_from_db(sqlite3_value *value, result_type<std::monostate>) {
|
||||
return std::monostate();
|
||||
}
|
||||
#endif
|
||||
|
||||
// str_ref
|
||||
template<>
|
||||
struct has_sqlite_type<std::string, SQLITE3_TEXT, void> : std::true_type {};
|
||||
inline int bind_col_in_db(sqlite3_stmt* stmt, int inx, str_ref val) {
|
||||
return sqlite3_bind_text(stmt, inx, val.data(), val.length(), SQLITE_STATIC);
|
||||
}
|
||||
|
||||
// Convert char* to string_view to trigger op<<(..., const str_ref )
|
||||
template<std::size_t N> inline int bind_col_in_db(sqlite3_stmt* stmt, int inx, const char(&STR)[N]) {
|
||||
return sqlite3_bind_text(stmt, inx, &STR[0], N-1, SQLITE_STATIC);
|
||||
}
|
||||
|
||||
inline std::string get_col_from_db(sqlite3_stmt* stmt, int inx, result_type<std::string>) {
|
||||
return sqlite3_column_type(stmt, inx) == SQLITE_NULL ? std::string() :
|
||||
std::string(reinterpret_cast<char const *>(sqlite3_column_text(stmt, inx)), sqlite3_column_bytes(stmt, inx));
|
||||
}
|
||||
inline std::string get_val_from_db(sqlite3_value *value, result_type<std::string >) {
|
||||
return sqlite3_value_type(value) == SQLITE_NULL ? std::string() :
|
||||
std::string(reinterpret_cast<char const *>(sqlite3_value_text(value)), sqlite3_value_bytes(value));
|
||||
}
|
||||
|
||||
inline void store_result_in_db(sqlite3_context* db, str_ref val) {
|
||||
sqlite3_result_text(db, val.data(), val.length(), SQLITE_TRANSIENT);
|
||||
}
|
||||
// u16str_ref
|
||||
template<>
|
||||
struct has_sqlite_type<std::u16string, SQLITE3_TEXT, void> : std::true_type {};
|
||||
inline int bind_col_in_db(sqlite3_stmt* stmt, int inx, u16str_ref val) {
|
||||
return sqlite3_bind_text16(stmt, inx, val.data(), sizeof(char16_t) * val.length(), SQLITE_STATIC);
|
||||
}
|
||||
|
||||
// Convert char* to string_view to trigger op<<(..., const str_ref )
|
||||
template<std::size_t N> inline int bind_col_in_db(sqlite3_stmt* stmt, int inx, const char16_t(&STR)[N]) {
|
||||
return sqlite3_bind_text16(stmt, inx, &STR[0], sizeof(char16_t) * (N-1), SQLITE_STATIC);
|
||||
}
|
||||
|
||||
inline std::u16string get_col_from_db(sqlite3_stmt* stmt, int inx, result_type<std::u16string>) {
|
||||
return sqlite3_column_type(stmt, inx) == SQLITE_NULL ? std::u16string() :
|
||||
std::u16string(reinterpret_cast<char16_t const *>(sqlite3_column_text16(stmt, inx)), sqlite3_column_bytes16(stmt, inx));
|
||||
}
|
||||
inline std::u16string get_val_from_db(sqlite3_value *value, result_type<std::u16string>) {
|
||||
return sqlite3_value_type(value) == SQLITE_NULL ? std::u16string() :
|
||||
std::u16string(reinterpret_cast<char16_t const *>(sqlite3_value_text16(value)), sqlite3_value_bytes16(value));
|
||||
}
|
||||
|
||||
inline void store_result_in_db(sqlite3_context* db, u16str_ref val) {
|
||||
sqlite3_result_text16(db, val.data(), sizeof(char16_t) * val.length(), SQLITE_TRANSIENT);
|
||||
}
|
||||
|
||||
// Other integer types
|
||||
template<class Integral>
|
||||
struct has_sqlite_type<Integral, SQLITE_INTEGER, typename std::enable_if<std::is_integral<Integral>::value>::type> : std::true_type {};
|
||||
|
||||
template<class Integral, class = typename std::enable_if<std::is_integral<Integral>::value>::type>
|
||||
inline int bind_col_in_db(sqlite3_stmt* stmt, int inx, const Integral& val) {
|
||||
return bind_col_in_db(stmt, inx, static_cast<sqlite3_int64>(val));
|
||||
}
|
||||
template<class Integral, class = std::enable_if<std::is_integral<Integral>::type>>
|
||||
inline void store_result_in_db(sqlite3_context* db, const Integral& val) {
|
||||
store_result_in_db(db, static_cast<sqlite3_int64>(val));
|
||||
}
|
||||
template<class Integral, class = typename std::enable_if<std::is_integral<Integral>::value>::type>
|
||||
inline Integral get_col_from_db(sqlite3_stmt* stmt, int inx, result_type<Integral>) {
|
||||
return get_col_from_db(stmt, inx, result_type<sqlite3_int64>());
|
||||
}
|
||||
template<class Integral, class = typename std::enable_if<std::is_integral<Integral>::value>::type>
|
||||
inline Integral get_val_from_db(sqlite3_value *value, result_type<Integral>) {
|
||||
return get_val_from_db(value, result_type<sqlite3_int64>());
|
||||
}
|
||||
|
||||
// vector<T, A>
|
||||
template<typename T, typename A>
|
||||
struct has_sqlite_type<std::vector<T, A>, SQLITE_BLOB, void> : std::true_type {};
|
||||
|
||||
template<typename T, typename A> inline int bind_col_in_db(sqlite3_stmt* stmt, int inx, const std::vector<T, A>& vec) {
|
||||
void const* buf = reinterpret_cast<void const *>(vec.data());
|
||||
int bytes = vec.size() * sizeof(T);
|
||||
return sqlite3_bind_blob(stmt, inx, buf, bytes, SQLITE_STATIC);
|
||||
}
|
||||
template<typename T, typename A> inline void store_result_in_db(sqlite3_context* db, const std::vector<T, A>& vec) {
|
||||
void const* buf = reinterpret_cast<void const *>(vec.data());
|
||||
int bytes = vec.size() * sizeof(T);
|
||||
sqlite3_result_blob(db, buf, bytes, SQLITE_TRANSIENT);
|
||||
}
|
||||
template<typename T, typename A> inline std::vector<T, A> get_col_from_db(sqlite3_stmt* stmt, int inx, result_type<std::vector<T, A>>) {
|
||||
if(sqlite3_column_type(stmt, inx) == SQLITE_NULL) {
|
||||
return {};
|
||||
}
|
||||
int bytes = sqlite3_column_bytes(stmt, inx);
|
||||
T const* buf = reinterpret_cast<T const *>(sqlite3_column_blob(stmt, inx));
|
||||
return std::vector<T, A>(buf, buf + bytes/sizeof(T));
|
||||
}
|
||||
template<typename T, typename A> inline std::vector<T, A> get_val_from_db(sqlite3_value *value, result_type<std::vector<T, A>>) {
|
||||
if(sqlite3_value_type(value) == SQLITE_NULL) {
|
||||
return {};
|
||||
}
|
||||
int bytes = sqlite3_value_bytes(value);
|
||||
T const* buf = reinterpret_cast<T const *>(sqlite3_value_blob(value));
|
||||
return std::vector<T, A>(buf, buf + bytes/sizeof(T));
|
||||
}
|
||||
|
||||
/* for unique_ptr<T> support */
|
||||
template<typename T, int Type>
|
||||
struct has_sqlite_type<std::unique_ptr<T>, Type, void> : has_sqlite_type<T, Type> {};
|
||||
template<typename T>
|
||||
struct has_sqlite_type<std::unique_ptr<T>, SQLITE_NULL, void> : std::true_type {};
|
||||
|
||||
template<typename T> inline int bind_col_in_db(sqlite3_stmt* stmt, int inx, const std::unique_ptr<T>& val) {
|
||||
return val ? bind_col_in_db(stmt, inx, *val) : bind_col_in_db(stmt, inx, nullptr);
|
||||
}
|
||||
template<typename T> inline std::unique_ptr<T> get_col_from_db(sqlite3_stmt* stmt, int inx, result_type<std::unique_ptr<T>>) {
|
||||
if(sqlite3_column_type(stmt, inx) == SQLITE_NULL) {
|
||||
return nullptr;
|
||||
}
|
||||
return std::make_unique<T>(get_col_from_db(stmt, inx, result_type<T>()));
|
||||
}
|
||||
template<typename T> inline std::unique_ptr<T> get_val_from_db(sqlite3_value *value, result_type<std::unique_ptr<T>>) {
|
||||
if(sqlite3_value_type(value) == SQLITE_NULL) {
|
||||
return nullptr;
|
||||
}
|
||||
return std::make_unique<T>(get_val_from_db(value, result_type<T>()));
|
||||
}
|
||||
|
||||
// std::optional support for NULL values
|
||||
#ifdef MODERN_SQLITE_STD_OPTIONAL_SUPPORT
|
||||
#ifdef MODERN_SQLITE_EXPERIMENTAL_OPTIONAL_SUPPORT
|
||||
template<class T>
|
||||
using optional = std::experimental::optional<T>;
|
||||
#else
|
||||
template<class T>
|
||||
using optional = std::optional<T>;
|
||||
#endif
|
||||
|
||||
template<typename T, int Type>
|
||||
struct has_sqlite_type<optional<T>, Type, void> : has_sqlite_type<T, Type> {};
|
||||
template<typename T>
|
||||
struct has_sqlite_type<optional<T>, SQLITE_NULL, void> : std::true_type {};
|
||||
|
||||
template <typename OptionalT> inline int bind_col_in_db(sqlite3_stmt* stmt, int inx, const optional<OptionalT>& val) {
|
||||
return val ? bind_col_in_db(stmt, inx, *val) : bind_col_in_db(stmt, inx, nullptr);
|
||||
}
|
||||
template <typename OptionalT> inline void store_result_in_db(sqlite3_context* db, const optional<OptionalT>& val) {
|
||||
if(val)
|
||||
store_result_in_db(db, *val);
|
||||
else
|
||||
sqlite3_result_null(db);
|
||||
}
|
||||
|
||||
template <typename OptionalT> inline optional<OptionalT> get_col_from_db(sqlite3_stmt* stmt, int inx, result_type<optional<OptionalT>>) {
|
||||
#ifdef MODERN_SQLITE_EXPERIMENTAL_OPTIONAL_SUPPORT
|
||||
if(sqlite3_column_type(stmt, inx) == SQLITE_NULL) {
|
||||
return std::experimental::nullopt;
|
||||
}
|
||||
return std::experimental::make_optional(get_col_from_db(stmt, inx, result_type<OptionalT>()));
|
||||
#else
|
||||
if(sqlite3_column_type(stmt, inx) == SQLITE_NULL) {
|
||||
return std::nullopt;
|
||||
}
|
||||
return std::make_optional(get_col_from_db(stmt, inx, result_type<OptionalT>()));
|
||||
#endif
|
||||
}
|
||||
template <typename OptionalT> inline optional<OptionalT> get_val_from_db(sqlite3_value *value, result_type<optional<OptionalT>>) {
|
||||
#ifdef MODERN_SQLITE_EXPERIMENTAL_OPTIONAL_SUPPORT
|
||||
if(sqlite3_value_type(value) == SQLITE_NULL) {
|
||||
return std::experimental::nullopt;
|
||||
}
|
||||
return std::experimental::make_optional(get_val_from_db(value, result_type<OptionalT>()));
|
||||
#else
|
||||
if(sqlite3_value_type(value) == SQLITE_NULL) {
|
||||
return std::nullopt;
|
||||
}
|
||||
return std::make_optional(get_val_from_db(value, result_type<OptionalT>()));
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef MODERN_SQLITE_STD_VARIANT_SUPPORT
|
||||
namespace detail {
|
||||
template<class T, class U>
|
||||
struct tag_trait : U { using tag = T; };
|
||||
}
|
||||
|
||||
template<int Type, class ...Options>
|
||||
struct has_sqlite_type<std::variant<Options...>, Type, void> : std::disjunction<detail::tag_trait<Options, has_sqlite_type<Options, Type>>...> {};
|
||||
|
||||
namespace detail {
|
||||
template<int Type, typename ...Options, typename Callback, typename first_compatible = has_sqlite_type<std::variant<Options...>, Type>>
|
||||
inline std::variant<Options...> variant_select_type(Callback &&callback) {
|
||||
if constexpr(first_compatible::value)
|
||||
return callback(result_type<typename first_compatible::tag>());
|
||||
else
|
||||
throw errors::mismatch("The value is unsupported by this variant.", "", SQLITE_MISMATCH);
|
||||
}
|
||||
template<typename ...Options, typename Callback> inline decltype(auto) variant_select(int type, Callback &&callback) {
|
||||
switch(type) {
|
||||
case SQLITE_NULL:
|
||||
return variant_select_type<SQLITE_NULL, Options...>(std::forward<Callback>(callback));
|
||||
case SQLITE_INTEGER:
|
||||
return variant_select_type<SQLITE_INTEGER, Options...>(std::forward<Callback>(callback));
|
||||
case SQLITE_FLOAT:
|
||||
return variant_select_type<SQLITE_FLOAT, Options...>(std::forward<Callback>(callback));
|
||||
case SQLITE_TEXT:
|
||||
return variant_select_type<SQLITE_TEXT, Options...>(std::forward<Callback>(callback));
|
||||
case SQLITE_BLOB:
|
||||
return variant_select_type<SQLITE_BLOB, Options...>(std::forward<Callback>(callback));
|
||||
}
|
||||
#ifdef _MSC_VER
|
||||
__assume(false);
|
||||
#else
|
||||
__builtin_unreachable();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
template <typename ...Args> inline int bind_col_in_db(sqlite3_stmt* stmt, int inx, const std::variant<Args...>& val) {
|
||||
return std::visit([&](auto &&opt) {return bind_col_in_db(stmt, inx, std::forward<decltype(opt)>(opt));}, val);
|
||||
}
|
||||
template <typename ...Args> inline void store_result_in_db(sqlite3_context* db, const std::variant<Args...>& val) {
|
||||
std::visit([&](auto &&opt) {store_result_in_db(db, std::forward<decltype(opt)>(opt));}, val);
|
||||
}
|
||||
template <typename ...Args> inline std::variant<Args...> get_col_from_db(sqlite3_stmt* stmt, int inx, result_type<std::variant<Args...>>) {
|
||||
return detail::variant_select<Args...>(sqlite3_column_type(stmt, inx), [&](auto v) {
|
||||
return std::variant<Args...>(std::in_place_type<typename decltype(v)::type>, get_col_from_db(stmt, inx, v));
|
||||
});
|
||||
}
|
||||
template <typename ...Args> inline std::variant<Args...> get_val_from_db(sqlite3_value *value, result_type<std::variant<Args...>>) {
|
||||
return detail::variant_select<Args...>(sqlite3_value_type(value), [&](auto v) {
|
||||
return std::variant<Args...>(std::in_place_type<typename decltype(v)::type>, get_val_from_db(value, v));
|
||||
});
|
||||
}
|
||||
#endif
|
||||
}
|
56
src/sqlite/hdr/sqlite_modern_cpp/utility/function_traits.h
Normal file
56
src/sqlite/hdr/sqlite_modern_cpp/utility/function_traits.h
Normal file
|
@ -0,0 +1,56 @@
|
|||
#pragma once
|
||||
|
||||
#include <tuple>
|
||||
#include<type_traits>
|
||||
|
||||
namespace sqlite {
|
||||
namespace utility {
|
||||
|
||||
template<typename> struct function_traits;
|
||||
|
||||
template <typename Function>
|
||||
struct function_traits : public function_traits<
|
||||
decltype(&std::remove_reference<Function>::type::operator())
|
||||
> { };
|
||||
|
||||
template <
|
||||
typename ClassType,
|
||||
typename ReturnType,
|
||||
typename... Arguments
|
||||
>
|
||||
struct function_traits<
|
||||
ReturnType(ClassType::*)(Arguments...) const
|
||||
> : function_traits<ReturnType(*)(Arguments...)> { };
|
||||
|
||||
/* support the non-const operator ()
|
||||
* this will work with user defined functors */
|
||||
template <
|
||||
typename ClassType,
|
||||
typename ReturnType,
|
||||
typename... Arguments
|
||||
>
|
||||
struct function_traits<
|
||||
ReturnType(ClassType::*)(Arguments...)
|
||||
> : function_traits<ReturnType(*)(Arguments...)> { };
|
||||
|
||||
template <
|
||||
typename ReturnType,
|
||||
typename... Arguments
|
||||
>
|
||||
struct function_traits<
|
||||
ReturnType(*)(Arguments...)
|
||||
> {
|
||||
typedef ReturnType result_type;
|
||||
|
||||
using argument_tuple = std::tuple<Arguments...>;
|
||||
template <std::size_t Index>
|
||||
using argument = typename std::tuple_element<
|
||||
Index,
|
||||
argument_tuple
|
||||
>::type;
|
||||
|
||||
static const std::size_t arity = sizeof...(Arguments);
|
||||
};
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
#pragma once
|
||||
|
||||
#include <cassert>
|
||||
#include <exception>
|
||||
#include <iostream>
|
||||
|
||||
// Consider that std::uncaught_exceptions is available if explicitly indicated
|
||||
// by the standard library, if compiler advertises full C++17 support or, as a
|
||||
// special case, for MSVS 2015+ (which doesn't define __cplusplus correctly by
|
||||
// default as of 2017.7 version and couldn't do it at all until it).
|
||||
#ifndef MODERN_SQLITE_UNCAUGHT_EXCEPTIONS_SUPPORT
|
||||
#ifdef __cpp_lib_uncaught_exceptions
|
||||
#define MODERN_SQLITE_UNCAUGHT_EXCEPTIONS_SUPPORT
|
||||
#elif __cplusplus >= 201703L
|
||||
#define MODERN_SQLITE_UNCAUGHT_EXCEPTIONS_SUPPORT
|
||||
#elif defined(_MSC_VER) && _MSC_VER >= 1900
|
||||
#define MODERN_SQLITE_UNCAUGHT_EXCEPTIONS_SUPPORT
|
||||
#endif
|
||||
#endif
|
||||
|
||||
namespace sqlite {
|
||||
namespace utility {
|
||||
#ifdef MODERN_SQLITE_UNCAUGHT_EXCEPTIONS_SUPPORT
|
||||
class UncaughtExceptionDetector {
|
||||
public:
|
||||
operator bool() {
|
||||
return count != std::uncaught_exceptions();
|
||||
}
|
||||
private:
|
||||
int count = std::uncaught_exceptions();
|
||||
};
|
||||
#else
|
||||
class UncaughtExceptionDetector {
|
||||
public:
|
||||
operator bool() {
|
||||
return std::uncaught_exception();
|
||||
}
|
||||
};
|
||||
#endif
|
||||
}
|
||||
}
|
42
src/sqlite/hdr/sqlite_modern_cpp/utility/utf16_utf8.h
Normal file
42
src/sqlite/hdr/sqlite_modern_cpp/utility/utf16_utf8.h
Normal file
|
@ -0,0 +1,42 @@
|
|||
#pragma once
|
||||
|
||||
#include <locale>
|
||||
#include <string>
|
||||
#include <algorithm>
|
||||
|
||||
#include "../errors.h"
|
||||
|
||||
namespace sqlite {
|
||||
namespace utility {
|
||||
inline std::string utf16_to_utf8(u16str_ref input) {
|
||||
struct : std::codecvt<char16_t, char, std::mbstate_t> {
|
||||
} codecvt;
|
||||
std::mbstate_t state{};
|
||||
std::string result((std::max)(input.size() * 3 / 2, std::size_t(4)), '\0');
|
||||
const char16_t *remaining_input = input.data();
|
||||
std::size_t produced_output = 0;
|
||||
while(true) {
|
||||
char *used_output;
|
||||
switch(codecvt.out(state, remaining_input, &input[input.size()],
|
||||
remaining_input, &result[produced_output],
|
||||
&result[result.size() - 1] + 1, used_output)) {
|
||||
case std::codecvt_base::ok:
|
||||
result.resize(used_output - result.data());
|
||||
return result;
|
||||
case std::codecvt_base::noconv:
|
||||
// This should be unreachable
|
||||
case std::codecvt_base::error:
|
||||
throw errors::invalid_utf16("Invalid UTF-16 input", "");
|
||||
case std::codecvt_base::partial:
|
||||
if(used_output == result.data() + produced_output)
|
||||
throw errors::invalid_utf16("Unexpected end of input", "");
|
||||
produced_output = used_output - result.data();
|
||||
result.resize(
|
||||
result.size()
|
||||
+ (std::max)((&input[input.size()] - remaining_input) * 3 / 2,
|
||||
std::ptrdiff_t(4)));
|
||||
}
|
||||
}
|
||||
}
|
||||
} // namespace utility
|
||||
} // namespace sqlite
|
18992
src/sqlite/shell.c
Normal file
18992
src/sqlite/shell.c
Normal file
File diff suppressed because it is too large
Load diff
223788
src/sqlite/sqlite3.c
Normal file
223788
src/sqlite/sqlite3.c
Normal file
File diff suppressed because it is too large
Load diff
11792
src/sqlite/sqlite3.h
Normal file
11792
src/sqlite/sqlite3.h
Normal file
File diff suppressed because it is too large
Load diff
634
src/sqlite/sqlite3ext.h
Normal file
634
src/sqlite/sqlite3ext.h
Normal file
|
@ -0,0 +1,634 @@
|
|||
/*
|
||||
** 2006 June 7
|
||||
**
|
||||
** The author disclaims copyright to this source code. In place of
|
||||
** a legal notice, here is a blessing:
|
||||
**
|
||||
** May you do good and not evil.
|
||||
** May you find forgiveness for yourself and forgive others.
|
||||
** May you share freely, never taking more than you give.
|
||||
**
|
||||
*************************************************************************
|
||||
** This header file defines the SQLite interface for use by
|
||||
** shared libraries that want to be imported as extensions into
|
||||
** an SQLite instance. Shared libraries that intend to be loaded
|
||||
** as extensions by SQLite should #include this file instead of
|
||||
** sqlite3.h.
|
||||
*/
|
||||
#ifndef SQLITE3EXT_H
|
||||
#define SQLITE3EXT_H
|
||||
#include "sqlite3.h"
|
||||
|
||||
/*
|
||||
** The following structure holds pointers to all of the SQLite API
|
||||
** routines.
|
||||
**
|
||||
** WARNING: In order to maintain backwards compatibility, add new
|
||||
** interfaces to the end of this structure only. If you insert new
|
||||
** interfaces in the middle of this structure, then older different
|
||||
** versions of SQLite will not be able to load each other's shared
|
||||
** libraries!
|
||||
*/
|
||||
struct sqlite3_api_routines {
|
||||
void * (*aggregate_context)(sqlite3_context*,int nBytes);
|
||||
int (*aggregate_count)(sqlite3_context*);
|
||||
int (*bind_blob)(sqlite3_stmt*,int,const void*,int n,void(*)(void*));
|
||||
int (*bind_double)(sqlite3_stmt*,int,double);
|
||||
int (*bind_int)(sqlite3_stmt*,int,int);
|
||||
int (*bind_int64)(sqlite3_stmt*,int,sqlite_int64);
|
||||
int (*bind_null)(sqlite3_stmt*,int);
|
||||
int (*bind_parameter_count)(sqlite3_stmt*);
|
||||
int (*bind_parameter_index)(sqlite3_stmt*,const char*zName);
|
||||
const char * (*bind_parameter_name)(sqlite3_stmt*,int);
|
||||
int (*bind_text)(sqlite3_stmt*,int,const char*,int n,void(*)(void*));
|
||||
int (*bind_text16)(sqlite3_stmt*,int,const void*,int,void(*)(void*));
|
||||
int (*bind_value)(sqlite3_stmt*,int,const sqlite3_value*);
|
||||
int (*busy_handler)(sqlite3*,int(*)(void*,int),void*);
|
||||
int (*busy_timeout)(sqlite3*,int ms);
|
||||
int (*changes)(sqlite3*);
|
||||
int (*close)(sqlite3*);
|
||||
int (*collation_needed)(sqlite3*,void*,void(*)(void*,sqlite3*,
|
||||
int eTextRep,const char*));
|
||||
int (*collation_needed16)(sqlite3*,void*,void(*)(void*,sqlite3*,
|
||||
int eTextRep,const void*));
|
||||
const void * (*column_blob)(sqlite3_stmt*,int iCol);
|
||||
int (*column_bytes)(sqlite3_stmt*,int iCol);
|
||||
int (*column_bytes16)(sqlite3_stmt*,int iCol);
|
||||
int (*column_count)(sqlite3_stmt*pStmt);
|
||||
const char * (*column_database_name)(sqlite3_stmt*,int);
|
||||
const void * (*column_database_name16)(sqlite3_stmt*,int);
|
||||
const char * (*column_decltype)(sqlite3_stmt*,int i);
|
||||
const void * (*column_decltype16)(sqlite3_stmt*,int);
|
||||
double (*column_double)(sqlite3_stmt*,int iCol);
|
||||
int (*column_int)(sqlite3_stmt*,int iCol);
|
||||
sqlite_int64 (*column_int64)(sqlite3_stmt*,int iCol);
|
||||
const char * (*column_name)(sqlite3_stmt*,int);
|
||||
const void * (*column_name16)(sqlite3_stmt*,int);
|
||||
const char * (*column_origin_name)(sqlite3_stmt*,int);
|
||||
const void * (*column_origin_name16)(sqlite3_stmt*,int);
|
||||
const char * (*column_table_name)(sqlite3_stmt*,int);
|
||||
const void * (*column_table_name16)(sqlite3_stmt*,int);
|
||||
const unsigned char * (*column_text)(sqlite3_stmt*,int iCol);
|
||||
const void * (*column_text16)(sqlite3_stmt*,int iCol);
|
||||
int (*column_type)(sqlite3_stmt*,int iCol);
|
||||
sqlite3_value* (*column_value)(sqlite3_stmt*,int iCol);
|
||||
void * (*commit_hook)(sqlite3*,int(*)(void*),void*);
|
||||
int (*complete)(const char*sql);
|
||||
int (*complete16)(const void*sql);
|
||||
int (*create_collation)(sqlite3*,const char*,int,void*,
|
||||
int(*)(void*,int,const void*,int,const void*));
|
||||
int (*create_collation16)(sqlite3*,const void*,int,void*,
|
||||
int(*)(void*,int,const void*,int,const void*));
|
||||
int (*create_function)(sqlite3*,const char*,int,int,void*,
|
||||
void (*xFunc)(sqlite3_context*,int,sqlite3_value**),
|
||||
void (*xStep)(sqlite3_context*,int,sqlite3_value**),
|
||||
void (*xFinal)(sqlite3_context*));
|
||||
int (*create_function16)(sqlite3*,const void*,int,int,void*,
|
||||
void (*xFunc)(sqlite3_context*,int,sqlite3_value**),
|
||||
void (*xStep)(sqlite3_context*,int,sqlite3_value**),
|
||||
void (*xFinal)(sqlite3_context*));
|
||||
int (*create_module)(sqlite3*,const char*,const sqlite3_module*,void*);
|
||||
int (*data_count)(sqlite3_stmt*pStmt);
|
||||
sqlite3 * (*db_handle)(sqlite3_stmt*);
|
||||
int (*declare_vtab)(sqlite3*,const char*);
|
||||
int (*enable_shared_cache)(int);
|
||||
int (*errcode)(sqlite3*db);
|
||||
const char * (*errmsg)(sqlite3*);
|
||||
const void * (*errmsg16)(sqlite3*);
|
||||
int (*exec)(sqlite3*,const char*,sqlite3_callback,void*,char**);
|
||||
int (*expired)(sqlite3_stmt*);
|
||||
int (*finalize)(sqlite3_stmt*pStmt);
|
||||
void (*free)(void*);
|
||||
void (*free_table)(char**result);
|
||||
int (*get_autocommit)(sqlite3*);
|
||||
void * (*get_auxdata)(sqlite3_context*,int);
|
||||
int (*get_table)(sqlite3*,const char*,char***,int*,int*,char**);
|
||||
int (*global_recover)(void);
|
||||
void (*interruptx)(sqlite3*);
|
||||
sqlite_int64 (*last_insert_rowid)(sqlite3*);
|
||||
const char * (*libversion)(void);
|
||||
int (*libversion_number)(void);
|
||||
void *(*malloc)(int);
|
||||
char * (*mprintf)(const char*,...);
|
||||
int (*open)(const char*,sqlite3**);
|
||||
int (*open16)(const void*,sqlite3**);
|
||||
int (*prepare)(sqlite3*,const char*,int,sqlite3_stmt**,const char**);
|
||||
int (*prepare16)(sqlite3*,const void*,int,sqlite3_stmt**,const void**);
|
||||
void * (*profile)(sqlite3*,void(*)(void*,const char*,sqlite_uint64),void*);
|
||||
void (*progress_handler)(sqlite3*,int,int(*)(void*),void*);
|
||||
void *(*realloc)(void*,int);
|
||||
int (*reset)(sqlite3_stmt*pStmt);
|
||||
void (*result_blob)(sqlite3_context*,const void*,int,void(*)(void*));
|
||||
void (*result_double)(sqlite3_context*,double);
|
||||
void (*result_error)(sqlite3_context*,const char*,int);
|
||||
void (*result_error16)(sqlite3_context*,const void*,int);
|
||||
void (*result_int)(sqlite3_context*,int);
|
||||
void (*result_int64)(sqlite3_context*,sqlite_int64);
|
||||
void (*result_null)(sqlite3_context*);
|
||||
void (*result_text)(sqlite3_context*,const char*,int,void(*)(void*));
|
||||
void (*result_text16)(sqlite3_context*,const void*,int,void(*)(void*));
|
||||
void (*result_text16be)(sqlite3_context*,const void*,int,void(*)(void*));
|
||||
void (*result_text16le)(sqlite3_context*,const void*,int,void(*)(void*));
|
||||
void (*result_value)(sqlite3_context*,sqlite3_value*);
|
||||
void * (*rollback_hook)(sqlite3*,void(*)(void*),void*);
|
||||
int (*set_authorizer)(sqlite3*,int(*)(void*,int,const char*,const char*,
|
||||
const char*,const char*),void*);
|
||||
void (*set_auxdata)(sqlite3_context*,int,void*,void (*)(void*));
|
||||
char * (*xsnprintf)(int,char*,const char*,...);
|
||||
int (*step)(sqlite3_stmt*);
|
||||
int (*table_column_metadata)(sqlite3*,const char*,const char*,const char*,
|
||||
char const**,char const**,int*,int*,int*);
|
||||
void (*thread_cleanup)(void);
|
||||
int (*total_changes)(sqlite3*);
|
||||
void * (*trace)(sqlite3*,void(*xTrace)(void*,const char*),void*);
|
||||
int (*transfer_bindings)(sqlite3_stmt*,sqlite3_stmt*);
|
||||
void * (*update_hook)(sqlite3*,void(*)(void*,int ,char const*,char const*,
|
||||
sqlite_int64),void*);
|
||||
void * (*user_data)(sqlite3_context*);
|
||||
const void * (*value_blob)(sqlite3_value*);
|
||||
int (*value_bytes)(sqlite3_value*);
|
||||
int (*value_bytes16)(sqlite3_value*);
|
||||
double (*value_double)(sqlite3_value*);
|
||||
int (*value_int)(sqlite3_value*);
|
||||
sqlite_int64 (*value_int64)(sqlite3_value*);
|
||||
int (*value_numeric_type)(sqlite3_value*);
|
||||
const unsigned char * (*value_text)(sqlite3_value*);
|
||||
const void * (*value_text16)(sqlite3_value*);
|
||||
const void * (*value_text16be)(sqlite3_value*);
|
||||
const void * (*value_text16le)(sqlite3_value*);
|
||||
int (*value_type)(sqlite3_value*);
|
||||
char *(*vmprintf)(const char*,va_list);
|
||||
/* Added ??? */
|
||||
int (*overload_function)(sqlite3*, const char *zFuncName, int nArg);
|
||||
/* Added by 3.3.13 */
|
||||
int (*prepare_v2)(sqlite3*,const char*,int,sqlite3_stmt**,const char**);
|
||||
int (*prepare16_v2)(sqlite3*,const void*,int,sqlite3_stmt**,const void**);
|
||||
int (*clear_bindings)(sqlite3_stmt*);
|
||||
/* Added by 3.4.1 */
|
||||
int (*create_module_v2)(sqlite3*,const char*,const sqlite3_module*,void*,
|
||||
void (*xDestroy)(void *));
|
||||
/* Added by 3.5.0 */
|
||||
int (*bind_zeroblob)(sqlite3_stmt*,int,int);
|
||||
int (*blob_bytes)(sqlite3_blob*);
|
||||
int (*blob_close)(sqlite3_blob*);
|
||||
int (*blob_open)(sqlite3*,const char*,const char*,const char*,sqlite3_int64,
|
||||
int,sqlite3_blob**);
|
||||
int (*blob_read)(sqlite3_blob*,void*,int,int);
|
||||
int (*blob_write)(sqlite3_blob*,const void*,int,int);
|
||||
int (*create_collation_v2)(sqlite3*,const char*,int,void*,
|
||||
int(*)(void*,int,const void*,int,const void*),
|
||||
void(*)(void*));
|
||||
int (*file_control)(sqlite3*,const char*,int,void*);
|
||||
sqlite3_int64 (*memory_highwater)(int);
|
||||
sqlite3_int64 (*memory_used)(void);
|
||||
sqlite3_mutex *(*mutex_alloc)(int);
|
||||
void (*mutex_enter)(sqlite3_mutex*);
|
||||
void (*mutex_free)(sqlite3_mutex*);
|
||||
void (*mutex_leave)(sqlite3_mutex*);
|
||||
int (*mutex_try)(sqlite3_mutex*);
|
||||
int (*open_v2)(const char*,sqlite3**,int,const char*);
|
||||
int (*release_memory)(int);
|
||||
void (*result_error_nomem)(sqlite3_context*);
|
||||
void (*result_error_toobig)(sqlite3_context*);
|
||||
int (*sleep)(int);
|
||||
void (*soft_heap_limit)(int);
|
||||
sqlite3_vfs *(*vfs_find)(const char*);
|
||||
int (*vfs_register)(sqlite3_vfs*,int);
|
||||
int (*vfs_unregister)(sqlite3_vfs*);
|
||||
int (*xthreadsafe)(void);
|
||||
void (*result_zeroblob)(sqlite3_context*,int);
|
||||
void (*result_error_code)(sqlite3_context*,int);
|
||||
int (*test_control)(int, ...);
|
||||
void (*randomness)(int,void*);
|
||||
sqlite3 *(*context_db_handle)(sqlite3_context*);
|
||||
int (*extended_result_codes)(sqlite3*,int);
|
||||
int (*limit)(sqlite3*,int,int);
|
||||
sqlite3_stmt *(*next_stmt)(sqlite3*,sqlite3_stmt*);
|
||||
const char *(*sql)(sqlite3_stmt*);
|
||||
int (*status)(int,int*,int*,int);
|
||||
int (*backup_finish)(sqlite3_backup*);
|
||||
sqlite3_backup *(*backup_init)(sqlite3*,const char*,sqlite3*,const char*);
|
||||
int (*backup_pagecount)(sqlite3_backup*);
|
||||
int (*backup_remaining)(sqlite3_backup*);
|
||||
int (*backup_step)(sqlite3_backup*,int);
|
||||
const char *(*compileoption_get)(int);
|
||||
int (*compileoption_used)(const char*);
|
||||
int (*create_function_v2)(sqlite3*,const char*,int,int,void*,
|
||||
void (*xFunc)(sqlite3_context*,int,sqlite3_value**),
|
||||
void (*xStep)(sqlite3_context*,int,sqlite3_value**),
|
||||
void (*xFinal)(sqlite3_context*),
|
||||
void(*xDestroy)(void*));
|
||||
int (*db_config)(sqlite3*,int,...);
|
||||
sqlite3_mutex *(*db_mutex)(sqlite3*);
|
||||
int (*db_status)(sqlite3*,int,int*,int*,int);
|
||||
int (*extended_errcode)(sqlite3*);
|
||||
void (*log)(int,const char*,...);
|
||||
sqlite3_int64 (*soft_heap_limit64)(sqlite3_int64);
|
||||
const char *(*sourceid)(void);
|
||||
int (*stmt_status)(sqlite3_stmt*,int,int);
|
||||
int (*strnicmp)(const char*,const char*,int);
|
||||
int (*unlock_notify)(sqlite3*,void(*)(void**,int),void*);
|
||||
int (*wal_autocheckpoint)(sqlite3*,int);
|
||||
int (*wal_checkpoint)(sqlite3*,const char*);
|
||||
void *(*wal_hook)(sqlite3*,int(*)(void*,sqlite3*,const char*,int),void*);
|
||||
int (*blob_reopen)(sqlite3_blob*,sqlite3_int64);
|
||||
int (*vtab_config)(sqlite3*,int op,...);
|
||||
int (*vtab_on_conflict)(sqlite3*);
|
||||
/* Version 3.7.16 and later */
|
||||
int (*close_v2)(sqlite3*);
|
||||
const char *(*db_filename)(sqlite3*,const char*);
|
||||
int (*db_readonly)(sqlite3*,const char*);
|
||||
int (*db_release_memory)(sqlite3*);
|
||||
const char *(*errstr)(int);
|
||||
int (*stmt_busy)(sqlite3_stmt*);
|
||||
int (*stmt_readonly)(sqlite3_stmt*);
|
||||
int (*stricmp)(const char*,const char*);
|
||||
int (*uri_boolean)(const char*,const char*,int);
|
||||
sqlite3_int64 (*uri_int64)(const char*,const char*,sqlite3_int64);
|
||||
const char *(*uri_parameter)(const char*,const char*);
|
||||
char *(*xvsnprintf)(int,char*,const char*,va_list);
|
||||
int (*wal_checkpoint_v2)(sqlite3*,const char*,int,int*,int*);
|
||||
/* Version 3.8.7 and later */
|
||||
int (*auto_extension)(void(*)(void));
|
||||
int (*bind_blob64)(sqlite3_stmt*,int,const void*,sqlite3_uint64,
|
||||
void(*)(void*));
|
||||
int (*bind_text64)(sqlite3_stmt*,int,const char*,sqlite3_uint64,
|
||||
void(*)(void*),unsigned char);
|
||||
int (*cancel_auto_extension)(void(*)(void));
|
||||
int (*load_extension)(sqlite3*,const char*,const char*,char**);
|
||||
void *(*malloc64)(sqlite3_uint64);
|
||||
sqlite3_uint64 (*msize)(void*);
|
||||
void *(*realloc64)(void*,sqlite3_uint64);
|
||||
void (*reset_auto_extension)(void);
|
||||
void (*result_blob64)(sqlite3_context*,const void*,sqlite3_uint64,
|
||||
void(*)(void*));
|
||||
void (*result_text64)(sqlite3_context*,const char*,sqlite3_uint64,
|
||||
void(*)(void*), unsigned char);
|
||||
int (*strglob)(const char*,const char*);
|
||||
/* Version 3.8.11 and later */
|
||||
sqlite3_value *(*value_dup)(const sqlite3_value*);
|
||||
void (*value_free)(sqlite3_value*);
|
||||
int (*result_zeroblob64)(sqlite3_context*,sqlite3_uint64);
|
||||
int (*bind_zeroblob64)(sqlite3_stmt*, int, sqlite3_uint64);
|
||||
/* Version 3.9.0 and later */
|
||||
unsigned int (*value_subtype)(sqlite3_value*);
|
||||
void (*result_subtype)(sqlite3_context*,unsigned int);
|
||||
/* Version 3.10.0 and later */
|
||||
int (*status64)(int,sqlite3_int64*,sqlite3_int64*,int);
|
||||
int (*strlike)(const char*,const char*,unsigned int);
|
||||
int (*db_cacheflush)(sqlite3*);
|
||||
/* Version 3.12.0 and later */
|
||||
int (*system_errno)(sqlite3*);
|
||||
/* Version 3.14.0 and later */
|
||||
int (*trace_v2)(sqlite3*,unsigned,int(*)(unsigned,void*,void*,void*),void*);
|
||||
char *(*expanded_sql)(sqlite3_stmt*);
|
||||
/* Version 3.18.0 and later */
|
||||
void (*set_last_insert_rowid)(sqlite3*,sqlite3_int64);
|
||||
/* Version 3.20.0 and later */
|
||||
int (*prepare_v3)(sqlite3*,const char*,int,unsigned int,
|
||||
sqlite3_stmt**,const char**);
|
||||
int (*prepare16_v3)(sqlite3*,const void*,int,unsigned int,
|
||||
sqlite3_stmt**,const void**);
|
||||
int (*bind_pointer)(sqlite3_stmt*,int,void*,const char*,void(*)(void*));
|
||||
void (*result_pointer)(sqlite3_context*,void*,const char*,void(*)(void*));
|
||||
void *(*value_pointer)(sqlite3_value*,const char*);
|
||||
int (*vtab_nochange)(sqlite3_context*);
|
||||
int (*value_nochange)(sqlite3_value*);
|
||||
const char *(*vtab_collation)(sqlite3_index_info*,int);
|
||||
/* Version 3.24.0 and later */
|
||||
int (*keyword_count)(void);
|
||||
int (*keyword_name)(int,const char**,int*);
|
||||
int (*keyword_check)(const char*,int);
|
||||
sqlite3_str *(*str_new)(sqlite3*);
|
||||
char *(*str_finish)(sqlite3_str*);
|
||||
void (*str_appendf)(sqlite3_str*, const char *zFormat, ...);
|
||||
void (*str_vappendf)(sqlite3_str*, const char *zFormat, va_list);
|
||||
void (*str_append)(sqlite3_str*, const char *zIn, int N);
|
||||
void (*str_appendall)(sqlite3_str*, const char *zIn);
|
||||
void (*str_appendchar)(sqlite3_str*, int N, char C);
|
||||
void (*str_reset)(sqlite3_str*);
|
||||
int (*str_errcode)(sqlite3_str*);
|
||||
int (*str_length)(sqlite3_str*);
|
||||
char *(*str_value)(sqlite3_str*);
|
||||
/* Version 3.25.0 and later */
|
||||
int (*create_window_function)(sqlite3*,const char*,int,int,void*,
|
||||
void (*xStep)(sqlite3_context*,int,sqlite3_value**),
|
||||
void (*xFinal)(sqlite3_context*),
|
||||
void (*xValue)(sqlite3_context*),
|
||||
void (*xInv)(sqlite3_context*,int,sqlite3_value**),
|
||||
void(*xDestroy)(void*));
|
||||
/* Version 3.26.0 and later */
|
||||
const char *(*normalized_sql)(sqlite3_stmt*);
|
||||
/* Version 3.28.0 and later */
|
||||
int (*stmt_isexplain)(sqlite3_stmt*);
|
||||
int (*value_frombind)(sqlite3_value*);
|
||||
};
|
||||
|
||||
/*
|
||||
** This is the function signature used for all extension entry points. It
|
||||
** is also defined in the file "loadext.c".
|
||||
*/
|
||||
typedef int (*sqlite3_loadext_entry)(
|
||||
sqlite3 *db, /* Handle to the database. */
|
||||
char **pzErrMsg, /* Used to set error string on failure. */
|
||||
const sqlite3_api_routines *pThunk /* Extension API function pointers. */
|
||||
);
|
||||
|
||||
/*
|
||||
** The following macros redefine the API routines so that they are
|
||||
** redirected through the global sqlite3_api structure.
|
||||
**
|
||||
** This header file is also used by the loadext.c source file
|
||||
** (part of the main SQLite library - not an extension) so that
|
||||
** it can get access to the sqlite3_api_routines structure
|
||||
** definition. But the main library does not want to redefine
|
||||
** the API. So the redefinition macros are only valid if the
|
||||
** SQLITE_CORE macros is undefined.
|
||||
*/
|
||||
#if !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION)
|
||||
#define sqlite3_aggregate_context sqlite3_api->aggregate_context
|
||||
#ifndef SQLITE_OMIT_DEPRECATED
|
||||
#define sqlite3_aggregate_count sqlite3_api->aggregate_count
|
||||
#endif
|
||||
#define sqlite3_bind_blob sqlite3_api->bind_blob
|
||||
#define sqlite3_bind_double sqlite3_api->bind_double
|
||||
#define sqlite3_bind_int sqlite3_api->bind_int
|
||||
#define sqlite3_bind_int64 sqlite3_api->bind_int64
|
||||
#define sqlite3_bind_null sqlite3_api->bind_null
|
||||
#define sqlite3_bind_parameter_count sqlite3_api->bind_parameter_count
|
||||
#define sqlite3_bind_parameter_index sqlite3_api->bind_parameter_index
|
||||
#define sqlite3_bind_parameter_name sqlite3_api->bind_parameter_name
|
||||
#define sqlite3_bind_text sqlite3_api->bind_text
|
||||
#define sqlite3_bind_text16 sqlite3_api->bind_text16
|
||||
#define sqlite3_bind_value sqlite3_api->bind_value
|
||||
#define sqlite3_busy_handler sqlite3_api->busy_handler
|
||||
#define sqlite3_busy_timeout sqlite3_api->busy_timeout
|
||||
#define sqlite3_changes sqlite3_api->changes
|
||||
#define sqlite3_close sqlite3_api->close
|
||||
#define sqlite3_collation_needed sqlite3_api->collation_needed
|
||||
#define sqlite3_collation_needed16 sqlite3_api->collation_needed16
|
||||
#define sqlite3_column_blob sqlite3_api->column_blob
|
||||
#define sqlite3_column_bytes sqlite3_api->column_bytes
|
||||
#define sqlite3_column_bytes16 sqlite3_api->column_bytes16
|
||||
#define sqlite3_column_count sqlite3_api->column_count
|
||||
#define sqlite3_column_database_name sqlite3_api->column_database_name
|
||||
#define sqlite3_column_database_name16 sqlite3_api->column_database_name16
|
||||
#define sqlite3_column_decltype sqlite3_api->column_decltype
|
||||
#define sqlite3_column_decltype16 sqlite3_api->column_decltype16
|
||||
#define sqlite3_column_double sqlite3_api->column_double
|
||||
#define sqlite3_column_int sqlite3_api->column_int
|
||||
#define sqlite3_column_int64 sqlite3_api->column_int64
|
||||
#define sqlite3_column_name sqlite3_api->column_name
|
||||
#define sqlite3_column_name16 sqlite3_api->column_name16
|
||||
#define sqlite3_column_origin_name sqlite3_api->column_origin_name
|
||||
#define sqlite3_column_origin_name16 sqlite3_api->column_origin_name16
|
||||
#define sqlite3_column_table_name sqlite3_api->column_table_name
|
||||
#define sqlite3_column_table_name16 sqlite3_api->column_table_name16
|
||||
#define sqlite3_column_text sqlite3_api->column_text
|
||||
#define sqlite3_column_text16 sqlite3_api->column_text16
|
||||
#define sqlite3_column_type sqlite3_api->column_type
|
||||
#define sqlite3_column_value sqlite3_api->column_value
|
||||
#define sqlite3_commit_hook sqlite3_api->commit_hook
|
||||
#define sqlite3_complete sqlite3_api->complete
|
||||
#define sqlite3_complete16 sqlite3_api->complete16
|
||||
#define sqlite3_create_collation sqlite3_api->create_collation
|
||||
#define sqlite3_create_collation16 sqlite3_api->create_collation16
|
||||
#define sqlite3_create_function sqlite3_api->create_function
|
||||
#define sqlite3_create_function16 sqlite3_api->create_function16
|
||||
#define sqlite3_create_module sqlite3_api->create_module
|
||||
#define sqlite3_create_module_v2 sqlite3_api->create_module_v2
|
||||
#define sqlite3_data_count sqlite3_api->data_count
|
||||
#define sqlite3_db_handle sqlite3_api->db_handle
|
||||
#define sqlite3_declare_vtab sqlite3_api->declare_vtab
|
||||
#define sqlite3_enable_shared_cache sqlite3_api->enable_shared_cache
|
||||
#define sqlite3_errcode sqlite3_api->errcode
|
||||
#define sqlite3_errmsg sqlite3_api->errmsg
|
||||
#define sqlite3_errmsg16 sqlite3_api->errmsg16
|
||||
#define sqlite3_exec sqlite3_api->exec
|
||||
#ifndef SQLITE_OMIT_DEPRECATED
|
||||
#define sqlite3_expired sqlite3_api->expired
|
||||
#endif
|
||||
#define sqlite3_finalize sqlite3_api->finalize
|
||||
#define sqlite3_free sqlite3_api->free
|
||||
#define sqlite3_free_table sqlite3_api->free_table
|
||||
#define sqlite3_get_autocommit sqlite3_api->get_autocommit
|
||||
#define sqlite3_get_auxdata sqlite3_api->get_auxdata
|
||||
#define sqlite3_get_table sqlite3_api->get_table
|
||||
#ifndef SQLITE_OMIT_DEPRECATED
|
||||
#define sqlite3_global_recover sqlite3_api->global_recover
|
||||
#endif
|
||||
#define sqlite3_interrupt sqlite3_api->interruptx
|
||||
#define sqlite3_last_insert_rowid sqlite3_api->last_insert_rowid
|
||||
#define sqlite3_libversion sqlite3_api->libversion
|
||||
#define sqlite3_libversion_number sqlite3_api->libversion_number
|
||||
#define sqlite3_malloc sqlite3_api->malloc
|
||||
#define sqlite3_mprintf sqlite3_api->mprintf
|
||||
#define sqlite3_open sqlite3_api->open
|
||||
#define sqlite3_open16 sqlite3_api->open16
|
||||
#define sqlite3_prepare sqlite3_api->prepare
|
||||
#define sqlite3_prepare16 sqlite3_api->prepare16
|
||||
#define sqlite3_prepare_v2 sqlite3_api->prepare_v2
|
||||
#define sqlite3_prepare16_v2 sqlite3_api->prepare16_v2
|
||||
#define sqlite3_profile sqlite3_api->profile
|
||||
#define sqlite3_progress_handler sqlite3_api->progress_handler
|
||||
#define sqlite3_realloc sqlite3_api->realloc
|
||||
#define sqlite3_reset sqlite3_api->reset
|
||||
#define sqlite3_result_blob sqlite3_api->result_blob
|
||||
#define sqlite3_result_double sqlite3_api->result_double
|
||||
#define sqlite3_result_error sqlite3_api->result_error
|
||||
#define sqlite3_result_error16 sqlite3_api->result_error16
|
||||
#define sqlite3_result_int sqlite3_api->result_int
|
||||
#define sqlite3_result_int64 sqlite3_api->result_int64
|
||||
#define sqlite3_result_null sqlite3_api->result_null
|
||||
#define sqlite3_result_text sqlite3_api->result_text
|
||||
#define sqlite3_result_text16 sqlite3_api->result_text16
|
||||
#define sqlite3_result_text16be sqlite3_api->result_text16be
|
||||
#define sqlite3_result_text16le sqlite3_api->result_text16le
|
||||
#define sqlite3_result_value sqlite3_api->result_value
|
||||
#define sqlite3_rollback_hook sqlite3_api->rollback_hook
|
||||
#define sqlite3_set_authorizer sqlite3_api->set_authorizer
|
||||
#define sqlite3_set_auxdata sqlite3_api->set_auxdata
|
||||
#define sqlite3_snprintf sqlite3_api->xsnprintf
|
||||
#define sqlite3_step sqlite3_api->step
|
||||
#define sqlite3_table_column_metadata sqlite3_api->table_column_metadata
|
||||
#define sqlite3_thread_cleanup sqlite3_api->thread_cleanup
|
||||
#define sqlite3_total_changes sqlite3_api->total_changes
|
||||
#define sqlite3_trace sqlite3_api->trace
|
||||
#ifndef SQLITE_OMIT_DEPRECATED
|
||||
#define sqlite3_transfer_bindings sqlite3_api->transfer_bindings
|
||||
#endif
|
||||
#define sqlite3_update_hook sqlite3_api->update_hook
|
||||
#define sqlite3_user_data sqlite3_api->user_data
|
||||
#define sqlite3_value_blob sqlite3_api->value_blob
|
||||
#define sqlite3_value_bytes sqlite3_api->value_bytes
|
||||
#define sqlite3_value_bytes16 sqlite3_api->value_bytes16
|
||||
#define sqlite3_value_double sqlite3_api->value_double
|
||||
#define sqlite3_value_int sqlite3_api->value_int
|
||||
#define sqlite3_value_int64 sqlite3_api->value_int64
|
||||
#define sqlite3_value_numeric_type sqlite3_api->value_numeric_type
|
||||
#define sqlite3_value_text sqlite3_api->value_text
|
||||
#define sqlite3_value_text16 sqlite3_api->value_text16
|
||||
#define sqlite3_value_text16be sqlite3_api->value_text16be
|
||||
#define sqlite3_value_text16le sqlite3_api->value_text16le
|
||||
#define sqlite3_value_type sqlite3_api->value_type
|
||||
#define sqlite3_vmprintf sqlite3_api->vmprintf
|
||||
#define sqlite3_vsnprintf sqlite3_api->xvsnprintf
|
||||
#define sqlite3_overload_function sqlite3_api->overload_function
|
||||
#define sqlite3_prepare_v2 sqlite3_api->prepare_v2
|
||||
#define sqlite3_prepare16_v2 sqlite3_api->prepare16_v2
|
||||
#define sqlite3_clear_bindings sqlite3_api->clear_bindings
|
||||
#define sqlite3_bind_zeroblob sqlite3_api->bind_zeroblob
|
||||
#define sqlite3_blob_bytes sqlite3_api->blob_bytes
|
||||
#define sqlite3_blob_close sqlite3_api->blob_close
|
||||
#define sqlite3_blob_open sqlite3_api->blob_open
|
||||
#define sqlite3_blob_read sqlite3_api->blob_read
|
||||
#define sqlite3_blob_write sqlite3_api->blob_write
|
||||
#define sqlite3_create_collation_v2 sqlite3_api->create_collation_v2
|
||||
#define sqlite3_file_control sqlite3_api->file_control
|
||||
#define sqlite3_memory_highwater sqlite3_api->memory_highwater
|
||||
#define sqlite3_memory_used sqlite3_api->memory_used
|
||||
#define sqlite3_mutex_alloc sqlite3_api->mutex_alloc
|
||||
#define sqlite3_mutex_enter sqlite3_api->mutex_enter
|
||||
#define sqlite3_mutex_free sqlite3_api->mutex_free
|
||||
#define sqlite3_mutex_leave sqlite3_api->mutex_leave
|
||||
#define sqlite3_mutex_try sqlite3_api->mutex_try
|
||||
#define sqlite3_open_v2 sqlite3_api->open_v2
|
||||
#define sqlite3_release_memory sqlite3_api->release_memory
|
||||
#define sqlite3_result_error_nomem sqlite3_api->result_error_nomem
|
||||
#define sqlite3_result_error_toobig sqlite3_api->result_error_toobig
|
||||
#define sqlite3_sleep sqlite3_api->sleep
|
||||
#define sqlite3_soft_heap_limit sqlite3_api->soft_heap_limit
|
||||
#define sqlite3_vfs_find sqlite3_api->vfs_find
|
||||
#define sqlite3_vfs_register sqlite3_api->vfs_register
|
||||
#define sqlite3_vfs_unregister sqlite3_api->vfs_unregister
|
||||
#define sqlite3_threadsafe sqlite3_api->xthreadsafe
|
||||
#define sqlite3_result_zeroblob sqlite3_api->result_zeroblob
|
||||
#define sqlite3_result_error_code sqlite3_api->result_error_code
|
||||
#define sqlite3_test_control sqlite3_api->test_control
|
||||
#define sqlite3_randomness sqlite3_api->randomness
|
||||
#define sqlite3_context_db_handle sqlite3_api->context_db_handle
|
||||
#define sqlite3_extended_result_codes sqlite3_api->extended_result_codes
|
||||
#define sqlite3_limit sqlite3_api->limit
|
||||
#define sqlite3_next_stmt sqlite3_api->next_stmt
|
||||
#define sqlite3_sql sqlite3_api->sql
|
||||
#define sqlite3_status sqlite3_api->status
|
||||
#define sqlite3_backup_finish sqlite3_api->backup_finish
|
||||
#define sqlite3_backup_init sqlite3_api->backup_init
|
||||
#define sqlite3_backup_pagecount sqlite3_api->backup_pagecount
|
||||
#define sqlite3_backup_remaining sqlite3_api->backup_remaining
|
||||
#define sqlite3_backup_step sqlite3_api->backup_step
|
||||
#define sqlite3_compileoption_get sqlite3_api->compileoption_get
|
||||
#define sqlite3_compileoption_used sqlite3_api->compileoption_used
|
||||
#define sqlite3_create_function_v2 sqlite3_api->create_function_v2
|
||||
#define sqlite3_db_config sqlite3_api->db_config
|
||||
#define sqlite3_db_mutex sqlite3_api->db_mutex
|
||||
#define sqlite3_db_status sqlite3_api->db_status
|
||||
#define sqlite3_extended_errcode sqlite3_api->extended_errcode
|
||||
#define sqlite3_log sqlite3_api->log
|
||||
#define sqlite3_soft_heap_limit64 sqlite3_api->soft_heap_limit64
|
||||
#define sqlite3_sourceid sqlite3_api->sourceid
|
||||
#define sqlite3_stmt_status sqlite3_api->stmt_status
|
||||
#define sqlite3_strnicmp sqlite3_api->strnicmp
|
||||
#define sqlite3_unlock_notify sqlite3_api->unlock_notify
|
||||
#define sqlite3_wal_autocheckpoint sqlite3_api->wal_autocheckpoint
|
||||
#define sqlite3_wal_checkpoint sqlite3_api->wal_checkpoint
|
||||
#define sqlite3_wal_hook sqlite3_api->wal_hook
|
||||
#define sqlite3_blob_reopen sqlite3_api->blob_reopen
|
||||
#define sqlite3_vtab_config sqlite3_api->vtab_config
|
||||
#define sqlite3_vtab_on_conflict sqlite3_api->vtab_on_conflict
|
||||
/* Version 3.7.16 and later */
|
||||
#define sqlite3_close_v2 sqlite3_api->close_v2
|
||||
#define sqlite3_db_filename sqlite3_api->db_filename
|
||||
#define sqlite3_db_readonly sqlite3_api->db_readonly
|
||||
#define sqlite3_db_release_memory sqlite3_api->db_release_memory
|
||||
#define sqlite3_errstr sqlite3_api->errstr
|
||||
#define sqlite3_stmt_busy sqlite3_api->stmt_busy
|
||||
#define sqlite3_stmt_readonly sqlite3_api->stmt_readonly
|
||||
#define sqlite3_stricmp sqlite3_api->stricmp
|
||||
#define sqlite3_uri_boolean sqlite3_api->uri_boolean
|
||||
#define sqlite3_uri_int64 sqlite3_api->uri_int64
|
||||
#define sqlite3_uri_parameter sqlite3_api->uri_parameter
|
||||
#define sqlite3_uri_vsnprintf sqlite3_api->xvsnprintf
|
||||
#define sqlite3_wal_checkpoint_v2 sqlite3_api->wal_checkpoint_v2
|
||||
/* Version 3.8.7 and later */
|
||||
#define sqlite3_auto_extension sqlite3_api->auto_extension
|
||||
#define sqlite3_bind_blob64 sqlite3_api->bind_blob64
|
||||
#define sqlite3_bind_text64 sqlite3_api->bind_text64
|
||||
#define sqlite3_cancel_auto_extension sqlite3_api->cancel_auto_extension
|
||||
#define sqlite3_load_extension sqlite3_api->load_extension
|
||||
#define sqlite3_malloc64 sqlite3_api->malloc64
|
||||
#define sqlite3_msize sqlite3_api->msize
|
||||
#define sqlite3_realloc64 sqlite3_api->realloc64
|
||||
#define sqlite3_reset_auto_extension sqlite3_api->reset_auto_extension
|
||||
#define sqlite3_result_blob64 sqlite3_api->result_blob64
|
||||
#define sqlite3_result_text64 sqlite3_api->result_text64
|
||||
#define sqlite3_strglob sqlite3_api->strglob
|
||||
/* Version 3.8.11 and later */
|
||||
#define sqlite3_value_dup sqlite3_api->value_dup
|
||||
#define sqlite3_value_free sqlite3_api->value_free
|
||||
#define sqlite3_result_zeroblob64 sqlite3_api->result_zeroblob64
|
||||
#define sqlite3_bind_zeroblob64 sqlite3_api->bind_zeroblob64
|
||||
/* Version 3.9.0 and later */
|
||||
#define sqlite3_value_subtype sqlite3_api->value_subtype
|
||||
#define sqlite3_result_subtype sqlite3_api->result_subtype
|
||||
/* Version 3.10.0 and later */
|
||||
#define sqlite3_status64 sqlite3_api->status64
|
||||
#define sqlite3_strlike sqlite3_api->strlike
|
||||
#define sqlite3_db_cacheflush sqlite3_api->db_cacheflush
|
||||
/* Version 3.12.0 and later */
|
||||
#define sqlite3_system_errno sqlite3_api->system_errno
|
||||
/* Version 3.14.0 and later */
|
||||
#define sqlite3_trace_v2 sqlite3_api->trace_v2
|
||||
#define sqlite3_expanded_sql sqlite3_api->expanded_sql
|
||||
/* Version 3.18.0 and later */
|
||||
#define sqlite3_set_last_insert_rowid sqlite3_api->set_last_insert_rowid
|
||||
/* Version 3.20.0 and later */
|
||||
#define sqlite3_prepare_v3 sqlite3_api->prepare_v3
|
||||
#define sqlite3_prepare16_v3 sqlite3_api->prepare16_v3
|
||||
#define sqlite3_bind_pointer sqlite3_api->bind_pointer
|
||||
#define sqlite3_result_pointer sqlite3_api->result_pointer
|
||||
#define sqlite3_value_pointer sqlite3_api->value_pointer
|
||||
/* Version 3.22.0 and later */
|
||||
#define sqlite3_vtab_nochange sqlite3_api->vtab_nochange
|
||||
#define sqlite3_value_nochange sqlite3_api->value_nochange
|
||||
#define sqlite3_vtab_collation sqlite3_api->vtab_collation
|
||||
/* Version 3.24.0 and later */
|
||||
#define sqlite3_keyword_count sqlite3_api->keyword_count
|
||||
#define sqlite3_keyword_name sqlite3_api->keyword_name
|
||||
#define sqlite3_keyword_check sqlite3_api->keyword_check
|
||||
#define sqlite3_str_new sqlite3_api->str_new
|
||||
#define sqlite3_str_finish sqlite3_api->str_finish
|
||||
#define sqlite3_str_appendf sqlite3_api->str_appendf
|
||||
#define sqlite3_str_vappendf sqlite3_api->str_vappendf
|
||||
#define sqlite3_str_append sqlite3_api->str_append
|
||||
#define sqlite3_str_appendall sqlite3_api->str_appendall
|
||||
#define sqlite3_str_appendchar sqlite3_api->str_appendchar
|
||||
#define sqlite3_str_reset sqlite3_api->str_reset
|
||||
#define sqlite3_str_errcode sqlite3_api->str_errcode
|
||||
#define sqlite3_str_length sqlite3_api->str_length
|
||||
#define sqlite3_str_value sqlite3_api->str_value
|
||||
/* Version 3.25.0 and later */
|
||||
#define sqlite3_create_window_function sqlite3_api->create_window_function
|
||||
/* Version 3.26.0 and later */
|
||||
#define sqlite3_normalized_sql sqlite3_api->normalized_sql
|
||||
/* Version 3.28.0 and later */
|
||||
#define sqlite3_stmt_isexplain sqlite3_api->isexplain
|
||||
#define sqlite3_value_frombind sqlite3_api->frombind
|
||||
#endif /* !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) */
|
||||
|
||||
#if !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION)
|
||||
/* This case when the file really is being compiled as a loadable
|
||||
** extension */
|
||||
# define SQLITE_EXTENSION_INIT1 const sqlite3_api_routines *sqlite3_api=0;
|
||||
# define SQLITE_EXTENSION_INIT2(v) sqlite3_api=v;
|
||||
# define SQLITE_EXTENSION_INIT3 \
|
||||
extern const sqlite3_api_routines *sqlite3_api;
|
||||
#else
|
||||
/* This case when the file is being statically linked into the
|
||||
** application */
|
||||
# define SQLITE_EXTENSION_INIT1 /*no-op*/
|
||||
# define SQLITE_EXTENSION_INIT2(v) (void)v; /* unused parameter */
|
||||
# define SQLITE_EXTENSION_INIT3 /*no-op*/
|
||||
#endif
|
||||
|
||||
#endif /* SQLITE3EXT_H */
|
|
@ -363,7 +363,7 @@ BOOST_AUTO_TEST_CASE(support_spend_test)
|
|||
uint32_t prevout = 0;
|
||||
CMutableTransaction tx;
|
||||
tx.nVersion = CTransaction::CURRENT_VERSION;
|
||||
tx.nLockTime = 1 << 31; // Disable BIP68
|
||||
tx.nLockTime = 1U << 31; // Disable BIP68
|
||||
tx.vin.resize(2);
|
||||
tx.vout.resize(1);
|
||||
tx.vin[0].prevout.hash = tx3.GetHash();
|
||||
|
@ -447,7 +447,7 @@ BOOST_AUTO_TEST_CASE(claimtrie_update_test)
|
|||
|
||||
CMutableTransaction tx;
|
||||
tx.nVersion = CTransaction::CURRENT_VERSION;
|
||||
tx.nLockTime = 1 << 31; // Disable BIP68
|
||||
tx.nLockTime = 1U << 31; // Disable BIP68
|
||||
tx.vin.resize(2);
|
||||
tx.vout.resize(1);
|
||||
tx.vin[0].prevout.hash = tx8.GetHash();
|
||||
|
@ -530,7 +530,7 @@ BOOST_AUTO_TEST_CASE(get_claim_by_id_test)
|
|||
|
||||
CClaimValue claimValue;
|
||||
std::string claimName;
|
||||
BOOST_CHECK(getClaimById(claimId, claimName, &claimValue));
|
||||
BOOST_CHECK(fixture.getClaimById(claimId, claimName, claimValue));
|
||||
BOOST_CHECK_EQUAL(claimName, name);
|
||||
BOOST_CHECK_EQUAL(claimValue.claimId, claimId);
|
||||
|
||||
|
@ -541,14 +541,14 @@ BOOST_AUTO_TEST_CASE(get_claim_by_id_test)
|
|||
uint160 claimId2 = ClaimIdHash(tx2.GetHash(), 0);
|
||||
fixture.IncrementBlocks(1);
|
||||
|
||||
BOOST_CHECK(getClaimById(claimId2, claimName, &claimValue));
|
||||
BOOST_CHECK(fixture.getClaimById(claimId2, claimName, claimValue));
|
||||
BOOST_CHECK_EQUAL(claimName, name);
|
||||
BOOST_CHECK_EQUAL(claimValue.claimId, claimId2);
|
||||
|
||||
|
||||
CMutableTransaction u1 = fixture.MakeUpdate(tx1, name, "updated one", claimId, 1);
|
||||
fixture.IncrementBlocks(1);
|
||||
BOOST_CHECK(getClaimById(claimId, claimName, &claimValue));
|
||||
BOOST_CHECK(fixture.getClaimById(claimId, claimName, claimValue));
|
||||
BOOST_CHECK_EQUAL(claimName, name);
|
||||
BOOST_CHECK_EQUAL(claimValue.claimId, claimId);
|
||||
BOOST_CHECK_EQUAL(claimValue.nAmount, 1);
|
||||
|
@ -556,24 +556,24 @@ BOOST_AUTO_TEST_CASE(get_claim_by_id_test)
|
|||
|
||||
fixture.Spend(u1);
|
||||
fixture.IncrementBlocks(1);
|
||||
BOOST_CHECK(!getClaimById(claimId, claimName, &claimValue));
|
||||
BOOST_CHECK(!fixture.getClaimById(claimId, claimName, claimValue));
|
||||
|
||||
fixture.DecrementBlocks(3);
|
||||
|
||||
CClaimValue claimValue2;
|
||||
claimName = "";
|
||||
BOOST_CHECK(!getClaimById(claimId2, claimName, &claimValue2));
|
||||
BOOST_CHECK(!fixture.getClaimById(claimId2, claimName, claimValue2));
|
||||
BOOST_CHECK(claimName != name);
|
||||
BOOST_CHECK(claimValue2.claimId != claimId2);
|
||||
|
||||
BOOST_CHECK(getClaimById(claimId, claimName, &claimValue));
|
||||
BOOST_CHECK(fixture.getClaimById(claimId, claimName, claimValue));
|
||||
BOOST_CHECK_EQUAL(claimName, name);
|
||||
BOOST_CHECK_EQUAL(claimValue.claimId, claimId);
|
||||
|
||||
fixture.DecrementBlocks(2);
|
||||
|
||||
claimName = "";
|
||||
BOOST_CHECK(!getClaimById(claimId, claimName, &claimValue2));
|
||||
BOOST_CHECK(!fixture.getClaimById(claimId, claimName, claimValue2));
|
||||
BOOST_CHECK(claimName != name);
|
||||
BOOST_CHECK(claimValue2.claimId != claimId);
|
||||
}
|
||||
|
@ -1816,7 +1816,7 @@ BOOST_AUTO_TEST_CASE(get_claim_by_id_test_2)
|
|||
|
||||
CClaimValue claimValue;
|
||||
std::string claimName;
|
||||
BOOST_CHECK(getClaimById(claimId, claimName, &claimValue));
|
||||
BOOST_CHECK(fixture.getClaimById(claimId, claimName, claimValue));
|
||||
BOOST_CHECK_EQUAL(claimName, name);
|
||||
BOOST_CHECK_EQUAL(claimValue.claimId, claimId);
|
||||
|
||||
|
@ -1824,16 +1824,16 @@ BOOST_AUTO_TEST_CASE(get_claim_by_id_test_2)
|
|||
CMutableTransaction txb = fixture.Spend(txx);
|
||||
|
||||
fixture.IncrementBlocks(1);
|
||||
BOOST_CHECK(!getClaimById(claimId, claimName, &claimValue));
|
||||
BOOST_CHECK(!getClaimById(claimIdx, claimName, &claimValue));
|
||||
BOOST_CHECK(!fixture.getClaimById(claimId, claimName, claimValue));
|
||||
BOOST_CHECK(!fixture.getClaimById(claimIdx, claimName, claimValue));
|
||||
|
||||
fixture.DecrementBlocks(1);
|
||||
BOOST_CHECK(getClaimById(claimId, claimName, &claimValue));
|
||||
BOOST_CHECK(fixture.getClaimById(claimId, claimName, claimValue));
|
||||
BOOST_CHECK_EQUAL(claimName, name);
|
||||
BOOST_CHECK_EQUAL(claimValue.claimId, claimId);
|
||||
|
||||
// this test fails
|
||||
BOOST_CHECK(getClaimById(claimIdx, claimName, &claimValue));
|
||||
BOOST_CHECK(fixture.getClaimById(claimIdx, claimName, claimValue));
|
||||
BOOST_CHECK_EQUAL(claimName, name);
|
||||
BOOST_CHECK_EQUAL(claimValue.claimId, claimIdx);
|
||||
}
|
||||
|
@ -1852,18 +1852,19 @@ BOOST_AUTO_TEST_CASE(update_on_support2_test)
|
|||
CMutableTransaction s2 = fixture.MakeSupport(fixture.GetCoinbase(), tx1, name, 1);
|
||||
fixture.IncrementBlocks(1);
|
||||
|
||||
auto it = pclaimTrie->find(name);
|
||||
BOOST_CHECK(it);
|
||||
BOOST_CHECK_EQUAL(it->nHeightOfLastTakeover, height + 1);
|
||||
uint160 claimId;
|
||||
int lastTakeover;
|
||||
BOOST_CHECK(fixture.getLastTakeoverForName(name, claimId, lastTakeover));
|
||||
BOOST_CHECK_EQUAL(lastTakeover, height + 1);
|
||||
BOOST_CHECK_EQUAL(ClaimIdHash(tx1.GetHash(), 0), claimId);
|
||||
|
||||
fixture.Spend(s1);
|
||||
fixture.Spend(s2);
|
||||
CMutableTransaction u1 = fixture.MakeUpdate(tx1, name, value, ClaimIdHash(tx1.GetHash(), 0), 3);
|
||||
fixture.IncrementBlocks(1);
|
||||
|
||||
it = pclaimTrie->find(name);
|
||||
BOOST_CHECK(it);
|
||||
BOOST_CHECK_EQUAL(it->nHeightOfLastTakeover, height + 1);
|
||||
BOOST_CHECK(fixture.getLastTakeoverForName(name, claimId, lastTakeover));
|
||||
BOOST_CHECK_EQUAL(lastTakeover, height + 1);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END()
|
||||
|
|
|
@ -17,29 +17,29 @@ public:
|
|||
{
|
||||
}
|
||||
|
||||
using CClaimTrieCacheBase::insertSupportIntoMap;
|
||||
using CClaimTrieCacheBase::removeSupportFromMap;
|
||||
using CClaimTrieCacheBase::insertClaimIntoTrie;
|
||||
using CClaimTrieCacheBase::removeClaimFromTrie;
|
||||
|
||||
void insert(const std::string& key, CClaimTrieData&& data)
|
||||
bool insertClaimIntoTrie(const std::string& key, const CClaimValue& data)
|
||||
{
|
||||
nodesToAddOrUpdate.insert(key, std::move(data));
|
||||
return addClaim(key, data.outPoint, data.claimId, data.nAmount, data.nHeight, {});
|
||||
}
|
||||
|
||||
bool erase(const std::string& key)
|
||||
{
|
||||
return nodesToAddOrUpdate.erase(key);
|
||||
bool removeClaimFromTrie(const std::string& key, const COutPoint& p) {
|
||||
int validHeight;
|
||||
std::string nodeName;
|
||||
auto ret = removeClaim(ClaimIdHash(p.hash, p.n), nodeName, validHeight);
|
||||
assert(!ret || nodeName == key);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int cacheSize()
|
||||
{
|
||||
return nodesToAddOrUpdate.height();
|
||||
bool insertSupportIntoMap(const std::string& key, const CSupportValue& value) {
|
||||
return addSupport(key, value.outPoint, value.nAmount, value.supportedClaimId, value.nHeight, {});
|
||||
}
|
||||
|
||||
CClaimTrie::iterator getCache(const std::string& key)
|
||||
{
|
||||
return nodesToAddOrUpdate.find(key);
|
||||
bool removeSupportFromMap(const std::string& key, const COutPoint& p) {
|
||||
int validHeight;
|
||||
std::string nodeName;
|
||||
auto ret = removeSupport(p, nodeName, validHeight);
|
||||
assert(!ret || nodeName == key);
|
||||
return ret;
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -53,13 +53,12 @@ BOOST_AUTO_TEST_CASE(merkle_hash_single_test)
|
|||
BOOST_CHECK_EQUAL(one, cc.getMerkleHash());
|
||||
|
||||
// we cannot have leaf root node
|
||||
auto it = cc.getCache("");
|
||||
BOOST_CHECK(!it);
|
||||
auto it = cc.getClaimsForName("");
|
||||
BOOST_CHECK_EQUAL(it.claimsNsupports.size(), 0U);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(merkle_hash_multiple_test)
|
||||
{
|
||||
CClaimValue unused;
|
||||
uint256 hash0(uint256S("0000000000000000000000000000000000000000000000000000000000000001"));
|
||||
uint160 hash160;
|
||||
CMutableTransaction tx1 = BuildTransaction(hash0);
|
||||
|
@ -90,19 +89,19 @@ BOOST_AUTO_TEST_CASE(merkle_hash_multiple_test)
|
|||
BOOST_CHECK(pclaimTrie->empty());
|
||||
|
||||
CClaimTrieCacheTest ntState(pclaimTrie);
|
||||
ntState.insertClaimIntoTrie(std::string("test"), CClaimValue(tx1OutPoint, hash160, 50, 100, 200), true);
|
||||
ntState.insertClaimIntoTrie(std::string("test2"), CClaimValue(tx2OutPoint, hash160, 50, 100, 200), true);
|
||||
ntState.insertClaimIntoTrie(std::string("test"), CClaimValue(tx1OutPoint, hash160, 50, 100, 200));
|
||||
ntState.insertClaimIntoTrie(std::string("test2"), CClaimValue(tx2OutPoint, hash160, 50, 100, 200));
|
||||
|
||||
BOOST_CHECK(pclaimTrie->empty());
|
||||
BOOST_CHECK(!ntState.empty());
|
||||
BOOST_CHECK(ntState.getTotalClaimsInTrie() > 0);
|
||||
BOOST_CHECK_EQUAL(ntState.getMerkleHash(), hash1);
|
||||
|
||||
ntState.insertClaimIntoTrie(std::string("test"), CClaimValue(tx3OutPoint, hash160, 50, 101, 201), true);
|
||||
ntState.insertClaimIntoTrie(std::string("test"), CClaimValue(tx3OutPoint, hash160, 50, 101, 201));
|
||||
BOOST_CHECK_EQUAL(ntState.getMerkleHash(), hash1);
|
||||
ntState.insertClaimIntoTrie(std::string("tes"), CClaimValue(tx4OutPoint, hash160, 50, 100, 200), true);
|
||||
ntState.insertClaimIntoTrie(std::string("tes"), CClaimValue(tx4OutPoint, hash160, 50, 100, 200));
|
||||
BOOST_CHECK_EQUAL(ntState.getMerkleHash(), hash2);
|
||||
ntState.insertClaimIntoTrie(std::string("testtesttesttest"), CClaimValue(tx5OutPoint, hash160, 50, 100, 200), true);
|
||||
ntState.removeClaimFromTrie(std::string("testtesttesttest"), tx5OutPoint, unused, true);
|
||||
ntState.insertClaimIntoTrie(std::string("testtesttesttest"), CClaimValue(tx5OutPoint, hash160, 50, 100, 200));
|
||||
ntState.removeClaimFromTrie(std::string("testtesttesttest"), tx5OutPoint);
|
||||
BOOST_CHECK_EQUAL(ntState.getMerkleHash(), hash2);
|
||||
ntState.flush();
|
||||
|
||||
|
@ -111,16 +110,16 @@ BOOST_AUTO_TEST_CASE(merkle_hash_multiple_test)
|
|||
BOOST_CHECK(ntState.checkConsistency());
|
||||
|
||||
CClaimTrieCacheTest ntState1(pclaimTrie);
|
||||
ntState1.removeClaimFromTrie(std::string("test"), tx1OutPoint, unused, true);
|
||||
ntState1.removeClaimFromTrie(std::string("test2"), tx2OutPoint, unused, true);
|
||||
ntState1.removeClaimFromTrie(std::string("test"), tx3OutPoint, unused, true);
|
||||
ntState1.removeClaimFromTrie(std::string("tes"), tx4OutPoint, unused, true);
|
||||
ntState1.removeClaimFromTrie(std::string("test"), tx1OutPoint);
|
||||
ntState1.removeClaimFromTrie(std::string("test2"), tx2OutPoint);
|
||||
ntState1.removeClaimFromTrie(std::string("test"), tx3OutPoint);
|
||||
ntState1.removeClaimFromTrie(std::string("tes"), tx4OutPoint);
|
||||
|
||||
BOOST_CHECK_EQUAL(ntState1.getMerkleHash(), hash0);
|
||||
|
||||
CClaimTrieCacheTest ntState2(pclaimTrie);
|
||||
ntState2.insertClaimIntoTrie(std::string("abab"), CClaimValue(tx6OutPoint, hash160, 50, 100, 200), true);
|
||||
ntState2.removeClaimFromTrie(std::string("test"), tx1OutPoint, unused, true);
|
||||
ntState2.insertClaimIntoTrie(std::string("abab"), CClaimValue(tx6OutPoint, hash160, 50, 100, 200));
|
||||
ntState2.removeClaimFromTrie(std::string("test"), tx1OutPoint);
|
||||
|
||||
BOOST_CHECK_EQUAL(ntState2.getMerkleHash(), hash3);
|
||||
|
||||
|
@ -131,7 +130,7 @@ BOOST_AUTO_TEST_CASE(merkle_hash_multiple_test)
|
|||
BOOST_CHECK(ntState2.checkConsistency());
|
||||
|
||||
CClaimTrieCacheTest ntState3(pclaimTrie);
|
||||
ntState3.insertClaimIntoTrie(std::string("test"), CClaimValue(tx1OutPoint, hash160, 50, 100, 200), true);
|
||||
ntState3.insertClaimIntoTrie(std::string("test"), CClaimValue(tx1OutPoint, hash160, 50, 100, 200));
|
||||
BOOST_CHECK_EQUAL(ntState3.getMerkleHash(), hash4);
|
||||
ntState3.flush();
|
||||
BOOST_CHECK(!pclaimTrie->empty());
|
||||
|
@ -139,7 +138,7 @@ BOOST_AUTO_TEST_CASE(merkle_hash_multiple_test)
|
|||
BOOST_CHECK(ntState3.checkConsistency());
|
||||
|
||||
CClaimTrieCacheTest ntState4(pclaimTrie);
|
||||
ntState4.removeClaimFromTrie(std::string("abab"), tx6OutPoint, unused, true);
|
||||
ntState4.removeClaimFromTrie(std::string("abab"), tx6OutPoint);
|
||||
BOOST_CHECK_EQUAL(ntState4.getMerkleHash(), hash2);
|
||||
ntState4.flush();
|
||||
BOOST_CHECK(!pclaimTrie->empty());
|
||||
|
@ -147,7 +146,7 @@ BOOST_AUTO_TEST_CASE(merkle_hash_multiple_test)
|
|||
BOOST_CHECK(ntState4.checkConsistency());
|
||||
|
||||
CClaimTrieCacheTest ntState5(pclaimTrie);
|
||||
ntState5.removeClaimFromTrie(std::string("test"), tx3OutPoint, unused, true);
|
||||
ntState5.removeClaimFromTrie(std::string("test"), tx3OutPoint);
|
||||
|
||||
BOOST_CHECK_EQUAL(ntState5.getMerkleHash(), hash2);
|
||||
ntState5.flush();
|
||||
|
@ -156,7 +155,7 @@ BOOST_AUTO_TEST_CASE(merkle_hash_multiple_test)
|
|||
BOOST_CHECK(ntState5.checkConsistency());
|
||||
|
||||
CClaimTrieCacheTest ntState6(pclaimTrie);
|
||||
ntState6.insertClaimIntoTrie(std::string("test"), CClaimValue(tx3OutPoint, hash160, 50, 101, 201), true);
|
||||
ntState6.insertClaimIntoTrie(std::string("test"), CClaimValue(tx3OutPoint, hash160, 50, 101, 201));
|
||||
|
||||
BOOST_CHECK_EQUAL(ntState6.getMerkleHash(), hash2);
|
||||
ntState6.flush();
|
||||
|
@ -165,10 +164,10 @@ BOOST_AUTO_TEST_CASE(merkle_hash_multiple_test)
|
|||
BOOST_CHECK(ntState6.checkConsistency());
|
||||
|
||||
CClaimTrieCacheTest ntState7(pclaimTrie);
|
||||
ntState7.removeClaimFromTrie(std::string("test"), tx3OutPoint, unused, true);
|
||||
ntState7.removeClaimFromTrie(std::string("test"), tx1OutPoint, unused, true);
|
||||
ntState7.removeClaimFromTrie(std::string("tes"), tx4OutPoint, unused, true);
|
||||
ntState7.removeClaimFromTrie(std::string("test2"), tx2OutPoint, unused, true);
|
||||
ntState7.removeClaimFromTrie(std::string("test"), tx3OutPoint);
|
||||
ntState7.removeClaimFromTrie(std::string("test"), tx1OutPoint);
|
||||
ntState7.removeClaimFromTrie(std::string("tes"), tx4OutPoint);
|
||||
ntState7.removeClaimFromTrie(std::string("test2"), tx2OutPoint);
|
||||
|
||||
BOOST_CHECK_EQUAL(ntState7.getMerkleHash(), hash0);
|
||||
ntState7.flush();
|
||||
|
@ -192,7 +191,7 @@ BOOST_AUTO_TEST_CASE(basic_insertion_info_test)
|
|||
int height = 0;
|
||||
int validHeight = 0;
|
||||
CClaimValue claimVal(claimOutPoint, claimId, amount, height, validHeight);
|
||||
ctc.insertClaimIntoTrie("test", claimVal, true);
|
||||
ctc.insertClaimIntoTrie("test", claimVal);
|
||||
|
||||
// try getClaimsForName, effectiveAmount, getInfoForName
|
||||
auto res = ctc.getClaimsForName("test");
|
||||
|
@ -213,7 +212,7 @@ BOOST_AUTO_TEST_CASE(basic_insertion_info_test)
|
|||
COutPoint supportOutPoint(tx2.GetHash(), 0);
|
||||
|
||||
CSupportValue support(supportOutPoint, claimId, supportAmount, height, validHeight);
|
||||
ctc.insertSupportIntoMap("test", support, false);
|
||||
ctc.insertSupportIntoMap("test", support);
|
||||
|
||||
auto res1 = ctc.getClaimsForName("test");
|
||||
BOOST_CHECK_EQUAL(res1.claimsNsupports.size(), 1);
|
||||
|
@ -223,71 +222,50 @@ BOOST_AUTO_TEST_CASE(basic_insertion_info_test)
|
|||
BOOST_CHECK_EQUAL(20, res1.claimsNsupports[0].effectiveAmount);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(recursive_prune_test)
|
||||
{
|
||||
CClaimTrieCacheTest cc(pclaimTrie);
|
||||
BOOST_CHECK_EQUAL(0, cc.cacheSize());
|
||||
|
||||
COutPoint outpoint;
|
||||
uint160 claimId;
|
||||
CAmount amount(20);
|
||||
int height = 0;
|
||||
int validAtHeight = 0;
|
||||
CClaimValue test_claim(outpoint, claimId, amount, height, validAtHeight);
|
||||
|
||||
CClaimTrieData data;
|
||||
// base node has a claim, so it should not be pruned
|
||||
data.insertClaim(test_claim);
|
||||
cc.insert("", std::move(data));
|
||||
|
||||
// node 1 has a claim so it should not be pruned
|
||||
data.insertClaim(test_claim);
|
||||
// set this just to make sure we get the right CClaimTrieNode back
|
||||
data.nHeightOfLastTakeover = 10;
|
||||
cc.insert("t", std::move(data));
|
||||
|
||||
//node 2 does not have a claim so it should be pruned
|
||||
// thus we should find pruned node 1 in cache
|
||||
cc.insert("te", CClaimTrieData{});
|
||||
|
||||
BOOST_CHECK(cc.erase("te"));
|
||||
BOOST_CHECK_EQUAL(2, cc.cacheSize());
|
||||
auto it = cc.getCache("t");
|
||||
BOOST_CHECK_EQUAL(10, it->nHeightOfLastTakeover);
|
||||
BOOST_CHECK_EQUAL(1, it->claims.size());
|
||||
BOOST_CHECK_EQUAL(2, cc.cacheSize());
|
||||
|
||||
cc.insert("te", CClaimTrieData{});
|
||||
// erasing "t" will make it weak
|
||||
BOOST_CHECK(cc.erase("t"));
|
||||
// so now we erase "e" as well as "t"
|
||||
BOOST_CHECK(cc.erase("te"));
|
||||
// we have claim in root
|
||||
BOOST_CHECK_EQUAL(1, cc.cacheSize());
|
||||
BOOST_CHECK(cc.erase(""));
|
||||
BOOST_CHECK_EQUAL(0, cc.cacheSize());
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(iteratetrie_test)
|
||||
{
|
||||
BOOST_CHECK(pclaimTrie->empty());
|
||||
CClaimTrieCacheTest ctc(pclaimTrie);
|
||||
|
||||
uint256 hash0(uint256S("0000000000000000000000000000000000000000000000000000000000000001"));
|
||||
CMutableTransaction tx1 = BuildTransaction(hash0);
|
||||
|
||||
const uint256 txhash = tx1.GetHash();
|
||||
CClaimValue claimVal(COutPoint(txhash, 0), ClaimIdHash(txhash, 0), CAmount(10), 0, 0);
|
||||
ctc.insertClaimIntoTrie("test", claimVal, true);
|
||||
BOOST_CHECK(ctc.flush());
|
||||
|
||||
auto hit = pclaimTrie->find("");
|
||||
BOOST_CHECK(hit);
|
||||
BOOST_CHECK_EQUAL(hit.children().size(), 1U);
|
||||
BOOST_CHECK(hit = pclaimTrie->find("test"));
|
||||
BOOST_CHECK_EQUAL(hit.children().size(), 0U);
|
||||
BOOST_CHECK_EQUAL(hit.data().claims.size(), 1);
|
||||
}
|
||||
//BOOST_AUTO_TEST_CASE(recursive_prune_test)
|
||||
//{
|
||||
// CClaimTrieCacheTest cc(pclaimTrie);
|
||||
// BOOST_CHECK_EQUAL(0, cc.getTotalClaimsInTrie());
|
||||
//
|
||||
// COutPoint outpoint;
|
||||
// uint160 claimId;
|
||||
// CAmount amount(20);
|
||||
// int height = 0;
|
||||
// int validAtHeight = 0;
|
||||
// CClaimValue test_claim(outpoint, claimId, amount, height, validAtHeight);
|
||||
//
|
||||
// CClaimTrieData data;
|
||||
// // base node has a claim, so it should not be pruned
|
||||
// data.insertClaim(test_claim);
|
||||
// cc.insert("", std::move(data));
|
||||
//
|
||||
// // node 1 has a claim so it should not be pruned
|
||||
// data.insertClaim(test_claim);
|
||||
// // set this just to make sure we get the right CClaimTrieNode back
|
||||
// data.nHeightOfLastTakeover = 10;
|
||||
// cc.insert("t", std::move(data));
|
||||
//
|
||||
// //node 2 does not have a claim so it should be pruned
|
||||
// // thus we should find pruned node 1 in cache
|
||||
// cc.insert("te", CClaimTrieData{});
|
||||
//
|
||||
// BOOST_CHECK(cc.erase("te"));
|
||||
// BOOST_CHECK_EQUAL(2, cc.cacheSize());
|
||||
// auto it = cc.getCache("t");
|
||||
// BOOST_CHECK_EQUAL(10, it->nHeightOfLastTakeover);
|
||||
// BOOST_CHECK_EQUAL(1, it->claims.size());
|
||||
// BOOST_CHECK_EQUAL(2, cc.cacheSize());
|
||||
//
|
||||
// cc.insert("te", CClaimTrieData{});
|
||||
// // erasing "t" will make it weak
|
||||
// BOOST_CHECK(cc.erase("t"));
|
||||
// // so now we erase "e" as well as "t"
|
||||
// BOOST_CHECK(cc.erase("te"));
|
||||
// // we have claim in root
|
||||
// BOOST_CHECK_EQUAL(1, cc.cacheSize());
|
||||
// BOOST_CHECK(cc.erase(""));
|
||||
// BOOST_CHECK_EQUAL(0, cc.cacheSize());
|
||||
//}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(trie_stays_consistent_test)
|
||||
{
|
||||
|
@ -300,14 +278,13 @@ BOOST_AUTO_TEST_CASE(trie_stays_consistent_test)
|
|||
CClaimValue value;
|
||||
|
||||
for (auto& name: names)
|
||||
BOOST_CHECK(cache.insertClaimIntoTrie(name, value, false));
|
||||
BOOST_CHECK(cache.insertClaimIntoTrie(name, value));
|
||||
|
||||
cache.flush();
|
||||
BOOST_CHECK(cache.checkConsistency());
|
||||
|
||||
for (auto& name: names) {
|
||||
CClaimValue temp;
|
||||
BOOST_CHECK(cache.removeClaimFromTrie(name, COutPoint(), temp, false));
|
||||
BOOST_CHECK(cache.removeClaimFromTrie(name, COutPoint()));
|
||||
cache.flush();
|
||||
BOOST_CHECK(cache.checkConsistency());
|
||||
}
|
||||
|
@ -332,37 +309,41 @@ BOOST_AUTO_TEST_CASE(takeover_workaround_triggers)
|
|||
CClaimValue value;
|
||||
value.nHeight = 1;
|
||||
|
||||
BOOST_CHECK(cache.insertClaimIntoTrie("a", value, true));
|
||||
BOOST_CHECK(cache.insertClaimIntoTrie("b", value, true));
|
||||
BOOST_CHECK(cache.insertClaimIntoTrie("c", value, true));
|
||||
BOOST_CHECK(cache.insertClaimIntoTrie("aa", value, true));
|
||||
BOOST_CHECK(cache.insertClaimIntoTrie("bb", value, true));
|
||||
BOOST_CHECK(cache.insertClaimIntoTrie("cc", value, true));
|
||||
BOOST_CHECK(cache.insertSupportIntoMap("aa", CSupportValue(), false));
|
||||
BOOST_CHECK(cache.insertClaimIntoTrie("a", value));
|
||||
BOOST_CHECK(cache.insertClaimIntoTrie("b", value));
|
||||
BOOST_CHECK(cache.insertClaimIntoTrie("c", value));
|
||||
BOOST_CHECK(cache.insertClaimIntoTrie("aa", value));
|
||||
BOOST_CHECK(cache.insertClaimIntoTrie("bb", value));
|
||||
BOOST_CHECK(cache.insertClaimIntoTrie("cc", value));
|
||||
BOOST_CHECK(cache.insertSupportIntoMap("aa", CSupportValue()));
|
||||
|
||||
BOOST_CHECK(cache.incrementBlock(icu, ecu, isu, esu, thu));
|
||||
BOOST_CHECK(cache.flush());
|
||||
BOOST_CHECK(cache.incrementBlock(icu, ecu, isu, esu, thu));
|
||||
BOOST_CHECK_EQUAL(0, cache.cacheSize());
|
||||
BOOST_CHECK_EQUAL(0, cache.getTotalNamesInTrie());
|
||||
|
||||
CSupportValue temp;
|
||||
BOOST_CHECK(cache.insertSupportIntoMap("bb", temp, false));
|
||||
BOOST_CHECK(!cache.getCache("aa"));
|
||||
BOOST_CHECK(cache.removeSupportFromMap("aa", COutPoint(), temp, false));
|
||||
CClaimValue cv;
|
||||
BOOST_CHECK(cache.insertSupportIntoMap("bb", temp));
|
||||
BOOST_CHECK(!cache.getInfoForName("aa", cv));
|
||||
BOOST_CHECK(cache.removeSupportFromMap("aa", COutPoint()));
|
||||
|
||||
BOOST_CHECK(cache.removeClaimFromTrie("aa", COutPoint(), value, false));
|
||||
BOOST_CHECK(cache.removeClaimFromTrie("bb", COutPoint(), value, false));
|
||||
BOOST_CHECK(cache.removeClaimFromTrie("cc", COutPoint(), value, false));
|
||||
BOOST_CHECK(cache.removeClaimFromTrie("aa", COutPoint()));
|
||||
BOOST_CHECK(cache.removeClaimFromTrie("bb", COutPoint()));
|
||||
BOOST_CHECK(cache.removeClaimFromTrie("cc", COutPoint()));
|
||||
|
||||
BOOST_CHECK(cache.insertClaimIntoTrie("aa", value, true));
|
||||
BOOST_CHECK(cache.insertClaimIntoTrie("bb", value, true));
|
||||
BOOST_CHECK(cache.insertClaimIntoTrie("cc", value, true));
|
||||
BOOST_CHECK(cache.insertClaimIntoTrie("aa", value));
|
||||
BOOST_CHECK(cache.insertClaimIntoTrie("bb", value));
|
||||
BOOST_CHECK(cache.insertClaimIntoTrie("cc", value));
|
||||
|
||||
BOOST_CHECK(cache.incrementBlock(icu, ecu, isu, esu, thu));
|
||||
|
||||
BOOST_CHECK_EQUAL(3, cache.getCache("aa")->nHeightOfLastTakeover);
|
||||
BOOST_CHECK_EQUAL(3, cache.getCache("bb")->nHeightOfLastTakeover);
|
||||
BOOST_CHECK_EQUAL(1, cache.getCache("cc")->nHeightOfLastTakeover);
|
||||
BOOST_CHECK(cache.getInfoForName("aa", cv));
|
||||
BOOST_CHECK_EQUAL(3, cv.nValidAtHeight);
|
||||
BOOST_CHECK(cache.getInfoForName("bb", cv));
|
||||
BOOST_CHECK_EQUAL(3, cv.nValidAtHeight);
|
||||
BOOST_CHECK(cache.getInfoForName("cc", cv));
|
||||
BOOST_CHECK_EQUAL(1, cv.nValidAtHeight);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(verify_basic_serialization)
|
||||
|
@ -384,67 +365,4 @@ BOOST_AUTO_TEST_CASE(verify_basic_serialization)
|
|||
BOOST_CHECK_EQUAL(cv, cv2);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(claimtrienode_serialize_unserialize)
|
||||
{
|
||||
CDataStream ss(SER_DISK, 0);
|
||||
|
||||
uint160 hash160;
|
||||
|
||||
CClaimTrieData n1;
|
||||
CClaimTrieData n2;
|
||||
CClaimValue throwaway;
|
||||
|
||||
ss << n1;
|
||||
ss >> n2;
|
||||
BOOST_CHECK_EQUAL(n1, n2);
|
||||
|
||||
CClaimValue v1(COutPoint(uint256S("0000000000000000000000000000000000000000000000000000000000000001"), 0), hash160, 50, 0, 100);
|
||||
CClaimValue v2(COutPoint(uint256S("0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"), 1), hash160, 100, 1, 101);
|
||||
|
||||
n1.insertClaim(v1);
|
||||
BOOST_CHECK(n1 != n2);
|
||||
ss << n1;
|
||||
ss >> n2;
|
||||
BOOST_CHECK_EQUAL(n1, n2);
|
||||
|
||||
n1.insertClaim(v2);
|
||||
BOOST_CHECK(n1 != n2);
|
||||
ss << n1;
|
||||
ss >> n2;
|
||||
BOOST_CHECK_EQUAL(n1, n2);
|
||||
|
||||
n1.removeClaim(v1.outPoint, throwaway);
|
||||
BOOST_CHECK(n1 != n2);
|
||||
ss << n1;
|
||||
ss >> n2;
|
||||
BOOST_CHECK_EQUAL(n1, n2);
|
||||
|
||||
n1.removeClaim(v2.outPoint, throwaway);
|
||||
BOOST_CHECK(n1 != n2);
|
||||
ss << n1;
|
||||
ss >> n2;
|
||||
BOOST_CHECK_EQUAL(n1, n2);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(claimtrienode_remove_invalid_claim)
|
||||
{
|
||||
uint160 hash160;
|
||||
|
||||
CClaimTrieData n1;
|
||||
CClaimTrieData n2;
|
||||
CClaimValue throwaway;
|
||||
|
||||
CClaimValue v1(COutPoint(uint256S("0000000000000000000000000000000000000000000000000000000000000001"), 0), hash160, 50, 0, 100);
|
||||
CClaimValue v2(COutPoint(uint256S("0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"), 1), hash160, 100, 1, 101);
|
||||
|
||||
n1.insertClaim(v1);
|
||||
n2.insertClaim(v2);
|
||||
|
||||
bool invalidClaim = n2.removeClaim(v1.outPoint, throwaway);
|
||||
BOOST_CHECK_EQUAL(invalidClaim, false);
|
||||
|
||||
invalidClaim = n1.removeClaim(v2.outPoint, throwaway);
|
||||
BOOST_CHECK_EQUAL(invalidClaim, false);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END()
|
||||
|
|
|
@ -276,7 +276,7 @@ BOOST_AUTO_TEST_CASE(hardfork_disk_test)
|
|||
BOOST_CHECK_EQUAL(fixture.expirationTime(), 3);
|
||||
fixture.IncrementBlocks(7, true);
|
||||
BOOST_CHECK_EQUAL(fixture.expirationTime(), 6);
|
||||
fixture.ReadFromDisk(chainActive.Tip());
|
||||
fixture.ValidateTipMatches(chainActive.Tip());
|
||||
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 +287,7 @@ BOOST_AUTO_TEST_CASE(hardfork_disk_test)
|
|||
CMutableTransaction s1 = fixture.MakeSupport(fixture.GetCoinbase(), tx1, "test", 1);
|
||||
fixture.IncrementBlocks(1);
|
||||
|
||||
fixture.ReadFromDisk(chainActive.Tip());
|
||||
fixture.ValidateTipMatches(chainActive.Tip());
|
||||
BOOST_CHECK_EQUAL(fixture.expirationTime(), 3);
|
||||
fixture.IncrementBlocks(1);
|
||||
BOOST_CHECK_EQUAL(fixture.expirationTime(), 6);
|
||||
|
@ -308,7 +308,7 @@ 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.ReadFromDisk(chainActive.Tip());
|
||||
fixture.ValidateTipMatches(chainActive.Tip());
|
||||
CMutableTransaction u2 = fixture.MakeUpdate(tx2, "test2", "two", ClaimIdHash(tx2.GetHash(), 0), 1);
|
||||
// increment to fork
|
||||
fixture.IncrementBlocks(2);
|
||||
|
@ -762,7 +762,7 @@ BOOST_AUTO_TEST_CASE(get_claim_by_id_test_3)
|
|||
|
||||
CClaimValue claimValue;
|
||||
std::string claimName;
|
||||
BOOST_CHECK(getClaimById(claimId, claimName, &claimValue));
|
||||
BOOST_CHECK(fixture.getClaimById(claimId, claimName, claimValue));
|
||||
BOOST_CHECK_EQUAL(claimName, name);
|
||||
BOOST_CHECK_EQUAL(claimValue.claimId, claimId);
|
||||
// make second claim with activation delay 1
|
||||
|
@ -772,14 +772,14 @@ BOOST_AUTO_TEST_CASE(get_claim_by_id_test_3)
|
|||
fixture.IncrementBlocks(1);
|
||||
// second claim is not activated yet, but can still access by claim id
|
||||
BOOST_CHECK(fixture.is_best_claim(name, tx1));
|
||||
BOOST_CHECK(getClaimById(claimId2, claimName, &claimValue));
|
||||
BOOST_CHECK(fixture.getClaimById(claimId2, claimName, claimValue));
|
||||
BOOST_CHECK_EQUAL(claimName, name);
|
||||
BOOST_CHECK_EQUAL(claimValue.claimId, claimId2);
|
||||
|
||||
fixture.IncrementBlocks(1);
|
||||
// second claim has activated
|
||||
BOOST_CHECK(fixture.is_best_claim(name, tx2));
|
||||
BOOST_CHECK(getClaimById(claimId2, claimName, &claimValue));
|
||||
BOOST_CHECK(fixture.getClaimById(claimId2, claimName, claimValue));
|
||||
BOOST_CHECK_EQUAL(claimName, name);
|
||||
BOOST_CHECK_EQUAL(claimValue.claimId, claimId2);
|
||||
|
||||
|
@ -788,14 +788,14 @@ BOOST_AUTO_TEST_CASE(get_claim_by_id_test_3)
|
|||
// second claim has been deactivated via decrement
|
||||
// should still be accesible via claim id
|
||||
BOOST_CHECK(fixture.is_best_claim(name, tx1));
|
||||
BOOST_CHECK(getClaimById(claimId2, claimName, &claimValue));
|
||||
BOOST_CHECK(fixture.getClaimById(claimId2, claimName, claimValue));
|
||||
BOOST_CHECK_EQUAL(claimName, name);
|
||||
BOOST_CHECK_EQUAL(claimValue.claimId, claimId2);
|
||||
|
||||
fixture.IncrementBlocks(1);
|
||||
// second claim should have been re activated via increment
|
||||
BOOST_CHECK(fixture.is_best_claim(name, tx2));
|
||||
BOOST_CHECK(getClaimById(claimId2, claimName, &claimValue));
|
||||
BOOST_CHECK(fixture.getClaimById(claimId2, claimName, claimValue));
|
||||
BOOST_CHECK_EQUAL(claimName, name);
|
||||
BOOST_CHECK_EQUAL(claimValue.claimId, claimId2);
|
||||
}
|
||||
|
|
|
@ -268,7 +268,6 @@ void ClaimTrieChainFixture::IncrementBlocks(int num_blocks, bool mark)
|
|||
if (mark)
|
||||
marks.push_back(chainActive.Height());
|
||||
|
||||
clear(); // clears the internal cache
|
||||
for (int i = 0; i < num_blocks; ++i) {
|
||||
CScript coinbase_scriptpubkey;
|
||||
coinbase_scriptpubkey << CScriptNum(chainActive.Height());
|
||||
|
@ -286,7 +285,6 @@ void ClaimTrieChainFixture::IncrementBlocks(int num_blocks, bool mark)
|
|||
// disconnect i blocks from tip
|
||||
void ClaimTrieChainFixture::DecrementBlocks(int num_blocks)
|
||||
{
|
||||
clear(); // clears the internal cache
|
||||
CValidationState state;
|
||||
{
|
||||
LOCK(cs_main);
|
||||
|
@ -309,52 +307,32 @@ void ClaimTrieChainFixture::DecrementBlocks()
|
|||
DecrementBlocks(chainActive.Height() - mark);
|
||||
}
|
||||
|
||||
template <typename K>
|
||||
bool ClaimTrieChainFixture::keyTypeEmpty(uint8_t keyType)
|
||||
{
|
||||
boost::scoped_ptr<CDBIterator> pcursor(base->db->NewIterator());
|
||||
pcursor->SeekToFirst();
|
||||
|
||||
while (pcursor->Valid()) {
|
||||
std::pair<uint8_t, K> key;
|
||||
if (pcursor->GetKey(key))
|
||||
if (key.first == keyType)
|
||||
return false;
|
||||
pcursor->Next();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ClaimTrieChainFixture::queueEmpty()
|
||||
{
|
||||
for (const auto& claimQueue: claimQueueCache)
|
||||
if (!claimQueue.second.empty())
|
||||
return false;
|
||||
return keyTypeEmpty<int>(CLAIM_QUEUE_ROW);
|
||||
int64_t count;
|
||||
base->_db << "SELECT COUNT(*) FROM claims WHERE validHeight >= ?" << nNextHeight >> count;
|
||||
return count == 0;
|
||||
}
|
||||
|
||||
bool ClaimTrieChainFixture::expirationQueueEmpty()
|
||||
{
|
||||
for (const auto& expirationQueue: expirationQueueCache)
|
||||
if (!expirationQueue.second.empty())
|
||||
return false;
|
||||
return keyTypeEmpty<int>(CLAIM_EXP_QUEUE_ROW);
|
||||
int64_t count;
|
||||
base->_db << "SELECT COUNT(*) FROM claims WHERE expirationHeight >= ?" << nNextHeight >> count;
|
||||
return count == 0;
|
||||
}
|
||||
|
||||
bool ClaimTrieChainFixture::supportEmpty()
|
||||
{
|
||||
for (const auto& entry: supportCache)
|
||||
if (!entry.second.empty())
|
||||
return false;
|
||||
return supportCache.empty() && keyTypeEmpty<std::string>(SUPPORT);
|
||||
int64_t count;
|
||||
base->_db << "SELECT COUNT(*) FROM supports" >> count;
|
||||
return count == 0;
|
||||
}
|
||||
|
||||
bool ClaimTrieChainFixture::supportQueueEmpty()
|
||||
{
|
||||
for (const auto& support: supportQueueCache)
|
||||
if (!support.second.empty())
|
||||
return false;
|
||||
return keyTypeEmpty<int>(SUPPORT_QUEUE_ROW);
|
||||
int64_t count;
|
||||
base->_db << "SELECT COUNT(*) FROM supports WHERE validHeight >= ?" << nNextHeight >> count;
|
||||
return count == 0;
|
||||
}
|
||||
|
||||
int ClaimTrieChainFixture::proportionalDelayFactor()
|
||||
|
@ -413,7 +391,7 @@ boost::test_tools::predicate_result ClaimTrieChainFixture::best_claim_effective_
|
|||
return true;
|
||||
}
|
||||
|
||||
std::size_t ClaimTrieChainFixture::getTotalNamesInTrie() const
|
||||
{
|
||||
return base->getTotalNamesInTrie();
|
||||
bool ClaimTrieChainFixture::getClaimById(const uint160 &claimId, std::string &name, CClaimValue &value) {
|
||||
std::vector<unsigned char> claim(claimId.begin(), claimId.end());
|
||||
return findNameForClaim(claim, value, name);
|
||||
}
|
||||
|
|
|
@ -28,8 +28,6 @@
|
|||
|
||||
extern ::CChainState g_chainstate;
|
||||
extern ::ArgsManager gArgs;
|
||||
extern std::vector<std::string> random_strings(std::size_t count);
|
||||
extern bool getClaimById(const uint160&, std::string&, CClaimValue*);
|
||||
|
||||
CMutableTransaction BuildTransaction(const uint256& prevhash);
|
||||
CMutableTransaction BuildTransaction(const CTransaction& prev, uint32_t prevout=0, unsigned int numOutputs=1, int locktime=0);
|
||||
|
@ -56,7 +54,7 @@ struct ClaimTrieChainFixture: public CClaimTrieCache
|
|||
|
||||
ClaimTrieChainFixture();
|
||||
|
||||
~ClaimTrieChainFixture();
|
||||
~ClaimTrieChainFixture() override;
|
||||
|
||||
void setExpirationForkHeight(int targetMinusCurrent, int64_t preForkExpirationTime, int64_t postForkExpirationTime);
|
||||
|
||||
|
@ -105,6 +103,8 @@ struct ClaimTrieChainFixture: public CClaimTrieCache
|
|||
|
||||
int proportionalDelayFactor();
|
||||
|
||||
bool getClaimById(const uint160& claimId, std::string& name, CClaimValue& value);
|
||||
|
||||
// is a claim in queue
|
||||
boost::test_tools::predicate_result is_claim_in_queue(const std::string& name, const CTransaction &tx);
|
||||
|
||||
|
@ -113,12 +113,6 @@ struct ClaimTrieChainFixture: public CClaimTrieCache
|
|||
|
||||
// check effective quantity of best claim
|
||||
boost::test_tools::predicate_result best_claim_effective_amount_equals(const std::string& name, CAmount amount);
|
||||
|
||||
std::size_t getTotalNamesInTrie() const;
|
||||
|
||||
private:
|
||||
template <typename K>
|
||||
bool keyTypeEmpty(uint8_t keyType);
|
||||
};
|
||||
|
||||
#endif // _CLAIMTRIEFIXTURE_H_
|
||||
|
|
|
@ -49,9 +49,7 @@ BOOST_AUTO_TEST_CASE(hash_includes_all_claims_single_test)
|
|||
uint160 claimId = ClaimIdHash(tx1.GetHash(), 0);
|
||||
|
||||
CClaimTrieProof proof;
|
||||
BOOST_CHECK(fixture.getProofForName("test", proof, [&claimId](const CClaimValue& claim) {
|
||||
return claim.claimId == claimId;
|
||||
}));
|
||||
BOOST_CHECK(fixture.getProofForName("test", claimId, proof));
|
||||
BOOST_CHECK(proof.hasValue);
|
||||
BOOST_CHECK_EQUAL(proof.outPoint, outPoint);
|
||||
auto claimHash = getValueHash(outPoint, proof.nHeightOfLastTakeover);
|
||||
|
@ -79,9 +77,7 @@ BOOST_AUTO_TEST_CASE(hash_includes_all_claims_triple_test)
|
|||
for (auto& claimSupports : fixture.getClaimsForName(name).claimsNsupports) {
|
||||
CClaimTrieProof proof;
|
||||
auto& claim = claimSupports.claim;
|
||||
BOOST_CHECK(fixture.getProofForName(name, proof, [&claim](const CClaimValue& value) {
|
||||
return claim.claimId == value.claimId;
|
||||
}));
|
||||
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);
|
||||
|
@ -110,9 +106,7 @@ BOOST_AUTO_TEST_CASE(hash_includes_all_claims_branched_test)
|
|||
for (auto& claimSupports : fixture.getClaimsForName(name).claimsNsupports) {
|
||||
CClaimTrieProof proof;
|
||||
auto& claim = claimSupports.claim;
|
||||
BOOST_CHECK(fixture.getProofForName(name, proof, [&claim](const CClaimValue& value) {
|
||||
return claim.claimId == value.claimId;
|
||||
}));
|
||||
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);
|
||||
|
@ -121,6 +115,34 @@ BOOST_AUTO_TEST_CASE(hash_includes_all_claims_branched_test)
|
|||
}
|
||||
}
|
||||
|
||||
std::vector<std::string> random_strings(std::size_t count)
|
||||
{
|
||||
static auto& chrs = "0123456789"
|
||||
"abcdefghijklmnopqrstuvwxyz"
|
||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
||||
|
||||
FastRandomContext frc(true);
|
||||
|
||||
std::unordered_set<std::string> strings;
|
||||
strings.reserve(count);
|
||||
|
||||
while(strings.size() < count) {
|
||||
auto length = frc.randrange(sizeof(chrs) - 2) + 1;
|
||||
|
||||
std::string s;
|
||||
s.reserve(length);
|
||||
|
||||
while (length--)
|
||||
s += chrs[frc.randrange(sizeof(chrs) - 1)];
|
||||
|
||||
strings.emplace(s);
|
||||
}
|
||||
|
||||
std::vector<std::string> ret(strings.begin(), strings.end());
|
||||
std::random_shuffle(ret.begin(), ret.end(), [&frc](std::size_t n) { return frc.randrange(n); });
|
||||
return ret;
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(hash_claims_children_fuzzer_test)
|
||||
{
|
||||
ClaimTrieChainFixture fixture;
|
||||
|
@ -145,9 +167,7 @@ BOOST_AUTO_TEST_CASE(hash_claims_children_fuzzer_test)
|
|||
for (auto& claimSupports : fixture.getClaimsForName(name).claimsNsupports) {
|
||||
CClaimTrieProof proof;
|
||||
auto& claim = claimSupports.claim;
|
||||
BOOST_CHECK(fixture.getProofForName(name, proof, [&claim](const CClaimValue& value) {
|
||||
return claim.claimId == value.claimId;
|
||||
}));
|
||||
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);
|
||||
|
@ -278,31 +298,31 @@ BOOST_AUTO_TEST_CASE(value_proof_test)
|
|||
|
||||
CClaimTrieProof proof;
|
||||
|
||||
BOOST_CHECK(fixture.getProofForName(sName1, proof));
|
||||
BOOST_CHECK(fixture.getProofForName(sName1, ClaimIdHash(tx1.GetHash(), 0), proof));
|
||||
BOOST_CHECK(verify_proof(proof, chainActive.Tip()->hashClaimTrie, sName1));
|
||||
BOOST_CHECK_EQUAL(proof.outPoint, tx1OutPoint);
|
||||
|
||||
BOOST_CHECK(fixture.getProofForName(sName2, proof));
|
||||
BOOST_CHECK(fixture.getProofForName(sName2, ClaimIdHash(tx2.GetHash(), 0), proof));
|
||||
BOOST_CHECK(verify_proof(proof, chainActive.Tip()->hashClaimTrie, sName2));
|
||||
BOOST_CHECK_EQUAL(proof.outPoint, tx2OutPoint);
|
||||
|
||||
BOOST_CHECK(fixture.getProofForName(sName3, proof));
|
||||
BOOST_CHECK(fixture.getProofForName(sName3, ClaimIdHash(tx3.GetHash(), 0), proof));
|
||||
BOOST_CHECK(verify_proof(proof, chainActive.Tip()->hashClaimTrie, sName3));
|
||||
BOOST_CHECK_EQUAL(proof.outPoint, tx3OutPoint);
|
||||
|
||||
BOOST_CHECK(fixture.getProofForName(sName4, proof));
|
||||
BOOST_CHECK(fixture.getProofForName(sName4, ClaimIdHash(tx4.GetHash(), 0), proof));
|
||||
BOOST_CHECK(verify_proof(proof, chainActive.Tip()->hashClaimTrie, sName4));
|
||||
BOOST_CHECK_EQUAL(proof.outPoint, tx4OutPoint);
|
||||
|
||||
BOOST_CHECK(fixture.getProofForName(sName5, proof));
|
||||
BOOST_CHECK(fixture.getProofForName(sName5, ClaimIdHash(tx1.GetHash(), 0), proof));
|
||||
BOOST_CHECK(verify_proof(proof, chainActive.Tip()->hashClaimTrie, sName5));
|
||||
BOOST_CHECK_EQUAL(proof.hasValue, false);
|
||||
|
||||
BOOST_CHECK(fixture.getProofForName(sName6, proof));
|
||||
BOOST_CHECK(fixture.getProofForName(sName6, ClaimIdHash({}, 0), proof));
|
||||
BOOST_CHECK(verify_proof(proof, chainActive.Tip()->hashClaimTrie, sName6));
|
||||
BOOST_CHECK_EQUAL(proof.hasValue, false);
|
||||
|
||||
BOOST_CHECK(fixture.getProofForName(sName7, proof));
|
||||
BOOST_CHECK(fixture.getProofForName(sName7, ClaimIdHash(fixture.getMerkleHash(), 0), proof));
|
||||
BOOST_CHECK(verify_proof(proof, chainActive.Tip()->hashClaimTrie, sName7));
|
||||
BOOST_CHECK_EQUAL(proof.hasValue, false);
|
||||
|
||||
|
@ -314,34 +334,26 @@ BOOST_AUTO_TEST_CASE(value_proof_test)
|
|||
BOOST_CHECK(fixture.getInfoForName(sName7, val));
|
||||
BOOST_CHECK_EQUAL(val.outPoint, tx5OutPoint);
|
||||
|
||||
BOOST_CHECK(fixture.getProofForName(sName1, proof));
|
||||
BOOST_CHECK(fixture.getProofForName(sName1, ClaimIdHash(tx1.GetHash(), 0), proof));
|
||||
BOOST_CHECK(verify_proof(proof, chainActive.Tip()->hashClaimTrie, sName1));
|
||||
BOOST_CHECK_EQUAL(proof.outPoint, tx1OutPoint);
|
||||
|
||||
BOOST_CHECK(fixture.getProofForName(sName2, proof));
|
||||
BOOST_CHECK(fixture.getProofForName(sName2, ClaimIdHash(tx2.GetHash(), 0), proof));
|
||||
BOOST_CHECK(verify_proof(proof, chainActive.Tip()->hashClaimTrie, sName2));
|
||||
BOOST_CHECK_EQUAL(proof.outPoint, tx2OutPoint);
|
||||
|
||||
BOOST_CHECK(fixture.getProofForName(sName3, proof));
|
||||
BOOST_CHECK(fixture.getProofForName(sName3, ClaimIdHash(tx3.GetHash(), 0), proof));
|
||||
BOOST_CHECK(verify_proof(proof, chainActive.Tip()->hashClaimTrie, sName3));
|
||||
BOOST_CHECK_EQUAL(proof.outPoint, tx3OutPoint);
|
||||
|
||||
BOOST_CHECK(fixture.getProofForName(sName4, proof));
|
||||
BOOST_CHECK(fixture.getProofForName(sName4, ClaimIdHash(tx4.GetHash(), 0), proof));
|
||||
BOOST_CHECK(verify_proof(proof, chainActive.Tip()->hashClaimTrie, sName4));
|
||||
BOOST_CHECK_EQUAL(proof.outPoint, tx4OutPoint);
|
||||
|
||||
BOOST_CHECK(fixture.getProofForName(sName5, proof));
|
||||
BOOST_CHECK(fixture.getProofForName(sName5, ClaimIdHash(tx5.GetHash(), 0), proof));
|
||||
BOOST_CHECK(verify_proof(proof, chainActive.Tip()->hashClaimTrie, sName5));
|
||||
BOOST_CHECK_EQUAL(proof.hasValue, false);
|
||||
|
||||
BOOST_CHECK(fixture.getProofForName(sName6, proof));
|
||||
BOOST_CHECK(verify_proof(proof, chainActive.Tip()->hashClaimTrie, sName6));
|
||||
BOOST_CHECK_EQUAL(proof.hasValue, false);
|
||||
|
||||
BOOST_CHECK(fixture.getProofForName(sName7, proof));
|
||||
BOOST_CHECK(verify_proof(proof, chainActive.Tip()->hashClaimTrie, sName7));
|
||||
BOOST_CHECK_EQUAL(proof.outPoint, tx5OutPoint);
|
||||
|
||||
fixture.DecrementBlocks();
|
||||
BOOST_CHECK(pclaimTrie->empty());
|
||||
BOOST_CHECK(fixture.queueEmpty());
|
||||
|
|
|
@ -93,8 +93,6 @@ BOOST_AUTO_TEST_CASE(claimtriebranching_normalization)
|
|||
BOOST_CHECK(fixture.is_best_claim("normalizetest", tx1));
|
||||
BOOST_CHECK(fixture.best_claim_effective_amount_equals("normalizetest", 3));
|
||||
|
||||
BOOST_CHECK(!pclaimTrie->find("normalizeTest"));
|
||||
|
||||
// Check equivalence of normalized claim names
|
||||
BOOST_CHECK(fixture.is_best_claim("normalizetest", tx1)); // collapsed tx2
|
||||
fixture.IncrementBlocks(1);
|
||||
|
@ -192,7 +190,7 @@ BOOST_AUTO_TEST_CASE(claimtriecache_normalization)
|
|||
|
||||
CClaimValue lookupClaim;
|
||||
std::string lookupName;
|
||||
BOOST_CHECK(getClaimById(ClaimIdHash(tx2.GetHash(), 0), lookupName, &lookupClaim));
|
||||
BOOST_CHECK(fixture.getClaimById(ClaimIdHash(tx2.GetHash(), 0), lookupName, lookupClaim));
|
||||
CClaimValue nval1;
|
||||
BOOST_CHECK(fixture.getInfoForName("amelie1", nval1));
|
||||
// amélie is not found cause normalization still not appear
|
||||
|
@ -219,12 +217,11 @@ BOOST_AUTO_TEST_CASE(claimtriecache_normalization)
|
|||
BOOST_CHECK(ReadBlockFromDisk(block, pindex, Params().GetConsensus()));
|
||||
BOOST_CHECK(g_chainstate.DisconnectBlock(block, pindex, coins, trieCache) == DisconnectResult::DISCONNECT_OK);
|
||||
BOOST_CHECK(!trieCache.shouldNormalize());
|
||||
BOOST_CHECK(!trieCache.spendClaim(name_normd, COutPoint(tx2.GetHash(), 0), currentHeight, amelieValidHeight));
|
||||
BOOST_CHECK(trieCache.spendClaim(name_upper, COutPoint(tx2.GetHash(), 0), currentHeight, amelieValidHeight));
|
||||
BOOST_CHECK(!trieCache.removeClaim(ClaimIdHash(tx2.GetHash(), 0), name_normd, amelieValidHeight));
|
||||
BOOST_CHECK(trieCache.removeClaim(ClaimIdHash(tx2.GetHash(), 0), name_upper, amelieValidHeight));
|
||||
|
||||
BOOST_CHECK(!pclaimTrie->find(name));
|
||||
BOOST_CHECK(trieCache.getInfoForName(name, nval1));
|
||||
BOOST_CHECK(trieCache.addClaim(name, COutPoint(tx1.GetHash(), 0), ClaimIdHash(tx1.GetHash(), 0), CAmount(2), currentHeight + 1));
|
||||
BOOST_CHECK(trieCache.addClaim(name, COutPoint(tx1.GetHash(), 0), ClaimIdHash(tx1.GetHash(), 0), CAmount(2), currentHeight + 1, {}));
|
||||
BOOST_CHECK(trieCache.getInfoForName(name, nval1));
|
||||
insertUndoType insertUndo;
|
||||
claimQueueRowType expireUndo;
|
||||
|
@ -233,10 +230,6 @@ BOOST_AUTO_TEST_CASE(claimtriecache_normalization)
|
|||
std::vector<std::pair<std::string, int> > takeoverHeightUndo;
|
||||
BOOST_CHECK(trieCache.incrementBlock(insertUndo, expireUndo, insertSupportUndo, expireSupportUndo, takeoverHeightUndo));
|
||||
BOOST_CHECK(trieCache.shouldNormalize());
|
||||
|
||||
// we cannot use getXXXForName cause they will normalized name
|
||||
for (auto it = pclaimTrie->cbegin(); it != pclaimTrie->cend(); ++it)
|
||||
BOOST_CHECK(it.key() != name);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(undo_normalization_does_not_kill_claim_order)
|
||||
|
@ -312,11 +305,11 @@ BOOST_AUTO_TEST_CASE(normalization_removal_test)
|
|||
|
||||
CClaimTrieCache cache(pclaimTrie);
|
||||
int height = chainActive.Height() + 1;
|
||||
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.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, {});
|
||||
insertUndoType insertUndo;
|
||||
claimQueueRowType expireUndo;
|
||||
insertUndoType insertSupportUndo;
|
||||
|
@ -329,11 +322,12 @@ BOOST_AUTO_TEST_CASE(normalization_removal_test)
|
|||
BOOST_CHECK(cache.getClaimsForName("ab").claimsNsupports[2].supports.size() == 1U);
|
||||
BOOST_CHECK(cache.decrementBlock(insertUndo, expireUndo, insertSupportUndo, expireSupportUndo));
|
||||
BOOST_CHECK(cache.finalizeDecrement(takeoverHeightUndo));
|
||||
BOOST_CHECK(cache.undoAddSupport("AB", COutPoint(sx1.GetHash(), 0), height));
|
||||
BOOST_CHECK(cache.undoAddSupport("Ab", COutPoint(sx2.GetHash(), 0), height));
|
||||
BOOST_CHECK(cache.undoAddClaim("AB", COutPoint(tx1.GetHash(), 0), height));
|
||||
BOOST_CHECK(cache.undoAddClaim("Ab", COutPoint(tx2.GetHash(), 0), height));
|
||||
BOOST_CHECK(cache.undoAddClaim("aB", COutPoint(tx3.GetHash(), 0), height));
|
||||
std::string unused;
|
||||
BOOST_CHECK(cache.removeSupport(COutPoint(sx1.GetHash(), 0), unused, height));
|
||||
BOOST_CHECK(cache.removeSupport(COutPoint(sx2.GetHash(), 0), unused, height));
|
||||
BOOST_CHECK(cache.removeClaim(ClaimIdHash(tx1.GetHash(), 0), unused, height));
|
||||
BOOST_CHECK(cache.removeClaim(ClaimIdHash(tx2.GetHash(), 0), unused, height));
|
||||
BOOST_CHECK(cache.removeClaim(ClaimIdHash(tx3.GetHash(), 0), unused, height));
|
||||
BOOST_CHECK(cache.getClaimsForName("ab").claimsNsupports.size() == 0U);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,293 +0,0 @@
|
|||
#include <claimtrie.h>
|
||||
#include <prefixtrie.h>
|
||||
#include <random.h>
|
||||
|
||||
#include <boost/test/unit_test.hpp>
|
||||
#include <test/claimtriefixture.h>
|
||||
#include <test/test_bitcoin.h>
|
||||
|
||||
#include <chrono>
|
||||
|
||||
std::vector<std::string> random_strings(std::size_t count)
|
||||
{
|
||||
static auto& chrs = "0123456789"
|
||||
"abcdefghijklmnopqrstuvwxyz"
|
||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
||||
|
||||
FastRandomContext frc(true);
|
||||
|
||||
std::unordered_set<std::string> strings;
|
||||
strings.reserve(count);
|
||||
|
||||
while(strings.size() < count) {
|
||||
auto length = frc.randrange(sizeof(chrs) - 2) + 1;
|
||||
|
||||
std::string s;
|
||||
s.reserve(length);
|
||||
|
||||
while (length--)
|
||||
s += chrs[frc.randrange(sizeof(chrs) - 1)];
|
||||
|
||||
strings.emplace(s);
|
||||
}
|
||||
|
||||
std::vector<std::string> ret(strings.begin(), strings.end());
|
||||
std::random_shuffle(ret.begin(), ret.end(), [&frc](std::size_t n) { return frc.randrange(n); });
|
||||
return ret;
|
||||
}
|
||||
|
||||
using namespace std;
|
||||
|
||||
BOOST_FIXTURE_TEST_SUITE(prefixtrie_tests, RegTestingSetup)
|
||||
|
||||
#ifndef MAC_OSX // can't find a random number generator that produces the same sequence on OSX
|
||||
BOOST_AUTO_TEST_CASE(triehash_fuzzer_test)
|
||||
{
|
||||
ClaimTrieChainFixture fixture;
|
||||
|
||||
auto envClaims = std::getenv("TRIEHASH_FUZZER_CLAIMS");
|
||||
auto envBlocks = std::getenv("TRIEHASH_FUZZER_BLOCKS");
|
||||
|
||||
const int claimsPerBlock = envClaims ? std::atoi(envClaims) : 100;
|
||||
const int blocks = envBlocks ? std::atoi(envBlocks) : 13;
|
||||
|
||||
auto names = random_strings(blocks * claimsPerBlock);
|
||||
|
||||
FastRandomContext frc(true);
|
||||
std::unordered_map<std::string, std::vector<CMutableTransaction>> existingClaims;
|
||||
std::vector<CMutableTransaction> existingSupports;
|
||||
std::string value(1024, 'c');
|
||||
|
||||
std::vector<CTransaction> cb {fixture.GetCoinbase()};
|
||||
for (int i = 0; i < blocks; ++i) {
|
||||
for (int j = 0; j < claimsPerBlock; ++j) {
|
||||
auto name = names[i * claimsPerBlock + j];
|
||||
auto supportFront = frc.randrange(4) == 0;
|
||||
auto supportBack = frc.randrange(4) == 0;
|
||||
auto removeClaim = frc.randrange(4) == 0;
|
||||
auto removeSupport = frc.randrange(4) == 0;
|
||||
auto hit = existingClaims.find(name);
|
||||
if (supportFront && hit != existingClaims.end() && hit->second.size()) {
|
||||
auto tx = fixture.MakeSupport(cb.back(), hit->second[frc.rand64() % hit->second.size()], name, 2);
|
||||
existingSupports.push_back(tx);
|
||||
cb.emplace_back(std::move(tx));
|
||||
}
|
||||
if (removeClaim && hit != existingClaims.end() && hit->second.size()) {
|
||||
auto idx = frc.rand64() % hit->second.size();
|
||||
fixture.Spend(hit->second[idx]);
|
||||
hit->second.erase(hit->second.begin() + idx);
|
||||
} else {
|
||||
auto tx = fixture.MakeClaim(cb.back(), name, value, 2);
|
||||
existingClaims[name].push_back(tx);
|
||||
hit = existingClaims.find(name);
|
||||
cb.emplace_back(std::move(tx));
|
||||
}
|
||||
if (supportBack && hit != existingClaims.end() && hit->second.size()) {
|
||||
auto tx = fixture.MakeSupport(cb.back(), hit->second[frc.rand64() % hit->second.size()], name, 2);
|
||||
existingSupports.push_back(tx);
|
||||
cb.emplace_back(std::move(tx));
|
||||
}
|
||||
if (removeSupport && (i & 7) == 7 && !existingSupports.empty()) {
|
||||
const auto tidx = frc.rand64() % existingSupports.size();
|
||||
const auto tx = existingSupports[tidx];
|
||||
fixture.Spend(tx);
|
||||
existingSupports.erase(existingSupports.begin() + tidx);
|
||||
}
|
||||
if (cb.back().GetValueOut() < 10 || cb.size() > 40000) {
|
||||
cb.clear();
|
||||
cb.push_back(fixture.GetCoinbase());
|
||||
}
|
||||
}
|
||||
fixture.IncrementBlocks(1);
|
||||
if (blocks > 13 && i % 50 == 0) // travisCI needs some periodic output
|
||||
std::cerr << "In triehash_fuzzer_test with " << fixture.getTotalNamesInTrie() << " names at block " << i << std::endl;
|
||||
}
|
||||
|
||||
if (blocks == 1000 && claimsPerBlock == 100)
|
||||
BOOST_CHECK_EQUAL(fixture.getMerkleHash().GetHex(), "28825257a129eef69cab87d6255c8359fc6dc083ca7f09222526e3a7971f382d");
|
||||
else if (blocks == 13 && claimsPerBlock == 100)
|
||||
BOOST_CHECK_EQUAL(fixture.getMerkleHash().GetHex(), "4e5984d6984f5f05d50e821e6228d56bcfbd16ca2093cd0308f6ff1c2bc8689a");
|
||||
else
|
||||
std::cerr << "Hash: " << fixture.getMerkleHash().GetHex() << std::endl;
|
||||
}
|
||||
#endif
|
||||
|
||||
BOOST_AUTO_TEST_CASE(insert_erase_test)
|
||||
{
|
||||
CPrefixTrie<std::string, CClaimTrieData> root;
|
||||
|
||||
BOOST_CHECK(root.empty());
|
||||
BOOST_CHECK_EQUAL(root.height(), 0);
|
||||
|
||||
CClaimTrieData data;
|
||||
data.insertClaim(CClaimValue{});
|
||||
BOOST_CHECK(root.insert("abc", std::move(data)) != root.end());
|
||||
BOOST_CHECK_EQUAL(root.height(), 1);
|
||||
|
||||
data.insertClaim(CClaimValue{});
|
||||
BOOST_CHECK(root.insert("abd", std::move(data)) != root.end());
|
||||
BOOST_CHECK_EQUAL(root.height(), 3);
|
||||
|
||||
// test expanding on ab
|
||||
BOOST_CHECK(root.find("ab") != root.end());
|
||||
|
||||
data.insertClaim(CClaimValue{});
|
||||
BOOST_CHECK(root.insert("a", std::move(data)) != root.end());
|
||||
BOOST_CHECK_EQUAL(root.height(), 4);
|
||||
|
||||
// test ab again
|
||||
BOOST_CHECK(root.find("ab") != root.end());
|
||||
|
||||
BOOST_CHECK(root.erase("abd"));
|
||||
BOOST_CHECK(root.find("abd") == root.end());
|
||||
BOOST_CHECK_EQUAL(root.height(), 2);
|
||||
|
||||
// collapsing of ab-c to abc so ab does not present any more
|
||||
BOOST_CHECK(root.find("ab") == root.end());
|
||||
|
||||
// a has children so only data is erased
|
||||
BOOST_CHECK(root.erase("a"));
|
||||
BOOST_CHECK(root.find("a") == root.end());
|
||||
|
||||
// erasing abc will erase all node refers to a
|
||||
BOOST_CHECK(root.erase("abc"));
|
||||
BOOST_CHECK(root.empty());
|
||||
BOOST_CHECK_EQUAL(root.height(), 0);
|
||||
BOOST_CHECK(root.find("a") == root.end());
|
||||
BOOST_CHECK(root.find("ab") == root.end());
|
||||
BOOST_CHECK(root.find("abc") == root.end());
|
||||
BOOST_CHECK(root.find("abd") == root.end());
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(iterate_test)
|
||||
{
|
||||
CPrefixTrie<std::string, CClaimTrieData> root;
|
||||
|
||||
BOOST_CHECK(root.empty());
|
||||
BOOST_CHECK_EQUAL(root.height(), 0);
|
||||
|
||||
BOOST_CHECK(root.insert("abc", CClaimTrieData{}) != root.end());
|
||||
BOOST_CHECK_EQUAL(root.height(), 1);
|
||||
|
||||
BOOST_CHECK(root.insert("abd", CClaimTrieData{}) != root.end());
|
||||
BOOST_CHECK_EQUAL(root.height(), 3);
|
||||
|
||||
BOOST_CHECK(root.insert("tdb", CClaimTrieData{}) != root.end());
|
||||
BOOST_CHECK_EQUAL(root.height(), 4);
|
||||
|
||||
for (auto it = root.begin(); it != root.end(); ++it) {
|
||||
auto& key = it.key();
|
||||
if (key.empty() ||
|
||||
key == "ab" ||
|
||||
key == "abc" ||
|
||||
key == "abd" ||
|
||||
key == "tdb") {
|
||||
} else {
|
||||
BOOST_CHECK(false); // should not happen
|
||||
}
|
||||
}
|
||||
|
||||
auto nodes = root.nodes("abd");
|
||||
BOOST_CHECK_EQUAL(nodes.size(), 3);
|
||||
|
||||
BOOST_CHECK_EQUAL(nodes[0].key(), "");
|
||||
BOOST_CHECK(nodes[0].hasChildren());
|
||||
BOOST_CHECK_EQUAL(nodes[0].children().size(), 2);
|
||||
|
||||
// children of ""
|
||||
for (auto& child : nodes[0].children()) {
|
||||
auto& key = child.key();
|
||||
if (key == "ab" || key == "tdb") {
|
||||
} else {
|
||||
BOOST_CHECK(false); // should not happen
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_CHECK_EQUAL(nodes[1].key(), "ab");
|
||||
BOOST_CHECK(nodes[1].hasChildren());
|
||||
BOOST_CHECK_EQUAL(nodes[1].children().size(), 2);
|
||||
|
||||
// children of "ab"
|
||||
for (auto& child : nodes[1].children()) {
|
||||
auto& key = child.key();
|
||||
if (key == "abc" || key == "abd") {
|
||||
} else {
|
||||
BOOST_CHECK(false); // should not happen
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_CHECK_EQUAL(nodes[2].key(), "abd");
|
||||
BOOST_CHECK(!nodes[2].hasChildren());
|
||||
BOOST_CHECK_EQUAL(nodes[2].children().size(), 0);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(erase_cleanup_test)
|
||||
{
|
||||
CPrefixTrie<std::string, CClaimTrieData> root;
|
||||
|
||||
CClaimTrieData data;
|
||||
data.insertClaim(CClaimValue{});
|
||||
BOOST_CHECK(root.insert("a", std::move(data)) != root.end());
|
||||
data.insertClaim(CClaimValue{});
|
||||
BOOST_CHECK(root.insert("adata", std::move(data)) != root.end());
|
||||
data.insertClaim(CClaimValue{});
|
||||
BOOST_CHECK(root.insert("adata2", std::move(data)) != root.end());
|
||||
data.insertClaim(CClaimValue{});
|
||||
BOOST_CHECK(root.insert("adota", std::move(data)) != root.end());
|
||||
BOOST_CHECK_EQUAL(root.height(), 5);
|
||||
BOOST_CHECK(root.erase("adata"));
|
||||
BOOST_CHECK(root.erase("adata2"));
|
||||
BOOST_CHECK_EQUAL(root.height(), 2);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(add_many_nodes) {
|
||||
// this if for testing performance and making sure erasure goes all the way to zero
|
||||
CPrefixTrie<std::string, CClaimTrieData> trie;
|
||||
std::size_t count = 100000; // bump this up to 1M for a better test
|
||||
auto strings = random_strings(count);
|
||||
|
||||
auto s1 = std::chrono::high_resolution_clock::now();
|
||||
for (std::size_t i = 0; i < count; i++) {
|
||||
CClaimTrieData d; d.nHeightOfLastTakeover = i;
|
||||
trie.insert(strings[i], std::move(d));
|
||||
}
|
||||
|
||||
auto s2 = std::chrono::high_resolution_clock::now();
|
||||
|
||||
auto nodes = trie.height();
|
||||
// run with --log_level=message to see these:
|
||||
BOOST_TEST_MESSAGE("Nodes:" + std::to_string(nodes));
|
||||
BOOST_TEST_MESSAGE("Insertion sec: " + std::to_string(std::chrono::duration_cast<std::chrono::duration<float> >(s2 - s1).count()));
|
||||
|
||||
auto s3 = std::chrono::high_resolution_clock::now();
|
||||
|
||||
for (std::size_t i = 0; i < count; i++) {
|
||||
auto& value = trie.at(strings[i]);
|
||||
BOOST_CHECK_EQUAL(value.nHeightOfLastTakeover, i);
|
||||
}
|
||||
|
||||
auto s4 = std::chrono::high_resolution_clock::now();
|
||||
BOOST_TEST_MESSAGE("Lookup sec: " + std::to_string(std::chrono::duration_cast<std::chrono::duration<float> >(s4 - s3).count()));
|
||||
|
||||
auto s5 = std::chrono::high_resolution_clock::now();
|
||||
|
||||
for (std::size_t i = 0; i < count; i++) {
|
||||
auto value = trie.nodes(strings[i]);
|
||||
BOOST_CHECK(!value.empty());
|
||||
}
|
||||
|
||||
auto s6 = std::chrono::high_resolution_clock::now();
|
||||
BOOST_TEST_MESSAGE("Parents sec: " + std::to_string(std::chrono::duration_cast<std::chrono::duration<float> >(s6 - s5).count()));
|
||||
|
||||
auto s7 = std::chrono::high_resolution_clock::now();
|
||||
for (std::size_t i = 0; i < count; i++) {
|
||||
trie.erase(strings[i]);
|
||||
}
|
||||
|
||||
BOOST_CHECK_EQUAL(trie.height(), 0);
|
||||
|
||||
auto s8 = std::chrono::high_resolution_clock::now();
|
||||
BOOST_TEST_MESSAGE("Deletion sec: " + std::to_string(std::chrono::duration_cast<std::chrono::duration<float> >(s8 - s7).count()));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END()
|
|
@ -61,12 +61,6 @@ std::ostream& operator<<(std::ostream& os, const COutPoint& point)
|
|||
return os;
|
||||
}
|
||||
|
||||
std::ostream& operator<<(std::ostream& os, const CClaimTrieData& data)
|
||||
{
|
||||
os << data.hash.ToString();
|
||||
return os;
|
||||
}
|
||||
|
||||
std::ostream& operator<<(std::ostream& os, const CClaimValue& claim)
|
||||
{
|
||||
os << "claim(" << claim.outPoint.ToString()
|
||||
|
|
|
@ -140,7 +140,4 @@ std::ostream& operator<<(std::ostream& os, const CClaimValue& claim);
|
|||
struct CSupportValue;
|
||||
std::ostream& operator<<(std::ostream& os, const CSupportValue& support);
|
||||
|
||||
struct CClaimTrieData;
|
||||
std::ostream& operator<<(std::ostream& os, const CClaimTrieData& data);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1562,8 +1562,6 @@ DisconnectResult CChainState::DisconnectBlock(const CBlock& block, const CBlockI
|
|||
assert(trieCache.finalizeDecrement(blockUndo.takeoverHeightUndo));
|
||||
auto merkleHash = trieCache.getMerkleHash();
|
||||
if (merkleHash != pindex->pprev->hashClaimTrie) {
|
||||
if (!trieCache.empty())
|
||||
trieCache.dumpToLog(trieCache.find({}));
|
||||
LogPrintf("Hash comparison failure at block %d\n", pindex->nHeight);
|
||||
assert(merkleHash == pindex->pprev->hashClaimTrie);
|
||||
}
|
||||
|
@ -2040,8 +2038,6 @@ bool CChainState::ConnectBlock(const CBlock& block, CValidationState& state, CBl
|
|||
|
||||
if (trieCache.getMerkleHash() != block.hashClaimTrie)
|
||||
{
|
||||
if (!trieCache.empty()) // we could run checkConsistency here, but it would take a while
|
||||
trieCache.dumpToLog(trieCache.find({}));
|
||||
return state.DoS(100, error("ConnectBlock() : the merkle root of the claim trie does not match "
|
||||
"(actual=%s vs block=%s on height=%d)", trieCache.getMerkleHash().GetHex(),
|
||||
block.hashClaimTrie.GetHex(), pindex->nHeight), REJECT_INVALID, "bad-claim-merkle-hash");
|
||||
|
|
Loading…
Reference in a new issue